blob: 92d9dc0df921abb4977ef070ffcbc826dd3a51c4 [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'
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +030064U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
65U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
66U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glass303f62f2019-05-17 22:00:46 -060067FSP_DATA = b'fsp'
68CMC_DATA = b'cmc'
69VBT_DATA = b'vbt'
70MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060071TEXT_DATA = 'text'
72TEXT_DATA2 = 'text2'
73TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060074CROS_EC_RW_DATA = b'ecrw'
75GBB_DATA = b'gbbd'
76BMPBLK_DATA = b'bmp'
77VBLOCK_DATA = b'vblk'
78FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
79 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060080COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060081COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060082REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060083FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060084FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060085FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060086ATF_BL31_DATA = b'bl31'
Roger Quadros5cdcea02022-02-19 20:50:04 +020087TEE_OS_DATA = b'this is some tee OS data'
Simon Glass3efb2972021-11-23 21:08:59 -070088ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080089OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050090SCP_DATA = b'scp'
Simon Glassa435cd12020-09-01 05:13:59 -060091TEST_FDT1_DATA = b'fdt1'
92TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060093ENV_DATA = b'var1=1\nvar2="2"'
Simon Glassa435cd12020-09-01 05:13:59 -060094
95# Subdirectory of the input dir to use to put test FDTs
96TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -060097
Simon Glass2c6adba2019-07-20 12:23:47 -060098# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -060099EXTRACT_DTB_SIZE = 0x3c9
100
Simon Glass2c6adba2019-07-20 12:23:47 -0600101# Properties expected to be in the device tree when update_dtb is used
102BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
103
Simon Glassfb30e292019-07-20 12:23:51 -0600104# Extra properties expected to be in the device tree when allow-repack is used
105REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
106
Simon Glass57454f42016-11-25 20:15:52 -0700107
108class TestFunctional(unittest.TestCase):
109 """Functional tests for binman
110
111 Most of these use a sample .dts file to build an image and then check
112 that it looks correct. The sample files are in the test/ subdirectory
113 and are numbered.
114
115 For each entry type a very small test file is created using fixed
116 string contents. This makes it easy to test that things look right, and
117 debug problems.
118
119 In some cases a 'real' file must be used - these are also supplied in
120 the test/ diurectory.
121 """
122 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600123 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700124 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600125 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700126
Simon Glass57454f42016-11-25 20:15:52 -0700127 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600128 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
129 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700130
131 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600132 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700133
134 # Create some test files
135 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
136 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
137 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600138 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700139 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700140 TestFunctional._MakeInputFile('me.bin', ME_DATA)
141 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600142 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600143
Jagdish Gediya311d4842018-09-03 21:35:08 +0530144 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600145
Simon Glassabab18c2019-08-24 07:22:49 -0600146 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
147 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700148 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600149 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600150 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600151
152 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
153 X86_RESET16_DATA)
154 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
155 X86_RESET16_SPL_DATA)
156 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
157 X86_RESET16_TPL_DATA)
158
Simon Glass57454f42016-11-25 20:15:52 -0700159 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700160 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
161 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600162 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
163 U_BOOT_TPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700164 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
165 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700166 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700167 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600168 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600169 TestFunctional._MakeInputDir('devkeys')
170 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600171 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600172 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600173 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600174 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700175
Simon Glassf6290892019-08-24 07:22:53 -0600176 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
177 elf_test.BuildElfTestFiles(cls._elf_testdir)
178
Simon Glass72232452016-11-25 20:15:53 -0700179 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600180 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700181 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700182
183 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600184 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700185
Simon Glass862f8e22019-08-24 07:22:43 -0600186 shutil.copytree(cls.TestFile('files'),
187 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600188
Simon Glass7ba33592018-09-14 04:57:26 -0600189 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600190 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600191 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200192 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700193 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800194 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500195 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600196
Simon Glassa435cd12020-09-01 05:13:59 -0600197 # Add a few .dtb files for testing
198 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
199 TEST_FDT1_DATA)
200 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
201 TEST_FDT2_DATA)
202
Simon Glassa0729502020-09-06 10:35:33 -0600203 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
204
Simon Glass9203c162022-01-09 20:14:06 -0700205 cls.have_lz4 = comp_util.HAVE_LZ4
Simon Glass1de34482019-07-08 13:18:53 -0600206
Simon Glass57454f42016-11-25 20:15:52 -0700207 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600208 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700209 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600210 if cls.preserve_indir:
211 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600212 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600213 if cls._indir:
214 shutil.rmtree(cls._indir)
215 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700216
Simon Glass1c420c92019-07-08 13:18:49 -0600217 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600218 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600219 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600220 """Accept arguments controlling test execution
221
222 Args:
223 preserve_indir: Preserve the shared input directory used by all
224 tests in this class.
225 preserve_outdir: Preserve the output directories used by tests. Each
226 test has its own, so this is normally only useful when running a
227 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600228 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600229 """
230 cls.preserve_indir = preserve_indir
231 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600232 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600233 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600234
Simon Glass1de34482019-07-08 13:18:53 -0600235 def _CheckLz4(self):
236 if not self.have_lz4:
237 self.skipTest('lz4 --no-frame-crc not available')
238
Simon Glassee9d10d2019-07-20 12:24:09 -0600239 def _CleanupOutputDir(self):
240 """Remove the temporary output directory"""
241 if self.preserve_outdirs:
242 print('Preserving output dir: %s' % tools.outdir)
243 else:
Simon Glass80025522022-01-29 14:14:04 -0700244 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600245
Simon Glass57454f42016-11-25 20:15:52 -0700246 def setUp(self):
247 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700248 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700249 command.test_result = None
250
251 def tearDown(self):
252 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600253 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700254
Simon Glassb3d6fc72019-07-20 12:24:10 -0600255 def _SetupImageInTmpdir(self):
256 """Set up the output image in a new temporary directory
257
258 This is used when an image has been generated in the output directory,
259 but we want to run binman again. This will create a new output
260 directory and fail to delete the original one.
261
262 This creates a new temporary directory, copies the image to it (with a
263 new name) and removes the old output directory.
264
265 Returns:
266 Tuple:
267 Temporary directory to use
268 New image filename
269 """
Simon Glass80025522022-01-29 14:14:04 -0700270 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600271 tmpdir = tempfile.mkdtemp(prefix='binman.')
272 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700273 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600274 self._CleanupOutputDir()
275 return tmpdir, updated_fname
276
Simon Glass8425a1f2018-07-17 13:25:48 -0600277 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600278 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600279 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
280 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
281 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
282
Simon Glass57454f42016-11-25 20:15:52 -0700283 def _RunBinman(self, *args, **kwargs):
284 """Run binman using the command line
285
286 Args:
287 Arguments to pass, as a list of strings
288 kwargs: Arguments to pass to Command.RunPipe()
289 """
Simon Glass840be732022-01-29 14:14:05 -0700290 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700291 capture=True, capture_stderr=True, raise_on_error=False)
292 if result.return_code and kwargs.get('raise_on_error', True):
293 raise Exception("Error running '%s': %s" % (' '.join(args),
294 result.stdout + result.stderr))
295 return result
296
Simon Glassf46732a2019-07-08 14:25:29 -0600297 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700298 """Run binman using directly (in the same process)
299
300 Args:
301 Arguments to pass, as a list of strings
302 Returns:
303 Return value (0 for success)
304 """
Simon Glassf46732a2019-07-08 14:25:29 -0600305 argv = list(argv)
306 args = cmdline.ParseArgs(argv)
307 args.pager = 'binman-invalid-pager'
308 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700309
310 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600311 # args.verbosity = tout.DEBUG
312 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700313
Simon Glass91710b32018-07-17 13:25:32 -0600314 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600315 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300316 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100317 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700318 test_section_timeout=False, update_fdt_in_elf=None,
319 force_missing_bintools=''):
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 Glass66152ce2022-01-09 20:14:09 -0700348 force_missing_tools (str): comma-separated list of bintools to
349 regard as missing
Simon Glass9a798402021-11-03 21:09:17 -0600350
351 Returns:
352 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700353 """
Simon Glassf46732a2019-07-08 14:25:29 -0600354 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700355 if debug:
356 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600357 if verbosity is not None:
358 args.append('-v%d' % verbosity)
359 elif self.verbosity:
360 args.append('-v%d' % self.verbosity)
361 if self.toolpath:
362 for path in self.toolpath:
363 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600364 if threads is not None:
365 args.append('-T%d' % threads)
366 if test_section_timeout:
367 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600368 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600369 if map:
370 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600371 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600372 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600373 if not use_real_dtb:
374 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300375 if not use_expanded:
376 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600377 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600378 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600379 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600380 if allow_missing:
381 args.append('-M')
Heiko Thiery6d451362022-01-06 11:49:41 +0100382 if allow_fake_blobs:
383 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700384 if force_missing_bintools:
385 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600386 if update_fdt_in_elf:
387 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600388 if images:
389 for image in images:
390 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600391 if extra_indirs:
392 for indir in extra_indirs:
393 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700394 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700395
396 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700397 """Set up a new test device-tree file
398
399 The given file is compiled and set up as the device tree to be used
400 for ths test.
401
402 Args:
403 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600404 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700405
406 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600407 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700408 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600409 tmpdir = tempfile.mkdtemp(prefix='binmant.')
410 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600411 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700412 data = fd.read()
413 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600414 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600415 return data
Simon Glass57454f42016-11-25 20:15:52 -0700416
Simon Glasse219aa42018-09-14 04:57:24 -0600417 def _GetDtbContentsForSplTpl(self, dtb_data, name):
418 """Create a version of the main DTB for SPL or SPL
419
420 For testing we don't actually have different versions of the DTB. With
421 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
422 we don't normally have any unwanted nodes.
423
424 We still want the DTBs for SPL and TPL to be different though, since
425 otherwise it is confusing to know which one we are looking at. So add
426 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600427
428 Args:
429 dtb_data: dtb data to modify (this should be a value devicetree)
430 name: Name of a new property to add
431
432 Returns:
433 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600434 """
435 dtb = fdt.Fdt.FromData(dtb_data)
436 dtb.Scan()
437 dtb.GetNode('/binman').AddZeroProp(name)
438 dtb.Sync(auto_resize=True)
439 dtb.Pack()
440 return dtb.GetContents()
441
Simon Glassed930672021-03-18 20:25:05 +1300442 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
443 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600444 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700445 """Run binman and return the resulting image
446
447 This runs binman with a given test file and then reads the resulting
448 output file. It is a shortcut function since most tests need to do
449 these steps.
450
451 Raises an assertion failure if binman returns a non-zero exit code.
452
453 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600454 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700455 use_real_dtb: True to use the test file as the contents of
456 the u-boot-dtb entry. Normally this is not needed and the
457 test contents (the U_BOOT_DTB_DATA string) can be used.
458 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300459 use_expanded: True to use expanded entries where available, e.g.
460 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600461 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600462 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600463 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600464 entry_args: Dict of entry args to supply to binman
465 key: arg name
466 value: value of that arg
467 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
468 function. If reset_dtbs is True, then the original test dtb
469 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600470 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600471 threads: Number of threads to use (None for default, 0 for
472 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700473
474 Returns:
475 Tuple:
476 Resulting image contents
477 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600478 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600479 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700480 """
Simon Glass72232452016-11-25 20:15:53 -0700481 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700482 # Use the compiled test file as the u-boot-dtb input
483 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700484 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600485
486 # For testing purposes, make a copy of the DT for SPL and TPL. Add
487 # a node indicating which it is, so aid verification.
488 for name in ['spl', 'tpl']:
489 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
490 outfile = os.path.join(self._indir, dtb_fname)
491 TestFunctional._MakeInputFile(dtb_fname,
492 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700493
494 try:
Simon Glass91710b32018-07-17 13:25:32 -0600495 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600496 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600497 use_expanded=use_expanded, extra_indirs=extra_indirs,
498 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700499 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700500 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700501
502 # Find the (only) image, read it and return its contents
503 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700504 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600505 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600506 if map:
Simon Glass80025522022-01-29 14:14:04 -0700507 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600508 with open(map_fname) as fd:
509 map_data = fd.read()
510 else:
511 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600512 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600513 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700514 finally:
515 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600516 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600517 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700518
Simon Glass5b4bce32019-07-08 14:25:26 -0600519 def _DoReadFileRealDtb(self, fname):
520 """Run binman with a real .dtb file and return the resulting data
521
522 Args:
523 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
524
525 Returns:
526 Resulting image contents
527 """
528 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
529
Simon Glass72232452016-11-25 20:15:53 -0700530 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600531 """Helper function which discards the device-tree binary
532
533 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600534 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600535 use_real_dtb: True to use the test file as the contents of
536 the u-boot-dtb entry. Normally this is not needed and the
537 test contents (the U_BOOT_DTB_DATA string) can be used.
538 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600539
540 Returns:
541 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600542 """
Simon Glass72232452016-11-25 20:15:53 -0700543 return self._DoReadFileDtb(fname, use_real_dtb)[0]
544
Simon Glass57454f42016-11-25 20:15:52 -0700545 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600546 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700547 """Create a new test input file, creating directories as needed
548
549 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600550 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700551 contents: File contents to write in to the file
552 Returns:
553 Full pathname of file created
554 """
Simon Glass862f8e22019-08-24 07:22:43 -0600555 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700556 dirname = os.path.dirname(pathname)
557 if dirname and not os.path.exists(dirname):
558 os.makedirs(dirname)
559 with open(pathname, 'wb') as fd:
560 fd.write(contents)
561 return pathname
562
563 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600564 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600565 """Create a new test input directory, creating directories as needed
566
567 Args:
568 dirname: Directory name to create
569
570 Returns:
571 Full pathname of directory created
572 """
Simon Glass862f8e22019-08-24 07:22:43 -0600573 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600574 if not os.path.exists(pathname):
575 os.makedirs(pathname)
576 return pathname
577
578 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600579 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600580 """Set up an ELF file with a '_dt_ucode_base_size' symbol
581
582 Args:
583 Filename of ELF file to use as SPL
584 """
Simon Glass93a806f2019-08-24 07:22:59 -0600585 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700586 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600587
588 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600589 def _SetupTplElf(cls, src_fname='bss_data'):
590 """Set up an ELF file with a '_dt_ucode_base_size' symbol
591
592 Args:
593 Filename of ELF file to use as TPL
594 """
595 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700596 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600597
598 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600599 def _SetupDescriptor(cls):
600 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
601 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
602
603 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600604 def TestFile(cls, fname):
605 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700606
Simon Glassf6290892019-08-24 07:22:53 -0600607 @classmethod
608 def ElfTestFile(cls, fname):
609 return os.path.join(cls._elf_testdir, fname)
610
Simon Glass57454f42016-11-25 20:15:52 -0700611 def AssertInList(self, grep_list, target):
612 """Assert that at least one of a list of things is in a target
613
614 Args:
615 grep_list: List of strings to check
616 target: Target string
617 """
618 for grep in grep_list:
619 if grep in target:
620 return
Simon Glass848cdb52019-05-17 22:00:50 -0600621 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700622
623 def CheckNoGaps(self, entries):
624 """Check that all entries fit together without gaps
625
626 Args:
627 entries: List of entries to check
628 """
Simon Glasse8561af2018-08-01 15:22:37 -0600629 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700630 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600631 self.assertEqual(offset, entry.offset)
632 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700633
Simon Glass72232452016-11-25 20:15:53 -0700634 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600635 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700636
637 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600638 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700639
640 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600641 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700642 """
643 return struct.unpack('>L', dtb[4:8])[0]
644
Simon Glass0f621332019-07-08 14:25:27 -0600645 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600646 def AddNode(node, path):
647 if node.name != '/':
648 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600649 for prop in node.props.values():
650 if prop.name in prop_names:
651 prop_path = path + ':' + prop.name
652 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
653 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600654 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600655 AddNode(subnode, path)
656
657 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600658 AddNode(dtb.GetRoot(), '')
659 return tree
660
Simon Glass57454f42016-11-25 20:15:52 -0700661 def testRun(self):
662 """Test a basic run with valid args"""
663 result = self._RunBinman('-h')
664
665 def testFullHelp(self):
666 """Test that the full help is displayed with -H"""
667 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300668 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500669 # Remove possible extraneous strings
670 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
671 gothelp = result.stdout.replace(extra, '')
672 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700673 self.assertEqual(0, len(result.stderr))
674 self.assertEqual(0, result.return_code)
675
676 def testFullHelpInternal(self):
677 """Test that the full help is displayed with -H"""
678 try:
679 command.test_result = command.CommandResult()
680 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300681 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700682 finally:
683 command.test_result = None
684
685 def testHelp(self):
686 """Test that the basic help is displayed with -h"""
687 result = self._RunBinman('-h')
688 self.assertTrue(len(result.stdout) > 200)
689 self.assertEqual(0, len(result.stderr))
690 self.assertEqual(0, result.return_code)
691
Simon Glass57454f42016-11-25 20:15:52 -0700692 def testBoard(self):
693 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600694 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700695 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300696 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700697 self.assertEqual(0, result)
698
699 def testNeedBoard(self):
700 """Test that we get an error when no board ius supplied"""
701 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600702 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700703 self.assertIn("Must provide a board to process (use -b <board>)",
704 str(e.exception))
705
706 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600707 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700708 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600709 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700710 # We get one error from libfdt, and a different one from fdtget.
711 self.AssertInList(["Couldn't open blob from 'missing_file'",
712 'No such file or directory'], str(e.exception))
713
714 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600715 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700716
717 Since this is a source file it should be compiled and the error
718 will come from the device-tree compiler (dtc).
719 """
720 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600721 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700722 self.assertIn("FATAL ERROR: Unable to parse input tree",
723 str(e.exception))
724
725 def testMissingNode(self):
726 """Test that a device tree without a 'binman' node generates an error"""
727 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600728 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700729 self.assertIn("does not have a 'binman' node", str(e.exception))
730
731 def testEmpty(self):
732 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600733 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700734 self.assertEqual(0, len(result.stderr))
735 self.assertEqual(0, result.return_code)
736
737 def testInvalidEntry(self):
738 """Test that an invalid entry is flagged"""
739 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600740 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600741 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700742 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
743 "'/binman/not-a-valid-type'", str(e.exception))
744
745 def testSimple(self):
746 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600747 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700748 self.assertEqual(U_BOOT_DATA, data)
749
Simon Glass075a45c2017-11-13 18:55:00 -0700750 def testSimpleDebug(self):
751 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600752 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700753
Simon Glass57454f42016-11-25 20:15:52 -0700754 def testDual(self):
755 """Test that we can handle creating two images
756
757 This also tests image padding.
758 """
Simon Glass511f6582018-10-01 12:22:30 -0600759 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700760 self.assertEqual(0, retcode)
761
762 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600763 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700764 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700765 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600766 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700767 data = fd.read()
768 self.assertEqual(U_BOOT_DATA, data)
769
770 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600771 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700772 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700773 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600774 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700775 data = fd.read()
776 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700777 self.assertEqual(tools.get_bytes(0, 3), data[:3])
778 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700779
780 def testBadAlign(self):
781 """Test that an invalid alignment value is detected"""
782 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600783 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700784 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
785 "of two", str(e.exception))
786
787 def testPackSimple(self):
788 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600789 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700790 self.assertEqual(0, retcode)
791 self.assertIn('image', control.images)
792 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600793 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700794 self.assertEqual(5, len(entries))
795
796 # First u-boot
797 self.assertIn('u-boot', entries)
798 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600799 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700800 self.assertEqual(len(U_BOOT_DATA), entry.size)
801
802 # Second u-boot, aligned to 16-byte boundary
803 self.assertIn('u-boot-align', entries)
804 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600805 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700806 self.assertEqual(len(U_BOOT_DATA), entry.size)
807
808 # Third u-boot, size 23 bytes
809 self.assertIn('u-boot-size', entries)
810 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600811 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700812 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
813 self.assertEqual(23, entry.size)
814
815 # Fourth u-boot, placed immediate after the above
816 self.assertIn('u-boot-next', entries)
817 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600818 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700819 self.assertEqual(len(U_BOOT_DATA), entry.size)
820
Simon Glasse8561af2018-08-01 15:22:37 -0600821 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700822 self.assertIn('u-boot-fixed', entries)
823 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600824 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700825 self.assertEqual(len(U_BOOT_DATA), entry.size)
826
Simon Glass39dd2152019-07-08 14:25:47 -0600827 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700828
829 def testPackExtra(self):
830 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600831 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
832 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700833
Simon Glass57454f42016-11-25 20:15:52 -0700834 self.assertIn('image', control.images)
835 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600836 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700837 self.assertEqual(5, len(entries))
838
839 # First u-boot with padding before and after
840 self.assertIn('u-boot', entries)
841 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600842 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700843 self.assertEqual(3, entry.pad_before)
844 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600845 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700846 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
847 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600848 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700849
850 # Second u-boot has an aligned size, but it has no effect
851 self.assertIn('u-boot-align-size-nop', entries)
852 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600853 self.assertEqual(pos, entry.offset)
854 self.assertEqual(len(U_BOOT_DATA), entry.size)
855 self.assertEqual(U_BOOT_DATA, entry.data)
856 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
857 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700858
859 # Third u-boot has an aligned size too
860 self.assertIn('u-boot-align-size', entries)
861 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600862 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700863 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600864 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700865 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600866 data[pos:pos + entry.size])
867 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700868
869 # Fourth u-boot has an aligned end
870 self.assertIn('u-boot-align-end', entries)
871 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600872 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700873 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600874 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700875 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600876 data[pos:pos + entry.size])
877 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700878
879 # Fifth u-boot immediately afterwards
880 self.assertIn('u-boot-align-both', entries)
881 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600882 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700883 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600884 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700885 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600886 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700887
888 self.CheckNoGaps(entries)
Simon Glass39dd2152019-07-08 14:25:47 -0600889 self.assertEqual(128, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700890
Simon Glassafb9caa2020-10-26 17:40:10 -0600891 dtb = fdt.Fdt(out_dtb_fname)
892 dtb.Scan()
893 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
894 expected = {
895 'image-pos': 0,
896 'offset': 0,
897 'size': 128,
898
899 'u-boot:image-pos': 0,
900 'u-boot:offset': 0,
901 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
902
903 'u-boot-align-size-nop:image-pos': 12,
904 'u-boot-align-size-nop:offset': 12,
905 'u-boot-align-size-nop:size': 4,
906
907 'u-boot-align-size:image-pos': 16,
908 'u-boot-align-size:offset': 16,
909 'u-boot-align-size:size': 32,
910
911 'u-boot-align-end:image-pos': 48,
912 'u-boot-align-end:offset': 48,
913 'u-boot-align-end:size': 16,
914
915 'u-boot-align-both:image-pos': 64,
916 'u-boot-align-both:offset': 64,
917 'u-boot-align-both:size': 64,
918 }
919 self.assertEqual(expected, props)
920
Simon Glass57454f42016-11-25 20:15:52 -0700921 def testPackAlignPowerOf2(self):
922 """Test that invalid entry alignment is detected"""
923 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600924 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700925 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
926 "of two", str(e.exception))
927
928 def testPackAlignSizePowerOf2(self):
929 """Test that invalid entry size alignment is detected"""
930 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600931 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700932 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
933 "power of two", str(e.exception))
934
935 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600936 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700937 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600938 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600939 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700940 "align 0x4 (4)", str(e.exception))
941
942 def testPackInvalidSizeAlign(self):
943 """Test that invalid entry size alignment is detected"""
944 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600945 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700946 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
947 "align-size 0x4 (4)", str(e.exception))
948
949 def testPackOverlap(self):
950 """Test that overlapping regions are detected"""
951 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600952 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600953 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700954 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
955 str(e.exception))
956
957 def testPackEntryOverflow(self):
958 """Test that entries that overflow their size are detected"""
959 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600960 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700961 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
962 "but entry size is 0x3 (3)", str(e.exception))
963
964 def testPackImageOverflow(self):
965 """Test that entries which overflow the image size are detected"""
966 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600967 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600968 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -0700969 "size 0x3 (3)", str(e.exception))
970
971 def testPackImageSize(self):
972 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -0600973 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700974 self.assertEqual(0, retcode)
975 self.assertIn('image', control.images)
976 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600977 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700978
979 def testPackImageSizeAlign(self):
980 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600981 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700982 self.assertEqual(0, retcode)
983 self.assertIn('image', control.images)
984 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600985 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700986
987 def testPackInvalidImageAlign(self):
988 """Test that invalid image alignment is detected"""
989 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600990 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600991 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700992 "align-size 0x8 (8)", str(e.exception))
993
Simon Glass2a0fa982022-02-11 13:23:21 -0700994 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -0700995 """Test that invalid image alignment is detected"""
996 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600997 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -0600998 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -0700999 "two", str(e.exception))
1000
1001 def testImagePadByte(self):
1002 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001003 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001004 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001005 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001006 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001007
1008 def testImageName(self):
1009 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001010 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001011 self.assertEqual(0, retcode)
1012 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001013 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001014 self.assertTrue(os.path.exists(fname))
1015
1016 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001017 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001018 self.assertTrue(os.path.exists(fname))
1019
1020 def testBlobFilename(self):
1021 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001022 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001023 self.assertEqual(BLOB_DATA, data)
1024
1025 def testPackSorted(self):
1026 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001027 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001028 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001029 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1030 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001031
Simon Glasse8561af2018-08-01 15:22:37 -06001032 def testPackZeroOffset(self):
1033 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -07001034 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001035 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001036 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001037 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1038 str(e.exception))
1039
1040 def testPackUbootDtb(self):
1041 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001042 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001043 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001044
1045 def testPackX86RomNoSize(self):
1046 """Test that the end-at-4gb property requires a size property"""
1047 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001048 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001049 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001050 "using end-at-4gb", str(e.exception))
1051
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301052 def test4gbAndSkipAtStartTogether(self):
1053 """Test that the end-at-4gb and skip-at-size property can't be used
1054 together"""
1055 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001056 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001057 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301058 "'skip-at-start'", str(e.exception))
1059
Simon Glass72232452016-11-25 20:15:53 -07001060 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001061 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -07001062 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001063 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001064 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1065 "is outside the section '/binman' starting at "
1066 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001067 str(e.exception))
1068
1069 def testPackX86Rom(self):
1070 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001071 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001072 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001073 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1074 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001075
1076 def testPackX86RomMeNoDesc(self):
1077 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001078 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001079 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001080 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001081 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001082 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1083 str(e.exception))
1084 finally:
1085 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001086
1087 def testPackX86RomBadDesc(self):
1088 """Test that the Intel requires a descriptor entry"""
1089 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001090 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001091 self.assertIn("Node '/binman/intel-me': No offset set with "
1092 "offset-unset: should another entry provide this correct "
1093 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001094
1095 def testPackX86RomMe(self):
1096 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001097 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001098 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001099 if data[:0x1000] != expected_desc:
1100 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001101 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1102
1103 def testPackVga(self):
1104 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001105 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001106 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1107
1108 def testPackStart16(self):
1109 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001110 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001111 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1112
Jagdish Gediya311d4842018-09-03 21:35:08 +05301113 def testPackPowerpcMpc85xxBootpgResetvec(self):
1114 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1115 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001116 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301117 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1118
Simon Glass6ba679c2018-07-06 10:27:17 -06001119 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001120 """Handle running a test for insertion of microcode
1121
1122 Args:
1123 dts_fname: Name of test .dts file
1124 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001125 ucode_second: True if the microsecond entry is second instead of
1126 third
Simon Glass820af1d2018-07-06 10:27:16 -06001127
1128 Returns:
1129 Tuple:
1130 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001131 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001132 in the above (two 4-byte words)
1133 """
Simon Glass3d274232017-11-12 21:52:27 -07001134 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001135
1136 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001137 if ucode_second:
1138 ucode_content = data[len(nodtb_data):]
1139 ucode_pos = len(nodtb_data)
1140 dtb_with_ucode = ucode_content[16:]
1141 fdt_len = self.GetFdtLen(dtb_with_ucode)
1142 else:
1143 dtb_with_ucode = data[len(nodtb_data):]
1144 fdt_len = self.GetFdtLen(dtb_with_ucode)
1145 ucode_content = dtb_with_ucode[fdt_len:]
1146 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001147 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001148 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001149 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001150 dtb = fdt.FdtScan(fname)
1151 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001152 self.assertTrue(ucode)
1153 for node in ucode.subnodes:
1154 self.assertFalse(node.props.get('data'))
1155
Simon Glass72232452016-11-25 20:15:53 -07001156 # Check that the microcode appears immediately after the Fdt
1157 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001158 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001159 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1160 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001161 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001162
1163 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001164 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001165 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1166 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001167 u_boot = data[:len(nodtb_data)]
1168 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001169
1170 def testPackUbootMicrocode(self):
1171 """Test that x86 microcode can be handled correctly
1172
1173 We expect to see the following in the image, in order:
1174 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1175 place
1176 u-boot.dtb with the microcode removed
1177 the microcode
1178 """
Simon Glass511f6582018-10-01 12:22:30 -06001179 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001180 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001181 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1182 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001183
Simon Glassbac25c82017-05-27 07:38:26 -06001184 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001185 """Test that x86 microcode can be handled correctly
1186
1187 We expect to see the following in the image, in order:
1188 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1189 place
1190 u-boot.dtb with the microcode
1191 an empty microcode region
1192 """
1193 # We need the libfdt library to run this test since only that allows
1194 # finding the offset of a property. This is required by
1195 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001196 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001197
1198 second = data[len(U_BOOT_NODTB_DATA):]
1199
1200 fdt_len = self.GetFdtLen(second)
1201 third = second[fdt_len:]
1202 second = second[:fdt_len]
1203
Simon Glassbac25c82017-05-27 07:38:26 -06001204 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1205 self.assertIn(ucode_data, second)
1206 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001207
Simon Glassbac25c82017-05-27 07:38:26 -06001208 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001209 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001210 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1211 len(ucode_data))
1212 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001213 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1214 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001215
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001216 def testPackUbootSingleMicrocode(self):
1217 """Test that x86 microcode can be handled correctly with fdt_normal.
1218 """
Simon Glassbac25c82017-05-27 07:38:26 -06001219 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001220
Simon Glass996021e2016-11-25 20:15:54 -07001221 def testUBootImg(self):
1222 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001223 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001224 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001225
1226 def testNoMicrocode(self):
1227 """Test that a missing microcode region is detected"""
1228 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001229 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001230 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1231 "node found in ", str(e.exception))
1232
1233 def testMicrocodeWithoutNode(self):
1234 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1235 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001236 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001237 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1238 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1239
1240 def testMicrocodeWithoutNode2(self):
1241 """Test that a missing u-boot-ucode node is detected"""
1242 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001243 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001244 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1245 "microcode region u-boot-ucode", str(e.exception))
1246
1247 def testMicrocodeWithoutPtrInElf(self):
1248 """Test that a U-Boot binary without the microcode symbol is detected"""
1249 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001250 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001251 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001252 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001253
1254 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001255 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001256 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1257 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1258
1259 finally:
1260 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001261 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001262 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001263
1264 def testMicrocodeNotInImage(self):
1265 """Test that microcode must be placed within the image"""
1266 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001267 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001268 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1269 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001270 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001271
1272 def testWithoutMicrocode(self):
1273 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001274 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001275 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001276 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001277
1278 # Now check the device tree has no microcode
1279 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1280 second = data[len(U_BOOT_NODTB_DATA):]
1281
1282 fdt_len = self.GetFdtLen(second)
1283 self.assertEqual(dtb, second[:fdt_len])
1284
1285 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1286 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001287 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001288
1289 def testUnknownPosSize(self):
1290 """Test that microcode must be placed within the image"""
1291 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001292 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001293 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001294 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001295
1296 def testPackFsp(self):
1297 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001298 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001299 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1300
1301 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001302 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001303 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001304 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001305
1306 def testPackVbt(self):
1307 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001308 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001309 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001310
Simon Glass7f94e832017-11-12 21:52:25 -07001311 def testSplBssPad(self):
1312 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001313 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001314 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001315 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001316 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001317 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001318
Simon Glass04cda032018-10-01 21:12:42 -06001319 def testSplBssPadMissing(self):
1320 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001321 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001322 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001323 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001324 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1325 str(e.exception))
1326
Simon Glasse83679d2017-11-12 21:52:26 -07001327 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001328 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001329 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001330 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1331
Simon Glass6ba679c2018-07-06 10:27:17 -06001332 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1333 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001334
1335 We expect to see the following in the image, in order:
1336 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1337 correct place
1338 u-boot.dtb with the microcode removed
1339 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001340
1341 Args:
1342 dts: Device tree file to use for test
1343 ucode_second: True if the microsecond entry is second instead of
1344 third
Simon Glass3d274232017-11-12 21:52:27 -07001345 """
Simon Glass7057d022018-10-01 21:12:47 -06001346 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001347 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1348 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001349 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1350 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001351
Simon Glass6ba679c2018-07-06 10:27:17 -06001352 def testPackUbootSplMicrocode(self):
1353 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001354 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001355
1356 def testPackUbootSplMicrocodeReorder(self):
1357 """Test that order doesn't matter for microcode entries
1358
1359 This is the same as testPackUbootSplMicrocode but when we process the
1360 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1361 entry, so we reply on binman to try later.
1362 """
Simon Glass511f6582018-10-01 12:22:30 -06001363 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001364 ucode_second=True)
1365
Simon Glassa409c932017-11-12 21:52:28 -07001366 def testPackMrc(self):
1367 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001368 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001369 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1370
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001371 def testSplDtb(self):
1372 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001373 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001374 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1375
Simon Glass0a6da312017-11-13 18:54:56 -07001376 def testSplNoDtb(self):
1377 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001378 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001379 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001380 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1381
Simon Glass7098b7f2021-03-21 18:24:30 +13001382 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1383 use_expanded=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001384 """Check the image contains the expected symbol values
1385
1386 Args:
1387 dts: Device tree file to use for test
1388 base_data: Data before and after 'u-boot' section
1389 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001390 entry_args: Dict of entry args to supply to binman
1391 key: arg name
1392 value: value of that arg
1393 use_expanded: True to use expanded entries where available, e.g.
1394 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001395 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001396 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001397 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1398 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass31e04cb2021-03-18 20:24:56 +13001399 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1400 addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001401
Simon Glass7057d022018-10-01 21:12:47 -06001402 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001403 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1404 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001405 # The image should contain the symbols from u_boot_binman_syms.c
1406 # Note that image_pos is adjusted by the base address of the image,
1407 # which is 0x10 in our test image
1408 sym_values = struct.pack('<LQLL', 0x00,
1409 u_boot_offset + len(U_BOOT_DATA),
1410 0x10 + u_boot_offset, 0x04)
1411 expected = (sym_values + base_data[20:] +
Simon Glass80025522022-01-29 14:14:04 -07001412 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glass31e04cb2021-03-18 20:24:56 +13001413 base_data[20:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001414 self.assertEqual(expected, data)
1415
Simon Glass31e04cb2021-03-18 20:24:56 +13001416 def testSymbols(self):
1417 """Test binman can assign symbols embedded in U-Boot"""
1418 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1419
1420 def testSymbolsNoDtb(self):
1421 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001422 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001423 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1424 0x38)
1425
Simon Glasse76a3e62018-06-01 09:38:11 -06001426 def testPackUnitAddress(self):
1427 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001428 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001429 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1430
Simon Glassa91e1152018-06-01 09:38:16 -06001431 def testSections(self):
1432 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001433 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001434 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1435 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1436 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001437 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001438
Simon Glass30732662018-06-01 09:38:20 -06001439 def testMap(self):
1440 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001441 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001442 self.assertEqual('''ImagePos Offset Size Name
144300000000 00000000 00000028 main-section
144400000000 00000000 00000010 section@0
144500000000 00000000 00000004 u-boot
144600000010 00000010 00000010 section@1
144700000010 00000000 00000004 u-boot
144800000020 00000020 00000004 section@2
144900000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001450''', map_data)
1451
Simon Glass3b78d532018-06-01 09:38:21 -06001452 def testNamePrefix(self):
1453 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001454 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001455 self.assertEqual('''ImagePos Offset Size Name
145600000000 00000000 00000028 main-section
145700000000 00000000 00000010 section@0
145800000000 00000000 00000004 ro-u-boot
145900000010 00000010 00000010 section@1
146000000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001461''', map_data)
1462
Simon Glass6ba679c2018-07-06 10:27:17 -06001463 def testUnknownContents(self):
1464 """Test that obtaining the contents works as expected"""
1465 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001466 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001467 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001468 "processing of contents: remaining ["
1469 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001470
Simon Glass2e1169f2018-07-06 10:27:19 -06001471 def testBadChangeSize(self):
1472 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001473 try:
1474 state.SetAllowEntryExpansion(False)
1475 with self.assertRaises(ValueError) as e:
1476 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001477 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001478 str(e.exception))
1479 finally:
1480 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001481
Simon Glassa87014e2018-07-06 10:27:42 -06001482 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001483 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001484 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001485 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001486 dtb = fdt.Fdt(out_dtb_fname)
1487 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001488 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001489 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001490 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001491 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001492 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001493 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001494 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001495 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001496 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001497 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001498 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001499 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001500 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001501
Simon Glasse8561af2018-08-01 15:22:37 -06001502 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001503 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001504 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001505 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001506 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001507 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001508 'size': 40
1509 }, props)
1510
1511 def testUpdateFdtBad(self):
1512 """Test that we detect when ProcessFdt never completes"""
1513 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001514 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001515 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001516 '[<binman.etype._testing.Entry__testing',
1517 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001518
Simon Glass91710b32018-07-17 13:25:32 -06001519 def testEntryArgs(self):
1520 """Test passing arguments to entries from the command line"""
1521 entry_args = {
1522 'test-str-arg': 'test1',
1523 'test-int-arg': '456',
1524 }
Simon Glass511f6582018-10-01 12:22:30 -06001525 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001526 self.assertIn('image', control.images)
1527 entry = control.images['image'].GetEntries()['_testing']
1528 self.assertEqual('test0', entry.test_str_fdt)
1529 self.assertEqual('test1', entry.test_str_arg)
1530 self.assertEqual(123, entry.test_int_fdt)
1531 self.assertEqual(456, entry.test_int_arg)
1532
1533 def testEntryArgsMissing(self):
1534 """Test missing arguments and properties"""
1535 entry_args = {
1536 'test-int-arg': '456',
1537 }
Simon Glass511f6582018-10-01 12:22:30 -06001538 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001539 entry = control.images['image'].GetEntries()['_testing']
1540 self.assertEqual('test0', entry.test_str_fdt)
1541 self.assertEqual(None, entry.test_str_arg)
1542 self.assertEqual(None, entry.test_int_fdt)
1543 self.assertEqual(456, entry.test_int_arg)
1544
1545 def testEntryArgsRequired(self):
1546 """Test missing arguments and properties"""
1547 entry_args = {
1548 'test-int-arg': '456',
1549 }
1550 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001551 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001552 self.assertIn("Node '/binman/_testing': "
1553 'Missing required properties/entry args: test-str-arg, '
1554 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001555 str(e.exception))
1556
1557 def testEntryArgsInvalidFormat(self):
1558 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001559 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1560 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001561 with self.assertRaises(ValueError) as e:
1562 self._DoBinman(*args)
1563 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1564
1565 def testEntryArgsInvalidInteger(self):
1566 """Test that an invalid entry-argument integer is detected"""
1567 entry_args = {
1568 'test-int-arg': 'abc',
1569 }
1570 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001571 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001572 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1573 "'test-int-arg' (value 'abc') to integer",
1574 str(e.exception))
1575
1576 def testEntryArgsInvalidDatatype(self):
1577 """Test that an invalid entry-argument datatype is detected
1578
1579 This test could be written in entry_test.py except that it needs
1580 access to control.entry_args, which seems more than that module should
1581 be able to see.
1582 """
1583 entry_args = {
1584 'test-bad-datatype-arg': '12',
1585 }
1586 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001587 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001588 entry_args=entry_args)
1589 self.assertIn('GetArg() internal error: Unknown data type ',
1590 str(e.exception))
1591
Simon Glass2ca52032018-07-17 13:25:33 -06001592 def testText(self):
1593 """Test for a text entry type"""
1594 entry_args = {
1595 'test-id': TEXT_DATA,
1596 'test-id2': TEXT_DATA2,
1597 'test-id3': TEXT_DATA3,
1598 }
Simon Glass511f6582018-10-01 12:22:30 -06001599 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001600 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001601 expected = (tools.to_bytes(TEXT_DATA) +
1602 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1603 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001604 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001605 self.assertEqual(expected, data)
1606
Simon Glass969616c2018-07-17 13:25:36 -06001607 def testEntryDocs(self):
1608 """Test for creation of entry documentation"""
1609 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001610 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001611 self.assertTrue(len(stdout.getvalue()) > 0)
1612
1613 def testEntryDocsMissing(self):
1614 """Test handling of missing entry documentation"""
1615 with self.assertRaises(ValueError) as e:
1616 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001617 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001618 self.assertIn('Documentation is missing for modules: u_boot',
1619 str(e.exception))
1620
Simon Glass704784b2018-07-17 13:25:38 -06001621 def testFmap(self):
1622 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001623 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001624 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001625 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1626 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001627 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001628 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001629 self.assertEqual(1, fhdr.ver_major)
1630 self.assertEqual(0, fhdr.ver_minor)
1631 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001632 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001633 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001634 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001635 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001636 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001637
Simon Glass82059c22021-04-03 11:05:09 +13001638 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001639 self.assertEqual(b'SECTION0', fentry.name)
1640 self.assertEqual(0, fentry.offset)
1641 self.assertEqual(16, fentry.size)
1642 self.assertEqual(0, fentry.flags)
1643
1644 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001645 self.assertEqual(b'RO_U_BOOT', fentry.name)
1646 self.assertEqual(0, fentry.offset)
1647 self.assertEqual(4, fentry.size)
1648 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001649
Simon Glass82059c22021-04-03 11:05:09 +13001650 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001651 self.assertEqual(b'SECTION1', fentry.name)
1652 self.assertEqual(16, fentry.offset)
1653 self.assertEqual(16, fentry.size)
1654 self.assertEqual(0, fentry.flags)
1655
1656 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001657 self.assertEqual(b'RW_U_BOOT', fentry.name)
1658 self.assertEqual(16, fentry.offset)
1659 self.assertEqual(4, fentry.size)
1660 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001661
Simon Glass82059c22021-04-03 11:05:09 +13001662 fentry = next(fiter)
1663 self.assertEqual(b'FMAP', fentry.name)
1664 self.assertEqual(32, fentry.offset)
1665 self.assertEqual(expect_size, fentry.size)
1666 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001667
Simon Glassdb168d42018-07-17 13:25:39 -06001668 def testBlobNamedByArg(self):
1669 """Test we can add a blob with the filename coming from an entry arg"""
1670 entry_args = {
1671 'cros-ec-rw-path': 'ecrw.bin',
1672 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001673 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001674
Simon Glass53f53992018-07-17 13:25:40 -06001675 def testFill(self):
1676 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001677 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001678 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001679 self.assertEqual(expected, data)
1680
1681 def testFillNoSize(self):
1682 """Test for an fill entry type with no size"""
1683 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001684 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001685 self.assertIn("'fill' entry must have a size property",
1686 str(e.exception))
1687
Simon Glassc1ae83c2018-07-17 13:25:44 -06001688 def _HandleGbbCommand(self, pipe_list):
1689 """Fake calls to the futility utility"""
1690 if pipe_list[0][0] == 'futility':
1691 fname = pipe_list[0][-1]
1692 # Append our GBB data to the file, which will happen every time the
1693 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001694 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001695 fd.write(GBB_DATA)
1696 return command.CommandResult()
1697
1698 def testGbb(self):
1699 """Test for the Chromium OS Google Binary Block"""
1700 command.test_result = self._HandleGbbCommand
1701 entry_args = {
1702 'keydir': 'devkeys',
1703 'bmpblk': 'bmpblk.bin',
1704 }
Simon Glass511f6582018-10-01 12:22:30 -06001705 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001706
1707 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001708 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1709 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001710 self.assertEqual(expected, data)
1711
1712 def testGbbTooSmall(self):
1713 """Test for the Chromium OS Google Binary Block being large enough"""
1714 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001715 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001716 self.assertIn("Node '/binman/gbb': GBB is too small",
1717 str(e.exception))
1718
1719 def testGbbNoSize(self):
1720 """Test for the Chromium OS Google Binary Block having a size"""
1721 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001722 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001723 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1724 str(e.exception))
1725
Simon Glass66152ce2022-01-09 20:14:09 -07001726 def testGbbMissing(self):
1727 """Test that binman still produces an image if futility is missing"""
1728 entry_args = {
1729 'keydir': 'devkeys',
1730 }
1731 with test_util.capture_sys_output() as (_, stderr):
1732 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1733 entry_args=entry_args)
1734 err = stderr.getvalue()
1735 self.assertRegex(err,
1736 "Image 'main-section'.*missing bintools.*: futility")
1737
Simon Glass5c350162018-07-17 13:25:47 -06001738 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001739 """Fake calls to the futility utility
1740
1741 The expected pipe is:
1742
1743 [('futility', 'vbutil_firmware', '--vblock',
1744 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1745 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1746 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1747 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1748
1749 This writes to the output file (here, 'vblock.vblock'). If
1750 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1751 of the input data (here, 'input.vblock').
1752 """
Simon Glass5c350162018-07-17 13:25:47 -06001753 if pipe_list[0][0] == 'futility':
1754 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001755 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001756 if self._hash_data:
1757 infile = pipe_list[0][11]
1758 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001759 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001760 m.update(data)
1761 fd.write(m.digest())
1762 else:
1763 fd.write(VBLOCK_DATA)
1764
Simon Glass5c350162018-07-17 13:25:47 -06001765 return command.CommandResult()
1766
1767 def testVblock(self):
1768 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001769 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001770 command.test_result = self._HandleVblockCommand
1771 entry_args = {
1772 'keydir': 'devkeys',
1773 }
Simon Glass511f6582018-10-01 12:22:30 -06001774 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001775 entry_args=entry_args)
1776 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1777 self.assertEqual(expected, data)
1778
1779 def testVblockNoContent(self):
1780 """Test we detect a vblock which has no content to sign"""
1781 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001782 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001783 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001784 'property', str(e.exception))
1785
1786 def testVblockBadPhandle(self):
1787 """Test that we detect a vblock with an invalid phandle in contents"""
1788 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001789 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001790 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1791 '1000', str(e.exception))
1792
1793 def testVblockBadEntry(self):
1794 """Test that we detect an entry that points to a non-entry"""
1795 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001796 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001797 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1798 "'other'", str(e.exception))
1799
Simon Glass220c6222021-01-06 21:35:17 -07001800 def testVblockContent(self):
1801 """Test that the vblock signs the right data"""
1802 self._hash_data = True
1803 command.test_result = self._HandleVblockCommand
1804 entry_args = {
1805 'keydir': 'devkeys',
1806 }
1807 data = self._DoReadFileDtb(
1808 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1809 entry_args=entry_args)[0]
1810 hashlen = 32 # SHA256 hash is 32 bytes
1811 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1812 hashval = data[-hashlen:]
1813 dtb = data[len(U_BOOT_DATA):-hashlen]
1814
1815 expected_data = U_BOOT_DATA + dtb
1816
1817 # The hashval should be a hash of the dtb
1818 m = hashlib.sha256()
1819 m.update(expected_data)
1820 expected_hashval = m.digest()
1821 self.assertEqual(expected_hashval, hashval)
1822
Simon Glass66152ce2022-01-09 20:14:09 -07001823 def testVblockMissing(self):
1824 """Test that binman still produces an image if futility is missing"""
1825 entry_args = {
1826 'keydir': 'devkeys',
1827 }
1828 with test_util.capture_sys_output() as (_, stderr):
1829 self._DoTestFile('074_vblock.dts',
1830 force_missing_bintools='futility',
1831 entry_args=entry_args)
1832 err = stderr.getvalue()
1833 self.assertRegex(err,
1834 "Image 'main-section'.*missing bintools.*: futility")
1835
Simon Glass8425a1f2018-07-17 13:25:48 -06001836 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001837 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001838 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001839 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001840 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001841 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1842
Simon Glass24b97442018-07-17 13:25:51 -06001843 def testUsesPos(self):
1844 """Test that the 'pos' property cannot be used anymore"""
1845 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001846 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001847 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1848 "'pos'", str(e.exception))
1849
Simon Glass274bf092018-09-14 04:57:08 -06001850 def testFillZero(self):
1851 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001852 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001853 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001854
Simon Glass267de432018-09-14 04:57:09 -06001855 def testTextMissing(self):
1856 """Test for a text entry type where there is no text"""
1857 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001858 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001859 self.assertIn("Node '/binman/text': No value provided for text label "
1860 "'test-id'", str(e.exception))
1861
Simon Glassed40e962018-09-14 04:57:10 -06001862 def testPackStart16Tpl(self):
1863 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001864 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001865 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1866
Simon Glass3b376c32018-09-14 04:57:12 -06001867 def testSelectImage(self):
1868 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001869 expected = 'Skipping images: image1'
1870
1871 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001872 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001873 with test_util.capture_sys_output() as (stdout, stderr):
1874 retcode = self._DoTestFile('006_dual_image.dts',
1875 verbosity=verbosity,
1876 images=['image2'])
1877 self.assertEqual(0, retcode)
1878 if verbosity:
1879 self.assertIn(expected, stdout.getvalue())
1880 else:
1881 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001882
Simon Glass80025522022-01-29 14:14:04 -07001883 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1884 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001885 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001886
Simon Glasse219aa42018-09-14 04:57:24 -06001887 def testUpdateFdtAll(self):
1888 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001889 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001890
1891 base_expected = {
1892 'section:image-pos': 0,
1893 'u-boot-tpl-dtb:size': 513,
1894 'u-boot-spl-dtb:size': 513,
1895 'u-boot-spl-dtb:offset': 493,
1896 'image-pos': 0,
1897 'section/u-boot-dtb:image-pos': 0,
1898 'u-boot-spl-dtb:image-pos': 493,
1899 'section/u-boot-dtb:size': 493,
1900 'u-boot-tpl-dtb:image-pos': 1006,
1901 'section/u-boot-dtb:offset': 0,
1902 'section:size': 493,
1903 'offset': 0,
1904 'section:offset': 0,
1905 'u-boot-tpl-dtb:offset': 1006,
1906 'size': 1519
1907 }
1908
1909 # We expect three device-tree files in the output, one after the other.
1910 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1911 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1912 # main U-Boot tree. All three should have the same postions and offset.
1913 start = 0
1914 for item in ['', 'spl', 'tpl']:
1915 dtb = fdt.Fdt.FromData(data[start:])
1916 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001917 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1918 ['spl', 'tpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001919 expected = dict(base_expected)
1920 if item:
1921 expected[item] = 0
1922 self.assertEqual(expected, props)
1923 start += dtb._fdt_obj.totalsize()
1924
1925 def testUpdateFdtOutput(self):
1926 """Test that output DTB files are updated"""
1927 try:
Simon Glass511f6582018-10-01 12:22:30 -06001928 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001929 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1930
1931 # Unfortunately, compiling a source file always results in a file
1932 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001933 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001934 # binman as a file called u-boot.dtb. To fix this, copy the file
1935 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001936 start = 0
1937 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1938 'tpl/u-boot-tpl.dtb.out']:
1939 dtb = fdt.Fdt.FromData(data[start:])
1940 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07001941 pathname = tools.get_output_filename(os.path.split(fname)[1])
1942 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06001943 name = os.path.split(fname)[0]
1944
1945 if name:
1946 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1947 else:
1948 orig_indata = dtb_data
1949 self.assertNotEqual(outdata, orig_indata,
1950 "Expected output file '%s' be updated" % pathname)
1951 self.assertEqual(outdata, data[start:start + size],
1952 "Expected output file '%s' to match output image" %
1953 pathname)
1954 start += size
1955 finally:
1956 self._ResetDtbs()
1957
Simon Glass7ba33592018-09-14 04:57:26 -06001958 def _decompress(self, data):
Simon Glassdd5c14ec2022-01-09 20:14:04 -07001959 return comp_util.decompress(data, 'lz4')
Simon Glass7ba33592018-09-14 04:57:26 -06001960
1961 def testCompress(self):
1962 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06001963 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001964 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001965 use_real_dtb=True, update_dtb=True)
1966 dtb = fdt.Fdt(out_dtb_fname)
1967 dtb.Scan()
1968 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1969 orig = self._decompress(data)
1970 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06001971
1972 # Do a sanity check on various fields
1973 image = control.images['image']
1974 entries = image.GetEntries()
1975 self.assertEqual(1, len(entries))
1976
1977 entry = entries['blob']
1978 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1979 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1980 orig = self._decompress(entry.data)
1981 self.assertEqual(orig, entry.uncomp_data)
1982
Simon Glass72eeff12020-10-26 17:40:16 -06001983 self.assertEqual(image.data, entry.data)
1984
Simon Glass7ba33592018-09-14 04:57:26 -06001985 expected = {
1986 'blob:uncomp-size': len(COMPRESS_DATA),
1987 'blob:size': len(data),
1988 'size': len(data),
1989 }
1990 self.assertEqual(expected, props)
1991
Simon Glassac6328c2018-09-14 04:57:28 -06001992 def testFiles(self):
1993 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06001994 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001995 self.assertEqual(FILES_DATA, data)
1996
1997 def testFilesCompress(self):
1998 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06001999 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002000 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002001
2002 image = control.images['image']
2003 entries = image.GetEntries()
2004 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002005 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002006
Simon Glass303f62f2019-05-17 22:00:46 -06002007 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002008 for i in range(1, 3):
2009 key = '%d.dat' % i
2010 start = entries[key].image_pos
2011 len = entries[key].size
2012 chunk = data[start:start + len]
2013 orig += self._decompress(chunk)
2014
2015 self.assertEqual(FILES_DATA, orig)
2016
2017 def testFilesMissing(self):
2018 """Test missing files"""
2019 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002020 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002021 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2022 'no files', str(e.exception))
2023
2024 def testFilesNoPattern(self):
2025 """Test missing files"""
2026 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002027 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002028 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2029 str(e.exception))
2030
Simon Glassfa79a812018-09-14 04:57:29 -06002031 def testExpandSize(self):
2032 """Test an expanding entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002033 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002034 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002035 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2036 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2037 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2038 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002039 self.assertEqual(expect, data)
2040 self.assertEqual('''ImagePos Offset Size Name
204100000000 00000000 00000028 main-section
204200000000 00000000 00000008 fill
204300000008 00000008 00000004 u-boot
20440000000c 0000000c 00000004 section
20450000000c 00000000 00000003 intel-mrc
204600000010 00000010 00000004 u-boot2
204700000014 00000014 0000000c section2
204800000014 00000000 00000008 fill
20490000001c 00000008 00000004 u-boot
205000000020 00000020 00000008 fill2
2051''', map_data)
2052
2053 def testExpandSizeBad(self):
2054 """Test an expanding entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002055 with test_util.capture_sys_output() as (stdout, stderr):
2056 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002057 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002058 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2059 'expanding entry', str(e.exception))
2060
Simon Glassae7cf032018-09-14 04:57:31 -06002061 def testHash(self):
2062 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002063 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002064 use_real_dtb=True, update_dtb=True)
2065 dtb = fdt.Fdt(out_dtb_fname)
2066 dtb.Scan()
2067 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2068 m = hashlib.sha256()
2069 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002070 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002071
2072 def testHashNoAlgo(self):
2073 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002074 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002075 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2076 'hash node', str(e.exception))
2077
2078 def testHashBadAlgo(self):
2079 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002080 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002081 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002082 str(e.exception))
2083
2084 def testHashSection(self):
2085 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002086 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002087 use_real_dtb=True, update_dtb=True)
2088 dtb = fdt.Fdt(out_dtb_fname)
2089 dtb.Scan()
2090 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2091 m = hashlib.sha256()
2092 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002093 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002094 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002095
Simon Glass3fb4f422018-09-14 04:57:32 -06002096 def testPackUBootTplMicrocode(self):
2097 """Test that x86 microcode can be handled correctly in TPL
2098
2099 We expect to see the following in the image, in order:
2100 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2101 place
2102 u-boot-tpl.dtb with the microcode removed
2103 the microcode
2104 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002105 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002106 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002107 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002108 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2109 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002110
Simon Glassc64aea52018-09-14 04:57:34 -06002111 def testFmapX86(self):
2112 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002113 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002114 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002115 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002116 self.assertEqual(expected, data[:32])
2117 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2118
2119 self.assertEqual(0x100, fhdr.image_size)
2120
2121 self.assertEqual(0, fentries[0].offset)
2122 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002123 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002124
2125 self.assertEqual(4, fentries[1].offset)
2126 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002127 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002128
2129 self.assertEqual(32, fentries[2].offset)
2130 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2131 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002132 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002133
2134 def testFmapX86Section(self):
2135 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002136 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002137 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002138 self.assertEqual(expected, data[:32])
2139 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2140
Simon Glassb1d414c2021-04-03 11:05:10 +13002141 self.assertEqual(0x180, fhdr.image_size)
2142 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002143 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002144
Simon Glass82059c22021-04-03 11:05:09 +13002145 fentry = next(fiter)
2146 self.assertEqual(b'U_BOOT', fentry.name)
2147 self.assertEqual(0, fentry.offset)
2148 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002149
Simon Glass82059c22021-04-03 11:05:09 +13002150 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002151 self.assertEqual(b'SECTION', fentry.name)
2152 self.assertEqual(4, fentry.offset)
2153 self.assertEqual(0x20 + expect_size, fentry.size)
2154
2155 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002156 self.assertEqual(b'INTEL_MRC', fentry.name)
2157 self.assertEqual(4, fentry.offset)
2158 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002159
Simon Glass82059c22021-04-03 11:05:09 +13002160 fentry = next(fiter)
2161 self.assertEqual(b'FMAP', fentry.name)
2162 self.assertEqual(36, fentry.offset)
2163 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002164
Simon Glassb1714232018-09-14 04:57:35 -06002165 def testElf(self):
2166 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002167 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002168 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002169 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002170 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002171 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002172
Simon Glass0d673792019-07-08 13:18:25 -06002173 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002174 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002175 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002176 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002177 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002178 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002179
Simon Glasscd817d52018-09-14 04:57:36 -06002180 def testPackOverlapMap(self):
2181 """Test that overlapping regions are detected"""
2182 with test_util.capture_sys_output() as (stdout, stderr):
2183 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002184 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002185 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002186 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2187 stdout.getvalue())
2188
2189 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002190 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002191 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002192 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002193 self.assertEqual('''ImagePos Offset Size Name
Simon Glassd99850b2020-10-26 17:40:24 -06002194<none> 00000000 00000008 main-section
Simon Glasscd817d52018-09-14 04:57:36 -06002195<none> 00000000 00000004 u-boot
2196<none> 00000003 00000004 u-boot-align
2197''', map_data)
2198
Simon Glass0d673792019-07-08 13:18:25 -06002199 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002200 """Test that an image with an Intel Reference code binary works"""
2201 data = self._DoReadFile('100_intel_refcode.dts')
2202 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2203
Simon Glasseb023b32019-04-25 21:58:39 -06002204 def testSectionOffset(self):
2205 """Tests use of a section with an offset"""
2206 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2207 map=True)
2208 self.assertEqual('''ImagePos Offset Size Name
220900000000 00000000 00000038 main-section
221000000004 00000004 00000010 section@0
221100000004 00000000 00000004 u-boot
221200000018 00000018 00000010 section@1
221300000018 00000000 00000004 u-boot
22140000002c 0000002c 00000004 section@2
22150000002c 00000000 00000004 u-boot
2216''', map_data)
2217 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002218 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2219 tools.get_bytes(0x21, 12) +
2220 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2221 tools.get_bytes(0x61, 12) +
2222 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2223 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002224
Simon Glass1de34482019-07-08 13:18:53 -06002225 def testCbfsRaw(self):
2226 """Test base handling of a Coreboot Filesystem (CBFS)
2227
2228 The exact contents of the CBFS is verified by similar tests in
2229 cbfs_util_test.py. The tests here merely check that the files added to
2230 the CBFS can be found in the final image.
2231 """
2232 data = self._DoReadFile('102_cbfs_raw.dts')
2233 size = 0xb0
2234
2235 cbfs = cbfs_util.CbfsReader(data)
2236 self.assertEqual(size, cbfs.rom_size)
2237
2238 self.assertIn('u-boot-dtb', cbfs.files)
2239 cfile = cbfs.files['u-boot-dtb']
2240 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2241
2242 def testCbfsArch(self):
2243 """Test on non-x86 architecture"""
2244 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2245 size = 0x100
2246
2247 cbfs = cbfs_util.CbfsReader(data)
2248 self.assertEqual(size, cbfs.rom_size)
2249
2250 self.assertIn('u-boot-dtb', cbfs.files)
2251 cfile = cbfs.files['u-boot-dtb']
2252 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2253
2254 def testCbfsStage(self):
2255 """Tests handling of a Coreboot Filesystem (CBFS)"""
2256 if not elf.ELF_TOOLS:
2257 self.skipTest('Python elftools not available')
2258 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2259 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2260 size = 0xb0
2261
2262 data = self._DoReadFile('104_cbfs_stage.dts')
2263 cbfs = cbfs_util.CbfsReader(data)
2264 self.assertEqual(size, cbfs.rom_size)
2265
2266 self.assertIn('u-boot', cbfs.files)
2267 cfile = cbfs.files['u-boot']
2268 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2269
2270 def testCbfsRawCompress(self):
2271 """Test handling of compressing raw files"""
2272 self._CheckLz4()
2273 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2274 size = 0x140
2275
2276 cbfs = cbfs_util.CbfsReader(data)
2277 self.assertIn('u-boot', cbfs.files)
2278 cfile = cbfs.files['u-boot']
2279 self.assertEqual(COMPRESS_DATA, cfile.data)
2280
2281 def testCbfsBadArch(self):
2282 """Test handling of a bad architecture"""
2283 with self.assertRaises(ValueError) as e:
2284 self._DoReadFile('106_cbfs_bad_arch.dts')
2285 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2286
2287 def testCbfsNoSize(self):
2288 """Test handling of a missing size property"""
2289 with self.assertRaises(ValueError) as e:
2290 self._DoReadFile('107_cbfs_no_size.dts')
2291 self.assertIn('entry must have a size property', str(e.exception))
2292
Simon Glass3e28f4f2021-11-23 11:03:54 -07002293 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002294 """Test handling of a CBFS entry which does not provide contentsy"""
2295 with self.assertRaises(ValueError) as e:
2296 self._DoReadFile('108_cbfs_no_contents.dts')
2297 self.assertIn('Could not complete processing of contents',
2298 str(e.exception))
2299
2300 def testCbfsBadCompress(self):
2301 """Test handling of a bad architecture"""
2302 with self.assertRaises(ValueError) as e:
2303 self._DoReadFile('109_cbfs_bad_compress.dts')
2304 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2305 str(e.exception))
2306
2307 def testCbfsNamedEntries(self):
2308 """Test handling of named entries"""
2309 data = self._DoReadFile('110_cbfs_name.dts')
2310
2311 cbfs = cbfs_util.CbfsReader(data)
2312 self.assertIn('FRED', cbfs.files)
2313 cfile1 = cbfs.files['FRED']
2314 self.assertEqual(U_BOOT_DATA, cfile1.data)
2315
2316 self.assertIn('hello', cbfs.files)
2317 cfile2 = cbfs.files['hello']
2318 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2319
Simon Glass759af872019-07-08 13:18:54 -06002320 def _SetupIfwi(self, fname):
2321 """Set up to run an IFWI test
2322
2323 Args:
2324 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2325 """
2326 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002327 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002328
2329 # Intel Integrated Firmware Image (IFWI) file
2330 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2331 data = fd.read()
2332 TestFunctional._MakeInputFile(fname,data)
2333
2334 def _CheckIfwi(self, data):
2335 """Check that an image with an IFWI contains the correct output
2336
2337 Args:
2338 data: Conents of output file
2339 """
Simon Glass80025522022-01-29 14:14:04 -07002340 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002341 if data[:0x1000] != expected_desc:
2342 self.fail('Expected descriptor binary at start of image')
2343
2344 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002345 image_fname = tools.get_output_filename('image.bin')
2346 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002347 ifwitool = bintool.Bintool.create('ifwitool')
2348 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002349
Simon Glass80025522022-01-29 14:14:04 -07002350 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002351 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002352
2353 def testPackX86RomIfwi(self):
2354 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2355 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002356 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002357 self._CheckIfwi(data)
2358
2359 def testPackX86RomIfwiNoDesc(self):
2360 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2361 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002362 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002363 self._CheckIfwi(data)
2364
2365 def testPackX86RomIfwiNoData(self):
2366 """Test that an x86 ROM with IFWI handles missing data"""
2367 self._SetupIfwi('ifwi.bin')
2368 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002369 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002370 self.assertIn('Could not complete processing of contents',
2371 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002372
Simon Glass66152ce2022-01-09 20:14:09 -07002373 def testIfwiMissing(self):
2374 """Test that binman still produces an image if ifwitool is missing"""
2375 self._SetupIfwi('fitimage.bin')
2376 with test_util.capture_sys_output() as (_, stderr):
2377 self._DoTestFile('111_x86_rom_ifwi.dts',
2378 force_missing_bintools='ifwitool')
2379 err = stderr.getvalue()
2380 self.assertRegex(err,
2381 "Image 'main-section'.*missing bintools.*: ifwitool")
2382
Simon Glassc2f1aed2019-07-08 13:18:56 -06002383 def testCbfsOffset(self):
2384 """Test a CBFS with files at particular offsets
2385
2386 Like all CFBS tests, this is just checking the logic that calls
2387 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2388 """
2389 data = self._DoReadFile('114_cbfs_offset.dts')
2390 size = 0x200
2391
2392 cbfs = cbfs_util.CbfsReader(data)
2393 self.assertEqual(size, cbfs.rom_size)
2394
2395 self.assertIn('u-boot', cbfs.files)
2396 cfile = cbfs.files['u-boot']
2397 self.assertEqual(U_BOOT_DATA, cfile.data)
2398 self.assertEqual(0x40, cfile.cbfs_offset)
2399
2400 self.assertIn('u-boot-dtb', cbfs.files)
2401 cfile2 = cbfs.files['u-boot-dtb']
2402 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2403 self.assertEqual(0x140, cfile2.cbfs_offset)
2404
Simon Glass0f621332019-07-08 14:25:27 -06002405 def testFdtmap(self):
2406 """Test an FDT map can be inserted in the image"""
2407 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2408 fdtmap_data = data[len(U_BOOT_DATA):]
2409 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002410 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002411 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002412
2413 fdt_data = fdtmap_data[16:]
2414 dtb = fdt.Fdt.FromData(fdt_data)
2415 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002416 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002417 self.assertEqual({
2418 'image-pos': 0,
2419 'offset': 0,
2420 'u-boot:offset': 0,
2421 'u-boot:size': len(U_BOOT_DATA),
2422 'u-boot:image-pos': 0,
2423 'fdtmap:image-pos': 4,
2424 'fdtmap:offset': 4,
2425 'fdtmap:size': len(fdtmap_data),
2426 'size': len(data),
2427 }, props)
2428
2429 def testFdtmapNoMatch(self):
2430 """Check handling of an FDT map when the section cannot be found"""
2431 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2432
2433 # Mangle the section name, which should cause a mismatch between the
2434 # correct FDT path and the one expected by the section
2435 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002436 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002437 entries = image.GetEntries()
2438 fdtmap = entries['fdtmap']
2439 with self.assertRaises(ValueError) as e:
2440 fdtmap._GetFdtmap()
2441 self.assertIn("Cannot locate node for path '/binman-suffix'",
2442 str(e.exception))
2443
Simon Glasscec34ba2019-07-08 14:25:28 -06002444 def testFdtmapHeader(self):
2445 """Test an FDT map and image header can be inserted in the image"""
2446 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2447 fdtmap_pos = len(U_BOOT_DATA)
2448 fdtmap_data = data[fdtmap_pos:]
2449 fdt_data = fdtmap_data[16:]
2450 dtb = fdt.Fdt.FromData(fdt_data)
2451 fdt_size = dtb.GetFdtObj().totalsize()
2452 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002453 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002454 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2455 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2456
2457 def testFdtmapHeaderStart(self):
2458 """Test an image header can be inserted at the image start"""
2459 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2460 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2461 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002462 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002463 offset = struct.unpack('<I', hdr_data[4:])[0]
2464 self.assertEqual(fdtmap_pos, offset)
2465
2466 def testFdtmapHeaderPos(self):
2467 """Test an image header can be inserted at a chosen position"""
2468 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2469 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2470 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002471 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002472 offset = struct.unpack('<I', hdr_data[4:])[0]
2473 self.assertEqual(fdtmap_pos, offset)
2474
2475 def testHeaderMissingFdtmap(self):
2476 """Test an image header requires an fdtmap"""
2477 with self.assertRaises(ValueError) as e:
2478 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2479 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2480 str(e.exception))
2481
2482 def testHeaderNoLocation(self):
2483 """Test an image header with a no specified location is detected"""
2484 with self.assertRaises(ValueError) as e:
2485 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2486 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2487 str(e.exception))
2488
Simon Glasse61b6f62019-07-08 14:25:37 -06002489 def testEntryExpand(self):
2490 """Test expanding an entry after it is packed"""
2491 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002492 self.assertEqual(b'aaa', data[:3])
2493 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2494 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002495
2496 def testEntryExpandBad(self):
2497 """Test expanding an entry after it is packed, twice"""
2498 with self.assertRaises(ValueError) as e:
2499 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002500 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002501 str(e.exception))
2502
2503 def testEntryExpandSection(self):
2504 """Test expanding an entry within a section after it is packed"""
2505 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002506 self.assertEqual(b'aaa', data[:3])
2507 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2508 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002509
Simon Glass90d29682019-07-08 14:25:38 -06002510 def testCompressDtb(self):
2511 """Test that compress of device-tree files is supported"""
2512 self._CheckLz4()
2513 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2514 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2515 comp_data = data[len(U_BOOT_DATA):]
2516 orig = self._decompress(comp_data)
2517 dtb = fdt.Fdt.FromData(orig)
2518 dtb.Scan()
2519 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2520 expected = {
2521 'u-boot:size': len(U_BOOT_DATA),
2522 'u-boot-dtb:uncomp-size': len(orig),
2523 'u-boot-dtb:size': len(comp_data),
2524 'size': len(data),
2525 }
2526 self.assertEqual(expected, props)
2527
Simon Glass151bbbf2019-07-08 14:25:41 -06002528 def testCbfsUpdateFdt(self):
2529 """Test that we can update the device tree with CBFS offset/size info"""
2530 self._CheckLz4()
2531 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2532 update_dtb=True)
2533 dtb = fdt.Fdt(out_dtb_fname)
2534 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002535 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002536 del props['cbfs/u-boot:size']
2537 self.assertEqual({
2538 'offset': 0,
2539 'size': len(data),
2540 'image-pos': 0,
2541 'cbfs:offset': 0,
2542 'cbfs:size': len(data),
2543 'cbfs:image-pos': 0,
2544 'cbfs/u-boot:offset': 0x38,
2545 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2546 'cbfs/u-boot:image-pos': 0x38,
2547 'cbfs/u-boot-dtb:offset': 0xb8,
2548 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2549 'cbfs/u-boot-dtb:image-pos': 0xb8,
2550 }, props)
2551
Simon Glass3c9b4f22019-07-08 14:25:42 -06002552 def testCbfsBadType(self):
2553 """Test an image header with a no specified location is detected"""
2554 with self.assertRaises(ValueError) as e:
2555 self._DoReadFile('126_cbfs_bad_type.dts')
2556 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2557
Simon Glass6b156f82019-07-08 14:25:43 -06002558 def testList(self):
2559 """Test listing the files in an image"""
2560 self._CheckLz4()
2561 data = self._DoReadFile('127_list.dts')
2562 image = control.images['image']
2563 entries = image.BuildEntryList()
2564 self.assertEqual(7, len(entries))
2565
2566 ent = entries[0]
2567 self.assertEqual(0, ent.indent)
2568 self.assertEqual('main-section', ent.name)
2569 self.assertEqual('section', ent.etype)
2570 self.assertEqual(len(data), ent.size)
2571 self.assertEqual(0, ent.image_pos)
2572 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002573 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002574
2575 ent = entries[1]
2576 self.assertEqual(1, ent.indent)
2577 self.assertEqual('u-boot', ent.name)
2578 self.assertEqual('u-boot', ent.etype)
2579 self.assertEqual(len(U_BOOT_DATA), ent.size)
2580 self.assertEqual(0, ent.image_pos)
2581 self.assertEqual(None, ent.uncomp_size)
2582 self.assertEqual(0, ent.offset)
2583
2584 ent = entries[2]
2585 self.assertEqual(1, ent.indent)
2586 self.assertEqual('section', ent.name)
2587 self.assertEqual('section', ent.etype)
2588 section_size = ent.size
2589 self.assertEqual(0x100, ent.image_pos)
2590 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002591 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002592
2593 ent = entries[3]
2594 self.assertEqual(2, ent.indent)
2595 self.assertEqual('cbfs', ent.name)
2596 self.assertEqual('cbfs', ent.etype)
2597 self.assertEqual(0x400, ent.size)
2598 self.assertEqual(0x100, ent.image_pos)
2599 self.assertEqual(None, ent.uncomp_size)
2600 self.assertEqual(0, ent.offset)
2601
2602 ent = entries[4]
2603 self.assertEqual(3, ent.indent)
2604 self.assertEqual('u-boot', ent.name)
2605 self.assertEqual('u-boot', ent.etype)
2606 self.assertEqual(len(U_BOOT_DATA), ent.size)
2607 self.assertEqual(0x138, ent.image_pos)
2608 self.assertEqual(None, ent.uncomp_size)
2609 self.assertEqual(0x38, ent.offset)
2610
2611 ent = entries[5]
2612 self.assertEqual(3, ent.indent)
2613 self.assertEqual('u-boot-dtb', ent.name)
2614 self.assertEqual('text', ent.etype)
2615 self.assertGreater(len(COMPRESS_DATA), ent.size)
2616 self.assertEqual(0x178, ent.image_pos)
2617 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2618 self.assertEqual(0x78, ent.offset)
2619
2620 ent = entries[6]
2621 self.assertEqual(2, ent.indent)
2622 self.assertEqual('u-boot-dtb', ent.name)
2623 self.assertEqual('u-boot-dtb', ent.etype)
2624 self.assertEqual(0x500, ent.image_pos)
2625 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2626 dtb_size = ent.size
2627 # Compressing this data expands it since headers are added
2628 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2629 self.assertEqual(0x400, ent.offset)
2630
2631 self.assertEqual(len(data), 0x100 + section_size)
2632 self.assertEqual(section_size, 0x400 + dtb_size)
2633
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002634 def testFindFdtmap(self):
2635 """Test locating an FDT map in an image"""
2636 self._CheckLz4()
2637 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2638 image = control.images['image']
2639 entries = image.GetEntries()
2640 entry = entries['fdtmap']
2641 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2642
2643 def testFindFdtmapMissing(self):
2644 """Test failing to locate an FDP map"""
2645 data = self._DoReadFile('005_simple.dts')
2646 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2647
Simon Glassed39a3c2019-07-08 14:25:45 -06002648 def testFindImageHeader(self):
2649 """Test locating a image header"""
2650 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002651 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002652 image = control.images['image']
2653 entries = image.GetEntries()
2654 entry = entries['fdtmap']
2655 # The header should point to the FDT map
2656 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2657
2658 def testFindImageHeaderStart(self):
2659 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002660 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002661 image = control.images['image']
2662 entries = image.GetEntries()
2663 entry = entries['fdtmap']
2664 # The header should point to the FDT map
2665 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2666
2667 def testFindImageHeaderMissing(self):
2668 """Test failing to locate an image header"""
2669 data = self._DoReadFile('005_simple.dts')
2670 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2671
Simon Glassb8424fa2019-07-08 14:25:46 -06002672 def testReadImage(self):
2673 """Test reading an image and accessing its FDT map"""
2674 self._CheckLz4()
2675 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002676 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002677 orig_image = control.images['image']
2678 image = Image.FromFile(image_fname)
2679 self.assertEqual(orig_image.GetEntries().keys(),
2680 image.GetEntries().keys())
2681
2682 orig_entry = orig_image.GetEntries()['fdtmap']
2683 entry = image.GetEntries()['fdtmap']
2684 self.assertEquals(orig_entry.offset, entry.offset)
2685 self.assertEquals(orig_entry.size, entry.size)
2686 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2687
2688 def testReadImageNoHeader(self):
2689 """Test accessing an image's FDT map without an image header"""
2690 self._CheckLz4()
2691 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002692 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002693 image = Image.FromFile(image_fname)
2694 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002695 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002696
2697 def testReadImageFail(self):
2698 """Test failing to read an image image's FDT map"""
2699 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002700 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002701 with self.assertRaises(ValueError) as e:
2702 image = Image.FromFile(image_fname)
2703 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002704
Simon Glassb2fd11d2019-07-08 14:25:48 -06002705 def testListCmd(self):
2706 """Test listing the files in an image using an Fdtmap"""
2707 self._CheckLz4()
2708 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2709
2710 # lz4 compression size differs depending on the version
2711 image = control.images['image']
2712 entries = image.GetEntries()
2713 section_size = entries['section'].size
2714 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2715 fdtmap_offset = entries['fdtmap'].offset
2716
Simon Glassb3d6fc72019-07-20 12:24:10 -06002717 try:
2718 tmpdir, updated_fname = self._SetupImageInTmpdir()
2719 with test_util.capture_sys_output() as (stdout, stderr):
2720 self._DoBinman('ls', '-i', updated_fname)
2721 finally:
2722 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002723 lines = stdout.getvalue().splitlines()
2724 expected = [
2725'Name Image-pos Size Entry-type Offset Uncomp-size',
2726'----------------------------------------------------------------------',
2727'main-section 0 c00 section 0',
2728' u-boot 0 4 u-boot 0',
2729' section 100 %x section 100' % section_size,
2730' cbfs 100 400 cbfs 0',
2731' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002732' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002733' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002734' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002735 (fdtmap_offset, fdtmap_offset),
2736' image-header bf8 8 image-header bf8',
2737 ]
2738 self.assertEqual(expected, lines)
2739
2740 def testListCmdFail(self):
2741 """Test failing to list an image"""
2742 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002743 try:
2744 tmpdir, updated_fname = self._SetupImageInTmpdir()
2745 with self.assertRaises(ValueError) as e:
2746 self._DoBinman('ls', '-i', updated_fname)
2747 finally:
2748 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002749 self.assertIn("Cannot find FDT map in image", str(e.exception))
2750
2751 def _RunListCmd(self, paths, expected):
2752 """List out entries and check the result
2753
2754 Args:
2755 paths: List of paths to pass to the list command
2756 expected: Expected list of filenames to be returned, in order
2757 """
2758 self._CheckLz4()
2759 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002760 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002761 image = Image.FromFile(image_fname)
2762 lines = image.GetListEntries(paths)[1]
2763 files = [line[0].strip() for line in lines[1:]]
2764 self.assertEqual(expected, files)
2765
2766 def testListCmdSection(self):
2767 """Test listing the files in a section"""
2768 self._RunListCmd(['section'],
2769 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2770
2771 def testListCmdFile(self):
2772 """Test listing a particular file"""
2773 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2774
2775 def testListCmdWildcard(self):
2776 """Test listing a wildcarded file"""
2777 self._RunListCmd(['*boot*'],
2778 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2779
2780 def testListCmdWildcardMulti(self):
2781 """Test listing a wildcarded file"""
2782 self._RunListCmd(['*cb*', '*head*'],
2783 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2784
2785 def testListCmdEmpty(self):
2786 """Test listing a wildcarded file"""
2787 self._RunListCmd(['nothing'], [])
2788
2789 def testListCmdPath(self):
2790 """Test listing the files in a sub-entry of a section"""
2791 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2792
Simon Glass4c613bf2019-07-08 14:25:50 -06002793 def _RunExtractCmd(self, entry_name, decomp=True):
2794 """Extract an entry from an image
2795
2796 Args:
2797 entry_name: Entry name to extract
2798 decomp: True to decompress the data if compressed, False to leave
2799 it in its raw uncompressed format
2800
2801 Returns:
2802 data from entry
2803 """
2804 self._CheckLz4()
2805 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002806 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002807 return control.ReadEntry(image_fname, entry_name, decomp)
2808
2809 def testExtractSimple(self):
2810 """Test extracting a single file"""
2811 data = self._RunExtractCmd('u-boot')
2812 self.assertEqual(U_BOOT_DATA, data)
2813
Simon Glass980a2842019-07-08 14:25:52 -06002814 def testExtractSection(self):
2815 """Test extracting the files in a section"""
2816 data = self._RunExtractCmd('section')
2817 cbfs_data = data[:0x400]
2818 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002819 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002820 dtb_data = data[0x400:]
2821 dtb = self._decompress(dtb_data)
2822 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2823
2824 def testExtractCompressed(self):
2825 """Test extracting compressed data"""
2826 data = self._RunExtractCmd('section/u-boot-dtb')
2827 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2828
2829 def testExtractRaw(self):
2830 """Test extracting compressed data without decompressing it"""
2831 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2832 dtb = self._decompress(data)
2833 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2834
2835 def testExtractCbfs(self):
2836 """Test extracting CBFS data"""
2837 data = self._RunExtractCmd('section/cbfs/u-boot')
2838 self.assertEqual(U_BOOT_DATA, data)
2839
2840 def testExtractCbfsCompressed(self):
2841 """Test extracting CBFS compressed data"""
2842 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2843 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2844
2845 def testExtractCbfsRaw(self):
2846 """Test extracting CBFS compressed data without decompressing it"""
2847 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07002848 dtb = comp_util.decompress(data, 'lzma', with_header=False)
Simon Glass980a2842019-07-08 14:25:52 -06002849 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2850
Simon Glass4c613bf2019-07-08 14:25:50 -06002851 def testExtractBadEntry(self):
2852 """Test extracting a bad section path"""
2853 with self.assertRaises(ValueError) as e:
2854 self._RunExtractCmd('section/does-not-exist')
2855 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2856 str(e.exception))
2857
2858 def testExtractMissingFile(self):
2859 """Test extracting file that does not exist"""
2860 with self.assertRaises(IOError) as e:
2861 control.ReadEntry('missing-file', 'name')
2862
2863 def testExtractBadFile(self):
2864 """Test extracting an invalid file"""
2865 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002866 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002867 with self.assertRaises(ValueError) as e:
2868 control.ReadEntry(fname, 'name')
2869
Simon Glass980a2842019-07-08 14:25:52 -06002870 def testExtractCmd(self):
2871 """Test extracting a file fron an image on the command line"""
2872 self._CheckLz4()
2873 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002874 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002875 try:
2876 tmpdir, updated_fname = self._SetupImageInTmpdir()
2877 with test_util.capture_sys_output() as (stdout, stderr):
2878 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2879 '-f', fname)
2880 finally:
2881 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07002882 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002883 self.assertEqual(U_BOOT_DATA, data)
2884
2885 def testExtractOneEntry(self):
2886 """Test extracting a single entry fron an image """
2887 self._CheckLz4()
2888 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002889 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002890 fname = os.path.join(self._indir, 'output.extact')
2891 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07002892 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002893 self.assertEqual(U_BOOT_DATA, data)
2894
2895 def _CheckExtractOutput(self, decomp):
2896 """Helper to test file output with and without decompression
2897
2898 Args:
2899 decomp: True to decompress entry data, False to output it raw
2900 """
2901 def _CheckPresent(entry_path, expect_data, expect_size=None):
2902 """Check and remove expected file
2903
2904 This checks the data/size of a file and removes the file both from
2905 the outfiles set and from the output directory. Once all files are
2906 processed, both the set and directory should be empty.
2907
2908 Args:
2909 entry_path: Entry path
2910 expect_data: Data to expect in file, or None to skip check
2911 expect_size: Size of data to expect in file, or None to skip
2912 """
2913 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07002914 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06002915 os.remove(path)
2916 if expect_data:
2917 self.assertEqual(expect_data, data)
2918 elif expect_size:
2919 self.assertEqual(expect_size, len(data))
2920 outfiles.remove(path)
2921
2922 def _CheckDirPresent(name):
2923 """Remove expected directory
2924
2925 This gives an error if the directory does not exist as expected
2926
2927 Args:
2928 name: Name of directory to remove
2929 """
2930 path = os.path.join(outdir, name)
2931 os.rmdir(path)
2932
2933 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002934 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002935 outdir = os.path.join(self._indir, 'extract')
2936 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2937
2938 # Create a set of all file that were output (should be 9)
2939 outfiles = set()
2940 for root, dirs, files in os.walk(outdir):
2941 outfiles |= set([os.path.join(root, fname) for fname in files])
2942 self.assertEqual(9, len(outfiles))
2943 self.assertEqual(9, len(einfos))
2944
2945 image = control.images['image']
2946 entries = image.GetEntries()
2947
2948 # Check the 9 files in various ways
2949 section = entries['section']
2950 section_entries = section.GetEntries()
2951 cbfs_entries = section_entries['cbfs'].GetEntries()
2952 _CheckPresent('u-boot', U_BOOT_DATA)
2953 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2954 dtb_len = EXTRACT_DTB_SIZE
2955 if not decomp:
2956 dtb_len = cbfs_entries['u-boot-dtb'].size
2957 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2958 if not decomp:
2959 dtb_len = section_entries['u-boot-dtb'].size
2960 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2961
2962 fdtmap = entries['fdtmap']
2963 _CheckPresent('fdtmap', fdtmap.data)
2964 hdr = entries['image-header']
2965 _CheckPresent('image-header', hdr.data)
2966
2967 _CheckPresent('section/root', section.data)
2968 cbfs = section_entries['cbfs']
2969 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07002970 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06002971 _CheckPresent('root', data)
2972
2973 # There should be no files left. Remove all the directories to check.
2974 # If there are any files/dirs remaining, one of these checks will fail.
2975 self.assertEqual(0, len(outfiles))
2976 _CheckDirPresent('section/cbfs')
2977 _CheckDirPresent('section')
2978 _CheckDirPresent('')
2979 self.assertFalse(os.path.exists(outdir))
2980
2981 def testExtractAllEntries(self):
2982 """Test extracting all entries"""
2983 self._CheckLz4()
2984 self._CheckExtractOutput(decomp=True)
2985
2986 def testExtractAllEntriesRaw(self):
2987 """Test extracting all entries without decompressing them"""
2988 self._CheckLz4()
2989 self._CheckExtractOutput(decomp=False)
2990
2991 def testExtractSelectedEntries(self):
2992 """Test extracting some entries"""
2993 self._CheckLz4()
2994 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002995 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002996 outdir = os.path.join(self._indir, 'extract')
2997 einfos = control.ExtractEntries(image_fname, None, outdir,
2998 ['*cb*', '*head*'])
2999
3000 # File output is tested by testExtractAllEntries(), so just check that
3001 # the expected entries are selected
3002 names = [einfo.name for einfo in einfos]
3003 self.assertEqual(names,
3004 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3005
3006 def testExtractNoEntryPaths(self):
3007 """Test extracting some entries"""
3008 self._CheckLz4()
3009 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003010 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003011 with self.assertRaises(ValueError) as e:
3012 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003013 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003014 str(e.exception))
3015
3016 def testExtractTooManyEntryPaths(self):
3017 """Test extracting some entries"""
3018 self._CheckLz4()
3019 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003020 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003021 with self.assertRaises(ValueError) as e:
3022 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003023 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003024 str(e.exception))
3025
Simon Glass52d06212019-07-08 14:25:53 -06003026 def testPackAlignSection(self):
3027 """Test that sections can have alignment"""
3028 self._DoReadFile('131_pack_align_section.dts')
3029
3030 self.assertIn('image', control.images)
3031 image = control.images['image']
3032 entries = image.GetEntries()
3033 self.assertEqual(3, len(entries))
3034
3035 # First u-boot
3036 self.assertIn('u-boot', entries)
3037 entry = entries['u-boot']
3038 self.assertEqual(0, entry.offset)
3039 self.assertEqual(0, entry.image_pos)
3040 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3041 self.assertEqual(len(U_BOOT_DATA), entry.size)
3042
3043 # Section0
3044 self.assertIn('section0', entries)
3045 section0 = entries['section0']
3046 self.assertEqual(0x10, section0.offset)
3047 self.assertEqual(0x10, section0.image_pos)
3048 self.assertEqual(len(U_BOOT_DATA), section0.size)
3049
3050 # Second u-boot
3051 section_entries = section0.GetEntries()
3052 self.assertIn('u-boot', section_entries)
3053 entry = section_entries['u-boot']
3054 self.assertEqual(0, entry.offset)
3055 self.assertEqual(0x10, entry.image_pos)
3056 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3057 self.assertEqual(len(U_BOOT_DATA), entry.size)
3058
3059 # Section1
3060 self.assertIn('section1', entries)
3061 section1 = entries['section1']
3062 self.assertEqual(0x14, section1.offset)
3063 self.assertEqual(0x14, section1.image_pos)
3064 self.assertEqual(0x20, section1.size)
3065
3066 # Second u-boot
3067 section_entries = section1.GetEntries()
3068 self.assertIn('u-boot', section_entries)
3069 entry = section_entries['u-boot']
3070 self.assertEqual(0, entry.offset)
3071 self.assertEqual(0x14, entry.image_pos)
3072 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3073 self.assertEqual(len(U_BOOT_DATA), entry.size)
3074
3075 # Section2
3076 self.assertIn('section2', section_entries)
3077 section2 = section_entries['section2']
3078 self.assertEqual(0x4, section2.offset)
3079 self.assertEqual(0x18, section2.image_pos)
3080 self.assertEqual(4, section2.size)
3081
3082 # Third u-boot
3083 section_entries = section2.GetEntries()
3084 self.assertIn('u-boot', section_entries)
3085 entry = section_entries['u-boot']
3086 self.assertEqual(0, entry.offset)
3087 self.assertEqual(0x18, entry.image_pos)
3088 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3089 self.assertEqual(len(U_BOOT_DATA), entry.size)
3090
Simon Glassf8a54bc2019-07-20 12:23:56 -06003091 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3092 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003093 """Replace an entry in an image
3094
3095 This writes the entry data to update it, then opens the updated file and
3096 returns the value that it now finds there.
3097
3098 Args:
3099 entry_name: Entry name to replace
3100 data: Data to replace it with
3101 decomp: True to compress the data if needed, False if data is
3102 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003103 allow_resize: True to allow entries to change size, False to raise
3104 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003105
3106 Returns:
3107 Tuple:
3108 data from entry
3109 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003110 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003111 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003112 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003113 update_dtb=True)[1]
3114
3115 self.assertIn('image', control.images)
3116 image = control.images['image']
3117 entries = image.GetEntries()
3118 orig_dtb_data = entries['u-boot-dtb'].data
3119 orig_fdtmap_data = entries['fdtmap'].data
3120
Simon Glass80025522022-01-29 14:14:04 -07003121 image_fname = tools.get_output_filename('image.bin')
3122 updated_fname = tools.get_output_filename('image-updated.bin')
3123 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003124 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3125 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003126 data = control.ReadEntry(updated_fname, entry_name, decomp)
3127
Simon Glassf8a54bc2019-07-20 12:23:56 -06003128 # The DT data should not change unless resized:
3129 if not allow_resize:
3130 new_dtb_data = entries['u-boot-dtb'].data
3131 self.assertEqual(new_dtb_data, orig_dtb_data)
3132 new_fdtmap_data = entries['fdtmap'].data
3133 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003134
Simon Glassf8a54bc2019-07-20 12:23:56 -06003135 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003136
3137 def testReplaceSimple(self):
3138 """Test replacing a single file"""
3139 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003140 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3141 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003142 self.assertEqual(expected, data)
3143
3144 # Test that the state looks right. There should be an FDT for the fdtmap
3145 # that we jsut read back in, and it should match what we find in the
3146 # 'control' tables. Checking for an FDT that does not exist should
3147 # return None.
3148 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003149 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003150 self.assertEqual(expected_fdtmap, fdtmap)
3151
3152 dtb = state.GetFdtForEtype('fdtmap')
3153 self.assertEqual(dtb.GetContents(), fdtmap)
3154
3155 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3156 self.assertIsNone(missing_path)
3157 self.assertIsNone(missing_fdtmap)
3158
3159 missing_dtb = state.GetFdtForEtype('missing')
3160 self.assertIsNone(missing_dtb)
3161
3162 self.assertEqual('/binman', state.fdt_path_prefix)
3163
3164 def testReplaceResizeFail(self):
3165 """Test replacing a file by something larger"""
3166 expected = U_BOOT_DATA + b'x'
3167 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003168 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3169 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003170 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3171 str(e.exception))
3172
3173 def testReplaceMulti(self):
3174 """Test replacing entry data where multiple images are generated"""
3175 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3176 update_dtb=True)[0]
3177 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003178 updated_fname = tools.get_output_filename('image-updated.bin')
3179 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003180 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003181 control.WriteEntry(updated_fname, entry_name, expected,
3182 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003183 data = control.ReadEntry(updated_fname, entry_name)
3184 self.assertEqual(expected, data)
3185
3186 # Check the state looks right.
3187 self.assertEqual('/binman/image', state.fdt_path_prefix)
3188
3189 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003190 image_fname = tools.get_output_filename('first-image.bin')
3191 updated_fname = tools.get_output_filename('first-updated.bin')
3192 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003193 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003194 control.WriteEntry(updated_fname, entry_name, expected,
3195 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003196 data = control.ReadEntry(updated_fname, entry_name)
3197 self.assertEqual(expected, data)
3198
3199 # Check the state looks right.
3200 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003201
Simon Glassfb30e292019-07-20 12:23:51 -06003202 def testUpdateFdtAllRepack(self):
3203 """Test that all device trees are updated with offset/size info"""
3204 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3205 SECTION_SIZE = 0x300
3206 DTB_SIZE = 602
3207 FDTMAP_SIZE = 608
3208 base_expected = {
3209 'offset': 0,
3210 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3211 'image-pos': 0,
3212 'section:offset': 0,
3213 'section:size': SECTION_SIZE,
3214 'section:image-pos': 0,
3215 'section/u-boot-dtb:offset': 4,
3216 'section/u-boot-dtb:size': 636,
3217 'section/u-boot-dtb:image-pos': 4,
3218 'u-boot-spl-dtb:offset': SECTION_SIZE,
3219 'u-boot-spl-dtb:size': DTB_SIZE,
3220 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3221 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3222 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3223 'u-boot-tpl-dtb:size': DTB_SIZE,
3224 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3225 'fdtmap:size': FDTMAP_SIZE,
3226 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3227 }
3228 main_expected = {
3229 'section:orig-size': SECTION_SIZE,
3230 'section/u-boot-dtb:orig-offset': 4,
3231 }
3232
3233 # We expect three device-tree files in the output, with the first one
3234 # within a fixed-size section.
3235 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3236 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3237 # main U-Boot tree. All three should have the same positions and offset
3238 # except that the main tree should include the main_expected properties
3239 start = 4
3240 for item in ['', 'spl', 'tpl', None]:
3241 if item is None:
3242 start += 16 # Move past fdtmap header
3243 dtb = fdt.Fdt.FromData(data[start:])
3244 dtb.Scan()
3245 props = self._GetPropTree(dtb,
3246 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3247 prefix='/' if item is None else '/binman/')
3248 expected = dict(base_expected)
3249 if item:
3250 expected[item] = 0
3251 else:
3252 # Main DTB and fdtdec should include the 'orig-' properties
3253 expected.update(main_expected)
3254 # Helpful for debugging:
3255 #for prop in sorted(props):
3256 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3257 self.assertEqual(expected, props)
3258 if item == '':
3259 start = SECTION_SIZE
3260 else:
3261 start += dtb._fdt_obj.totalsize()
3262
Simon Glass11453762019-07-20 12:23:55 -06003263 def testFdtmapHeaderMiddle(self):
3264 """Test an FDT map in the middle of an image when it should be at end"""
3265 with self.assertRaises(ValueError) as e:
3266 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3267 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3268 str(e.exception))
3269
3270 def testFdtmapHeaderStartBad(self):
3271 """Test an FDT map in middle of an image when it should be at start"""
3272 with self.assertRaises(ValueError) as e:
3273 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3274 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3275 str(e.exception))
3276
3277 def testFdtmapHeaderEndBad(self):
3278 """Test an FDT map at the start of an image when it should be at end"""
3279 with self.assertRaises(ValueError) as e:
3280 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3281 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3282 str(e.exception))
3283
3284 def testFdtmapHeaderNoSize(self):
3285 """Test an image header at the end of an image with undefined size"""
3286 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3287
Simon Glassf8a54bc2019-07-20 12:23:56 -06003288 def testReplaceResize(self):
3289 """Test replacing a single file in an entry with a larger file"""
3290 expected = U_BOOT_DATA + b'x'
3291 data, _, image = self._RunReplaceCmd('u-boot', expected,
3292 dts='139_replace_repack.dts')
3293 self.assertEqual(expected, data)
3294
3295 entries = image.GetEntries()
3296 dtb_data = entries['u-boot-dtb'].data
3297 dtb = fdt.Fdt.FromData(dtb_data)
3298 dtb.Scan()
3299
3300 # The u-boot section should now be larger in the dtb
3301 node = dtb.GetNode('/binman/u-boot')
3302 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3303
3304 # Same for the fdtmap
3305 fdata = entries['fdtmap'].data
3306 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3307 fdtb.Scan()
3308 fnode = fdtb.GetNode('/u-boot')
3309 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3310
3311 def testReplaceResizeNoRepack(self):
3312 """Test replacing an entry with a larger file when not allowed"""
3313 expected = U_BOOT_DATA + b'x'
3314 with self.assertRaises(ValueError) as e:
3315 self._RunReplaceCmd('u-boot', expected)
3316 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3317 str(e.exception))
3318
Simon Glass9d8ee322019-07-20 12:23:58 -06003319 def testEntryShrink(self):
3320 """Test contracting an entry after it is packed"""
3321 try:
3322 state.SetAllowEntryContraction(True)
3323 data = self._DoReadFileDtb('140_entry_shrink.dts',
3324 update_dtb=True)[0]
3325 finally:
3326 state.SetAllowEntryContraction(False)
3327 self.assertEqual(b'a', data[:1])
3328 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3329 self.assertEqual(b'a', data[-1:])
3330
3331 def testEntryShrinkFail(self):
3332 """Test not being allowed to contract an entry after it is packed"""
3333 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3334
3335 # In this case there is a spare byte at the end of the data. The size of
3336 # the contents is only 1 byte but we still have the size before it
3337 # shrunk.
3338 self.assertEqual(b'a\0', data[:2])
3339 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3340 self.assertEqual(b'a\0', data[-2:])
3341
Simon Glass70e32982019-07-20 12:24:01 -06003342 def testDescriptorOffset(self):
3343 """Test that the Intel descriptor is always placed at at the start"""
3344 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3345 image = control.images['image']
3346 entries = image.GetEntries()
3347 desc = entries['intel-descriptor']
3348 self.assertEqual(0xff800000, desc.offset);
3349 self.assertEqual(0xff800000, desc.image_pos);
3350
Simon Glass37fdd142019-07-20 12:24:06 -06003351 def testReplaceCbfs(self):
3352 """Test replacing a single file in CBFS without changing the size"""
3353 self._CheckLz4()
3354 expected = b'x' * len(U_BOOT_DATA)
3355 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003356 updated_fname = tools.get_output_filename('image-updated.bin')
3357 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003358 entry_name = 'section/cbfs/u-boot'
3359 control.WriteEntry(updated_fname, entry_name, expected,
3360 allow_resize=True)
3361 data = control.ReadEntry(updated_fname, entry_name)
3362 self.assertEqual(expected, data)
3363
3364 def testReplaceResizeCbfs(self):
3365 """Test replacing a single file in CBFS with one of a different size"""
3366 self._CheckLz4()
3367 expected = U_BOOT_DATA + b'x'
3368 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003369 updated_fname = tools.get_output_filename('image-updated.bin')
3370 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003371 entry_name = 'section/cbfs/u-boot'
3372 control.WriteEntry(updated_fname, entry_name, expected,
3373 allow_resize=True)
3374 data = control.ReadEntry(updated_fname, entry_name)
3375 self.assertEqual(expected, data)
3376
Simon Glass30033c22019-07-20 12:24:15 -06003377 def _SetupForReplace(self):
3378 """Set up some files to use to replace entries
3379
3380 This generates an image, copies it to a new file, extracts all the files
3381 in it and updates some of them
3382
3383 Returns:
3384 List
3385 Image filename
3386 Output directory
3387 Expected values for updated entries, each a string
3388 """
3389 data = self._DoReadFileRealDtb('143_replace_all.dts')
3390
Simon Glass80025522022-01-29 14:14:04 -07003391 updated_fname = tools.get_output_filename('image-updated.bin')
3392 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003393
3394 outdir = os.path.join(self._indir, 'extract')
3395 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3396
3397 expected1 = b'x' + U_BOOT_DATA + b'y'
3398 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003399 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003400
3401 expected2 = b'a' + U_BOOT_DATA + b'b'
3402 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003403 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003404
3405 expected_text = b'not the same text'
3406 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003407 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003408
3409 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3410 dtb = fdt.FdtScan(dtb_fname)
3411 node = dtb.GetNode('/binman/text')
3412 node.AddString('my-property', 'the value')
3413 dtb.Sync(auto_resize=True)
3414 dtb.Flush()
3415
3416 return updated_fname, outdir, expected1, expected2, expected_text
3417
3418 def _CheckReplaceMultiple(self, entry_paths):
3419 """Handle replacing the contents of multiple entries
3420
3421 Args:
3422 entry_paths: List of entry paths to replace
3423
3424 Returns:
3425 List
3426 Dict of entries in the image:
3427 key: Entry name
3428 Value: Entry object
3429 Expected values for updated entries, each a string
3430 """
3431 updated_fname, outdir, expected1, expected2, expected_text = (
3432 self._SetupForReplace())
3433 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3434
3435 image = Image.FromFile(updated_fname)
3436 image.LoadData()
3437 return image.GetEntries(), expected1, expected2, expected_text
3438
3439 def testReplaceAll(self):
3440 """Test replacing the contents of all entries"""
3441 entries, expected1, expected2, expected_text = (
3442 self._CheckReplaceMultiple([]))
3443 data = entries['u-boot'].data
3444 self.assertEqual(expected1, data)
3445
3446 data = entries['u-boot2'].data
3447 self.assertEqual(expected2, data)
3448
3449 data = entries['text'].data
3450 self.assertEqual(expected_text, data)
3451
3452 # Check that the device tree is updated
3453 data = entries['u-boot-dtb'].data
3454 dtb = fdt.Fdt.FromData(data)
3455 dtb.Scan()
3456 node = dtb.GetNode('/binman/text')
3457 self.assertEqual('the value', node.props['my-property'].value)
3458
3459 def testReplaceSome(self):
3460 """Test replacing the contents of a few entries"""
3461 entries, expected1, expected2, expected_text = (
3462 self._CheckReplaceMultiple(['u-boot2', 'text']))
3463
3464 # This one should not change
3465 data = entries['u-boot'].data
3466 self.assertEqual(U_BOOT_DATA, data)
3467
3468 data = entries['u-boot2'].data
3469 self.assertEqual(expected2, data)
3470
3471 data = entries['text'].data
3472 self.assertEqual(expected_text, data)
3473
3474 def testReplaceCmd(self):
3475 """Test replacing a file fron an image on the command line"""
3476 self._DoReadFileRealDtb('143_replace_all.dts')
3477
3478 try:
3479 tmpdir, updated_fname = self._SetupImageInTmpdir()
3480
3481 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3482 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003483 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003484
3485 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003486 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003487 self.assertEqual(expected, data[:len(expected)])
3488 map_fname = os.path.join(tmpdir, 'image-updated.map')
3489 self.assertFalse(os.path.exists(map_fname))
3490 finally:
3491 shutil.rmtree(tmpdir)
3492
3493 def testReplaceCmdSome(self):
3494 """Test replacing some files fron an image on the command line"""
3495 updated_fname, outdir, expected1, expected2, expected_text = (
3496 self._SetupForReplace())
3497
3498 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3499 'u-boot2', 'text')
3500
Simon Glass80025522022-01-29 14:14:04 -07003501 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003502 image = Image.FromFile(updated_fname)
3503 image.LoadData()
3504 entries = image.GetEntries()
3505
3506 # This one should not change
3507 data = entries['u-boot'].data
3508 self.assertEqual(U_BOOT_DATA, data)
3509
3510 data = entries['u-boot2'].data
3511 self.assertEqual(expected2, data)
3512
3513 data = entries['text'].data
3514 self.assertEqual(expected_text, data)
3515
3516 def testReplaceMissing(self):
3517 """Test replacing entries where the file is missing"""
3518 updated_fname, outdir, expected1, expected2, expected_text = (
3519 self._SetupForReplace())
3520
3521 # Remove one of the files, to generate a warning
3522 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3523 os.remove(u_boot_fname1)
3524
3525 with test_util.capture_sys_output() as (stdout, stderr):
3526 control.ReplaceEntries(updated_fname, None, outdir, [])
3527 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003528 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003529
3530 def testReplaceCmdMap(self):
3531 """Test replacing a file fron an image on the command line"""
3532 self._DoReadFileRealDtb('143_replace_all.dts')
3533
3534 try:
3535 tmpdir, updated_fname = self._SetupImageInTmpdir()
3536
3537 fname = os.path.join(self._indir, 'update-u-boot.bin')
3538 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003539 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003540
3541 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3542 '-f', fname, '-m')
3543 map_fname = os.path.join(tmpdir, 'image-updated.map')
3544 self.assertTrue(os.path.exists(map_fname))
3545 finally:
3546 shutil.rmtree(tmpdir)
3547
3548 def testReplaceNoEntryPaths(self):
3549 """Test replacing an entry without an entry path"""
3550 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003551 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003552 with self.assertRaises(ValueError) as e:
3553 control.ReplaceEntries(image_fname, 'fname', None, [])
3554 self.assertIn('Must specify an entry path to read with -f',
3555 str(e.exception))
3556
3557 def testReplaceTooManyEntryPaths(self):
3558 """Test extracting some entries"""
3559 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003560 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003561 with self.assertRaises(ValueError) as e:
3562 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3563 self.assertIn('Must specify exactly one entry path to write with -f',
3564 str(e.exception))
3565
Simon Glass0b074d62019-08-24 07:22:48 -06003566 def testPackReset16(self):
3567 """Test that an image with an x86 reset16 region can be created"""
3568 data = self._DoReadFile('144_x86_reset16.dts')
3569 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3570
3571 def testPackReset16Spl(self):
3572 """Test that an image with an x86 reset16-spl region can be created"""
3573 data = self._DoReadFile('145_x86_reset16_spl.dts')
3574 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3575
3576 def testPackReset16Tpl(self):
3577 """Test that an image with an x86 reset16-tpl region can be created"""
3578 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3579 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3580
Simon Glass232f90c2019-08-24 07:22:50 -06003581 def testPackIntelFit(self):
3582 """Test that an image with an Intel FIT and pointer can be created"""
3583 data = self._DoReadFile('147_intel_fit.dts')
3584 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3585 fit = data[16:32];
3586 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3587 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3588
3589 image = control.images['image']
3590 entries = image.GetEntries()
3591 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3592 self.assertEqual(expected_ptr, ptr)
3593
3594 def testPackIntelFitMissing(self):
3595 """Test detection of a FIT pointer with not FIT region"""
3596 with self.assertRaises(ValueError) as e:
3597 self._DoReadFile('148_intel_fit_missing.dts')
3598 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3599 str(e.exception))
3600
Simon Glass72555fa2019-11-06 17:22:44 -07003601 def _CheckSymbolsTplSection(self, dts, expected_vals):
3602 data = self._DoReadFile(dts)
3603 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003604 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003605 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003606 self.assertEqual(expected1, data[:upto1])
3607
3608 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003609 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003610 self.assertEqual(expected2, data[upto1:upto2])
3611
Simon Glass4e353e22019-08-24 07:23:04 -06003612 upto3 = 0x34 + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003613 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003614 self.assertEqual(expected3, data[upto2:upto3])
3615
Simon Glass3f8ff012019-08-24 07:23:05 -06003616 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass72555fa2019-11-06 17:22:44 -07003617 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3618
3619 def testSymbolsTplSection(self):
3620 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3621 self._SetupSplElf('u_boot_binman_syms')
3622 self._SetupTplElf('u_boot_binman_syms')
3623 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3624 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3625
3626 def testSymbolsTplSectionX86(self):
3627 """Test binman can assign symbols in a section with end-at-4gb"""
3628 self._SetupSplElf('u_boot_binman_syms_x86')
3629 self._SetupTplElf('u_boot_binman_syms_x86')
3630 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3631 [0xffffff04, 0xffffff1c, 0xffffff34,
3632 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003633
Simon Glass98c59572019-08-24 07:23:03 -06003634 def testPackX86RomIfwiSectiom(self):
3635 """Test that a section can be placed in an IFWI region"""
3636 self._SetupIfwi('fitimage.bin')
3637 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3638 self._CheckIfwi(data)
3639
Simon Glassba7985d2019-08-24 07:23:07 -06003640 def testPackFspM(self):
3641 """Test that an image with a FSP memory-init binary can be created"""
3642 data = self._DoReadFile('152_intel_fsp_m.dts')
3643 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3644
Simon Glass4d9086d2019-10-20 21:31:35 -06003645 def testPackFspS(self):
3646 """Test that an image with a FSP silicon-init binary can be created"""
3647 data = self._DoReadFile('153_intel_fsp_s.dts')
3648 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003649
Simon Glass9ea87b22019-10-20 21:31:36 -06003650 def testPackFspT(self):
3651 """Test that an image with a FSP temp-ram-init binary can be created"""
3652 data = self._DoReadFile('154_intel_fsp_t.dts')
3653 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3654
Simon Glass48f3aad2020-07-09 18:39:31 -06003655 def testMkimage(self):
3656 """Test using mkimage to build an image"""
3657 data = self._DoReadFile('156_mkimage.dts')
3658
3659 # Just check that the data appears in the file somewhere
3660 self.assertIn(U_BOOT_SPL_DATA, data)
3661
Simon Glass66152ce2022-01-09 20:14:09 -07003662 def testMkimageMissing(self):
3663 """Test that binman still produces an image if mkimage is missing"""
3664 with test_util.capture_sys_output() as (_, stderr):
3665 self._DoTestFile('156_mkimage.dts',
3666 force_missing_bintools='mkimage')
3667 err = stderr.getvalue()
3668 self.assertRegex(err,
3669 "Image 'main-section'.*missing bintools.*: mkimage")
3670
Simon Glass5e560182020-07-09 18:39:36 -06003671 def testExtblob(self):
3672 """Test an image with an external blob"""
3673 data = self._DoReadFile('157_blob_ext.dts')
3674 self.assertEqual(REFCODE_DATA, data)
3675
3676 def testExtblobMissing(self):
3677 """Test an image with a missing external blob"""
3678 with self.assertRaises(ValueError) as e:
3679 self._DoReadFile('158_blob_ext_missing.dts')
3680 self.assertIn("Filename 'missing-file' not found in input path",
3681 str(e.exception))
3682
Simon Glass5d94cc62020-07-09 18:39:38 -06003683 def testExtblobMissingOk(self):
3684 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003685 with test_util.capture_sys_output() as (stdout, stderr):
3686 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3687 err = stderr.getvalue()
3688 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3689
3690 def testExtblobMissingOkSect(self):
3691 """Test an image with an missing external blob that is allowed"""
3692 with test_util.capture_sys_output() as (stdout, stderr):
3693 self._DoTestFile('159_blob_ext_missing_sect.dts',
3694 allow_missing=True)
3695 err = stderr.getvalue()
3696 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3697 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003698
Simon Glasse88cef92020-07-09 18:39:41 -06003699 def testPackX86RomMeMissingDesc(self):
3700 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003701 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003702 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003703 err = stderr.getvalue()
3704 self.assertRegex(err,
3705 "Image 'main-section'.*missing.*: intel-descriptor")
3706
3707 def testPackX86RomMissingIfwi(self):
3708 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3709 self._SetupIfwi('fitimage.bin')
3710 pathname = os.path.join(self._indir, 'fitimage.bin')
3711 os.remove(pathname)
3712 with test_util.capture_sys_output() as (stdout, stderr):
3713 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3714 err = stderr.getvalue()
3715 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3716
Simon Glass2a0fa982022-02-11 13:23:21 -07003717 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003718 """Test that zero-size overlapping regions are ignored"""
3719 self._DoTestFile('160_pack_overlap_zero.dts')
3720
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003721 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003722 # The data should be inside the FIT
3723 dtb = fdt.Fdt.FromData(fit_data)
3724 dtb.Scan()
3725 fnode = dtb.GetNode('/images/kernel')
3726 self.assertIn('data', fnode.props)
3727
3728 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003729 tools.write_file(fname, fit_data)
3730 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003731
3732 # Check a few features to make sure the plumbing works. We don't need
3733 # to test the operation of mkimage or dumpimage here. First convert the
3734 # output into a dict where the keys are the fields printed by dumpimage
3735 # and the values are a list of values for each field
3736 lines = out.splitlines()
3737
3738 # Converts "Compression: gzip compressed" into two groups:
3739 # 'Compression' and 'gzip compressed'
3740 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3741 vals = collections.defaultdict(list)
3742 for line in lines:
3743 mat = re_line.match(line)
3744 vals[mat.group(1)].append(mat.group(2))
3745
3746 self.assertEquals('FIT description: test-desc', lines[0])
3747 self.assertIn('Created:', lines[1])
3748 self.assertIn('Image 0 (kernel)', vals)
3749 self.assertIn('Hash value', vals)
3750 data_sizes = vals.get('Data Size')
3751 self.assertIsNotNone(data_sizes)
3752 self.assertEqual(2, len(data_sizes))
3753 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003754 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3755 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3756
3757 def testSimpleFit(self):
3758 """Test an image with a FIT inside"""
3759 data = self._DoReadFile('161_fit.dts')
3760 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3761 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3762 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3763
3764 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3765
3766 def testSimpleFitExpandsSubentries(self):
3767 """Test that FIT images expand their subentries"""
3768 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3769 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3770 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3771 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3772
3773 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003774
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003775 def testSimpleFitImagePos(self):
3776 """Test that we have correct image-pos for FIT subentries"""
3777 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3778 update_dtb=True)
3779 dtb = fdt.Fdt(out_dtb_fname)
3780 dtb.Scan()
3781 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3782
3783 self.assertEqual({
3784 'image-pos': 0,
3785 'offset': 0,
3786 'size': 1890,
3787
3788 'u-boot:image-pos': 0,
3789 'u-boot:offset': 0,
3790 'u-boot:size': 4,
3791
3792 'fit:image-pos': 4,
3793 'fit:offset': 4,
3794 'fit:size': 1840,
3795
3796 'fit/images/kernel:image-pos': 160,
3797 'fit/images/kernel:offset': 156,
3798 'fit/images/kernel:size': 4,
3799
3800 'fit/images/kernel/u-boot:image-pos': 160,
3801 'fit/images/kernel/u-boot:offset': 0,
3802 'fit/images/kernel/u-boot:size': 4,
3803
3804 'fit/images/fdt-1:image-pos': 456,
3805 'fit/images/fdt-1:offset': 452,
3806 'fit/images/fdt-1:size': 6,
3807
3808 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 456,
3809 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3810 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3811
3812 'u-boot-nodtb:image-pos': 1844,
3813 'u-boot-nodtb:offset': 1844,
3814 'u-boot-nodtb:size': 46,
3815 }, props)
3816
3817 # Actually check the data is where we think it is
3818 for node, expected in [
3819 ("u-boot", U_BOOT_DATA),
3820 ("fit/images/kernel", U_BOOT_DATA),
3821 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3822 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3823 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3824 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3825 ]:
3826 image_pos = props[f"{node}:image-pos"]
3827 size = props[f"{node}:size"]
3828 self.assertEqual(len(expected), size)
3829 self.assertEqual(expected, data[image_pos:image_pos+size])
3830
Simon Glass45d556d2020-07-09 18:39:45 -06003831 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003832 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003833 data = self._DoReadFile('162_fit_external.dts')
3834 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3835
Simon Glass7932c882022-01-09 20:13:39 -07003836 # Size of the external-data region as set up by mkimage
3837 external_data_size = len(U_BOOT_DATA) + 2
3838 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003839 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003840 len(U_BOOT_NODTB_DATA))
3841
Simon Glass45d556d2020-07-09 18:39:45 -06003842 # The data should be outside the FIT
3843 dtb = fdt.Fdt.FromData(fit_data)
3844 dtb.Scan()
3845 fnode = dtb.GetNode('/images/kernel')
3846 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003847 self.assertEqual(len(U_BOOT_DATA),
3848 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3849 fit_pos = 0x400;
3850 self.assertEqual(
3851 fit_pos,
3852 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3853
3854 self.assertEquals(expected_size, len(data))
3855 actual_pos = len(U_BOOT_DATA) + fit_pos
3856 self.assertEqual(U_BOOT_DATA + b'aa',
3857 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003858
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003859 def testFitExternalImagePos(self):
3860 """Test that we have correct image-pos for external FIT subentries"""
3861 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3862 update_dtb=True)
3863 dtb = fdt.Fdt(out_dtb_fname)
3864 dtb.Scan()
3865 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3866
3867 self.assertEqual({
3868 'image-pos': 0,
3869 'offset': 0,
3870 'size': 1082,
3871
3872 'u-boot:image-pos': 0,
3873 'u-boot:offset': 0,
3874 'u-boot:size': 4,
3875
3876 'fit:size': 1032,
3877 'fit:offset': 4,
3878 'fit:image-pos': 4,
3879
3880 'fit/images/kernel:size': 4,
3881 'fit/images/kernel:offset': 1024,
3882 'fit/images/kernel:image-pos': 1028,
3883
3884 'fit/images/kernel/u-boot:size': 4,
3885 'fit/images/kernel/u-boot:offset': 0,
3886 'fit/images/kernel/u-boot:image-pos': 1028,
3887
3888 'fit/images/fdt-1:size': 2,
3889 'fit/images/fdt-1:offset': 1028,
3890 'fit/images/fdt-1:image-pos': 1032,
3891
3892 'fit/images/fdt-1/_testing:size': 2,
3893 'fit/images/fdt-1/_testing:offset': 0,
3894 'fit/images/fdt-1/_testing:image-pos': 1032,
3895
3896 'u-boot-nodtb:image-pos': 1036,
3897 'u-boot-nodtb:offset': 1036,
3898 'u-boot-nodtb:size': 46,
3899 }, props)
3900
3901 # Actually check the data is where we think it is
3902 for node, expected in [
3903 ("u-boot", U_BOOT_DATA),
3904 ("fit/images/kernel", U_BOOT_DATA),
3905 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3906 ("fit/images/fdt-1", b'aa'),
3907 ("fit/images/fdt-1/_testing", b'aa'),
3908 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3909 ]:
3910 image_pos = props[f"{node}:image-pos"]
3911 size = props[f"{node}:size"]
3912 self.assertEqual(len(expected), size)
3913 self.assertEqual(expected, data[image_pos:image_pos+size])
3914
Simon Glass66152ce2022-01-09 20:14:09 -07003915 def testFitMissing(self):
3916 """Test that binman still produces a FIT image if mkimage is missing"""
3917 with test_util.capture_sys_output() as (_, stderr):
3918 self._DoTestFile('162_fit_external.dts',
3919 force_missing_bintools='mkimage')
3920 err = stderr.getvalue()
3921 self.assertRegex(err,
3922 "Image 'main-section'.*missing bintools.*: mkimage")
3923
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003924 def testSectionIgnoreHashSignature(self):
3925 """Test that sections ignore hash, signature nodes for its data"""
3926 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3927 expected = (U_BOOT_DATA + U_BOOT_DATA)
3928 self.assertEqual(expected, data)
3929
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003930 def testPadInSections(self):
3931 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06003932 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3933 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07003934 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
3935 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003936 U_BOOT_DATA)
3937 self.assertEqual(expected, data)
3938
Simon Glassd12599d2020-10-26 17:40:09 -06003939 dtb = fdt.Fdt(out_dtb_fname)
3940 dtb.Scan()
3941 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3942 expected = {
3943 'image-pos': 0,
3944 'offset': 0,
3945 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3946
3947 'section:image-pos': 0,
3948 'section:offset': 0,
3949 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3950
3951 'section/before:image-pos': 0,
3952 'section/before:offset': 0,
3953 'section/before:size': len(U_BOOT_DATA),
3954
3955 'section/u-boot:image-pos': 4,
3956 'section/u-boot:offset': 4,
3957 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3958
3959 'section/after:image-pos': 26,
3960 'section/after:offset': 26,
3961 'section/after:size': len(U_BOOT_DATA),
3962 }
3963 self.assertEqual(expected, props)
3964
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003965 def testFitImageSubentryAlignment(self):
3966 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03003967 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003968 entry_args = {
3969 'test-id': TEXT_DATA,
3970 }
3971 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3972 entry_args=entry_args)
3973 dtb = fdt.Fdt.FromData(data)
3974 dtb.Scan()
3975
3976 node = dtb.GetNode('/images/kernel')
3977 data = dtb.GetProps(node)["data"].bytes
3978 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07003979 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
3980 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003981 self.assertEqual(expected, data)
3982
3983 node = dtb.GetNode('/images/fdt-1')
3984 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07003985 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
3986 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003987 U_BOOT_DTB_DATA)
3988 self.assertEqual(expected, data)
3989
3990 def testFitExtblobMissingOk(self):
3991 """Test a FIT with a missing external blob that is allowed"""
3992 with test_util.capture_sys_output() as (stdout, stderr):
3993 self._DoTestFile('168_fit_missing_blob.dts',
3994 allow_missing=True)
3995 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06003996 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003997
Simon Glass21db0ff2020-09-01 05:13:54 -06003998 def testBlobNamedByArgMissing(self):
3999 """Test handling of a missing entry arg"""
4000 with self.assertRaises(ValueError) as e:
4001 self._DoReadFile('068_blob_named_by_arg.dts')
4002 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4003 str(e.exception))
4004
Simon Glass559c4de2020-09-01 05:13:58 -06004005 def testPackBl31(self):
4006 """Test that an image with an ATF BL31 binary can be created"""
4007 data = self._DoReadFile('169_atf_bl31.dts')
4008 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4009
Samuel Holland9d8cc632020-10-21 21:12:15 -05004010 def testPackScp(self):
4011 """Test that an image with an SCP binary can be created"""
4012 data = self._DoReadFile('172_scp.dts')
4013 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4014
Simon Glassa435cd12020-09-01 05:13:59 -06004015 def testFitFdt(self):
4016 """Test an image with an FIT with multiple FDT images"""
4017 def _CheckFdt(seq, expected_data):
4018 """Check the FDT nodes
4019
4020 Args:
4021 seq: Sequence number to check (0 or 1)
4022 expected_data: Expected contents of 'data' property
4023 """
4024 name = 'fdt-%d' % seq
4025 fnode = dtb.GetNode('/images/%s' % name)
4026 self.assertIsNotNone(fnode)
4027 self.assertEqual({'description','type', 'compression', 'data'},
4028 set(fnode.props.keys()))
4029 self.assertEqual(expected_data, fnode.props['data'].bytes)
4030 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4031 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004032 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004033
4034 def _CheckConfig(seq, expected_data):
4035 """Check the configuration nodes
4036
4037 Args:
4038 seq: Sequence number to check (0 or 1)
4039 expected_data: Expected contents of 'data' property
4040 """
4041 cnode = dtb.GetNode('/configurations')
4042 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004043 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004044
4045 name = 'config-%d' % seq
4046 fnode = dtb.GetNode('/configurations/%s' % name)
4047 self.assertIsNotNone(fnode)
4048 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4049 set(fnode.props.keys()))
4050 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4051 fnode.props['description'].value)
4052 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4053
4054 entry_args = {
4055 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004056 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004057 }
4058 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004059 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004060 entry_args=entry_args,
4061 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4062 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4063 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4064
4065 dtb = fdt.Fdt.FromData(fit_data)
4066 dtb.Scan()
4067 fnode = dtb.GetNode('/images/kernel')
4068 self.assertIn('data', fnode.props)
4069
4070 # Check all the properties in fdt-1 and fdt-2
4071 _CheckFdt(1, TEST_FDT1_DATA)
4072 _CheckFdt(2, TEST_FDT2_DATA)
4073
4074 # Check configurations
4075 _CheckConfig(1, TEST_FDT1_DATA)
4076 _CheckConfig(2, TEST_FDT2_DATA)
4077
4078 def testFitFdtMissingList(self):
4079 """Test handling of a missing 'of-list' entry arg"""
4080 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004081 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004082 self.assertIn("Generator node requires 'of-list' entry argument",
4083 str(e.exception))
4084
4085 def testFitFdtEmptyList(self):
4086 """Test handling of an empty 'of-list' entry arg"""
4087 entry_args = {
4088 'of-list': '',
4089 }
4090 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4091
4092 def testFitFdtMissingProp(self):
4093 """Test handling of a missing 'fit,fdt-list' property"""
4094 with self.assertRaises(ValueError) as e:
4095 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4096 self.assertIn("Generator node requires 'fit,fdt-list' property",
4097 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004098
Simon Glass1032acc2020-09-06 10:39:08 -06004099 def testFitFdtMissing(self):
4100 """Test handling of a missing 'default-dt' entry arg"""
4101 entry_args = {
4102 'of-list': 'test-fdt1 test-fdt2',
4103 }
4104 with self.assertRaises(ValueError) as e:
4105 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004106 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004107 entry_args=entry_args,
4108 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4109 self.assertIn("Generated 'default' node requires default-dt entry argument",
4110 str(e.exception))
4111
4112 def testFitFdtNotInList(self):
4113 """Test handling of a default-dt that is not in the of-list"""
4114 entry_args = {
4115 'of-list': 'test-fdt1 test-fdt2',
4116 'default-dt': 'test-fdt3',
4117 }
4118 with self.assertRaises(ValueError) as e:
4119 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004120 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004121 entry_args=entry_args,
4122 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4123 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4124 str(e.exception))
4125
Simon Glassa820af72020-09-06 10:39:09 -06004126 def testFitExtblobMissingHelp(self):
4127 """Test display of help messages when an external blob is missing"""
4128 control.missing_blob_help = control._ReadMissingBlobHelp()
4129 control.missing_blob_help['wibble'] = 'Wibble test'
4130 control.missing_blob_help['another'] = 'Another test'
4131 with test_util.capture_sys_output() as (stdout, stderr):
4132 self._DoTestFile('168_fit_missing_blob.dts',
4133 allow_missing=True)
4134 err = stderr.getvalue()
4135
4136 # We can get the tag from the name, the type or the missing-msg
4137 # property. Check all three.
4138 self.assertIn('You may need to build ARM Trusted', err)
4139 self.assertIn('Wibble test', err)
4140 self.assertIn('Another test', err)
4141
Simon Glass6f1f4d42020-09-06 10:35:32 -06004142 def testMissingBlob(self):
4143 """Test handling of a blob containing a missing file"""
4144 with self.assertRaises(ValueError) as e:
4145 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4146 self.assertIn("Filename 'missing' not found in input path",
4147 str(e.exception))
4148
Simon Glassa0729502020-09-06 10:35:33 -06004149 def testEnvironment(self):
4150 """Test adding a U-Boot environment"""
4151 data = self._DoReadFile('174_env.dts')
4152 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4153 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4154 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4155 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4156 env)
4157
4158 def testEnvironmentNoSize(self):
4159 """Test that a missing 'size' property is detected"""
4160 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004161 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004162 self.assertIn("'u-boot-env' entry must have a size property",
4163 str(e.exception))
4164
4165 def testEnvironmentTooSmall(self):
4166 """Test handling of an environment that does not fit"""
4167 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004168 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004169
4170 # checksum, start byte, environment with \0 terminator, final \0
4171 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4172 short = need - 0x8
4173 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4174 str(e.exception))
4175
Simon Glassd1fdf752020-10-26 17:40:01 -06004176 def testSkipAtStart(self):
4177 """Test handling of skip-at-start section"""
4178 data = self._DoReadFile('177_skip_at_start.dts')
4179 self.assertEqual(U_BOOT_DATA, data)
4180
4181 image = control.images['image']
4182 entries = image.GetEntries()
4183 section = entries['section']
4184 self.assertEqual(0, section.offset)
4185 self.assertEqual(len(U_BOOT_DATA), section.size)
4186 self.assertEqual(U_BOOT_DATA, section.GetData())
4187
4188 entry = section.GetEntries()['u-boot']
4189 self.assertEqual(16, entry.offset)
4190 self.assertEqual(len(U_BOOT_DATA), entry.size)
4191 self.assertEqual(U_BOOT_DATA, entry.data)
4192
4193 def testSkipAtStartPad(self):
4194 """Test handling of skip-at-start section with padded entry"""
4195 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004196 before = tools.get_bytes(0, 8)
4197 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004198 all = before + U_BOOT_DATA + after
4199 self.assertEqual(all, data)
4200
4201 image = control.images['image']
4202 entries = image.GetEntries()
4203 section = entries['section']
4204 self.assertEqual(0, section.offset)
4205 self.assertEqual(len(all), section.size)
4206 self.assertEqual(all, section.GetData())
4207
4208 entry = section.GetEntries()['u-boot']
4209 self.assertEqual(16, entry.offset)
4210 self.assertEqual(len(all), entry.size)
4211 self.assertEqual(U_BOOT_DATA, entry.data)
4212
4213 def testSkipAtStartSectionPad(self):
4214 """Test handling of skip-at-start section with padding"""
4215 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004216 before = tools.get_bytes(0, 8)
4217 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004218 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004219 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004220
4221 image = control.images['image']
4222 entries = image.GetEntries()
4223 section = entries['section']
4224 self.assertEqual(0, section.offset)
4225 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004226 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004227 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004228
4229 entry = section.GetEntries()['u-boot']
4230 self.assertEqual(16, entry.offset)
4231 self.assertEqual(len(U_BOOT_DATA), entry.size)
4232 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004233
Simon Glassbb395742020-10-26 17:40:14 -06004234 def testSectionPad(self):
4235 """Testing padding with sections"""
4236 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004237 expected = (tools.get_bytes(ord('&'), 3) +
4238 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004239 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004240 tools.get_bytes(ord('!'), 1) +
4241 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004242 self.assertEqual(expected, data)
4243
4244 def testSectionAlign(self):
4245 """Testing alignment with sections"""
4246 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4247 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004248 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004249 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004250 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004251 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004252 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4253 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004254 self.assertEqual(expected, data)
4255
Simon Glassd92c8362020-10-26 17:40:25 -06004256 def testCompressImage(self):
4257 """Test compression of the entire image"""
4258 self._CheckLz4()
4259 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4260 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4261 dtb = fdt.Fdt(out_dtb_fname)
4262 dtb.Scan()
4263 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4264 'uncomp-size'])
4265 orig = self._decompress(data)
4266 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4267
4268 # Do a sanity check on various fields
4269 image = control.images['image']
4270 entries = image.GetEntries()
4271 self.assertEqual(2, len(entries))
4272
4273 entry = entries['blob']
4274 self.assertEqual(COMPRESS_DATA, entry.data)
4275 self.assertEqual(len(COMPRESS_DATA), entry.size)
4276
4277 entry = entries['u-boot']
4278 self.assertEqual(U_BOOT_DATA, entry.data)
4279 self.assertEqual(len(U_BOOT_DATA), entry.size)
4280
4281 self.assertEqual(len(data), image.size)
4282 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4283 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4284 orig = self._decompress(image.data)
4285 self.assertEqual(orig, image.uncomp_data)
4286
4287 expected = {
4288 'blob:offset': 0,
4289 'blob:size': len(COMPRESS_DATA),
4290 'u-boot:offset': len(COMPRESS_DATA),
4291 'u-boot:size': len(U_BOOT_DATA),
4292 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4293 'offset': 0,
4294 'image-pos': 0,
4295 'size': len(data),
4296 }
4297 self.assertEqual(expected, props)
4298
4299 def testCompressImageLess(self):
4300 """Test compression where compression reduces the image size"""
4301 self._CheckLz4()
4302 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4303 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4304 dtb = fdt.Fdt(out_dtb_fname)
4305 dtb.Scan()
4306 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4307 'uncomp-size'])
4308 orig = self._decompress(data)
4309
4310 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4311
4312 # Do a sanity check on various fields
4313 image = control.images['image']
4314 entries = image.GetEntries()
4315 self.assertEqual(2, len(entries))
4316
4317 entry = entries['blob']
4318 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4319 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4320
4321 entry = entries['u-boot']
4322 self.assertEqual(U_BOOT_DATA, entry.data)
4323 self.assertEqual(len(U_BOOT_DATA), entry.size)
4324
4325 self.assertEqual(len(data), image.size)
4326 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4327 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4328 image.uncomp_size)
4329 orig = self._decompress(image.data)
4330 self.assertEqual(orig, image.uncomp_data)
4331
4332 expected = {
4333 'blob:offset': 0,
4334 'blob:size': len(COMPRESS_DATA_BIG),
4335 'u-boot:offset': len(COMPRESS_DATA_BIG),
4336 'u-boot:size': len(U_BOOT_DATA),
4337 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4338 'offset': 0,
4339 'image-pos': 0,
4340 'size': len(data),
4341 }
4342 self.assertEqual(expected, props)
4343
4344 def testCompressSectionSize(self):
4345 """Test compression of a section with a fixed size"""
4346 self._CheckLz4()
4347 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4348 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4349 dtb = fdt.Fdt(out_dtb_fname)
4350 dtb.Scan()
4351 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4352 'uncomp-size'])
4353 orig = self._decompress(data)
4354 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4355 expected = {
4356 'section/blob:offset': 0,
4357 'section/blob:size': len(COMPRESS_DATA),
4358 'section/u-boot:offset': len(COMPRESS_DATA),
4359 'section/u-boot:size': len(U_BOOT_DATA),
4360 'section:offset': 0,
4361 'section:image-pos': 0,
4362 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4363 'section:size': 0x30,
4364 'offset': 0,
4365 'image-pos': 0,
4366 'size': 0x30,
4367 }
4368 self.assertEqual(expected, props)
4369
4370 def testCompressSection(self):
4371 """Test compression of a section with no fixed size"""
4372 self._CheckLz4()
4373 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4374 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4375 dtb = fdt.Fdt(out_dtb_fname)
4376 dtb.Scan()
4377 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4378 'uncomp-size'])
4379 orig = self._decompress(data)
4380 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4381 expected = {
4382 'section/blob:offset': 0,
4383 'section/blob:size': len(COMPRESS_DATA),
4384 'section/u-boot:offset': len(COMPRESS_DATA),
4385 'section/u-boot:size': len(U_BOOT_DATA),
4386 'section:offset': 0,
4387 'section:image-pos': 0,
4388 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4389 'section:size': len(data),
4390 'offset': 0,
4391 'image-pos': 0,
4392 'size': len(data),
4393 }
4394 self.assertEqual(expected, props)
4395
4396 def testCompressExtra(self):
4397 """Test compression of a section with no fixed size"""
4398 self._CheckLz4()
4399 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4400 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4401 dtb = fdt.Fdt(out_dtb_fname)
4402 dtb.Scan()
4403 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4404 'uncomp-size'])
4405
4406 base = data[len(U_BOOT_DATA):]
4407 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4408 rest = base[len(U_BOOT_DATA):]
4409
4410 # Check compressed data
4411 section1 = self._decompress(rest)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07004412 expect1 = comp_util.compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
Simon Glassd92c8362020-10-26 17:40:25 -06004413 self.assertEquals(expect1, rest[:len(expect1)])
4414 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4415 rest1 = rest[len(expect1):]
4416
4417 section2 = self._decompress(rest1)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07004418 expect2 = comp_util.compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
Simon Glassd92c8362020-10-26 17:40:25 -06004419 self.assertEquals(expect2, rest1[:len(expect2)])
4420 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4421 rest2 = rest1[len(expect2):]
4422
4423 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4424 len(expect2) + len(U_BOOT_DATA))
4425 #self.assertEquals(expect_size, len(data))
4426
4427 #self.assertEquals(U_BOOT_DATA, rest2)
4428
4429 self.maxDiff = None
4430 expected = {
4431 'u-boot:offset': 0,
4432 'u-boot:image-pos': 0,
4433 'u-boot:size': len(U_BOOT_DATA),
4434
4435 'base:offset': len(U_BOOT_DATA),
4436 'base:image-pos': len(U_BOOT_DATA),
4437 'base:size': len(data) - len(U_BOOT_DATA),
4438 'base/u-boot:offset': 0,
4439 'base/u-boot:image-pos': len(U_BOOT_DATA),
4440 'base/u-boot:size': len(U_BOOT_DATA),
4441 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4442 len(expect2),
4443 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4444 len(expect2),
4445 'base/u-boot2:size': len(U_BOOT_DATA),
4446
4447 'base/section:offset': len(U_BOOT_DATA),
4448 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4449 'base/section:size': len(expect1),
4450 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4451 'base/section/blob:offset': 0,
4452 'base/section/blob:size': len(COMPRESS_DATA),
4453 'base/section/u-boot:offset': len(COMPRESS_DATA),
4454 'base/section/u-boot:size': len(U_BOOT_DATA),
4455
4456 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4457 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4458 'base/section2:size': len(expect2),
4459 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4460 'base/section2/blob:offset': 0,
4461 'base/section2/blob:size': len(COMPRESS_DATA),
4462 'base/section2/blob2:offset': len(COMPRESS_DATA),
4463 'base/section2/blob2:size': len(COMPRESS_DATA),
4464
4465 'offset': 0,
4466 'image-pos': 0,
4467 'size': len(data),
4468 }
4469 self.assertEqual(expected, props)
4470
Simon Glassecbe4732021-01-06 21:35:15 -07004471 def testSymbolsSubsection(self):
4472 """Test binman can assign symbols from a subsection"""
Simon Glass31e04cb2021-03-18 20:24:56 +13004473 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glassecbe4732021-01-06 21:35:15 -07004474
Simon Glass3fb25402021-01-06 21:35:16 -07004475 def testReadImageEntryArg(self):
4476 """Test reading an image that would need an entry arg to generate"""
4477 entry_args = {
4478 'cros-ec-rw-path': 'ecrw.bin',
4479 }
4480 data = self.data = self._DoReadFileDtb(
4481 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4482 entry_args=entry_args)
4483
Simon Glass80025522022-01-29 14:14:04 -07004484 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004485 orig_image = control.images['image']
4486
4487 # This should not generate an error about the missing 'cros-ec-rw-path'
4488 # since we are reading the image from a file. Compare with
4489 # testEntryArgsRequired()
4490 image = Image.FromFile(image_fname)
4491 self.assertEqual(orig_image.GetEntries().keys(),
4492 image.GetEntries().keys())
4493
Simon Glassa2af7302021-01-06 21:35:18 -07004494 def testFilesAlign(self):
4495 """Test alignment with files"""
4496 data = self._DoReadFile('190_files_align.dts')
4497
4498 # The first string is 15 bytes so will align to 16
4499 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4500 self.assertEqual(expect, data)
4501
Simon Glassdb84b562021-01-06 21:35:19 -07004502 def testReadImageSkip(self):
4503 """Test reading an image and accessing its FDT map"""
4504 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004505 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004506 orig_image = control.images['image']
4507 image = Image.FromFile(image_fname)
4508 self.assertEqual(orig_image.GetEntries().keys(),
4509 image.GetEntries().keys())
4510
4511 orig_entry = orig_image.GetEntries()['fdtmap']
4512 entry = image.GetEntries()['fdtmap']
4513 self.assertEqual(orig_entry.offset, entry.offset)
4514 self.assertEqual(orig_entry.size, entry.size)
4515 self.assertEqual(16, entry.image_pos)
4516
4517 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4518
4519 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4520
Simon Glassc98de972021-03-18 20:24:57 +13004521 def testTplNoDtb(self):
4522 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004523 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004524 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4525 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4526 data[:len(U_BOOT_TPL_NODTB_DATA)])
4527
Simon Glass63f41d42021-03-18 20:24:58 +13004528 def testTplBssPad(self):
4529 """Test that we can pad TPL's BSS with zeros"""
4530 # ELF file with a '__bss_size' symbol
4531 self._SetupTplElf()
4532 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004533 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004534 data)
4535
4536 def testTplBssPadMissing(self):
4537 """Test that a missing symbol is detected"""
4538 self._SetupTplElf('u_boot_ucode_ptr')
4539 with self.assertRaises(ValueError) as e:
4540 self._DoReadFile('193_tpl_bss_pad.dts')
4541 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4542 str(e.exception))
4543
Simon Glass718b5292021-03-18 20:25:07 +13004544 def checkDtbSizes(self, data, pad_len, start):
4545 """Check the size arguments in a dtb embedded in an image
4546
4547 Args:
4548 data: The image data
4549 pad_len: Length of the pad section in the image, in bytes
4550 start: Start offset of the devicetree to examine, within the image
4551
4552 Returns:
4553 Size of the devicetree in bytes
4554 """
4555 dtb_data = data[start:]
4556 dtb = fdt.Fdt.FromData(dtb_data)
4557 fdt_size = dtb.GetFdtObj().totalsize()
4558 dtb.Scan()
4559 props = self._GetPropTree(dtb, 'size')
4560 self.assertEqual({
4561 'size': len(data),
4562 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4563 'u-boot-spl/u-boot-spl-dtb:size': 801,
4564 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4565 'u-boot-spl:size': 860,
4566 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4567 'u-boot/u-boot-dtb:size': 781,
4568 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4569 'u-boot:size': 827,
4570 }, props)
4571 return fdt_size
4572
4573 def testExpanded(self):
4574 """Test that an expanded entry type is selected when needed"""
4575 self._SetupSplElf()
4576 self._SetupTplElf()
4577
4578 # SPL has a devicetree, TPL does not
4579 entry_args = {
4580 'spl-dtb': '1',
4581 'spl-bss-pad': 'y',
4582 'tpl-dtb': '',
4583 }
4584 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4585 entry_args=entry_args)
4586 image = control.images['image']
4587 entries = image.GetEntries()
4588 self.assertEqual(3, len(entries))
4589
4590 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4591 self.assertIn('u-boot', entries)
4592 entry = entries['u-boot']
4593 self.assertEqual('u-boot-expanded', entry.etype)
4594 subent = entry.GetEntries()
4595 self.assertEqual(2, len(subent))
4596 self.assertIn('u-boot-nodtb', subent)
4597 self.assertIn('u-boot-dtb', subent)
4598
4599 # Second, u-boot-spl, which should be expanded into three parts
4600 self.assertIn('u-boot-spl', entries)
4601 entry = entries['u-boot-spl']
4602 self.assertEqual('u-boot-spl-expanded', entry.etype)
4603 subent = entry.GetEntries()
4604 self.assertEqual(3, len(subent))
4605 self.assertIn('u-boot-spl-nodtb', subent)
4606 self.assertIn('u-boot-spl-bss-pad', subent)
4607 self.assertIn('u-boot-spl-dtb', subent)
4608
4609 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4610 # devicetree
4611 self.assertIn('u-boot-tpl', entries)
4612 entry = entries['u-boot-tpl']
4613 self.assertEqual('u-boot-tpl', entry.etype)
4614 self.assertEqual(None, entry.GetEntries())
4615
4616 def testExpandedTpl(self):
4617 """Test that an expanded entry type is selected for TPL when needed"""
4618 self._SetupTplElf()
4619
4620 entry_args = {
4621 'tpl-bss-pad': 'y',
4622 'tpl-dtb': 'y',
4623 }
4624 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4625 entry_args=entry_args)
4626 image = control.images['image']
4627 entries = image.GetEntries()
4628 self.assertEqual(1, len(entries))
4629
4630 # We only have u-boot-tpl, which be expanded
4631 self.assertIn('u-boot-tpl', entries)
4632 entry = entries['u-boot-tpl']
4633 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4634 subent = entry.GetEntries()
4635 self.assertEqual(3, len(subent))
4636 self.assertIn('u-boot-tpl-nodtb', subent)
4637 self.assertIn('u-boot-tpl-bss-pad', subent)
4638 self.assertIn('u-boot-tpl-dtb', subent)
4639
4640 def testExpandedNoPad(self):
4641 """Test an expanded entry without BSS pad enabled"""
4642 self._SetupSplElf()
4643 self._SetupTplElf()
4644
4645 # SPL has a devicetree, TPL does not
4646 entry_args = {
4647 'spl-dtb': 'something',
4648 'spl-bss-pad': 'n',
4649 'tpl-dtb': '',
4650 }
4651 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4652 entry_args=entry_args)
4653 image = control.images['image']
4654 entries = image.GetEntries()
4655
4656 # Just check u-boot-spl, which should be expanded into two parts
4657 self.assertIn('u-boot-spl', entries)
4658 entry = entries['u-boot-spl']
4659 self.assertEqual('u-boot-spl-expanded', entry.etype)
4660 subent = entry.GetEntries()
4661 self.assertEqual(2, len(subent))
4662 self.assertIn('u-boot-spl-nodtb', subent)
4663 self.assertIn('u-boot-spl-dtb', subent)
4664
4665 def testExpandedTplNoPad(self):
4666 """Test that an expanded entry type with padding disabled in TPL"""
4667 self._SetupTplElf()
4668
4669 entry_args = {
4670 'tpl-bss-pad': '',
4671 'tpl-dtb': 'y',
4672 }
4673 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4674 entry_args=entry_args)
4675 image = control.images['image']
4676 entries = image.GetEntries()
4677 self.assertEqual(1, len(entries))
4678
4679 # We only have u-boot-tpl, which be expanded
4680 self.assertIn('u-boot-tpl', entries)
4681 entry = entries['u-boot-tpl']
4682 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4683 subent = entry.GetEntries()
4684 self.assertEqual(2, len(subent))
4685 self.assertIn('u-boot-tpl-nodtb', subent)
4686 self.assertIn('u-boot-tpl-dtb', subent)
4687
4688 def testFdtInclude(self):
4689 """Test that an Fdt is update within all binaries"""
4690 self._SetupSplElf()
4691 self._SetupTplElf()
4692
4693 # SPL has a devicetree, TPL does not
4694 self.maxDiff = None
4695 entry_args = {
4696 'spl-dtb': '1',
4697 'spl-bss-pad': 'y',
4698 'tpl-dtb': '',
4699 }
4700 # Build the image. It includes two separate devicetree binaries, each
4701 # with their own contents, but all contain the binman definition.
4702 data = self._DoReadFileDtb(
4703 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4704 update_dtb=True, entry_args=entry_args)[0]
4705 pad_len = 10
4706
4707 # Check the U-Boot dtb
4708 start = len(U_BOOT_NODTB_DATA)
4709 fdt_size = self.checkDtbSizes(data, pad_len, start)
4710
4711 # Now check SPL
4712 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4713 fdt_size = self.checkDtbSizes(data, pad_len, start)
4714
4715 # TPL has no devicetree
4716 start += fdt_size + len(U_BOOT_TPL_DATA)
4717 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004718
Simon Glass7098b7f2021-03-21 18:24:30 +13004719 def testSymbolsExpanded(self):
4720 """Test binman can assign symbols in expanded entries"""
4721 entry_args = {
4722 'spl-dtb': '1',
4723 }
4724 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4725 U_BOOT_SPL_DTB_DATA, 0x38,
4726 entry_args=entry_args, use_expanded=True)
4727
Simon Glasse1915782021-03-21 18:24:31 +13004728 def testCollection(self):
4729 """Test a collection"""
4730 data = self._DoReadFile('198_collection.dts')
4731 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004732 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4733 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004734 data)
4735
Simon Glass27a7f772021-03-21 18:24:32 +13004736 def testCollectionSection(self):
4737 """Test a collection where a section must be built first"""
4738 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004739 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004740 # building the contents, producing an error is anything is still
4741 # missing.
4742 data = self._DoReadFile('199_collection_section.dts')
4743 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004744 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4745 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004746 data)
4747
Simon Glassf427c5f2021-03-21 18:24:33 +13004748 def testAlignDefault(self):
4749 """Test that default alignment works on sections"""
4750 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004751 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004752 U_BOOT_DATA)
4753 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004754 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004755 # No alignment within the nested section
4756 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4757 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004758 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004759 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004760
Bin Mengc0b15742021-05-10 20:23:33 +08004761 def testPackOpenSBI(self):
4762 """Test that an image with an OpenSBI binary can be created"""
4763 data = self._DoReadFile('201_opensbi.dts')
4764 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4765
Simon Glass76f496d2021-07-06 10:36:37 -06004766 def testSectionsSingleThread(self):
4767 """Test sections without multithreading"""
4768 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004769 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4770 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4771 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004772 self.assertEqual(expected, data)
4773
4774 def testThreadTimeout(self):
4775 """Test handling a thread that takes too long"""
4776 with self.assertRaises(ValueError) as e:
4777 self._DoTestFile('202_section_timeout.dts',
4778 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004779 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004780
Simon Glass748a1d42021-07-06 10:36:41 -06004781 def testTiming(self):
4782 """Test output of timing information"""
4783 data = self._DoReadFile('055_sections.dts')
4784 with test_util.capture_sys_output() as (stdout, stderr):
4785 state.TimingShow()
4786 self.assertIn('read:', stdout.getvalue())
4787 self.assertIn('compress:', stdout.getvalue())
4788
Simon Glassadfb8492021-11-03 21:09:18 -06004789 def testUpdateFdtInElf(self):
4790 """Test that we can update the devicetree in an ELF file"""
4791 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4792 outfile = os.path.join(self._indir, 'u-boot.out')
4793 begin_sym = 'dtb_embed_begin'
4794 end_sym = 'dtb_embed_end'
4795 retcode = self._DoTestFile(
4796 '060_fdt_update.dts', update_dtb=True,
4797 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4798 self.assertEqual(0, retcode)
4799
4800 # Check that the output file does in fact contact a dtb with the binman
4801 # definition in the correct place
4802 syms = elf.GetSymbolFileOffset(infile,
4803 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004804 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004805 dtb_data = data[syms['dtb_embed_begin'].offset:
4806 syms['dtb_embed_end'].offset]
4807
4808 dtb = fdt.Fdt.FromData(dtb_data)
4809 dtb.Scan()
4810 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4811 self.assertEqual({
4812 'image-pos': 0,
4813 'offset': 0,
4814 '_testing:offset': 32,
4815 '_testing:size': 2,
4816 '_testing:image-pos': 32,
4817 'section@0/u-boot:offset': 0,
4818 'section@0/u-boot:size': len(U_BOOT_DATA),
4819 'section@0/u-boot:image-pos': 0,
4820 'section@0:offset': 0,
4821 'section@0:size': 16,
4822 'section@0:image-pos': 0,
4823
4824 'section@1/u-boot:offset': 0,
4825 'section@1/u-boot:size': len(U_BOOT_DATA),
4826 'section@1/u-boot:image-pos': 16,
4827 'section@1:offset': 16,
4828 'section@1:size': 16,
4829 'section@1:image-pos': 16,
4830 'size': 40
4831 }, props)
4832
4833 def testUpdateFdtInElfInvalid(self):
4834 """Test that invalid args are detected with --update-fdt-in-elf"""
4835 with self.assertRaises(ValueError) as e:
4836 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4837 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4838 str(e.exception))
4839
4840 def testUpdateFdtInElfNoSyms(self):
4841 """Test that missing symbols are detected with --update-fdt-in-elf"""
4842 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4843 outfile = ''
4844 begin_sym = 'wrong_begin'
4845 end_sym = 'wrong_end'
4846 with self.assertRaises(ValueError) as e:
4847 self._DoTestFile(
4848 '060_fdt_update.dts',
4849 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4850 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4851 str(e.exception))
4852
4853 def testUpdateFdtInElfTooSmall(self):
4854 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4855 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4856 outfile = os.path.join(self._indir, 'u-boot.out')
4857 begin_sym = 'dtb_embed_begin'
4858 end_sym = 'dtb_embed_end'
4859 with self.assertRaises(ValueError) as e:
4860 self._DoTestFile(
4861 '060_fdt_update.dts', update_dtb=True,
4862 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4863 self.assertRegex(
4864 str(e.exception),
4865 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4866
Simon Glass88e04da2021-11-23 11:03:42 -07004867 def testVersion(self):
4868 """Test we can get the binman version"""
4869 version = '(unreleased)'
4870 self.assertEqual(version, state.GetVersion(self._indir))
4871
4872 with self.assertRaises(SystemExit):
4873 with test_util.capture_sys_output() as (_, stderr):
4874 self._DoBinman('-V')
4875 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4876
4877 # Try running the tool too, just to be safe
4878 result = self._RunBinman('-V')
4879 self.assertEqual('Binman %s\n' % version, result.stderr)
4880
4881 # Set up a version file to make sure that works
4882 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07004883 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07004884 binary=False)
4885 self.assertEqual(version, state.GetVersion(self._indir))
4886
Simon Glass637958f2021-11-23 21:09:50 -07004887 def testAltFormat(self):
4888 """Test that alternative formats can be used to extract"""
4889 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4890
4891 try:
4892 tmpdir, updated_fname = self._SetupImageInTmpdir()
4893 with test_util.capture_sys_output() as (stdout, _):
4894 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4895 self.assertEqual(
4896 '''Flag (-F) Entry type Description
4897fdt fdtmap Extract the devicetree blob from the fdtmap
4898''',
4899 stdout.getvalue())
4900
4901 dtb = os.path.join(tmpdir, 'fdt.dtb')
4902 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4903 dtb, 'fdtmap')
4904
4905 # Check that we can read it and it can be scanning, meaning it does
4906 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07004907 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07004908 dtb = fdt.Fdt.FromData(data)
4909 dtb.Scan()
4910
4911 # Now check u-boot which has no alt_format
4912 fname = os.path.join(tmpdir, 'fdt.dtb')
4913 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4914 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07004915 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07004916 self.assertEqual(U_BOOT_DATA, data)
4917
4918 finally:
4919 shutil.rmtree(tmpdir)
4920
Simon Glass0b00ae62021-11-23 21:09:52 -07004921 def testExtblobList(self):
4922 """Test an image with an external blob list"""
4923 data = self._DoReadFile('215_blob_ext_list.dts')
4924 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4925
4926 def testExtblobListMissing(self):
4927 """Test an image with a missing external blob"""
4928 with self.assertRaises(ValueError) as e:
4929 self._DoReadFile('216_blob_ext_list_missing.dts')
4930 self.assertIn("Filename 'missing-file' not found in input path",
4931 str(e.exception))
4932
4933 def testExtblobListMissingOk(self):
4934 """Test an image with an missing external blob that is allowed"""
4935 with test_util.capture_sys_output() as (stdout, stderr):
4936 self._DoTestFile('216_blob_ext_list_missing.dts',
4937 allow_missing=True)
4938 err = stderr.getvalue()
4939 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4940
Simon Glass3efb2972021-11-23 21:08:59 -07004941 def testFip(self):
4942 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4943 data = self._DoReadFile('203_fip.dts')
4944 hdr, fents = fip_util.decode_fip(data)
4945 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4946 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4947 self.assertEqual(0x123, hdr.flags)
4948
4949 self.assertEqual(2, len(fents))
4950
4951 fent = fents[0]
4952 self.assertEqual(
4953 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4954 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4955 self.assertEqual('soc-fw', fent.fip_type)
4956 self.assertEqual(0x88, fent.offset)
4957 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4958 self.assertEqual(0x123456789abcdef, fent.flags)
4959 self.assertEqual(ATF_BL31_DATA, fent.data)
4960 self.assertEqual(True, fent.valid)
4961
4962 fent = fents[1]
4963 self.assertEqual(
4964 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4965 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4966 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4967 self.assertEqual(0x8c, fent.offset)
4968 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4969 self.assertEqual(0, fent.flags)
4970 self.assertEqual(ATF_BL2U_DATA, fent.data)
4971 self.assertEqual(True, fent.valid)
4972
4973 def testFipOther(self):
4974 """Basic FIP with something that isn't a external blob"""
4975 data = self._DoReadFile('204_fip_other.dts')
4976 hdr, fents = fip_util.decode_fip(data)
4977
4978 self.assertEqual(2, len(fents))
4979 fent = fents[1]
4980 self.assertEqual('rot-cert', fent.fip_type)
4981 self.assertEqual(b'aa', fent.data)
4982
Simon Glass3efb2972021-11-23 21:08:59 -07004983 def testFipNoType(self):
4984 """FIP with an entry of an unknown type"""
4985 with self.assertRaises(ValueError) as e:
4986 self._DoReadFile('205_fip_no_type.dts')
4987 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
4988 str(e.exception))
4989
4990 def testFipUuid(self):
4991 """Basic FIP with a manual uuid"""
4992 data = self._DoReadFile('206_fip_uuid.dts')
4993 hdr, fents = fip_util.decode_fip(data)
4994
4995 self.assertEqual(2, len(fents))
4996 fent = fents[1]
4997 self.assertEqual(None, fent.fip_type)
4998 self.assertEqual(
4999 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5000 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5001 fent.uuid)
5002 self.assertEqual(U_BOOT_DATA, fent.data)
5003
5004 def testFipLs(self):
5005 """Test listing a FIP"""
5006 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5007 hdr, fents = fip_util.decode_fip(data)
5008
5009 try:
5010 tmpdir, updated_fname = self._SetupImageInTmpdir()
5011 with test_util.capture_sys_output() as (stdout, stderr):
5012 self._DoBinman('ls', '-i', updated_fname)
5013 finally:
5014 shutil.rmtree(tmpdir)
5015 lines = stdout.getvalue().splitlines()
5016 expected = [
5017'Name Image-pos Size Entry-type Offset Uncomp-size',
5018'----------------------------------------------------------------',
5019'main-section 0 2d3 section 0',
5020' atf-fip 0 90 atf-fip 0',
5021' soc-fw 88 4 blob-ext 88',
5022' u-boot 8c 4 u-boot 8c',
5023' fdtmap 90 243 fdtmap 90',
5024]
5025 self.assertEqual(expected, lines)
5026
5027 image = control.images['image']
5028 entries = image.GetEntries()
5029 fdtmap = entries['fdtmap']
5030
5031 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5032 magic = fdtmap_data[:8]
5033 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005034 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005035
5036 fdt_data = fdtmap_data[16:]
5037 dtb = fdt.Fdt.FromData(fdt_data)
5038 dtb.Scan()
5039 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5040 self.assertEqual({
5041 'atf-fip/soc-fw:image-pos': 136,
5042 'atf-fip/soc-fw:offset': 136,
5043 'atf-fip/soc-fw:size': 4,
5044 'atf-fip/u-boot:image-pos': 140,
5045 'atf-fip/u-boot:offset': 140,
5046 'atf-fip/u-boot:size': 4,
5047 'atf-fip:image-pos': 0,
5048 'atf-fip:offset': 0,
5049 'atf-fip:size': 144,
5050 'image-pos': 0,
5051 'offset': 0,
5052 'fdtmap:image-pos': fdtmap.image_pos,
5053 'fdtmap:offset': fdtmap.offset,
5054 'fdtmap:size': len(fdtmap_data),
5055 'size': len(data),
5056 }, props)
5057
5058 def testFipExtractOneEntry(self):
5059 """Test extracting a single entry fron an FIP"""
5060 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005061 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005062 fname = os.path.join(self._indir, 'output.extact')
5063 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005064 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005065 self.assertEqual(U_BOOT_DATA, data)
5066
5067 def testFipReplace(self):
5068 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005069 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005070 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005071 updated_fname = tools.get_output_filename('image-updated.bin')
5072 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005073 entry_name = 'atf-fip/u-boot'
5074 control.WriteEntry(updated_fname, entry_name, expected,
5075 allow_resize=True)
5076 actual = control.ReadEntry(updated_fname, entry_name)
5077 self.assertEqual(expected, actual)
5078
Simon Glass80025522022-01-29 14:14:04 -07005079 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005080 hdr, fents = fip_util.decode_fip(new_data)
5081
5082 self.assertEqual(2, len(fents))
5083
5084 # Check that the FIP entry is updated
5085 fent = fents[1]
5086 self.assertEqual(0x8c, fent.offset)
5087 self.assertEqual(len(expected), fent.size)
5088 self.assertEqual(0, fent.flags)
5089 self.assertEqual(expected, fent.data)
5090 self.assertEqual(True, fent.valid)
5091
5092 def testFipMissing(self):
5093 with test_util.capture_sys_output() as (stdout, stderr):
5094 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5095 err = stderr.getvalue()
5096 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
5097
5098 def testFipSize(self):
5099 """Test a FIP with a size property"""
5100 data = self._DoReadFile('210_fip_size.dts')
5101 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5102 hdr, fents = fip_util.decode_fip(data)
5103 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5104 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5105
5106 self.assertEqual(1, len(fents))
5107
5108 fent = fents[0]
5109 self.assertEqual('soc-fw', fent.fip_type)
5110 self.assertEqual(0x60, fent.offset)
5111 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5112 self.assertEqual(ATF_BL31_DATA, fent.data)
5113 self.assertEqual(True, fent.valid)
5114
5115 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005116 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005117
5118 def testFipBadAlign(self):
5119 """Test that an invalid alignment value in a FIP is detected"""
5120 with self.assertRaises(ValueError) as e:
5121 self._DoTestFile('211_fip_bad_align.dts')
5122 self.assertIn(
5123 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5124 str(e.exception))
5125
5126 def testFipCollection(self):
5127 """Test using a FIP in a collection"""
5128 data = self._DoReadFile('212_fip_collection.dts')
5129 entry1 = control.images['image'].GetEntries()['collection']
5130 data1 = data[:entry1.size]
5131 hdr1, fents2 = fip_util.decode_fip(data1)
5132
5133 entry2 = control.images['image'].GetEntries()['atf-fip']
5134 data2 = data[entry2.offset:entry2.offset + entry2.size]
5135 hdr1, fents2 = fip_util.decode_fip(data2)
5136
5137 # The 'collection' entry should have U-Boot included at the end
5138 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5139 self.assertEqual(data1, data2 + U_BOOT_DATA)
5140 self.assertEqual(U_BOOT_DATA, data1[-4:])
5141
5142 # There should be a U-Boot after the final FIP
5143 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005144
Simon Glassccae6862022-01-12 13:10:35 -07005145 def testFakeBlob(self):
5146 """Test handling of faking an external blob"""
5147 with test_util.capture_sys_output() as (stdout, stderr):
5148 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5149 allow_fake_blobs=True)
5150 err = stderr.getvalue()
5151 self.assertRegex(
5152 err,
5153 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005154
Simon Glassceb5f912022-01-09 20:13:46 -07005155 def testExtblobListFaked(self):
5156 """Test an extblob with missing external blob that are faked"""
5157 with test_util.capture_sys_output() as (stdout, stderr):
5158 self._DoTestFile('216_blob_ext_list_missing.dts',
5159 allow_fake_blobs=True)
5160 err = stderr.getvalue()
5161 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
5162
Simon Glass162017b2022-01-09 20:13:57 -07005163 def testListBintools(self):
5164 args = ['tool', '--list']
5165 with test_util.capture_sys_output() as (stdout, _):
5166 self._DoBinman(*args)
5167 out = stdout.getvalue().splitlines()
5168 self.assertTrue(len(out) >= 2)
5169
5170 def testFetchBintools(self):
5171 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005172 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005173 raise urllib.error.URLError('my error')
5174
5175 args = ['tool']
5176 with self.assertRaises(ValueError) as e:
5177 self._DoBinman(*args)
5178 self.assertIn("Invalid arguments to 'tool' subcommand",
5179 str(e.exception))
5180
5181 args = ['tool', '--fetch']
5182 with self.assertRaises(ValueError) as e:
5183 self._DoBinman(*args)
5184 self.assertIn('Please specify bintools to fetch', str(e.exception))
5185
5186 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005187 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005188 side_effect=fail_download):
5189 with test_util.capture_sys_output() as (stdout, _):
5190 self._DoBinman(*args)
5191 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5192
Simon Glassdab7c142022-01-09 20:14:10 -07005193 def testInvalidCompress(self):
5194 with self.assertRaises(ValueError) as e:
5195 comp_util.compress(b'', 'invalid')
5196 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5197
5198 with self.assertRaises(ValueError) as e:
5199 comp_util.decompress(b'1234', 'invalid')
5200 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5201
Simon Glass620c4462022-01-09 20:14:11 -07005202 def testBintoolDocs(self):
5203 """Test for creation of bintool documentation"""
5204 with test_util.capture_sys_output() as (stdout, stderr):
5205 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5206 self.assertTrue(len(stdout.getvalue()) > 0)
5207
5208 def testBintoolDocsMissing(self):
5209 """Test handling of missing bintool documentation"""
5210 with self.assertRaises(ValueError) as e:
5211 with test_util.capture_sys_output() as (stdout, stderr):
5212 control.write_bintool_docs(
5213 control.bintool.Bintool.get_tool_list(), 'mkimage')
5214 self.assertIn('Documentation is missing for modules: mkimage',
5215 str(e.exception))
5216
Jan Kiszka58c407f2022-01-28 20:37:53 +01005217 def testListWithGenNode(self):
5218 """Check handling of an FDT map when the section cannot be found"""
5219 entry_args = {
5220 'of-list': 'test-fdt1 test-fdt2',
5221 }
5222 data = self._DoReadFileDtb(
5223 '219_fit_gennode.dts',
5224 entry_args=entry_args,
5225 use_real_dtb=True,
5226 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5227
5228 try:
5229 tmpdir, updated_fname = self._SetupImageInTmpdir()
5230 with test_util.capture_sys_output() as (stdout, stderr):
5231 self._RunBinman('ls', '-i', updated_fname)
5232 finally:
5233 shutil.rmtree(tmpdir)
5234
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005235 def testFitSubentryUsesBintool(self):
5236 """Test that binman FIT subentries can use bintools"""
5237 command.test_result = self._HandleGbbCommand
5238 entry_args = {
5239 'keydir': 'devkeys',
5240 'bmpblk': 'bmpblk.bin',
5241 }
5242 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5243 entry_args=entry_args)
5244
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005245 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5246 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005247 self.assertIn(expected, data)
5248
5249 def testFitSubentryMissingBintool(self):
5250 """Test that binman reports missing bintools for FIT subentries"""
5251 entry_args = {
5252 'keydir': 'devkeys',
5253 }
5254 with test_util.capture_sys_output() as (_, stderr):
5255 self._DoTestFile('220_fit_subentry_bintool.dts',
5256 force_missing_bintools='futility', entry_args=entry_args)
5257 err = stderr.getvalue()
5258 self.assertRegex(err,
5259 "Image 'main-section'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005260
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005261 def testFitSubentryHashSubnode(self):
5262 """Test an image with a FIT inside"""
5263 data, _, _, out_dtb_name = self._DoReadFileDtb(
5264 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5265
5266 mkimage_dtb = fdt.Fdt.FromData(data)
5267 mkimage_dtb.Scan()
5268 binman_dtb = fdt.Fdt(out_dtb_name)
5269 binman_dtb.Scan()
5270
5271 # Check that binman didn't add hash values
5272 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5273 self.assertNotIn('value', fnode.props)
5274
5275 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5276 self.assertNotIn('value', fnode.props)
5277
5278 # Check that mkimage added hash values
5279 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5280 self.assertIn('value', fnode.props)
5281
5282 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5283 self.assertIn('value', fnode.props)
5284
Roger Quadros5cdcea02022-02-19 20:50:04 +02005285 def testPackTeeOs(self):
5286 """Test that an image with an TEE binary can be created"""
5287 data = self._DoReadFile('222_tee_os.dts')
5288 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5289
Simon Glass912339f2022-02-08 11:50:03 -07005290 def testFitFdtOper(self):
5291 """Check handling of a specified FIT operation"""
5292 entry_args = {
5293 'of-list': 'test-fdt1 test-fdt2',
5294 'default-dt': 'test-fdt2',
5295 }
5296 self._DoReadFileDtb(
5297 '223_fit_fdt_oper.dts',
5298 entry_args=entry_args,
5299 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5300
5301 def testFitFdtBadOper(self):
5302 """Check handling of an FDT map when the section cannot be found"""
5303 with self.assertRaises(ValueError) as exc:
5304 self._DoReadFileDtb('224_fit_bad_oper.dts')
5305 self.assertIn("Node '/binman/fit': Unknown operation 'unknown'",
5306 str(exc.exception))
5307
Roger Quadros5cdcea02022-02-19 20:50:04 +02005308
Simon Glassac599912017-11-12 21:52:22 -07005309if __name__ == "__main__":
5310 unittest.main()