blob: 18a6b140d54aa74504ea5d6f8f2aa079a7f350f8 [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 Glassdd156a42022-03-05 20:18:59 -07002031 def testExtendSize(self):
2032 """Test an extending entry"""
2033 data, _, map_data, _ = self._DoReadFileDtb('088_extend_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
Simon Glassdd156a42022-03-05 20:18:59 -07002053 def testExtendSizeBad(self):
2054 """Test an extending 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 Glassdd156a42022-03-05 20:18:59 -07002057 self._DoReadFileDtb('089_extend_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):
Simon Glassdd156a42022-03-05 20:18:59 -07002490 """Test extending an entry after it is packed"""
2491 data = self._DoReadFile('121_entry_extend.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
Simon Glassdd156a42022-03-05 20:18:59 -07002496 def testEntryExtendBad(self):
2497 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002498 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002499 self._DoReadFile('122_entry_extend_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
Simon Glassdd156a42022-03-05 20:18:59 -07002503 def testEntryExtendSection(self):
2504 """Test extending an entry within a section after it is packed"""
2505 data = self._DoReadFile('123_entry_extend_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
Simon Glassb7bad182022-03-05 20:19:01 -07003783 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003784 self.assertEqual({
3785 'image-pos': 0,
3786 'offset': 0,
3787 'size': 1890,
3788
3789 'u-boot:image-pos': 0,
3790 'u-boot:offset': 0,
3791 'u-boot:size': 4,
3792
3793 'fit:image-pos': 4,
3794 'fit:offset': 4,
3795 'fit:size': 1840,
3796
Simon Glassb7bad182022-03-05 20:19:01 -07003797 'fit/images/kernel:image-pos': 304,
3798 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003799 'fit/images/kernel:size': 4,
3800
Simon Glassb7bad182022-03-05 20:19:01 -07003801 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003802 'fit/images/kernel/u-boot:offset': 0,
3803 'fit/images/kernel/u-boot:size': 4,
3804
Simon Glassb7bad182022-03-05 20:19:01 -07003805 'fit/images/fdt-1:image-pos': 552,
3806 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003807 'fit/images/fdt-1:size': 6,
3808
Simon Glassb7bad182022-03-05 20:19:01 -07003809 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003810 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3811 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3812
3813 'u-boot-nodtb:image-pos': 1844,
3814 'u-boot-nodtb:offset': 1844,
3815 'u-boot-nodtb:size': 46,
3816 }, props)
3817
3818 # Actually check the data is where we think it is
3819 for node, expected in [
3820 ("u-boot", U_BOOT_DATA),
3821 ("fit/images/kernel", U_BOOT_DATA),
3822 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3823 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3824 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3825 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3826 ]:
3827 image_pos = props[f"{node}:image-pos"]
3828 size = props[f"{node}:size"]
3829 self.assertEqual(len(expected), size)
3830 self.assertEqual(expected, data[image_pos:image_pos+size])
3831
Simon Glass45d556d2020-07-09 18:39:45 -06003832 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003833 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003834 data = self._DoReadFile('162_fit_external.dts')
3835 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3836
Simon Glass7932c882022-01-09 20:13:39 -07003837 # Size of the external-data region as set up by mkimage
3838 external_data_size = len(U_BOOT_DATA) + 2
3839 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003840 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003841 len(U_BOOT_NODTB_DATA))
3842
Simon Glass45d556d2020-07-09 18:39:45 -06003843 # The data should be outside the FIT
3844 dtb = fdt.Fdt.FromData(fit_data)
3845 dtb.Scan()
3846 fnode = dtb.GetNode('/images/kernel')
3847 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003848 self.assertEqual(len(U_BOOT_DATA),
3849 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3850 fit_pos = 0x400;
3851 self.assertEqual(
3852 fit_pos,
3853 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3854
3855 self.assertEquals(expected_size, len(data))
3856 actual_pos = len(U_BOOT_DATA) + fit_pos
3857 self.assertEqual(U_BOOT_DATA + b'aa',
3858 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003859
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003860 def testFitExternalImagePos(self):
3861 """Test that we have correct image-pos for external FIT subentries"""
3862 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3863 update_dtb=True)
3864 dtb = fdt.Fdt(out_dtb_fname)
3865 dtb.Scan()
3866 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3867
3868 self.assertEqual({
3869 'image-pos': 0,
3870 'offset': 0,
3871 'size': 1082,
3872
3873 'u-boot:image-pos': 0,
3874 'u-boot:offset': 0,
3875 'u-boot:size': 4,
3876
3877 'fit:size': 1032,
3878 'fit:offset': 4,
3879 'fit:image-pos': 4,
3880
3881 'fit/images/kernel:size': 4,
3882 'fit/images/kernel:offset': 1024,
3883 'fit/images/kernel:image-pos': 1028,
3884
3885 'fit/images/kernel/u-boot:size': 4,
3886 'fit/images/kernel/u-boot:offset': 0,
3887 'fit/images/kernel/u-boot:image-pos': 1028,
3888
3889 'fit/images/fdt-1:size': 2,
3890 'fit/images/fdt-1:offset': 1028,
3891 'fit/images/fdt-1:image-pos': 1032,
3892
3893 'fit/images/fdt-1/_testing:size': 2,
3894 'fit/images/fdt-1/_testing:offset': 0,
3895 'fit/images/fdt-1/_testing:image-pos': 1032,
3896
3897 'u-boot-nodtb:image-pos': 1036,
3898 'u-boot-nodtb:offset': 1036,
3899 'u-boot-nodtb:size': 46,
3900 }, props)
3901
3902 # Actually check the data is where we think it is
3903 for node, expected in [
3904 ("u-boot", U_BOOT_DATA),
3905 ("fit/images/kernel", U_BOOT_DATA),
3906 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3907 ("fit/images/fdt-1", b'aa'),
3908 ("fit/images/fdt-1/_testing", b'aa'),
3909 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3910 ]:
3911 image_pos = props[f"{node}:image-pos"]
3912 size = props[f"{node}:size"]
3913 self.assertEqual(len(expected), size)
3914 self.assertEqual(expected, data[image_pos:image_pos+size])
3915
Simon Glass66152ce2022-01-09 20:14:09 -07003916 def testFitMissing(self):
3917 """Test that binman still produces a FIT image if mkimage is missing"""
3918 with test_util.capture_sys_output() as (_, stderr):
3919 self._DoTestFile('162_fit_external.dts',
3920 force_missing_bintools='mkimage')
3921 err = stderr.getvalue()
3922 self.assertRegex(err,
3923 "Image 'main-section'.*missing bintools.*: mkimage")
3924
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003925 def testSectionIgnoreHashSignature(self):
3926 """Test that sections ignore hash, signature nodes for its data"""
3927 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3928 expected = (U_BOOT_DATA + U_BOOT_DATA)
3929 self.assertEqual(expected, data)
3930
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003931 def testPadInSections(self):
3932 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06003933 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3934 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07003935 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
3936 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003937 U_BOOT_DATA)
3938 self.assertEqual(expected, data)
3939
Simon Glassd12599d2020-10-26 17:40:09 -06003940 dtb = fdt.Fdt(out_dtb_fname)
3941 dtb.Scan()
3942 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3943 expected = {
3944 'image-pos': 0,
3945 'offset': 0,
3946 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3947
3948 'section:image-pos': 0,
3949 'section:offset': 0,
3950 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3951
3952 'section/before:image-pos': 0,
3953 'section/before:offset': 0,
3954 'section/before:size': len(U_BOOT_DATA),
3955
3956 'section/u-boot:image-pos': 4,
3957 'section/u-boot:offset': 4,
3958 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3959
3960 'section/after:image-pos': 26,
3961 'section/after:offset': 26,
3962 'section/after:size': len(U_BOOT_DATA),
3963 }
3964 self.assertEqual(expected, props)
3965
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003966 def testFitImageSubentryAlignment(self):
3967 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03003968 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003969 entry_args = {
3970 'test-id': TEXT_DATA,
3971 }
3972 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3973 entry_args=entry_args)
3974 dtb = fdt.Fdt.FromData(data)
3975 dtb.Scan()
3976
3977 node = dtb.GetNode('/images/kernel')
3978 data = dtb.GetProps(node)["data"].bytes
3979 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07003980 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
3981 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003982 self.assertEqual(expected, data)
3983
3984 node = dtb.GetNode('/images/fdt-1')
3985 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07003986 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
3987 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003988 U_BOOT_DTB_DATA)
3989 self.assertEqual(expected, data)
3990
3991 def testFitExtblobMissingOk(self):
3992 """Test a FIT with a missing external blob that is allowed"""
3993 with test_util.capture_sys_output() as (stdout, stderr):
3994 self._DoTestFile('168_fit_missing_blob.dts',
3995 allow_missing=True)
3996 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06003997 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003998
Simon Glass21db0ff2020-09-01 05:13:54 -06003999 def testBlobNamedByArgMissing(self):
4000 """Test handling of a missing entry arg"""
4001 with self.assertRaises(ValueError) as e:
4002 self._DoReadFile('068_blob_named_by_arg.dts')
4003 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4004 str(e.exception))
4005
Simon Glass559c4de2020-09-01 05:13:58 -06004006 def testPackBl31(self):
4007 """Test that an image with an ATF BL31 binary can be created"""
4008 data = self._DoReadFile('169_atf_bl31.dts')
4009 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4010
Samuel Holland9d8cc632020-10-21 21:12:15 -05004011 def testPackScp(self):
4012 """Test that an image with an SCP binary can be created"""
4013 data = self._DoReadFile('172_scp.dts')
4014 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4015
Simon Glassa435cd12020-09-01 05:13:59 -06004016 def testFitFdt(self):
4017 """Test an image with an FIT with multiple FDT images"""
4018 def _CheckFdt(seq, expected_data):
4019 """Check the FDT nodes
4020
4021 Args:
4022 seq: Sequence number to check (0 or 1)
4023 expected_data: Expected contents of 'data' property
4024 """
4025 name = 'fdt-%d' % seq
4026 fnode = dtb.GetNode('/images/%s' % name)
4027 self.assertIsNotNone(fnode)
4028 self.assertEqual({'description','type', 'compression', 'data'},
4029 set(fnode.props.keys()))
4030 self.assertEqual(expected_data, fnode.props['data'].bytes)
4031 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4032 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004033 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004034
4035 def _CheckConfig(seq, expected_data):
4036 """Check the configuration nodes
4037
4038 Args:
4039 seq: Sequence number to check (0 or 1)
4040 expected_data: Expected contents of 'data' property
4041 """
4042 cnode = dtb.GetNode('/configurations')
4043 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004044 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004045
4046 name = 'config-%d' % seq
4047 fnode = dtb.GetNode('/configurations/%s' % name)
4048 self.assertIsNotNone(fnode)
4049 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4050 set(fnode.props.keys()))
4051 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4052 fnode.props['description'].value)
4053 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4054
4055 entry_args = {
4056 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004057 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004058 }
4059 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004060 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004061 entry_args=entry_args,
4062 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4063 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4064 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4065
4066 dtb = fdt.Fdt.FromData(fit_data)
4067 dtb.Scan()
4068 fnode = dtb.GetNode('/images/kernel')
4069 self.assertIn('data', fnode.props)
4070
4071 # Check all the properties in fdt-1 and fdt-2
4072 _CheckFdt(1, TEST_FDT1_DATA)
4073 _CheckFdt(2, TEST_FDT2_DATA)
4074
4075 # Check configurations
4076 _CheckConfig(1, TEST_FDT1_DATA)
4077 _CheckConfig(2, TEST_FDT2_DATA)
4078
4079 def testFitFdtMissingList(self):
4080 """Test handling of a missing 'of-list' entry arg"""
4081 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004082 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004083 self.assertIn("Generator node requires 'of-list' entry argument",
4084 str(e.exception))
4085
4086 def testFitFdtEmptyList(self):
4087 """Test handling of an empty 'of-list' entry arg"""
4088 entry_args = {
4089 'of-list': '',
4090 }
4091 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4092
4093 def testFitFdtMissingProp(self):
4094 """Test handling of a missing 'fit,fdt-list' property"""
4095 with self.assertRaises(ValueError) as e:
4096 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4097 self.assertIn("Generator node requires 'fit,fdt-list' property",
4098 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004099
Simon Glass1032acc2020-09-06 10:39:08 -06004100 def testFitFdtMissing(self):
4101 """Test handling of a missing 'default-dt' entry arg"""
4102 entry_args = {
4103 'of-list': 'test-fdt1 test-fdt2',
4104 }
4105 with self.assertRaises(ValueError) as e:
4106 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004107 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004108 entry_args=entry_args,
4109 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4110 self.assertIn("Generated 'default' node requires default-dt entry argument",
4111 str(e.exception))
4112
4113 def testFitFdtNotInList(self):
4114 """Test handling of a default-dt that is not in the of-list"""
4115 entry_args = {
4116 'of-list': 'test-fdt1 test-fdt2',
4117 'default-dt': 'test-fdt3',
4118 }
4119 with self.assertRaises(ValueError) as e:
4120 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004121 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004122 entry_args=entry_args,
4123 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4124 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4125 str(e.exception))
4126
Simon Glassa820af72020-09-06 10:39:09 -06004127 def testFitExtblobMissingHelp(self):
4128 """Test display of help messages when an external blob is missing"""
4129 control.missing_blob_help = control._ReadMissingBlobHelp()
4130 control.missing_blob_help['wibble'] = 'Wibble test'
4131 control.missing_blob_help['another'] = 'Another test'
4132 with test_util.capture_sys_output() as (stdout, stderr):
4133 self._DoTestFile('168_fit_missing_blob.dts',
4134 allow_missing=True)
4135 err = stderr.getvalue()
4136
4137 # We can get the tag from the name, the type or the missing-msg
4138 # property. Check all three.
4139 self.assertIn('You may need to build ARM Trusted', err)
4140 self.assertIn('Wibble test', err)
4141 self.assertIn('Another test', err)
4142
Simon Glass6f1f4d42020-09-06 10:35:32 -06004143 def testMissingBlob(self):
4144 """Test handling of a blob containing a missing file"""
4145 with self.assertRaises(ValueError) as e:
4146 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4147 self.assertIn("Filename 'missing' not found in input path",
4148 str(e.exception))
4149
Simon Glassa0729502020-09-06 10:35:33 -06004150 def testEnvironment(self):
4151 """Test adding a U-Boot environment"""
4152 data = self._DoReadFile('174_env.dts')
4153 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4154 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4155 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4156 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4157 env)
4158
4159 def testEnvironmentNoSize(self):
4160 """Test that a missing 'size' property is detected"""
4161 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004162 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004163 self.assertIn("'u-boot-env' entry must have a size property",
4164 str(e.exception))
4165
4166 def testEnvironmentTooSmall(self):
4167 """Test handling of an environment that does not fit"""
4168 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004169 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004170
4171 # checksum, start byte, environment with \0 terminator, final \0
4172 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4173 short = need - 0x8
4174 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4175 str(e.exception))
4176
Simon Glassd1fdf752020-10-26 17:40:01 -06004177 def testSkipAtStart(self):
4178 """Test handling of skip-at-start section"""
4179 data = self._DoReadFile('177_skip_at_start.dts')
4180 self.assertEqual(U_BOOT_DATA, data)
4181
4182 image = control.images['image']
4183 entries = image.GetEntries()
4184 section = entries['section']
4185 self.assertEqual(0, section.offset)
4186 self.assertEqual(len(U_BOOT_DATA), section.size)
4187 self.assertEqual(U_BOOT_DATA, section.GetData())
4188
4189 entry = section.GetEntries()['u-boot']
4190 self.assertEqual(16, entry.offset)
4191 self.assertEqual(len(U_BOOT_DATA), entry.size)
4192 self.assertEqual(U_BOOT_DATA, entry.data)
4193
4194 def testSkipAtStartPad(self):
4195 """Test handling of skip-at-start section with padded entry"""
4196 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004197 before = tools.get_bytes(0, 8)
4198 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004199 all = before + U_BOOT_DATA + after
4200 self.assertEqual(all, data)
4201
4202 image = control.images['image']
4203 entries = image.GetEntries()
4204 section = entries['section']
4205 self.assertEqual(0, section.offset)
4206 self.assertEqual(len(all), section.size)
4207 self.assertEqual(all, section.GetData())
4208
4209 entry = section.GetEntries()['u-boot']
4210 self.assertEqual(16, entry.offset)
4211 self.assertEqual(len(all), entry.size)
4212 self.assertEqual(U_BOOT_DATA, entry.data)
4213
4214 def testSkipAtStartSectionPad(self):
4215 """Test handling of skip-at-start section with padding"""
4216 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004217 before = tools.get_bytes(0, 8)
4218 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004219 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004220 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004221
4222 image = control.images['image']
4223 entries = image.GetEntries()
4224 section = entries['section']
4225 self.assertEqual(0, section.offset)
4226 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004227 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004228 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004229
4230 entry = section.GetEntries()['u-boot']
4231 self.assertEqual(16, entry.offset)
4232 self.assertEqual(len(U_BOOT_DATA), entry.size)
4233 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004234
Simon Glassbb395742020-10-26 17:40:14 -06004235 def testSectionPad(self):
4236 """Testing padding with sections"""
4237 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004238 expected = (tools.get_bytes(ord('&'), 3) +
4239 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004240 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004241 tools.get_bytes(ord('!'), 1) +
4242 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004243 self.assertEqual(expected, data)
4244
4245 def testSectionAlign(self):
4246 """Testing alignment with sections"""
4247 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4248 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004249 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004250 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004251 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004252 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004253 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4254 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004255 self.assertEqual(expected, data)
4256
Simon Glassd92c8362020-10-26 17:40:25 -06004257 def testCompressImage(self):
4258 """Test compression of the entire image"""
4259 self._CheckLz4()
4260 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4261 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4262 dtb = fdt.Fdt(out_dtb_fname)
4263 dtb.Scan()
4264 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4265 'uncomp-size'])
4266 orig = self._decompress(data)
4267 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4268
4269 # Do a sanity check on various fields
4270 image = control.images['image']
4271 entries = image.GetEntries()
4272 self.assertEqual(2, len(entries))
4273
4274 entry = entries['blob']
4275 self.assertEqual(COMPRESS_DATA, entry.data)
4276 self.assertEqual(len(COMPRESS_DATA), entry.size)
4277
4278 entry = entries['u-boot']
4279 self.assertEqual(U_BOOT_DATA, entry.data)
4280 self.assertEqual(len(U_BOOT_DATA), entry.size)
4281
4282 self.assertEqual(len(data), image.size)
4283 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4284 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4285 orig = self._decompress(image.data)
4286 self.assertEqual(orig, image.uncomp_data)
4287
4288 expected = {
4289 'blob:offset': 0,
4290 'blob:size': len(COMPRESS_DATA),
4291 'u-boot:offset': len(COMPRESS_DATA),
4292 'u-boot:size': len(U_BOOT_DATA),
4293 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4294 'offset': 0,
4295 'image-pos': 0,
4296 'size': len(data),
4297 }
4298 self.assertEqual(expected, props)
4299
4300 def testCompressImageLess(self):
4301 """Test compression where compression reduces the image size"""
4302 self._CheckLz4()
4303 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4304 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4305 dtb = fdt.Fdt(out_dtb_fname)
4306 dtb.Scan()
4307 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4308 'uncomp-size'])
4309 orig = self._decompress(data)
4310
4311 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4312
4313 # Do a sanity check on various fields
4314 image = control.images['image']
4315 entries = image.GetEntries()
4316 self.assertEqual(2, len(entries))
4317
4318 entry = entries['blob']
4319 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4320 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4321
4322 entry = entries['u-boot']
4323 self.assertEqual(U_BOOT_DATA, entry.data)
4324 self.assertEqual(len(U_BOOT_DATA), entry.size)
4325
4326 self.assertEqual(len(data), image.size)
4327 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4328 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4329 image.uncomp_size)
4330 orig = self._decompress(image.data)
4331 self.assertEqual(orig, image.uncomp_data)
4332
4333 expected = {
4334 'blob:offset': 0,
4335 'blob:size': len(COMPRESS_DATA_BIG),
4336 'u-boot:offset': len(COMPRESS_DATA_BIG),
4337 'u-boot:size': len(U_BOOT_DATA),
4338 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4339 'offset': 0,
4340 'image-pos': 0,
4341 'size': len(data),
4342 }
4343 self.assertEqual(expected, props)
4344
4345 def testCompressSectionSize(self):
4346 """Test compression of a section with a fixed size"""
4347 self._CheckLz4()
4348 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4349 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4350 dtb = fdt.Fdt(out_dtb_fname)
4351 dtb.Scan()
4352 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4353 'uncomp-size'])
4354 orig = self._decompress(data)
4355 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4356 expected = {
4357 'section/blob:offset': 0,
4358 'section/blob:size': len(COMPRESS_DATA),
4359 'section/u-boot:offset': len(COMPRESS_DATA),
4360 'section/u-boot:size': len(U_BOOT_DATA),
4361 'section:offset': 0,
4362 'section:image-pos': 0,
4363 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4364 'section:size': 0x30,
4365 'offset': 0,
4366 'image-pos': 0,
4367 'size': 0x30,
4368 }
4369 self.assertEqual(expected, props)
4370
4371 def testCompressSection(self):
4372 """Test compression of a section with no fixed size"""
4373 self._CheckLz4()
4374 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4375 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4376 dtb = fdt.Fdt(out_dtb_fname)
4377 dtb.Scan()
4378 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4379 'uncomp-size'])
4380 orig = self._decompress(data)
4381 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4382 expected = {
4383 'section/blob:offset': 0,
4384 'section/blob:size': len(COMPRESS_DATA),
4385 'section/u-boot:offset': len(COMPRESS_DATA),
4386 'section/u-boot:size': len(U_BOOT_DATA),
4387 'section:offset': 0,
4388 'section:image-pos': 0,
4389 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4390 'section:size': len(data),
4391 'offset': 0,
4392 'image-pos': 0,
4393 'size': len(data),
4394 }
4395 self.assertEqual(expected, props)
4396
4397 def testCompressExtra(self):
4398 """Test compression of a section with no fixed size"""
4399 self._CheckLz4()
4400 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4401 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4402 dtb = fdt.Fdt(out_dtb_fname)
4403 dtb.Scan()
4404 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4405 'uncomp-size'])
4406
4407 base = data[len(U_BOOT_DATA):]
4408 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4409 rest = base[len(U_BOOT_DATA):]
4410
4411 # Check compressed data
4412 section1 = self._decompress(rest)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07004413 expect1 = comp_util.compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
Simon Glassd92c8362020-10-26 17:40:25 -06004414 self.assertEquals(expect1, rest[:len(expect1)])
4415 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4416 rest1 = rest[len(expect1):]
4417
4418 section2 = self._decompress(rest1)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07004419 expect2 = comp_util.compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
Simon Glassd92c8362020-10-26 17:40:25 -06004420 self.assertEquals(expect2, rest1[:len(expect2)])
4421 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4422 rest2 = rest1[len(expect2):]
4423
4424 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4425 len(expect2) + len(U_BOOT_DATA))
4426 #self.assertEquals(expect_size, len(data))
4427
4428 #self.assertEquals(U_BOOT_DATA, rest2)
4429
4430 self.maxDiff = None
4431 expected = {
4432 'u-boot:offset': 0,
4433 'u-boot:image-pos': 0,
4434 'u-boot:size': len(U_BOOT_DATA),
4435
4436 'base:offset': len(U_BOOT_DATA),
4437 'base:image-pos': len(U_BOOT_DATA),
4438 'base:size': len(data) - len(U_BOOT_DATA),
4439 'base/u-boot:offset': 0,
4440 'base/u-boot:image-pos': len(U_BOOT_DATA),
4441 'base/u-boot:size': len(U_BOOT_DATA),
4442 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4443 len(expect2),
4444 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4445 len(expect2),
4446 'base/u-boot2:size': len(U_BOOT_DATA),
4447
4448 'base/section:offset': len(U_BOOT_DATA),
4449 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4450 'base/section:size': len(expect1),
4451 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4452 'base/section/blob:offset': 0,
4453 'base/section/blob:size': len(COMPRESS_DATA),
4454 'base/section/u-boot:offset': len(COMPRESS_DATA),
4455 'base/section/u-boot:size': len(U_BOOT_DATA),
4456
4457 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4458 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4459 'base/section2:size': len(expect2),
4460 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4461 'base/section2/blob:offset': 0,
4462 'base/section2/blob:size': len(COMPRESS_DATA),
4463 'base/section2/blob2:offset': len(COMPRESS_DATA),
4464 'base/section2/blob2:size': len(COMPRESS_DATA),
4465
4466 'offset': 0,
4467 'image-pos': 0,
4468 'size': len(data),
4469 }
4470 self.assertEqual(expected, props)
4471
Simon Glassecbe4732021-01-06 21:35:15 -07004472 def testSymbolsSubsection(self):
4473 """Test binman can assign symbols from a subsection"""
Simon Glass31e04cb2021-03-18 20:24:56 +13004474 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glassecbe4732021-01-06 21:35:15 -07004475
Simon Glass3fb25402021-01-06 21:35:16 -07004476 def testReadImageEntryArg(self):
4477 """Test reading an image that would need an entry arg to generate"""
4478 entry_args = {
4479 'cros-ec-rw-path': 'ecrw.bin',
4480 }
4481 data = self.data = self._DoReadFileDtb(
4482 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4483 entry_args=entry_args)
4484
Simon Glass80025522022-01-29 14:14:04 -07004485 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004486 orig_image = control.images['image']
4487
4488 # This should not generate an error about the missing 'cros-ec-rw-path'
4489 # since we are reading the image from a file. Compare with
4490 # testEntryArgsRequired()
4491 image = Image.FromFile(image_fname)
4492 self.assertEqual(orig_image.GetEntries().keys(),
4493 image.GetEntries().keys())
4494
Simon Glassa2af7302021-01-06 21:35:18 -07004495 def testFilesAlign(self):
4496 """Test alignment with files"""
4497 data = self._DoReadFile('190_files_align.dts')
4498
4499 # The first string is 15 bytes so will align to 16
4500 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4501 self.assertEqual(expect, data)
4502
Simon Glassdb84b562021-01-06 21:35:19 -07004503 def testReadImageSkip(self):
4504 """Test reading an image and accessing its FDT map"""
4505 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004506 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004507 orig_image = control.images['image']
4508 image = Image.FromFile(image_fname)
4509 self.assertEqual(orig_image.GetEntries().keys(),
4510 image.GetEntries().keys())
4511
4512 orig_entry = orig_image.GetEntries()['fdtmap']
4513 entry = image.GetEntries()['fdtmap']
4514 self.assertEqual(orig_entry.offset, entry.offset)
4515 self.assertEqual(orig_entry.size, entry.size)
4516 self.assertEqual(16, entry.image_pos)
4517
4518 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4519
4520 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4521
Simon Glassc98de972021-03-18 20:24:57 +13004522 def testTplNoDtb(self):
4523 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004524 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004525 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4526 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4527 data[:len(U_BOOT_TPL_NODTB_DATA)])
4528
Simon Glass63f41d42021-03-18 20:24:58 +13004529 def testTplBssPad(self):
4530 """Test that we can pad TPL's BSS with zeros"""
4531 # ELF file with a '__bss_size' symbol
4532 self._SetupTplElf()
4533 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004534 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004535 data)
4536
4537 def testTplBssPadMissing(self):
4538 """Test that a missing symbol is detected"""
4539 self._SetupTplElf('u_boot_ucode_ptr')
4540 with self.assertRaises(ValueError) as e:
4541 self._DoReadFile('193_tpl_bss_pad.dts')
4542 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4543 str(e.exception))
4544
Simon Glass718b5292021-03-18 20:25:07 +13004545 def checkDtbSizes(self, data, pad_len, start):
4546 """Check the size arguments in a dtb embedded in an image
4547
4548 Args:
4549 data: The image data
4550 pad_len: Length of the pad section in the image, in bytes
4551 start: Start offset of the devicetree to examine, within the image
4552
4553 Returns:
4554 Size of the devicetree in bytes
4555 """
4556 dtb_data = data[start:]
4557 dtb = fdt.Fdt.FromData(dtb_data)
4558 fdt_size = dtb.GetFdtObj().totalsize()
4559 dtb.Scan()
4560 props = self._GetPropTree(dtb, 'size')
4561 self.assertEqual({
4562 'size': len(data),
4563 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4564 'u-boot-spl/u-boot-spl-dtb:size': 801,
4565 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4566 'u-boot-spl:size': 860,
4567 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4568 'u-boot/u-boot-dtb:size': 781,
4569 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4570 'u-boot:size': 827,
4571 }, props)
4572 return fdt_size
4573
4574 def testExpanded(self):
4575 """Test that an expanded entry type is selected when needed"""
4576 self._SetupSplElf()
4577 self._SetupTplElf()
4578
4579 # SPL has a devicetree, TPL does not
4580 entry_args = {
4581 'spl-dtb': '1',
4582 'spl-bss-pad': 'y',
4583 'tpl-dtb': '',
4584 }
4585 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4586 entry_args=entry_args)
4587 image = control.images['image']
4588 entries = image.GetEntries()
4589 self.assertEqual(3, len(entries))
4590
4591 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4592 self.assertIn('u-boot', entries)
4593 entry = entries['u-boot']
4594 self.assertEqual('u-boot-expanded', entry.etype)
4595 subent = entry.GetEntries()
4596 self.assertEqual(2, len(subent))
4597 self.assertIn('u-boot-nodtb', subent)
4598 self.assertIn('u-boot-dtb', subent)
4599
4600 # Second, u-boot-spl, which should be expanded into three parts
4601 self.assertIn('u-boot-spl', entries)
4602 entry = entries['u-boot-spl']
4603 self.assertEqual('u-boot-spl-expanded', entry.etype)
4604 subent = entry.GetEntries()
4605 self.assertEqual(3, len(subent))
4606 self.assertIn('u-boot-spl-nodtb', subent)
4607 self.assertIn('u-boot-spl-bss-pad', subent)
4608 self.assertIn('u-boot-spl-dtb', subent)
4609
4610 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4611 # devicetree
4612 self.assertIn('u-boot-tpl', entries)
4613 entry = entries['u-boot-tpl']
4614 self.assertEqual('u-boot-tpl', entry.etype)
4615 self.assertEqual(None, entry.GetEntries())
4616
4617 def testExpandedTpl(self):
4618 """Test that an expanded entry type is selected for TPL when needed"""
4619 self._SetupTplElf()
4620
4621 entry_args = {
4622 'tpl-bss-pad': 'y',
4623 'tpl-dtb': 'y',
4624 }
4625 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4626 entry_args=entry_args)
4627 image = control.images['image']
4628 entries = image.GetEntries()
4629 self.assertEqual(1, len(entries))
4630
4631 # We only have u-boot-tpl, which be expanded
4632 self.assertIn('u-boot-tpl', entries)
4633 entry = entries['u-boot-tpl']
4634 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4635 subent = entry.GetEntries()
4636 self.assertEqual(3, len(subent))
4637 self.assertIn('u-boot-tpl-nodtb', subent)
4638 self.assertIn('u-boot-tpl-bss-pad', subent)
4639 self.assertIn('u-boot-tpl-dtb', subent)
4640
4641 def testExpandedNoPad(self):
4642 """Test an expanded entry without BSS pad enabled"""
4643 self._SetupSplElf()
4644 self._SetupTplElf()
4645
4646 # SPL has a devicetree, TPL does not
4647 entry_args = {
4648 'spl-dtb': 'something',
4649 'spl-bss-pad': 'n',
4650 'tpl-dtb': '',
4651 }
4652 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4653 entry_args=entry_args)
4654 image = control.images['image']
4655 entries = image.GetEntries()
4656
4657 # Just check u-boot-spl, which should be expanded into two parts
4658 self.assertIn('u-boot-spl', entries)
4659 entry = entries['u-boot-spl']
4660 self.assertEqual('u-boot-spl-expanded', entry.etype)
4661 subent = entry.GetEntries()
4662 self.assertEqual(2, len(subent))
4663 self.assertIn('u-boot-spl-nodtb', subent)
4664 self.assertIn('u-boot-spl-dtb', subent)
4665
4666 def testExpandedTplNoPad(self):
4667 """Test that an expanded entry type with padding disabled in TPL"""
4668 self._SetupTplElf()
4669
4670 entry_args = {
4671 'tpl-bss-pad': '',
4672 'tpl-dtb': 'y',
4673 }
4674 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4675 entry_args=entry_args)
4676 image = control.images['image']
4677 entries = image.GetEntries()
4678 self.assertEqual(1, len(entries))
4679
4680 # We only have u-boot-tpl, which be expanded
4681 self.assertIn('u-boot-tpl', entries)
4682 entry = entries['u-boot-tpl']
4683 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4684 subent = entry.GetEntries()
4685 self.assertEqual(2, len(subent))
4686 self.assertIn('u-boot-tpl-nodtb', subent)
4687 self.assertIn('u-boot-tpl-dtb', subent)
4688
4689 def testFdtInclude(self):
4690 """Test that an Fdt is update within all binaries"""
4691 self._SetupSplElf()
4692 self._SetupTplElf()
4693
4694 # SPL has a devicetree, TPL does not
4695 self.maxDiff = None
4696 entry_args = {
4697 'spl-dtb': '1',
4698 'spl-bss-pad': 'y',
4699 'tpl-dtb': '',
4700 }
4701 # Build the image. It includes two separate devicetree binaries, each
4702 # with their own contents, but all contain the binman definition.
4703 data = self._DoReadFileDtb(
4704 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4705 update_dtb=True, entry_args=entry_args)[0]
4706 pad_len = 10
4707
4708 # Check the U-Boot dtb
4709 start = len(U_BOOT_NODTB_DATA)
4710 fdt_size = self.checkDtbSizes(data, pad_len, start)
4711
4712 # Now check SPL
4713 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4714 fdt_size = self.checkDtbSizes(data, pad_len, start)
4715
4716 # TPL has no devicetree
4717 start += fdt_size + len(U_BOOT_TPL_DATA)
4718 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004719
Simon Glass7098b7f2021-03-21 18:24:30 +13004720 def testSymbolsExpanded(self):
4721 """Test binman can assign symbols in expanded entries"""
4722 entry_args = {
4723 'spl-dtb': '1',
4724 }
4725 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4726 U_BOOT_SPL_DTB_DATA, 0x38,
4727 entry_args=entry_args, use_expanded=True)
4728
Simon Glasse1915782021-03-21 18:24:31 +13004729 def testCollection(self):
4730 """Test a collection"""
4731 data = self._DoReadFile('198_collection.dts')
4732 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004733 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4734 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004735 data)
4736
Simon Glass27a7f772021-03-21 18:24:32 +13004737 def testCollectionSection(self):
4738 """Test a collection where a section must be built first"""
4739 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004740 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004741 # building the contents, producing an error is anything is still
4742 # missing.
4743 data = self._DoReadFile('199_collection_section.dts')
4744 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004745 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4746 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004747 data)
4748
Simon Glassf427c5f2021-03-21 18:24:33 +13004749 def testAlignDefault(self):
4750 """Test that default alignment works on sections"""
4751 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004752 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004753 U_BOOT_DATA)
4754 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004755 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004756 # No alignment within the nested section
4757 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4758 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004759 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004760 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004761
Bin Mengc0b15742021-05-10 20:23:33 +08004762 def testPackOpenSBI(self):
4763 """Test that an image with an OpenSBI binary can be created"""
4764 data = self._DoReadFile('201_opensbi.dts')
4765 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4766
Simon Glass76f496d2021-07-06 10:36:37 -06004767 def testSectionsSingleThread(self):
4768 """Test sections without multithreading"""
4769 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004770 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4771 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4772 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004773 self.assertEqual(expected, data)
4774
4775 def testThreadTimeout(self):
4776 """Test handling a thread that takes too long"""
4777 with self.assertRaises(ValueError) as e:
4778 self._DoTestFile('202_section_timeout.dts',
4779 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004780 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004781
Simon Glass748a1d42021-07-06 10:36:41 -06004782 def testTiming(self):
4783 """Test output of timing information"""
4784 data = self._DoReadFile('055_sections.dts')
4785 with test_util.capture_sys_output() as (stdout, stderr):
4786 state.TimingShow()
4787 self.assertIn('read:', stdout.getvalue())
4788 self.assertIn('compress:', stdout.getvalue())
4789
Simon Glassadfb8492021-11-03 21:09:18 -06004790 def testUpdateFdtInElf(self):
4791 """Test that we can update the devicetree in an ELF file"""
4792 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4793 outfile = os.path.join(self._indir, 'u-boot.out')
4794 begin_sym = 'dtb_embed_begin'
4795 end_sym = 'dtb_embed_end'
4796 retcode = self._DoTestFile(
4797 '060_fdt_update.dts', update_dtb=True,
4798 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4799 self.assertEqual(0, retcode)
4800
4801 # Check that the output file does in fact contact a dtb with the binman
4802 # definition in the correct place
4803 syms = elf.GetSymbolFileOffset(infile,
4804 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004805 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004806 dtb_data = data[syms['dtb_embed_begin'].offset:
4807 syms['dtb_embed_end'].offset]
4808
4809 dtb = fdt.Fdt.FromData(dtb_data)
4810 dtb.Scan()
4811 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4812 self.assertEqual({
4813 'image-pos': 0,
4814 'offset': 0,
4815 '_testing:offset': 32,
4816 '_testing:size': 2,
4817 '_testing:image-pos': 32,
4818 'section@0/u-boot:offset': 0,
4819 'section@0/u-boot:size': len(U_BOOT_DATA),
4820 'section@0/u-boot:image-pos': 0,
4821 'section@0:offset': 0,
4822 'section@0:size': 16,
4823 'section@0:image-pos': 0,
4824
4825 'section@1/u-boot:offset': 0,
4826 'section@1/u-boot:size': len(U_BOOT_DATA),
4827 'section@1/u-boot:image-pos': 16,
4828 'section@1:offset': 16,
4829 'section@1:size': 16,
4830 'section@1:image-pos': 16,
4831 'size': 40
4832 }, props)
4833
4834 def testUpdateFdtInElfInvalid(self):
4835 """Test that invalid args are detected with --update-fdt-in-elf"""
4836 with self.assertRaises(ValueError) as e:
4837 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4838 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4839 str(e.exception))
4840
4841 def testUpdateFdtInElfNoSyms(self):
4842 """Test that missing symbols are detected with --update-fdt-in-elf"""
4843 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4844 outfile = ''
4845 begin_sym = 'wrong_begin'
4846 end_sym = 'wrong_end'
4847 with self.assertRaises(ValueError) as e:
4848 self._DoTestFile(
4849 '060_fdt_update.dts',
4850 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4851 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4852 str(e.exception))
4853
4854 def testUpdateFdtInElfTooSmall(self):
4855 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4856 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4857 outfile = os.path.join(self._indir, 'u-boot.out')
4858 begin_sym = 'dtb_embed_begin'
4859 end_sym = 'dtb_embed_end'
4860 with self.assertRaises(ValueError) as e:
4861 self._DoTestFile(
4862 '060_fdt_update.dts', update_dtb=True,
4863 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4864 self.assertRegex(
4865 str(e.exception),
4866 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4867
Simon Glass88e04da2021-11-23 11:03:42 -07004868 def testVersion(self):
4869 """Test we can get the binman version"""
4870 version = '(unreleased)'
4871 self.assertEqual(version, state.GetVersion(self._indir))
4872
4873 with self.assertRaises(SystemExit):
4874 with test_util.capture_sys_output() as (_, stderr):
4875 self._DoBinman('-V')
4876 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4877
4878 # Try running the tool too, just to be safe
4879 result = self._RunBinman('-V')
4880 self.assertEqual('Binman %s\n' % version, result.stderr)
4881
4882 # Set up a version file to make sure that works
4883 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07004884 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07004885 binary=False)
4886 self.assertEqual(version, state.GetVersion(self._indir))
4887
Simon Glass637958f2021-11-23 21:09:50 -07004888 def testAltFormat(self):
4889 """Test that alternative formats can be used to extract"""
4890 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4891
4892 try:
4893 tmpdir, updated_fname = self._SetupImageInTmpdir()
4894 with test_util.capture_sys_output() as (stdout, _):
4895 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4896 self.assertEqual(
4897 '''Flag (-F) Entry type Description
4898fdt fdtmap Extract the devicetree blob from the fdtmap
4899''',
4900 stdout.getvalue())
4901
4902 dtb = os.path.join(tmpdir, 'fdt.dtb')
4903 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4904 dtb, 'fdtmap')
4905
4906 # Check that we can read it and it can be scanning, meaning it does
4907 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07004908 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07004909 dtb = fdt.Fdt.FromData(data)
4910 dtb.Scan()
4911
4912 # Now check u-boot which has no alt_format
4913 fname = os.path.join(tmpdir, 'fdt.dtb')
4914 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4915 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07004916 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07004917 self.assertEqual(U_BOOT_DATA, data)
4918
4919 finally:
4920 shutil.rmtree(tmpdir)
4921
Simon Glass0b00ae62021-11-23 21:09:52 -07004922 def testExtblobList(self):
4923 """Test an image with an external blob list"""
4924 data = self._DoReadFile('215_blob_ext_list.dts')
4925 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4926
4927 def testExtblobListMissing(self):
4928 """Test an image with a missing external blob"""
4929 with self.assertRaises(ValueError) as e:
4930 self._DoReadFile('216_blob_ext_list_missing.dts')
4931 self.assertIn("Filename 'missing-file' not found in input path",
4932 str(e.exception))
4933
4934 def testExtblobListMissingOk(self):
4935 """Test an image with an missing external blob that is allowed"""
4936 with test_util.capture_sys_output() as (stdout, stderr):
4937 self._DoTestFile('216_blob_ext_list_missing.dts',
4938 allow_missing=True)
4939 err = stderr.getvalue()
4940 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4941
Simon Glass3efb2972021-11-23 21:08:59 -07004942 def testFip(self):
4943 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4944 data = self._DoReadFile('203_fip.dts')
4945 hdr, fents = fip_util.decode_fip(data)
4946 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4947 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4948 self.assertEqual(0x123, hdr.flags)
4949
4950 self.assertEqual(2, len(fents))
4951
4952 fent = fents[0]
4953 self.assertEqual(
4954 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4955 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4956 self.assertEqual('soc-fw', fent.fip_type)
4957 self.assertEqual(0x88, fent.offset)
4958 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4959 self.assertEqual(0x123456789abcdef, fent.flags)
4960 self.assertEqual(ATF_BL31_DATA, fent.data)
4961 self.assertEqual(True, fent.valid)
4962
4963 fent = fents[1]
4964 self.assertEqual(
4965 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4966 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4967 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4968 self.assertEqual(0x8c, fent.offset)
4969 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4970 self.assertEqual(0, fent.flags)
4971 self.assertEqual(ATF_BL2U_DATA, fent.data)
4972 self.assertEqual(True, fent.valid)
4973
4974 def testFipOther(self):
4975 """Basic FIP with something that isn't a external blob"""
4976 data = self._DoReadFile('204_fip_other.dts')
4977 hdr, fents = fip_util.decode_fip(data)
4978
4979 self.assertEqual(2, len(fents))
4980 fent = fents[1]
4981 self.assertEqual('rot-cert', fent.fip_type)
4982 self.assertEqual(b'aa', fent.data)
4983
Simon Glass3efb2972021-11-23 21:08:59 -07004984 def testFipNoType(self):
4985 """FIP with an entry of an unknown type"""
4986 with self.assertRaises(ValueError) as e:
4987 self._DoReadFile('205_fip_no_type.dts')
4988 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
4989 str(e.exception))
4990
4991 def testFipUuid(self):
4992 """Basic FIP with a manual uuid"""
4993 data = self._DoReadFile('206_fip_uuid.dts')
4994 hdr, fents = fip_util.decode_fip(data)
4995
4996 self.assertEqual(2, len(fents))
4997 fent = fents[1]
4998 self.assertEqual(None, fent.fip_type)
4999 self.assertEqual(
5000 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5001 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5002 fent.uuid)
5003 self.assertEqual(U_BOOT_DATA, fent.data)
5004
5005 def testFipLs(self):
5006 """Test listing a FIP"""
5007 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5008 hdr, fents = fip_util.decode_fip(data)
5009
5010 try:
5011 tmpdir, updated_fname = self._SetupImageInTmpdir()
5012 with test_util.capture_sys_output() as (stdout, stderr):
5013 self._DoBinman('ls', '-i', updated_fname)
5014 finally:
5015 shutil.rmtree(tmpdir)
5016 lines = stdout.getvalue().splitlines()
5017 expected = [
5018'Name Image-pos Size Entry-type Offset Uncomp-size',
5019'----------------------------------------------------------------',
5020'main-section 0 2d3 section 0',
5021' atf-fip 0 90 atf-fip 0',
5022' soc-fw 88 4 blob-ext 88',
5023' u-boot 8c 4 u-boot 8c',
5024' fdtmap 90 243 fdtmap 90',
5025]
5026 self.assertEqual(expected, lines)
5027
5028 image = control.images['image']
5029 entries = image.GetEntries()
5030 fdtmap = entries['fdtmap']
5031
5032 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5033 magic = fdtmap_data[:8]
5034 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005035 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005036
5037 fdt_data = fdtmap_data[16:]
5038 dtb = fdt.Fdt.FromData(fdt_data)
5039 dtb.Scan()
5040 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5041 self.assertEqual({
5042 'atf-fip/soc-fw:image-pos': 136,
5043 'atf-fip/soc-fw:offset': 136,
5044 'atf-fip/soc-fw:size': 4,
5045 'atf-fip/u-boot:image-pos': 140,
5046 'atf-fip/u-boot:offset': 140,
5047 'atf-fip/u-boot:size': 4,
5048 'atf-fip:image-pos': 0,
5049 'atf-fip:offset': 0,
5050 'atf-fip:size': 144,
5051 'image-pos': 0,
5052 'offset': 0,
5053 'fdtmap:image-pos': fdtmap.image_pos,
5054 'fdtmap:offset': fdtmap.offset,
5055 'fdtmap:size': len(fdtmap_data),
5056 'size': len(data),
5057 }, props)
5058
5059 def testFipExtractOneEntry(self):
5060 """Test extracting a single entry fron an FIP"""
5061 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005062 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005063 fname = os.path.join(self._indir, 'output.extact')
5064 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005065 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005066 self.assertEqual(U_BOOT_DATA, data)
5067
5068 def testFipReplace(self):
5069 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005070 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005071 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005072 updated_fname = tools.get_output_filename('image-updated.bin')
5073 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005074 entry_name = 'atf-fip/u-boot'
5075 control.WriteEntry(updated_fname, entry_name, expected,
5076 allow_resize=True)
5077 actual = control.ReadEntry(updated_fname, entry_name)
5078 self.assertEqual(expected, actual)
5079
Simon Glass80025522022-01-29 14:14:04 -07005080 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005081 hdr, fents = fip_util.decode_fip(new_data)
5082
5083 self.assertEqual(2, len(fents))
5084
5085 # Check that the FIP entry is updated
5086 fent = fents[1]
5087 self.assertEqual(0x8c, fent.offset)
5088 self.assertEqual(len(expected), fent.size)
5089 self.assertEqual(0, fent.flags)
5090 self.assertEqual(expected, fent.data)
5091 self.assertEqual(True, fent.valid)
5092
5093 def testFipMissing(self):
5094 with test_util.capture_sys_output() as (stdout, stderr):
5095 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5096 err = stderr.getvalue()
5097 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
5098
5099 def testFipSize(self):
5100 """Test a FIP with a size property"""
5101 data = self._DoReadFile('210_fip_size.dts')
5102 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5103 hdr, fents = fip_util.decode_fip(data)
5104 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5105 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5106
5107 self.assertEqual(1, len(fents))
5108
5109 fent = fents[0]
5110 self.assertEqual('soc-fw', fent.fip_type)
5111 self.assertEqual(0x60, fent.offset)
5112 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5113 self.assertEqual(ATF_BL31_DATA, fent.data)
5114 self.assertEqual(True, fent.valid)
5115
5116 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005117 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005118
5119 def testFipBadAlign(self):
5120 """Test that an invalid alignment value in a FIP is detected"""
5121 with self.assertRaises(ValueError) as e:
5122 self._DoTestFile('211_fip_bad_align.dts')
5123 self.assertIn(
5124 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5125 str(e.exception))
5126
5127 def testFipCollection(self):
5128 """Test using a FIP in a collection"""
5129 data = self._DoReadFile('212_fip_collection.dts')
5130 entry1 = control.images['image'].GetEntries()['collection']
5131 data1 = data[:entry1.size]
5132 hdr1, fents2 = fip_util.decode_fip(data1)
5133
5134 entry2 = control.images['image'].GetEntries()['atf-fip']
5135 data2 = data[entry2.offset:entry2.offset + entry2.size]
5136 hdr1, fents2 = fip_util.decode_fip(data2)
5137
5138 # The 'collection' entry should have U-Boot included at the end
5139 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5140 self.assertEqual(data1, data2 + U_BOOT_DATA)
5141 self.assertEqual(U_BOOT_DATA, data1[-4:])
5142
5143 # There should be a U-Boot after the final FIP
5144 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005145
Simon Glassccae6862022-01-12 13:10:35 -07005146 def testFakeBlob(self):
5147 """Test handling of faking an external blob"""
5148 with test_util.capture_sys_output() as (stdout, stderr):
5149 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5150 allow_fake_blobs=True)
5151 err = stderr.getvalue()
5152 self.assertRegex(
5153 err,
5154 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005155
Simon Glassceb5f912022-01-09 20:13:46 -07005156 def testExtblobListFaked(self):
5157 """Test an extblob with missing external blob that are faked"""
5158 with test_util.capture_sys_output() as (stdout, stderr):
5159 self._DoTestFile('216_blob_ext_list_missing.dts',
5160 allow_fake_blobs=True)
5161 err = stderr.getvalue()
5162 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
5163
Simon Glass162017b2022-01-09 20:13:57 -07005164 def testListBintools(self):
5165 args = ['tool', '--list']
5166 with test_util.capture_sys_output() as (stdout, _):
5167 self._DoBinman(*args)
5168 out = stdout.getvalue().splitlines()
5169 self.assertTrue(len(out) >= 2)
5170
5171 def testFetchBintools(self):
5172 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005173 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005174 raise urllib.error.URLError('my error')
5175
5176 args = ['tool']
5177 with self.assertRaises(ValueError) as e:
5178 self._DoBinman(*args)
5179 self.assertIn("Invalid arguments to 'tool' subcommand",
5180 str(e.exception))
5181
5182 args = ['tool', '--fetch']
5183 with self.assertRaises(ValueError) as e:
5184 self._DoBinman(*args)
5185 self.assertIn('Please specify bintools to fetch', str(e.exception))
5186
5187 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005188 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005189 side_effect=fail_download):
5190 with test_util.capture_sys_output() as (stdout, _):
5191 self._DoBinman(*args)
5192 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5193
Simon Glassdab7c142022-01-09 20:14:10 -07005194 def testInvalidCompress(self):
5195 with self.assertRaises(ValueError) as e:
5196 comp_util.compress(b'', 'invalid')
5197 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5198
5199 with self.assertRaises(ValueError) as e:
5200 comp_util.decompress(b'1234', 'invalid')
5201 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5202
Simon Glass620c4462022-01-09 20:14:11 -07005203 def testBintoolDocs(self):
5204 """Test for creation of bintool documentation"""
5205 with test_util.capture_sys_output() as (stdout, stderr):
5206 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5207 self.assertTrue(len(stdout.getvalue()) > 0)
5208
5209 def testBintoolDocsMissing(self):
5210 """Test handling of missing bintool documentation"""
5211 with self.assertRaises(ValueError) as e:
5212 with test_util.capture_sys_output() as (stdout, stderr):
5213 control.write_bintool_docs(
5214 control.bintool.Bintool.get_tool_list(), 'mkimage')
5215 self.assertIn('Documentation is missing for modules: mkimage',
5216 str(e.exception))
5217
Jan Kiszka58c407f2022-01-28 20:37:53 +01005218 def testListWithGenNode(self):
5219 """Check handling of an FDT map when the section cannot be found"""
5220 entry_args = {
5221 'of-list': 'test-fdt1 test-fdt2',
5222 }
5223 data = self._DoReadFileDtb(
5224 '219_fit_gennode.dts',
5225 entry_args=entry_args,
5226 use_real_dtb=True,
5227 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5228
5229 try:
5230 tmpdir, updated_fname = self._SetupImageInTmpdir()
5231 with test_util.capture_sys_output() as (stdout, stderr):
5232 self._RunBinman('ls', '-i', updated_fname)
5233 finally:
5234 shutil.rmtree(tmpdir)
5235
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005236 def testFitSubentryUsesBintool(self):
5237 """Test that binman FIT subentries can use bintools"""
5238 command.test_result = self._HandleGbbCommand
5239 entry_args = {
5240 'keydir': 'devkeys',
5241 'bmpblk': 'bmpblk.bin',
5242 }
5243 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5244 entry_args=entry_args)
5245
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005246 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5247 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005248 self.assertIn(expected, data)
5249
5250 def testFitSubentryMissingBintool(self):
5251 """Test that binman reports missing bintools for FIT subentries"""
5252 entry_args = {
5253 'keydir': 'devkeys',
5254 }
5255 with test_util.capture_sys_output() as (_, stderr):
5256 self._DoTestFile('220_fit_subentry_bintool.dts',
5257 force_missing_bintools='futility', entry_args=entry_args)
5258 err = stderr.getvalue()
5259 self.assertRegex(err,
5260 "Image 'main-section'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005261
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005262 def testFitSubentryHashSubnode(self):
5263 """Test an image with a FIT inside"""
5264 data, _, _, out_dtb_name = self._DoReadFileDtb(
5265 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5266
5267 mkimage_dtb = fdt.Fdt.FromData(data)
5268 mkimage_dtb.Scan()
5269 binman_dtb = fdt.Fdt(out_dtb_name)
5270 binman_dtb.Scan()
5271
5272 # Check that binman didn't add hash values
5273 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5274 self.assertNotIn('value', fnode.props)
5275
5276 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5277 self.assertNotIn('value', fnode.props)
5278
5279 # Check that mkimage added hash values
5280 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5281 self.assertIn('value', fnode.props)
5282
5283 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5284 self.assertIn('value', fnode.props)
5285
Roger Quadros5cdcea02022-02-19 20:50:04 +02005286 def testPackTeeOs(self):
5287 """Test that an image with an TEE binary can be created"""
5288 data = self._DoReadFile('222_tee_os.dts')
5289 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5290
Simon Glass912339f2022-02-08 11:50:03 -07005291 def testFitFdtOper(self):
5292 """Check handling of a specified FIT operation"""
5293 entry_args = {
5294 'of-list': 'test-fdt1 test-fdt2',
5295 'default-dt': 'test-fdt2',
5296 }
5297 self._DoReadFileDtb(
5298 '223_fit_fdt_oper.dts',
5299 entry_args=entry_args,
5300 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5301
5302 def testFitFdtBadOper(self):
5303 """Check handling of an FDT map when the section cannot be found"""
5304 with self.assertRaises(ValueError) as exc:
5305 self._DoReadFileDtb('224_fit_bad_oper.dts')
5306 self.assertIn("Node '/binman/fit': Unknown operation 'unknown'",
5307 str(exc.exception))
5308
Simon Glassdd156a42022-03-05 20:18:59 -07005309 def test_uses_expand_size(self):
5310 """Test that the 'expand-size' property cannot be used anymore"""
5311 with self.assertRaises(ValueError) as e:
5312 data = self._DoReadFile('225_expand_size_bad.dts')
5313 self.assertIn(
5314 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5315 str(e.exception))
5316
Roger Quadros5cdcea02022-02-19 20:50:04 +02005317
Simon Glassac599912017-11-12 21:52:22 -07005318if __name__ == "__main__":
5319 unittest.main()