blob: 123fdb15f78686d3c26d827ee7106df82cd2989d [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass57454f42016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass57454f42016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glass45d556d2020-07-09 18:39:45 -06009import collections
Simon Glassc585dd42020-04-17 18:09:03 -060010import gzip
Simon Glassae7cf032018-09-14 04:57:31 -060011import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glass45d556d2020-07-09 18:39:45 -060014import re
Simon Glass57454f42016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
Simon Glass162017b2022-01-09 20:13:57 -070020import unittest.mock
21import urllib.error
Simon Glass57454f42016-11-25 20:15:52 -070022
Simon Glass4eae9252022-01-09 20:13:50 -070023from binman import bintool
Simon Glassc585dd42020-04-17 18:09:03 -060024from binman import cbfs_util
25from binman import cmdline
Simon Glass3ac7d832022-01-09 20:14:03 -070026from binman import comp_util
Simon Glassc585dd42020-04-17 18:09:03 -060027from binman import control
28from binman import elf
29from binman import elf_test
Simon Glass3efb2972021-11-23 21:08:59 -070030from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060031from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060032from binman import state
33from dtoc import fdt
34from dtoc import fdt_util
35from binman.etype import fdtmap
36from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060037from binman.image import Image
Simon Glassa997ea52020-04-17 18:09:04 -060038from patman import command
39from patman import test_util
40from patman import tools
41from patman import tout
Simon Glass57454f42016-11-25 20:15:52 -070042
43# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060044U_BOOT_DATA = b'1234'
45U_BOOT_IMG_DATA = b'img'
Simon Glass4e353e22019-08-24 07:23:04 -060046U_BOOT_SPL_DATA = b'56780123456789abcdefghi'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazyw'
Simon Glass303f62f2019-05-17 22:00:46 -060048BLOB_DATA = b'89'
49ME_DATA = b'0abcd'
50VGA_DATA = b'vga'
51U_BOOT_DTB_DATA = b'udtb'
52U_BOOT_SPL_DTB_DATA = b'spldtb'
53U_BOOT_TPL_DTB_DATA = b'tpldtb'
54X86_START16_DATA = b'start16'
55X86_START16_SPL_DATA = b'start16spl'
56X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060057X86_RESET16_DATA = b'reset16'
58X86_RESET16_SPL_DATA = b'reset16spl'
59X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060060PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
61U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
62U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
63U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
64FSP_DATA = b'fsp'
65CMC_DATA = b'cmc'
66VBT_DATA = b'vbt'
67MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060068TEXT_DATA = 'text'
69TEXT_DATA2 = 'text2'
70TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060071CROS_EC_RW_DATA = b'ecrw'
72GBB_DATA = b'gbbd'
73BMPBLK_DATA = b'bmp'
74VBLOCK_DATA = b'vblk'
75FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
76 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060077COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060078COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060079REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060080FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060081FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060082FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060083ATF_BL31_DATA = b'bl31'
Simon Glass3efb2972021-11-23 21:08:59 -070084ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080085OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050086SCP_DATA = b'scp'
Simon Glassa435cd12020-09-01 05:13:59 -060087TEST_FDT1_DATA = b'fdt1'
88TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060089ENV_DATA = b'var1=1\nvar2="2"'
Simon Glassa435cd12020-09-01 05:13:59 -060090
91# Subdirectory of the input dir to use to put test FDTs
92TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -060093
Simon Glass2c6adba2019-07-20 12:23:47 -060094# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -060095EXTRACT_DTB_SIZE = 0x3c9
96
Simon Glass2c6adba2019-07-20 12:23:47 -060097# Properties expected to be in the device tree when update_dtb is used
98BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
99
Simon Glassfb30e292019-07-20 12:23:51 -0600100# Extra properties expected to be in the device tree when allow-repack is used
101REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
102
Simon Glass57454f42016-11-25 20:15:52 -0700103
104class TestFunctional(unittest.TestCase):
105 """Functional tests for binman
106
107 Most of these use a sample .dts file to build an image and then check
108 that it looks correct. The sample files are in the test/ subdirectory
109 and are numbered.
110
111 For each entry type a very small test file is created using fixed
112 string contents. This makes it easy to test that things look right, and
113 debug problems.
114
115 In some cases a 'real' file must be used - these are also supplied in
116 the test/ diurectory.
117 """
118 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600119 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700120 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600121 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700122
Simon Glass57454f42016-11-25 20:15:52 -0700123 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600124 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
125 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700126
127 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600128 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700129
130 # Create some test files
131 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
132 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
133 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600134 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700135 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700136 TestFunctional._MakeInputFile('me.bin', ME_DATA)
137 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600138 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600139
Jagdish Gediya311d4842018-09-03 21:35:08 +0530140 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600141
Simon Glassabab18c2019-08-24 07:22:49 -0600142 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
143 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700144 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600145 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600146 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600147
148 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
149 X86_RESET16_DATA)
150 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
151 X86_RESET16_SPL_DATA)
152 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
153 X86_RESET16_TPL_DATA)
154
Simon Glass57454f42016-11-25 20:15:52 -0700155 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700156 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
157 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600158 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
159 U_BOOT_TPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700160 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
161 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700162 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700163 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600164 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600165 TestFunctional._MakeInputDir('devkeys')
166 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600167 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600168 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600169 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600170 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700171
Simon Glassf6290892019-08-24 07:22:53 -0600172 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
173 elf_test.BuildElfTestFiles(cls._elf_testdir)
174
Simon Glass72232452016-11-25 20:15:53 -0700175 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600176 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700177 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700178
179 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600180 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700181
Simon Glass862f8e22019-08-24 07:22:43 -0600182 shutil.copytree(cls.TestFile('files'),
183 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600184
Simon Glass7ba33592018-09-14 04:57:26 -0600185 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600186 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600187 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700188 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800189 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500190 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600191
Simon Glassa435cd12020-09-01 05:13:59 -0600192 # Add a few .dtb files for testing
193 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
194 TEST_FDT1_DATA)
195 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
196 TEST_FDT2_DATA)
197
Simon Glassa0729502020-09-06 10:35:33 -0600198 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
199
Simon Glass9203c162022-01-09 20:14:06 -0700200 cls.have_lz4 = comp_util.HAVE_LZ4
Simon Glass1de34482019-07-08 13:18:53 -0600201
Simon Glass57454f42016-11-25 20:15:52 -0700202 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600203 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700204 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600205 if cls.preserve_indir:
206 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600207 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600208 if cls._indir:
209 shutil.rmtree(cls._indir)
210 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700211
Simon Glass1c420c92019-07-08 13:18:49 -0600212 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600213 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600214 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600215 """Accept arguments controlling test execution
216
217 Args:
218 preserve_indir: Preserve the shared input directory used by all
219 tests in this class.
220 preserve_outdir: Preserve the output directories used by tests. Each
221 test has its own, so this is normally only useful when running a
222 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600223 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600224 """
225 cls.preserve_indir = preserve_indir
226 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600227 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600228 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600229
Simon Glass1de34482019-07-08 13:18:53 -0600230 def _CheckLz4(self):
231 if not self.have_lz4:
232 self.skipTest('lz4 --no-frame-crc not available')
233
Simon Glassee9d10d2019-07-20 12:24:09 -0600234 def _CleanupOutputDir(self):
235 """Remove the temporary output directory"""
236 if self.preserve_outdirs:
237 print('Preserving output dir: %s' % tools.outdir)
238 else:
Simon Glass80025522022-01-29 14:14:04 -0700239 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600240
Simon Glass57454f42016-11-25 20:15:52 -0700241 def setUp(self):
242 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700243 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700244 command.test_result = None
245
246 def tearDown(self):
247 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600248 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700249
Simon Glassb3d6fc72019-07-20 12:24:10 -0600250 def _SetupImageInTmpdir(self):
251 """Set up the output image in a new temporary directory
252
253 This is used when an image has been generated in the output directory,
254 but we want to run binman again. This will create a new output
255 directory and fail to delete the original one.
256
257 This creates a new temporary directory, copies the image to it (with a
258 new name) and removes the old output directory.
259
260 Returns:
261 Tuple:
262 Temporary directory to use
263 New image filename
264 """
Simon Glass80025522022-01-29 14:14:04 -0700265 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600266 tmpdir = tempfile.mkdtemp(prefix='binman.')
267 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700268 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600269 self._CleanupOutputDir()
270 return tmpdir, updated_fname
271
Simon Glass8425a1f2018-07-17 13:25:48 -0600272 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600273 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600274 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
275 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
276 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
277
Simon Glass57454f42016-11-25 20:15:52 -0700278 def _RunBinman(self, *args, **kwargs):
279 """Run binman using the command line
280
281 Args:
282 Arguments to pass, as a list of strings
283 kwargs: Arguments to pass to Command.RunPipe()
284 """
Simon Glass840be732022-01-29 14:14:05 -0700285 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700286 capture=True, capture_stderr=True, raise_on_error=False)
287 if result.return_code and kwargs.get('raise_on_error', True):
288 raise Exception("Error running '%s': %s" % (' '.join(args),
289 result.stdout + result.stderr))
290 return result
291
Simon Glassf46732a2019-07-08 14:25:29 -0600292 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700293 """Run binman using directly (in the same process)
294
295 Args:
296 Arguments to pass, as a list of strings
297 Returns:
298 Return value (0 for success)
299 """
Simon Glassf46732a2019-07-08 14:25:29 -0600300 argv = list(argv)
301 args = cmdline.ParseArgs(argv)
302 args.pager = 'binman-invalid-pager'
303 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700304
305 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600306 # args.verbosity = tout.DEBUG
307 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700308
Simon Glass91710b32018-07-17 13:25:32 -0600309 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600310 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300311 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100312 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700313 test_section_timeout=False, update_fdt_in_elf=None,
314 force_missing_bintools=''):
Simon Glass57454f42016-11-25 20:15:52 -0700315 """Run binman with a given test file
316
317 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600318 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600319 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600320 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600321 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600322 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600323 entry_args: Dict of entry args to supply to binman
324 key: arg name
325 value: value of that arg
326 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600327 use_real_dtb: True to use the test file as the contents of
328 the u-boot-dtb entry. Normally this is not needed and the
329 test contents (the U_BOOT_DTB_DATA string) can be used.
330 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300331 use_expanded: True to use expanded entries where available, e.g.
332 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600333 verbosity: Verbosity level to use (0-3, None=don't set it)
334 allow_missing: Set the '--allow-missing' flag so that missing
335 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100336 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600337 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600338 threads: Number of threads to use (None for default, 0 for
339 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600340 test_section_timeout: True to force the first time to timeout, as
341 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600342 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass66152ce2022-01-09 20:14:09 -0700343 force_missing_tools (str): comma-separated list of bintools to
344 regard as missing
Simon Glass9a798402021-11-03 21:09:17 -0600345
346 Returns:
347 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700348 """
Simon Glassf46732a2019-07-08 14:25:29 -0600349 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700350 if debug:
351 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600352 if verbosity is not None:
353 args.append('-v%d' % verbosity)
354 elif self.verbosity:
355 args.append('-v%d' % self.verbosity)
356 if self.toolpath:
357 for path in self.toolpath:
358 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600359 if threads is not None:
360 args.append('-T%d' % threads)
361 if test_section_timeout:
362 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600363 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600364 if map:
365 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600366 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600367 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600368 if not use_real_dtb:
369 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300370 if not use_expanded:
371 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600372 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600373 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600374 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600375 if allow_missing:
376 args.append('-M')
Heiko Thiery6d451362022-01-06 11:49:41 +0100377 if allow_fake_blobs:
378 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700379 if force_missing_bintools:
380 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600381 if update_fdt_in_elf:
382 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600383 if images:
384 for image in images:
385 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600386 if extra_indirs:
387 for indir in extra_indirs:
388 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700389 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700390
391 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700392 """Set up a new test device-tree file
393
394 The given file is compiled and set up as the device tree to be used
395 for ths test.
396
397 Args:
398 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600399 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700400
401 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600402 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700403 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600404 tmpdir = tempfile.mkdtemp(prefix='binmant.')
405 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600406 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700407 data = fd.read()
408 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600409 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600410 return data
Simon Glass57454f42016-11-25 20:15:52 -0700411
Simon Glasse219aa42018-09-14 04:57:24 -0600412 def _GetDtbContentsForSplTpl(self, dtb_data, name):
413 """Create a version of the main DTB for SPL or SPL
414
415 For testing we don't actually have different versions of the DTB. With
416 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
417 we don't normally have any unwanted nodes.
418
419 We still want the DTBs for SPL and TPL to be different though, since
420 otherwise it is confusing to know which one we are looking at. So add
421 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600422
423 Args:
424 dtb_data: dtb data to modify (this should be a value devicetree)
425 name: Name of a new property to add
426
427 Returns:
428 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600429 """
430 dtb = fdt.Fdt.FromData(dtb_data)
431 dtb.Scan()
432 dtb.GetNode('/binman').AddZeroProp(name)
433 dtb.Sync(auto_resize=True)
434 dtb.Pack()
435 return dtb.GetContents()
436
Simon Glassed930672021-03-18 20:25:05 +1300437 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
438 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600439 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700440 """Run binman and return the resulting image
441
442 This runs binman with a given test file and then reads the resulting
443 output file. It is a shortcut function since most tests need to do
444 these steps.
445
446 Raises an assertion failure if binman returns a non-zero exit code.
447
448 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600449 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700450 use_real_dtb: True to use the test file as the contents of
451 the u-boot-dtb entry. Normally this is not needed and the
452 test contents (the U_BOOT_DTB_DATA string) can be used.
453 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300454 use_expanded: True to use expanded entries where available, e.g.
455 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600456 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600457 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600458 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600459 entry_args: Dict of entry args to supply to binman
460 key: arg name
461 value: value of that arg
462 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
463 function. If reset_dtbs is True, then the original test dtb
464 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600465 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600466 threads: Number of threads to use (None for default, 0 for
467 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700468
469 Returns:
470 Tuple:
471 Resulting image contents
472 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600473 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600474 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700475 """
Simon Glass72232452016-11-25 20:15:53 -0700476 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700477 # Use the compiled test file as the u-boot-dtb input
478 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700479 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600480
481 # For testing purposes, make a copy of the DT for SPL and TPL. Add
482 # a node indicating which it is, so aid verification.
483 for name in ['spl', 'tpl']:
484 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
485 outfile = os.path.join(self._indir, dtb_fname)
486 TestFunctional._MakeInputFile(dtb_fname,
487 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700488
489 try:
Simon Glass91710b32018-07-17 13:25:32 -0600490 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600491 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600492 use_expanded=use_expanded, extra_indirs=extra_indirs,
493 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700494 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700495 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700496
497 # Find the (only) image, read it and return its contents
498 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700499 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600500 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600501 if map:
Simon Glass80025522022-01-29 14:14:04 -0700502 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600503 with open(map_fname) as fd:
504 map_data = fd.read()
505 else:
506 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600507 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600508 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700509 finally:
510 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600511 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600512 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700513
Simon Glass5b4bce32019-07-08 14:25:26 -0600514 def _DoReadFileRealDtb(self, fname):
515 """Run binman with a real .dtb file and return the resulting data
516
517 Args:
518 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
519
520 Returns:
521 Resulting image contents
522 """
523 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
524
Simon Glass72232452016-11-25 20:15:53 -0700525 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600526 """Helper function which discards the device-tree binary
527
528 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600529 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600530 use_real_dtb: True to use the test file as the contents of
531 the u-boot-dtb entry. Normally this is not needed and the
532 test contents (the U_BOOT_DTB_DATA string) can be used.
533 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600534
535 Returns:
536 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600537 """
Simon Glass72232452016-11-25 20:15:53 -0700538 return self._DoReadFileDtb(fname, use_real_dtb)[0]
539
Simon Glass57454f42016-11-25 20:15:52 -0700540 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600541 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700542 """Create a new test input file, creating directories as needed
543
544 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600545 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700546 contents: File contents to write in to the file
547 Returns:
548 Full pathname of file created
549 """
Simon Glass862f8e22019-08-24 07:22:43 -0600550 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700551 dirname = os.path.dirname(pathname)
552 if dirname and not os.path.exists(dirname):
553 os.makedirs(dirname)
554 with open(pathname, 'wb') as fd:
555 fd.write(contents)
556 return pathname
557
558 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600559 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600560 """Create a new test input directory, creating directories as needed
561
562 Args:
563 dirname: Directory name to create
564
565 Returns:
566 Full pathname of directory created
567 """
Simon Glass862f8e22019-08-24 07:22:43 -0600568 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600569 if not os.path.exists(pathname):
570 os.makedirs(pathname)
571 return pathname
572
573 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600574 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600575 """Set up an ELF file with a '_dt_ucode_base_size' symbol
576
577 Args:
578 Filename of ELF file to use as SPL
579 """
Simon Glass93a806f2019-08-24 07:22:59 -0600580 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700581 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600582
583 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600584 def _SetupTplElf(cls, src_fname='bss_data'):
585 """Set up an ELF file with a '_dt_ucode_base_size' symbol
586
587 Args:
588 Filename of ELF file to use as TPL
589 """
590 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700591 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600592
593 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600594 def _SetupDescriptor(cls):
595 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
596 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
597
598 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600599 def TestFile(cls, fname):
600 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700601
Simon Glassf6290892019-08-24 07:22:53 -0600602 @classmethod
603 def ElfTestFile(cls, fname):
604 return os.path.join(cls._elf_testdir, fname)
605
Simon Glass57454f42016-11-25 20:15:52 -0700606 def AssertInList(self, grep_list, target):
607 """Assert that at least one of a list of things is in a target
608
609 Args:
610 grep_list: List of strings to check
611 target: Target string
612 """
613 for grep in grep_list:
614 if grep in target:
615 return
Simon Glass848cdb52019-05-17 22:00:50 -0600616 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700617
618 def CheckNoGaps(self, entries):
619 """Check that all entries fit together without gaps
620
621 Args:
622 entries: List of entries to check
623 """
Simon Glasse8561af2018-08-01 15:22:37 -0600624 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700625 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600626 self.assertEqual(offset, entry.offset)
627 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700628
Simon Glass72232452016-11-25 20:15:53 -0700629 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600630 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700631
632 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600633 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700634
635 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600636 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700637 """
638 return struct.unpack('>L', dtb[4:8])[0]
639
Simon Glass0f621332019-07-08 14:25:27 -0600640 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600641 def AddNode(node, path):
642 if node.name != '/':
643 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600644 for prop in node.props.values():
645 if prop.name in prop_names:
646 prop_path = path + ':' + prop.name
647 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
648 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600649 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600650 AddNode(subnode, path)
651
652 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600653 AddNode(dtb.GetRoot(), '')
654 return tree
655
Simon Glass57454f42016-11-25 20:15:52 -0700656 def testRun(self):
657 """Test a basic run with valid args"""
658 result = self._RunBinman('-h')
659
660 def testFullHelp(self):
661 """Test that the full help is displayed with -H"""
662 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300663 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500664 # Remove possible extraneous strings
665 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
666 gothelp = result.stdout.replace(extra, '')
667 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700668 self.assertEqual(0, len(result.stderr))
669 self.assertEqual(0, result.return_code)
670
671 def testFullHelpInternal(self):
672 """Test that the full help is displayed with -H"""
673 try:
674 command.test_result = command.CommandResult()
675 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300676 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700677 finally:
678 command.test_result = None
679
680 def testHelp(self):
681 """Test that the basic help is displayed with -h"""
682 result = self._RunBinman('-h')
683 self.assertTrue(len(result.stdout) > 200)
684 self.assertEqual(0, len(result.stderr))
685 self.assertEqual(0, result.return_code)
686
Simon Glass57454f42016-11-25 20:15:52 -0700687 def testBoard(self):
688 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600689 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700690 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300691 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700692 self.assertEqual(0, result)
693
694 def testNeedBoard(self):
695 """Test that we get an error when no board ius supplied"""
696 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600697 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700698 self.assertIn("Must provide a board to process (use -b <board>)",
699 str(e.exception))
700
701 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600702 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700703 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600704 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700705 # We get one error from libfdt, and a different one from fdtget.
706 self.AssertInList(["Couldn't open blob from 'missing_file'",
707 'No such file or directory'], str(e.exception))
708
709 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600710 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700711
712 Since this is a source file it should be compiled and the error
713 will come from the device-tree compiler (dtc).
714 """
715 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600716 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700717 self.assertIn("FATAL ERROR: Unable to parse input tree",
718 str(e.exception))
719
720 def testMissingNode(self):
721 """Test that a device tree without a 'binman' node generates an error"""
722 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600723 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700724 self.assertIn("does not have a 'binman' node", str(e.exception))
725
726 def testEmpty(self):
727 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600728 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700729 self.assertEqual(0, len(result.stderr))
730 self.assertEqual(0, result.return_code)
731
732 def testInvalidEntry(self):
733 """Test that an invalid entry is flagged"""
734 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600735 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600736 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700737 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
738 "'/binman/not-a-valid-type'", str(e.exception))
739
740 def testSimple(self):
741 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600742 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700743 self.assertEqual(U_BOOT_DATA, data)
744
Simon Glass075a45c2017-11-13 18:55:00 -0700745 def testSimpleDebug(self):
746 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600747 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700748
Simon Glass57454f42016-11-25 20:15:52 -0700749 def testDual(self):
750 """Test that we can handle creating two images
751
752 This also tests image padding.
753 """
Simon Glass511f6582018-10-01 12:22:30 -0600754 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700755 self.assertEqual(0, retcode)
756
757 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600758 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700759 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700760 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600761 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700762 data = fd.read()
763 self.assertEqual(U_BOOT_DATA, data)
764
765 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600766 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700767 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700768 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600769 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700770 data = fd.read()
771 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700772 self.assertEqual(tools.get_bytes(0, 3), data[:3])
773 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700774
775 def testBadAlign(self):
776 """Test that an invalid alignment value is detected"""
777 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600778 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700779 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
780 "of two", str(e.exception))
781
782 def testPackSimple(self):
783 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600784 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700785 self.assertEqual(0, retcode)
786 self.assertIn('image', control.images)
787 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600788 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700789 self.assertEqual(5, len(entries))
790
791 # First u-boot
792 self.assertIn('u-boot', entries)
793 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600794 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700795 self.assertEqual(len(U_BOOT_DATA), entry.size)
796
797 # Second u-boot, aligned to 16-byte boundary
798 self.assertIn('u-boot-align', entries)
799 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600800 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700801 self.assertEqual(len(U_BOOT_DATA), entry.size)
802
803 # Third u-boot, size 23 bytes
804 self.assertIn('u-boot-size', entries)
805 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600806 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700807 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
808 self.assertEqual(23, entry.size)
809
810 # Fourth u-boot, placed immediate after the above
811 self.assertIn('u-boot-next', entries)
812 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600813 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700814 self.assertEqual(len(U_BOOT_DATA), entry.size)
815
Simon Glasse8561af2018-08-01 15:22:37 -0600816 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700817 self.assertIn('u-boot-fixed', entries)
818 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600819 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700820 self.assertEqual(len(U_BOOT_DATA), entry.size)
821
Simon Glass39dd2152019-07-08 14:25:47 -0600822 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700823
824 def testPackExtra(self):
825 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600826 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
827 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700828
Simon Glass57454f42016-11-25 20:15:52 -0700829 self.assertIn('image', control.images)
830 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600831 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700832 self.assertEqual(5, len(entries))
833
834 # First u-boot with padding before and after
835 self.assertIn('u-boot', entries)
836 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600837 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700838 self.assertEqual(3, entry.pad_before)
839 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600840 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700841 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
842 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600843 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700844
845 # Second u-boot has an aligned size, but it has no effect
846 self.assertIn('u-boot-align-size-nop', entries)
847 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600848 self.assertEqual(pos, entry.offset)
849 self.assertEqual(len(U_BOOT_DATA), entry.size)
850 self.assertEqual(U_BOOT_DATA, entry.data)
851 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
852 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700853
854 # Third u-boot has an aligned size too
855 self.assertIn('u-boot-align-size', entries)
856 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600857 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700858 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600859 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700860 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600861 data[pos:pos + entry.size])
862 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700863
864 # Fourth u-boot has an aligned end
865 self.assertIn('u-boot-align-end', entries)
866 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600867 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700868 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600869 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700870 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600871 data[pos:pos + entry.size])
872 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700873
874 # Fifth u-boot immediately afterwards
875 self.assertIn('u-boot-align-both', entries)
876 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600877 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700878 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600879 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700880 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600881 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700882
883 self.CheckNoGaps(entries)
Simon Glass39dd2152019-07-08 14:25:47 -0600884 self.assertEqual(128, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700885
Simon Glassafb9caa2020-10-26 17:40:10 -0600886 dtb = fdt.Fdt(out_dtb_fname)
887 dtb.Scan()
888 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
889 expected = {
890 'image-pos': 0,
891 'offset': 0,
892 'size': 128,
893
894 'u-boot:image-pos': 0,
895 'u-boot:offset': 0,
896 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
897
898 'u-boot-align-size-nop:image-pos': 12,
899 'u-boot-align-size-nop:offset': 12,
900 'u-boot-align-size-nop:size': 4,
901
902 'u-boot-align-size:image-pos': 16,
903 'u-boot-align-size:offset': 16,
904 'u-boot-align-size:size': 32,
905
906 'u-boot-align-end:image-pos': 48,
907 'u-boot-align-end:offset': 48,
908 'u-boot-align-end:size': 16,
909
910 'u-boot-align-both:image-pos': 64,
911 'u-boot-align-both:offset': 64,
912 'u-boot-align-both:size': 64,
913 }
914 self.assertEqual(expected, props)
915
Simon Glass57454f42016-11-25 20:15:52 -0700916 def testPackAlignPowerOf2(self):
917 """Test that invalid entry alignment is detected"""
918 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600919 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700920 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
921 "of two", str(e.exception))
922
923 def testPackAlignSizePowerOf2(self):
924 """Test that invalid entry size alignment is detected"""
925 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600926 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700927 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
928 "power of two", str(e.exception))
929
930 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600931 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700932 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600933 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600934 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700935 "align 0x4 (4)", str(e.exception))
936
937 def testPackInvalidSizeAlign(self):
938 """Test that invalid entry size alignment is detected"""
939 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600940 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700941 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
942 "align-size 0x4 (4)", str(e.exception))
943
944 def testPackOverlap(self):
945 """Test that overlapping regions are detected"""
946 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600947 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600948 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700949 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
950 str(e.exception))
951
952 def testPackEntryOverflow(self):
953 """Test that entries that overflow their size are detected"""
954 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600955 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700956 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
957 "but entry size is 0x3 (3)", str(e.exception))
958
959 def testPackImageOverflow(self):
960 """Test that entries which overflow the image size are detected"""
961 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600962 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600963 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -0700964 "size 0x3 (3)", str(e.exception))
965
966 def testPackImageSize(self):
967 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -0600968 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700969 self.assertEqual(0, retcode)
970 self.assertIn('image', control.images)
971 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600972 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700973
974 def testPackImageSizeAlign(self):
975 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600976 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700977 self.assertEqual(0, retcode)
978 self.assertIn('image', control.images)
979 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600980 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700981
982 def testPackInvalidImageAlign(self):
983 """Test that invalid image alignment is detected"""
984 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600985 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600986 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700987 "align-size 0x8 (8)", str(e.exception))
988
989 def testPackAlignPowerOf2(self):
990 """Test that invalid image alignment is detected"""
991 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600992 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -0600993 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -0700994 "two", str(e.exception))
995
996 def testImagePadByte(self):
997 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -0600998 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -0600999 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001000 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001001 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001002
1003 def testImageName(self):
1004 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001005 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001006 self.assertEqual(0, retcode)
1007 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001008 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001009 self.assertTrue(os.path.exists(fname))
1010
1011 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001012 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001013 self.assertTrue(os.path.exists(fname))
1014
1015 def testBlobFilename(self):
1016 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001017 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001018 self.assertEqual(BLOB_DATA, data)
1019
1020 def testPackSorted(self):
1021 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001022 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001023 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001024 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1025 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001026
Simon Glasse8561af2018-08-01 15:22:37 -06001027 def testPackZeroOffset(self):
1028 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -07001029 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001030 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001031 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001032 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1033 str(e.exception))
1034
1035 def testPackUbootDtb(self):
1036 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001037 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001038 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001039
1040 def testPackX86RomNoSize(self):
1041 """Test that the end-at-4gb property requires a size property"""
1042 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001043 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001044 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001045 "using end-at-4gb", str(e.exception))
1046
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301047 def test4gbAndSkipAtStartTogether(self):
1048 """Test that the end-at-4gb and skip-at-size property can't be used
1049 together"""
1050 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001051 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001052 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301053 "'skip-at-start'", str(e.exception))
1054
Simon Glass72232452016-11-25 20:15:53 -07001055 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001056 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -07001057 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001058 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001059 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1060 "is outside the section '/binman' starting at "
1061 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001062 str(e.exception))
1063
1064 def testPackX86Rom(self):
1065 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001066 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001067 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001068 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1069 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001070
1071 def testPackX86RomMeNoDesc(self):
1072 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001073 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001074 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001075 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001076 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001077 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1078 str(e.exception))
1079 finally:
1080 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001081
1082 def testPackX86RomBadDesc(self):
1083 """Test that the Intel requires a descriptor entry"""
1084 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001085 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001086 self.assertIn("Node '/binman/intel-me': No offset set with "
1087 "offset-unset: should another entry provide this correct "
1088 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001089
1090 def testPackX86RomMe(self):
1091 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001092 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001093 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001094 if data[:0x1000] != expected_desc:
1095 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001096 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1097
1098 def testPackVga(self):
1099 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001100 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001101 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1102
1103 def testPackStart16(self):
1104 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001105 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001106 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1107
Jagdish Gediya311d4842018-09-03 21:35:08 +05301108 def testPackPowerpcMpc85xxBootpgResetvec(self):
1109 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1110 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001111 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301112 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1113
Simon Glass6ba679c2018-07-06 10:27:17 -06001114 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001115 """Handle running a test for insertion of microcode
1116
1117 Args:
1118 dts_fname: Name of test .dts file
1119 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001120 ucode_second: True if the microsecond entry is second instead of
1121 third
Simon Glass820af1d2018-07-06 10:27:16 -06001122
1123 Returns:
1124 Tuple:
1125 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001126 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001127 in the above (two 4-byte words)
1128 """
Simon Glass3d274232017-11-12 21:52:27 -07001129 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001130
1131 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001132 if ucode_second:
1133 ucode_content = data[len(nodtb_data):]
1134 ucode_pos = len(nodtb_data)
1135 dtb_with_ucode = ucode_content[16:]
1136 fdt_len = self.GetFdtLen(dtb_with_ucode)
1137 else:
1138 dtb_with_ucode = data[len(nodtb_data):]
1139 fdt_len = self.GetFdtLen(dtb_with_ucode)
1140 ucode_content = dtb_with_ucode[fdt_len:]
1141 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001142 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001143 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001144 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001145 dtb = fdt.FdtScan(fname)
1146 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001147 self.assertTrue(ucode)
1148 for node in ucode.subnodes:
1149 self.assertFalse(node.props.get('data'))
1150
Simon Glass72232452016-11-25 20:15:53 -07001151 # Check that the microcode appears immediately after the Fdt
1152 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001153 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001154 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1155 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001156 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001157
1158 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001159 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001160 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1161 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001162 u_boot = data[:len(nodtb_data)]
1163 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001164
1165 def testPackUbootMicrocode(self):
1166 """Test that x86 microcode can be handled correctly
1167
1168 We expect to see the following in the image, in order:
1169 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1170 place
1171 u-boot.dtb with the microcode removed
1172 the microcode
1173 """
Simon Glass511f6582018-10-01 12:22:30 -06001174 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001175 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001176 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1177 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001178
Simon Glassbac25c82017-05-27 07:38:26 -06001179 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001180 """Test that x86 microcode can be handled correctly
1181
1182 We expect to see the following in the image, in order:
1183 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1184 place
1185 u-boot.dtb with the microcode
1186 an empty microcode region
1187 """
1188 # We need the libfdt library to run this test since only that allows
1189 # finding the offset of a property. This is required by
1190 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001191 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001192
1193 second = data[len(U_BOOT_NODTB_DATA):]
1194
1195 fdt_len = self.GetFdtLen(second)
1196 third = second[fdt_len:]
1197 second = second[:fdt_len]
1198
Simon Glassbac25c82017-05-27 07:38:26 -06001199 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1200 self.assertIn(ucode_data, second)
1201 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001202
Simon Glassbac25c82017-05-27 07:38:26 -06001203 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001204 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001205 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1206 len(ucode_data))
1207 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001208 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1209 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001210
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001211 def testPackUbootSingleMicrocode(self):
1212 """Test that x86 microcode can be handled correctly with fdt_normal.
1213 """
Simon Glassbac25c82017-05-27 07:38:26 -06001214 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001215
Simon Glass996021e2016-11-25 20:15:54 -07001216 def testUBootImg(self):
1217 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001218 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001219 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001220
1221 def testNoMicrocode(self):
1222 """Test that a missing microcode region is detected"""
1223 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001224 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001225 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1226 "node found in ", str(e.exception))
1227
1228 def testMicrocodeWithoutNode(self):
1229 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1230 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001231 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001232 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1233 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1234
1235 def testMicrocodeWithoutNode2(self):
1236 """Test that a missing u-boot-ucode node is detected"""
1237 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001238 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001239 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1240 "microcode region u-boot-ucode", str(e.exception))
1241
1242 def testMicrocodeWithoutPtrInElf(self):
1243 """Test that a U-Boot binary without the microcode symbol is detected"""
1244 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001245 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001246 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001247 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001248
1249 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001250 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001251 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1252 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1253
1254 finally:
1255 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001256 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001257 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001258
1259 def testMicrocodeNotInImage(self):
1260 """Test that microcode must be placed within the image"""
1261 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001262 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001263 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1264 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001265 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001266
1267 def testWithoutMicrocode(self):
1268 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001269 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001270 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001271 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001272
1273 # Now check the device tree has no microcode
1274 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1275 second = data[len(U_BOOT_NODTB_DATA):]
1276
1277 fdt_len = self.GetFdtLen(second)
1278 self.assertEqual(dtb, second[:fdt_len])
1279
1280 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1281 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001282 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001283
1284 def testUnknownPosSize(self):
1285 """Test that microcode must be placed within the image"""
1286 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001287 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001288 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001289 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001290
1291 def testPackFsp(self):
1292 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001293 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001294 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1295
1296 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001297 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001298 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001299 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001300
1301 def testPackVbt(self):
1302 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001303 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001304 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001305
Simon Glass7f94e832017-11-12 21:52:25 -07001306 def testSplBssPad(self):
1307 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001308 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001309 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001310 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001311 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001312 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001313
Simon Glass04cda032018-10-01 21:12:42 -06001314 def testSplBssPadMissing(self):
1315 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001316 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001317 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001318 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001319 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1320 str(e.exception))
1321
Simon Glasse83679d2017-11-12 21:52:26 -07001322 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001323 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001324 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001325 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1326
Simon Glass6ba679c2018-07-06 10:27:17 -06001327 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1328 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001329
1330 We expect to see the following in the image, in order:
1331 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1332 correct place
1333 u-boot.dtb with the microcode removed
1334 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001335
1336 Args:
1337 dts: Device tree file to use for test
1338 ucode_second: True if the microsecond entry is second instead of
1339 third
Simon Glass3d274232017-11-12 21:52:27 -07001340 """
Simon Glass7057d022018-10-01 21:12:47 -06001341 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001342 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1343 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001344 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1345 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001346
Simon Glass6ba679c2018-07-06 10:27:17 -06001347 def testPackUbootSplMicrocode(self):
1348 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001349 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001350
1351 def testPackUbootSplMicrocodeReorder(self):
1352 """Test that order doesn't matter for microcode entries
1353
1354 This is the same as testPackUbootSplMicrocode but when we process the
1355 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1356 entry, so we reply on binman to try later.
1357 """
Simon Glass511f6582018-10-01 12:22:30 -06001358 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001359 ucode_second=True)
1360
Simon Glassa409c932017-11-12 21:52:28 -07001361 def testPackMrc(self):
1362 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001363 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001364 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1365
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001366 def testSplDtb(self):
1367 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001368 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001369 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1370
Simon Glass0a6da312017-11-13 18:54:56 -07001371 def testSplNoDtb(self):
1372 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001373 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001374 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001375 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1376
Simon Glass7098b7f2021-03-21 18:24:30 +13001377 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1378 use_expanded=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001379 """Check the image contains the expected symbol values
1380
1381 Args:
1382 dts: Device tree file to use for test
1383 base_data: Data before and after 'u-boot' section
1384 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001385 entry_args: Dict of entry args to supply to binman
1386 key: arg name
1387 value: value of that arg
1388 use_expanded: True to use expanded entries where available, e.g.
1389 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001390 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001391 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001392 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1393 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Simon Glass31e04cb2021-03-18 20:24:56 +13001394 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
1395 addr)
Simon Glass4ca8e042017-11-13 18:55:01 -07001396
Simon Glass7057d022018-10-01 21:12:47 -06001397 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001398 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1399 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001400 # The image should contain the symbols from u_boot_binman_syms.c
1401 # Note that image_pos is adjusted by the base address of the image,
1402 # which is 0x10 in our test image
1403 sym_values = struct.pack('<LQLL', 0x00,
1404 u_boot_offset + len(U_BOOT_DATA),
1405 0x10 + u_boot_offset, 0x04)
1406 expected = (sym_values + base_data[20:] +
Simon Glass80025522022-01-29 14:14:04 -07001407 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
Simon Glass31e04cb2021-03-18 20:24:56 +13001408 base_data[20:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001409 self.assertEqual(expected, data)
1410
Simon Glass31e04cb2021-03-18 20:24:56 +13001411 def testSymbols(self):
1412 """Test binman can assign symbols embedded in U-Boot"""
1413 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x18)
1414
1415 def testSymbolsNoDtb(self):
1416 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001417 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001418 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1419 0x38)
1420
Simon Glasse76a3e62018-06-01 09:38:11 -06001421 def testPackUnitAddress(self):
1422 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001423 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001424 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1425
Simon Glassa91e1152018-06-01 09:38:16 -06001426 def testSections(self):
1427 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001428 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001429 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1430 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1431 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001432 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001433
Simon Glass30732662018-06-01 09:38:20 -06001434 def testMap(self):
1435 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001436 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001437 self.assertEqual('''ImagePos Offset Size Name
143800000000 00000000 00000028 main-section
143900000000 00000000 00000010 section@0
144000000000 00000000 00000004 u-boot
144100000010 00000010 00000010 section@1
144200000010 00000000 00000004 u-boot
144300000020 00000020 00000004 section@2
144400000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001445''', map_data)
1446
Simon Glass3b78d532018-06-01 09:38:21 -06001447 def testNamePrefix(self):
1448 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001449 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001450 self.assertEqual('''ImagePos Offset Size Name
145100000000 00000000 00000028 main-section
145200000000 00000000 00000010 section@0
145300000000 00000000 00000004 ro-u-boot
145400000010 00000010 00000010 section@1
145500000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001456''', map_data)
1457
Simon Glass6ba679c2018-07-06 10:27:17 -06001458 def testUnknownContents(self):
1459 """Test that obtaining the contents works as expected"""
1460 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001461 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001462 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001463 "processing of contents: remaining ["
1464 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001465
Simon Glass2e1169f2018-07-06 10:27:19 -06001466 def testBadChangeSize(self):
1467 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001468 try:
1469 state.SetAllowEntryExpansion(False)
1470 with self.assertRaises(ValueError) as e:
1471 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001472 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001473 str(e.exception))
1474 finally:
1475 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001476
Simon Glassa87014e2018-07-06 10:27:42 -06001477 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001478 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001479 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001480 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001481 dtb = fdt.Fdt(out_dtb_fname)
1482 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001483 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001484 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001485 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001486 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001487 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001488 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001489 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001490 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001491 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001492 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001493 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001494 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001495 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001496
Simon Glasse8561af2018-08-01 15:22:37 -06001497 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001498 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001499 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001500 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001501 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001502 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001503 'size': 40
1504 }, props)
1505
1506 def testUpdateFdtBad(self):
1507 """Test that we detect when ProcessFdt never completes"""
1508 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001509 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001510 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001511 '[<binman.etype._testing.Entry__testing',
1512 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001513
Simon Glass91710b32018-07-17 13:25:32 -06001514 def testEntryArgs(self):
1515 """Test passing arguments to entries from the command line"""
1516 entry_args = {
1517 'test-str-arg': 'test1',
1518 'test-int-arg': '456',
1519 }
Simon Glass511f6582018-10-01 12:22:30 -06001520 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001521 self.assertIn('image', control.images)
1522 entry = control.images['image'].GetEntries()['_testing']
1523 self.assertEqual('test0', entry.test_str_fdt)
1524 self.assertEqual('test1', entry.test_str_arg)
1525 self.assertEqual(123, entry.test_int_fdt)
1526 self.assertEqual(456, entry.test_int_arg)
1527
1528 def testEntryArgsMissing(self):
1529 """Test missing arguments and properties"""
1530 entry_args = {
1531 'test-int-arg': '456',
1532 }
Simon Glass511f6582018-10-01 12:22:30 -06001533 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001534 entry = control.images['image'].GetEntries()['_testing']
1535 self.assertEqual('test0', entry.test_str_fdt)
1536 self.assertEqual(None, entry.test_str_arg)
1537 self.assertEqual(None, entry.test_int_fdt)
1538 self.assertEqual(456, entry.test_int_arg)
1539
1540 def testEntryArgsRequired(self):
1541 """Test missing arguments and properties"""
1542 entry_args = {
1543 'test-int-arg': '456',
1544 }
1545 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001546 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001547 self.assertIn("Node '/binman/_testing': "
1548 'Missing required properties/entry args: test-str-arg, '
1549 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001550 str(e.exception))
1551
1552 def testEntryArgsInvalidFormat(self):
1553 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001554 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1555 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001556 with self.assertRaises(ValueError) as e:
1557 self._DoBinman(*args)
1558 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1559
1560 def testEntryArgsInvalidInteger(self):
1561 """Test that an invalid entry-argument integer is detected"""
1562 entry_args = {
1563 'test-int-arg': 'abc',
1564 }
1565 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001566 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001567 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1568 "'test-int-arg' (value 'abc') to integer",
1569 str(e.exception))
1570
1571 def testEntryArgsInvalidDatatype(self):
1572 """Test that an invalid entry-argument datatype is detected
1573
1574 This test could be written in entry_test.py except that it needs
1575 access to control.entry_args, which seems more than that module should
1576 be able to see.
1577 """
1578 entry_args = {
1579 'test-bad-datatype-arg': '12',
1580 }
1581 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001582 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001583 entry_args=entry_args)
1584 self.assertIn('GetArg() internal error: Unknown data type ',
1585 str(e.exception))
1586
Simon Glass2ca52032018-07-17 13:25:33 -06001587 def testText(self):
1588 """Test for a text entry type"""
1589 entry_args = {
1590 'test-id': TEXT_DATA,
1591 'test-id2': TEXT_DATA2,
1592 'test-id3': TEXT_DATA3,
1593 }
Simon Glass511f6582018-10-01 12:22:30 -06001594 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001595 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001596 expected = (tools.to_bytes(TEXT_DATA) +
1597 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1598 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001599 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001600 self.assertEqual(expected, data)
1601
Simon Glass969616c2018-07-17 13:25:36 -06001602 def testEntryDocs(self):
1603 """Test for creation of entry documentation"""
1604 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001605 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001606 self.assertTrue(len(stdout.getvalue()) > 0)
1607
1608 def testEntryDocsMissing(self):
1609 """Test handling of missing entry documentation"""
1610 with self.assertRaises(ValueError) as e:
1611 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001612 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001613 self.assertIn('Documentation is missing for modules: u_boot',
1614 str(e.exception))
1615
Simon Glass704784b2018-07-17 13:25:38 -06001616 def testFmap(self):
1617 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001618 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001619 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001620 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1621 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001622 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001623 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001624 self.assertEqual(1, fhdr.ver_major)
1625 self.assertEqual(0, fhdr.ver_minor)
1626 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001627 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001628 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001629 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001630 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001631 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001632
Simon Glass82059c22021-04-03 11:05:09 +13001633 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001634 self.assertEqual(b'SECTION0', fentry.name)
1635 self.assertEqual(0, fentry.offset)
1636 self.assertEqual(16, fentry.size)
1637 self.assertEqual(0, fentry.flags)
1638
1639 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001640 self.assertEqual(b'RO_U_BOOT', fentry.name)
1641 self.assertEqual(0, fentry.offset)
1642 self.assertEqual(4, fentry.size)
1643 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001644
Simon Glass82059c22021-04-03 11:05:09 +13001645 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001646 self.assertEqual(b'SECTION1', fentry.name)
1647 self.assertEqual(16, fentry.offset)
1648 self.assertEqual(16, fentry.size)
1649 self.assertEqual(0, fentry.flags)
1650
1651 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001652 self.assertEqual(b'RW_U_BOOT', fentry.name)
1653 self.assertEqual(16, fentry.offset)
1654 self.assertEqual(4, fentry.size)
1655 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001656
Simon Glass82059c22021-04-03 11:05:09 +13001657 fentry = next(fiter)
1658 self.assertEqual(b'FMAP', fentry.name)
1659 self.assertEqual(32, fentry.offset)
1660 self.assertEqual(expect_size, fentry.size)
1661 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001662
Simon Glassdb168d42018-07-17 13:25:39 -06001663 def testBlobNamedByArg(self):
1664 """Test we can add a blob with the filename coming from an entry arg"""
1665 entry_args = {
1666 'cros-ec-rw-path': 'ecrw.bin',
1667 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001668 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001669
Simon Glass53f53992018-07-17 13:25:40 -06001670 def testFill(self):
1671 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001672 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001673 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001674 self.assertEqual(expected, data)
1675
1676 def testFillNoSize(self):
1677 """Test for an fill entry type with no size"""
1678 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001679 self._DoReadFile('070_fill_no_size.dts')
Simon Glass53f53992018-07-17 13:25:40 -06001680 self.assertIn("'fill' entry must have a size property",
1681 str(e.exception))
1682
Simon Glassc1ae83c2018-07-17 13:25:44 -06001683 def _HandleGbbCommand(self, pipe_list):
1684 """Fake calls to the futility utility"""
1685 if pipe_list[0][0] == 'futility':
1686 fname = pipe_list[0][-1]
1687 # Append our GBB data to the file, which will happen every time the
1688 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001689 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001690 fd.write(GBB_DATA)
1691 return command.CommandResult()
1692
1693 def testGbb(self):
1694 """Test for the Chromium OS Google Binary Block"""
1695 command.test_result = self._HandleGbbCommand
1696 entry_args = {
1697 'keydir': 'devkeys',
1698 'bmpblk': 'bmpblk.bin',
1699 }
Simon Glass511f6582018-10-01 12:22:30 -06001700 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001701
1702 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001703 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1704 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001705 self.assertEqual(expected, data)
1706
1707 def testGbbTooSmall(self):
1708 """Test for the Chromium OS Google Binary Block being large enough"""
1709 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001710 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001711 self.assertIn("Node '/binman/gbb': GBB is too small",
1712 str(e.exception))
1713
1714 def testGbbNoSize(self):
1715 """Test for the Chromium OS Google Binary Block having a size"""
1716 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001717 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001718 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1719 str(e.exception))
1720
Simon Glass66152ce2022-01-09 20:14:09 -07001721 def testGbbMissing(self):
1722 """Test that binman still produces an image if futility is missing"""
1723 entry_args = {
1724 'keydir': 'devkeys',
1725 }
1726 with test_util.capture_sys_output() as (_, stderr):
1727 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1728 entry_args=entry_args)
1729 err = stderr.getvalue()
1730 self.assertRegex(err,
1731 "Image 'main-section'.*missing bintools.*: futility")
1732
Simon Glass5c350162018-07-17 13:25:47 -06001733 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001734 """Fake calls to the futility utility
1735
1736 The expected pipe is:
1737
1738 [('futility', 'vbutil_firmware', '--vblock',
1739 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1740 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1741 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1742 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1743
1744 This writes to the output file (here, 'vblock.vblock'). If
1745 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1746 of the input data (here, 'input.vblock').
1747 """
Simon Glass5c350162018-07-17 13:25:47 -06001748 if pipe_list[0][0] == 'futility':
1749 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001750 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001751 if self._hash_data:
1752 infile = pipe_list[0][11]
1753 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001754 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001755 m.update(data)
1756 fd.write(m.digest())
1757 else:
1758 fd.write(VBLOCK_DATA)
1759
Simon Glass5c350162018-07-17 13:25:47 -06001760 return command.CommandResult()
1761
1762 def testVblock(self):
1763 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001764 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001765 command.test_result = self._HandleVblockCommand
1766 entry_args = {
1767 'keydir': 'devkeys',
1768 }
Simon Glass511f6582018-10-01 12:22:30 -06001769 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001770 entry_args=entry_args)
1771 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1772 self.assertEqual(expected, data)
1773
1774 def testVblockNoContent(self):
1775 """Test we detect a vblock which has no content to sign"""
1776 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001777 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001778 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001779 'property', str(e.exception))
1780
1781 def testVblockBadPhandle(self):
1782 """Test that we detect a vblock with an invalid phandle in contents"""
1783 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001784 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001785 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1786 '1000', str(e.exception))
1787
1788 def testVblockBadEntry(self):
1789 """Test that we detect an entry that points to a non-entry"""
1790 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001791 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001792 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1793 "'other'", str(e.exception))
1794
Simon Glass220c6222021-01-06 21:35:17 -07001795 def testVblockContent(self):
1796 """Test that the vblock signs the right data"""
1797 self._hash_data = True
1798 command.test_result = self._HandleVblockCommand
1799 entry_args = {
1800 'keydir': 'devkeys',
1801 }
1802 data = self._DoReadFileDtb(
1803 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1804 entry_args=entry_args)[0]
1805 hashlen = 32 # SHA256 hash is 32 bytes
1806 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1807 hashval = data[-hashlen:]
1808 dtb = data[len(U_BOOT_DATA):-hashlen]
1809
1810 expected_data = U_BOOT_DATA + dtb
1811
1812 # The hashval should be a hash of the dtb
1813 m = hashlib.sha256()
1814 m.update(expected_data)
1815 expected_hashval = m.digest()
1816 self.assertEqual(expected_hashval, hashval)
1817
Simon Glass66152ce2022-01-09 20:14:09 -07001818 def testVblockMissing(self):
1819 """Test that binman still produces an image if futility is missing"""
1820 entry_args = {
1821 'keydir': 'devkeys',
1822 }
1823 with test_util.capture_sys_output() as (_, stderr):
1824 self._DoTestFile('074_vblock.dts',
1825 force_missing_bintools='futility',
1826 entry_args=entry_args)
1827 err = stderr.getvalue()
1828 self.assertRegex(err,
1829 "Image 'main-section'.*missing bintools.*: futility")
1830
Simon Glass8425a1f2018-07-17 13:25:48 -06001831 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001832 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001833 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001834 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001835 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001836 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1837
Simon Glass24b97442018-07-17 13:25:51 -06001838 def testUsesPos(self):
1839 """Test that the 'pos' property cannot be used anymore"""
1840 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001841 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001842 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1843 "'pos'", str(e.exception))
1844
Simon Glass274bf092018-09-14 04:57:08 -06001845 def testFillZero(self):
1846 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001847 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001848 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001849
Simon Glass267de432018-09-14 04:57:09 -06001850 def testTextMissing(self):
1851 """Test for a text entry type where there is no text"""
1852 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001853 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001854 self.assertIn("Node '/binman/text': No value provided for text label "
1855 "'test-id'", str(e.exception))
1856
Simon Glassed40e962018-09-14 04:57:10 -06001857 def testPackStart16Tpl(self):
1858 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001859 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001860 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1861
Simon Glass3b376c32018-09-14 04:57:12 -06001862 def testSelectImage(self):
1863 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001864 expected = 'Skipping images: image1'
1865
1866 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001867 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001868 with test_util.capture_sys_output() as (stdout, stderr):
1869 retcode = self._DoTestFile('006_dual_image.dts',
1870 verbosity=verbosity,
1871 images=['image2'])
1872 self.assertEqual(0, retcode)
1873 if verbosity:
1874 self.assertIn(expected, stdout.getvalue())
1875 else:
1876 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001877
Simon Glass80025522022-01-29 14:14:04 -07001878 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1879 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001880 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001881
Simon Glasse219aa42018-09-14 04:57:24 -06001882 def testUpdateFdtAll(self):
1883 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001884 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001885
1886 base_expected = {
1887 'section:image-pos': 0,
1888 'u-boot-tpl-dtb:size': 513,
1889 'u-boot-spl-dtb:size': 513,
1890 'u-boot-spl-dtb:offset': 493,
1891 'image-pos': 0,
1892 'section/u-boot-dtb:image-pos': 0,
1893 'u-boot-spl-dtb:image-pos': 493,
1894 'section/u-boot-dtb:size': 493,
1895 'u-boot-tpl-dtb:image-pos': 1006,
1896 'section/u-boot-dtb:offset': 0,
1897 'section:size': 493,
1898 'offset': 0,
1899 'section:offset': 0,
1900 'u-boot-tpl-dtb:offset': 1006,
1901 'size': 1519
1902 }
1903
1904 # We expect three device-tree files in the output, one after the other.
1905 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1906 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1907 # main U-Boot tree. All three should have the same postions and offset.
1908 start = 0
1909 for item in ['', 'spl', 'tpl']:
1910 dtb = fdt.Fdt.FromData(data[start:])
1911 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001912 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1913 ['spl', 'tpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001914 expected = dict(base_expected)
1915 if item:
1916 expected[item] = 0
1917 self.assertEqual(expected, props)
1918 start += dtb._fdt_obj.totalsize()
1919
1920 def testUpdateFdtOutput(self):
1921 """Test that output DTB files are updated"""
1922 try:
Simon Glass511f6582018-10-01 12:22:30 -06001923 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001924 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1925
1926 # Unfortunately, compiling a source file always results in a file
1927 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001928 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001929 # binman as a file called u-boot.dtb. To fix this, copy the file
1930 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001931 start = 0
1932 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1933 'tpl/u-boot-tpl.dtb.out']:
1934 dtb = fdt.Fdt.FromData(data[start:])
1935 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07001936 pathname = tools.get_output_filename(os.path.split(fname)[1])
1937 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06001938 name = os.path.split(fname)[0]
1939
1940 if name:
1941 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1942 else:
1943 orig_indata = dtb_data
1944 self.assertNotEqual(outdata, orig_indata,
1945 "Expected output file '%s' be updated" % pathname)
1946 self.assertEqual(outdata, data[start:start + size],
1947 "Expected output file '%s' to match output image" %
1948 pathname)
1949 start += size
1950 finally:
1951 self._ResetDtbs()
1952
Simon Glass7ba33592018-09-14 04:57:26 -06001953 def _decompress(self, data):
Simon Glassdd5c14ec2022-01-09 20:14:04 -07001954 return comp_util.decompress(data, 'lz4')
Simon Glass7ba33592018-09-14 04:57:26 -06001955
1956 def testCompress(self):
1957 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06001958 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001959 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001960 use_real_dtb=True, update_dtb=True)
1961 dtb = fdt.Fdt(out_dtb_fname)
1962 dtb.Scan()
1963 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1964 orig = self._decompress(data)
1965 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06001966
1967 # Do a sanity check on various fields
1968 image = control.images['image']
1969 entries = image.GetEntries()
1970 self.assertEqual(1, len(entries))
1971
1972 entry = entries['blob']
1973 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1974 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1975 orig = self._decompress(entry.data)
1976 self.assertEqual(orig, entry.uncomp_data)
1977
Simon Glass72eeff12020-10-26 17:40:16 -06001978 self.assertEqual(image.data, entry.data)
1979
Simon Glass7ba33592018-09-14 04:57:26 -06001980 expected = {
1981 'blob:uncomp-size': len(COMPRESS_DATA),
1982 'blob:size': len(data),
1983 'size': len(data),
1984 }
1985 self.assertEqual(expected, props)
1986
Simon Glassac6328c2018-09-14 04:57:28 -06001987 def testFiles(self):
1988 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06001989 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001990 self.assertEqual(FILES_DATA, data)
1991
1992 def testFilesCompress(self):
1993 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06001994 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001995 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06001996
1997 image = control.images['image']
1998 entries = image.GetEntries()
1999 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002000 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002001
Simon Glass303f62f2019-05-17 22:00:46 -06002002 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002003 for i in range(1, 3):
2004 key = '%d.dat' % i
2005 start = entries[key].image_pos
2006 len = entries[key].size
2007 chunk = data[start:start + len]
2008 orig += self._decompress(chunk)
2009
2010 self.assertEqual(FILES_DATA, orig)
2011
2012 def testFilesMissing(self):
2013 """Test missing files"""
2014 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002015 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002016 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2017 'no files', str(e.exception))
2018
2019 def testFilesNoPattern(self):
2020 """Test missing files"""
2021 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002022 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002023 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2024 str(e.exception))
2025
Simon Glassfa79a812018-09-14 04:57:29 -06002026 def testExpandSize(self):
2027 """Test an expanding entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002028 data, _, map_data, _ = self._DoReadFileDtb('088_expand_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002029 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002030 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2031 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2032 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2033 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002034 self.assertEqual(expect, data)
2035 self.assertEqual('''ImagePos Offset Size Name
203600000000 00000000 00000028 main-section
203700000000 00000000 00000008 fill
203800000008 00000008 00000004 u-boot
20390000000c 0000000c 00000004 section
20400000000c 00000000 00000003 intel-mrc
204100000010 00000010 00000004 u-boot2
204200000014 00000014 0000000c section2
204300000014 00000000 00000008 fill
20440000001c 00000008 00000004 u-boot
204500000020 00000020 00000008 fill2
2046''', map_data)
2047
2048 def testExpandSizeBad(self):
2049 """Test an expanding entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002050 with test_util.capture_sys_output() as (stdout, stderr):
2051 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002052 self._DoReadFileDtb('089_expand_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002053 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2054 'expanding entry', str(e.exception))
2055
Simon Glassae7cf032018-09-14 04:57:31 -06002056 def testHash(self):
2057 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002058 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002059 use_real_dtb=True, update_dtb=True)
2060 dtb = fdt.Fdt(out_dtb_fname)
2061 dtb.Scan()
2062 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2063 m = hashlib.sha256()
2064 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002065 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002066
2067 def testHashNoAlgo(self):
2068 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002069 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002070 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2071 'hash node', str(e.exception))
2072
2073 def testHashBadAlgo(self):
2074 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002075 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002076 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm",
2077 str(e.exception))
2078
2079 def testHashSection(self):
2080 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002081 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002082 use_real_dtb=True, update_dtb=True)
2083 dtb = fdt.Fdt(out_dtb_fname)
2084 dtb.Scan()
2085 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2086 m = hashlib.sha256()
2087 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002088 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002089 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002090
Simon Glass3fb4f422018-09-14 04:57:32 -06002091 def testPackUBootTplMicrocode(self):
2092 """Test that x86 microcode can be handled correctly in TPL
2093
2094 We expect to see the following in the image, in order:
2095 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2096 place
2097 u-boot-tpl.dtb with the microcode removed
2098 the microcode
2099 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002100 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002101 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002102 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002103 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2104 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002105
Simon Glassc64aea52018-09-14 04:57:34 -06002106 def testFmapX86(self):
2107 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002108 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002109 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002110 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002111 self.assertEqual(expected, data[:32])
2112 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2113
2114 self.assertEqual(0x100, fhdr.image_size)
2115
2116 self.assertEqual(0, fentries[0].offset)
2117 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002118 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002119
2120 self.assertEqual(4, fentries[1].offset)
2121 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002122 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002123
2124 self.assertEqual(32, fentries[2].offset)
2125 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2126 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002127 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002128
2129 def testFmapX86Section(self):
2130 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002131 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002132 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002133 self.assertEqual(expected, data[:32])
2134 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2135
Simon Glassb1d414c2021-04-03 11:05:10 +13002136 self.assertEqual(0x180, fhdr.image_size)
2137 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002138 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002139
Simon Glass82059c22021-04-03 11:05:09 +13002140 fentry = next(fiter)
2141 self.assertEqual(b'U_BOOT', fentry.name)
2142 self.assertEqual(0, fentry.offset)
2143 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002144
Simon Glass82059c22021-04-03 11:05:09 +13002145 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002146 self.assertEqual(b'SECTION', fentry.name)
2147 self.assertEqual(4, fentry.offset)
2148 self.assertEqual(0x20 + expect_size, fentry.size)
2149
2150 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002151 self.assertEqual(b'INTEL_MRC', fentry.name)
2152 self.assertEqual(4, fentry.offset)
2153 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002154
Simon Glass82059c22021-04-03 11:05:09 +13002155 fentry = next(fiter)
2156 self.assertEqual(b'FMAP', fentry.name)
2157 self.assertEqual(36, fentry.offset)
2158 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002159
Simon Glassb1714232018-09-14 04:57:35 -06002160 def testElf(self):
2161 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002162 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002163 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002164 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002165 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002166 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002167
Simon Glass0d673792019-07-08 13:18:25 -06002168 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002169 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002170 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002171 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002172 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002173 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002174
Simon Glasscd817d52018-09-14 04:57:36 -06002175 def testPackOverlapMap(self):
2176 """Test that overlapping regions are detected"""
2177 with test_util.capture_sys_output() as (stdout, stderr):
2178 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002179 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002180 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002181 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2182 stdout.getvalue())
2183
2184 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002185 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002186 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002187 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002188 self.assertEqual('''ImagePos Offset Size Name
Simon Glassd99850b2020-10-26 17:40:24 -06002189<none> 00000000 00000008 main-section
Simon Glasscd817d52018-09-14 04:57:36 -06002190<none> 00000000 00000004 u-boot
2191<none> 00000003 00000004 u-boot-align
2192''', map_data)
2193
Simon Glass0d673792019-07-08 13:18:25 -06002194 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002195 """Test that an image with an Intel Reference code binary works"""
2196 data = self._DoReadFile('100_intel_refcode.dts')
2197 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2198
Simon Glasseb023b32019-04-25 21:58:39 -06002199 def testSectionOffset(self):
2200 """Tests use of a section with an offset"""
2201 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2202 map=True)
2203 self.assertEqual('''ImagePos Offset Size Name
220400000000 00000000 00000038 main-section
220500000004 00000004 00000010 section@0
220600000004 00000000 00000004 u-boot
220700000018 00000018 00000010 section@1
220800000018 00000000 00000004 u-boot
22090000002c 0000002c 00000004 section@2
22100000002c 00000000 00000004 u-boot
2211''', map_data)
2212 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002213 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2214 tools.get_bytes(0x21, 12) +
2215 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2216 tools.get_bytes(0x61, 12) +
2217 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2218 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002219
Simon Glass1de34482019-07-08 13:18:53 -06002220 def testCbfsRaw(self):
2221 """Test base handling of a Coreboot Filesystem (CBFS)
2222
2223 The exact contents of the CBFS is verified by similar tests in
2224 cbfs_util_test.py. The tests here merely check that the files added to
2225 the CBFS can be found in the final image.
2226 """
2227 data = self._DoReadFile('102_cbfs_raw.dts')
2228 size = 0xb0
2229
2230 cbfs = cbfs_util.CbfsReader(data)
2231 self.assertEqual(size, cbfs.rom_size)
2232
2233 self.assertIn('u-boot-dtb', cbfs.files)
2234 cfile = cbfs.files['u-boot-dtb']
2235 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2236
2237 def testCbfsArch(self):
2238 """Test on non-x86 architecture"""
2239 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2240 size = 0x100
2241
2242 cbfs = cbfs_util.CbfsReader(data)
2243 self.assertEqual(size, cbfs.rom_size)
2244
2245 self.assertIn('u-boot-dtb', cbfs.files)
2246 cfile = cbfs.files['u-boot-dtb']
2247 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2248
2249 def testCbfsStage(self):
2250 """Tests handling of a Coreboot Filesystem (CBFS)"""
2251 if not elf.ELF_TOOLS:
2252 self.skipTest('Python elftools not available')
2253 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2254 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2255 size = 0xb0
2256
2257 data = self._DoReadFile('104_cbfs_stage.dts')
2258 cbfs = cbfs_util.CbfsReader(data)
2259 self.assertEqual(size, cbfs.rom_size)
2260
2261 self.assertIn('u-boot', cbfs.files)
2262 cfile = cbfs.files['u-boot']
2263 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2264
2265 def testCbfsRawCompress(self):
2266 """Test handling of compressing raw files"""
2267 self._CheckLz4()
2268 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2269 size = 0x140
2270
2271 cbfs = cbfs_util.CbfsReader(data)
2272 self.assertIn('u-boot', cbfs.files)
2273 cfile = cbfs.files['u-boot']
2274 self.assertEqual(COMPRESS_DATA, cfile.data)
2275
2276 def testCbfsBadArch(self):
2277 """Test handling of a bad architecture"""
2278 with self.assertRaises(ValueError) as e:
2279 self._DoReadFile('106_cbfs_bad_arch.dts')
2280 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2281
2282 def testCbfsNoSize(self):
2283 """Test handling of a missing size property"""
2284 with self.assertRaises(ValueError) as e:
2285 self._DoReadFile('107_cbfs_no_size.dts')
2286 self.assertIn('entry must have a size property', str(e.exception))
2287
Simon Glass3e28f4f2021-11-23 11:03:54 -07002288 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002289 """Test handling of a CBFS entry which does not provide contentsy"""
2290 with self.assertRaises(ValueError) as e:
2291 self._DoReadFile('108_cbfs_no_contents.dts')
2292 self.assertIn('Could not complete processing of contents',
2293 str(e.exception))
2294
2295 def testCbfsBadCompress(self):
2296 """Test handling of a bad architecture"""
2297 with self.assertRaises(ValueError) as e:
2298 self._DoReadFile('109_cbfs_bad_compress.dts')
2299 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2300 str(e.exception))
2301
2302 def testCbfsNamedEntries(self):
2303 """Test handling of named entries"""
2304 data = self._DoReadFile('110_cbfs_name.dts')
2305
2306 cbfs = cbfs_util.CbfsReader(data)
2307 self.assertIn('FRED', cbfs.files)
2308 cfile1 = cbfs.files['FRED']
2309 self.assertEqual(U_BOOT_DATA, cfile1.data)
2310
2311 self.assertIn('hello', cbfs.files)
2312 cfile2 = cbfs.files['hello']
2313 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2314
Simon Glass759af872019-07-08 13:18:54 -06002315 def _SetupIfwi(self, fname):
2316 """Set up to run an IFWI test
2317
2318 Args:
2319 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2320 """
2321 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002322 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002323
2324 # Intel Integrated Firmware Image (IFWI) file
2325 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2326 data = fd.read()
2327 TestFunctional._MakeInputFile(fname,data)
2328
2329 def _CheckIfwi(self, data):
2330 """Check that an image with an IFWI contains the correct output
2331
2332 Args:
2333 data: Conents of output file
2334 """
Simon Glass80025522022-01-29 14:14:04 -07002335 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002336 if data[:0x1000] != expected_desc:
2337 self.fail('Expected descriptor binary at start of image')
2338
2339 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002340 image_fname = tools.get_output_filename('image.bin')
2341 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002342 ifwitool = bintool.Bintool.create('ifwitool')
2343 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002344
Simon Glass80025522022-01-29 14:14:04 -07002345 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002346 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002347
2348 def testPackX86RomIfwi(self):
2349 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2350 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002351 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002352 self._CheckIfwi(data)
2353
2354 def testPackX86RomIfwiNoDesc(self):
2355 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2356 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002357 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002358 self._CheckIfwi(data)
2359
2360 def testPackX86RomIfwiNoData(self):
2361 """Test that an x86 ROM with IFWI handles missing data"""
2362 self._SetupIfwi('ifwi.bin')
2363 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002364 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002365 self.assertIn('Could not complete processing of contents',
2366 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002367
Simon Glass66152ce2022-01-09 20:14:09 -07002368 def testIfwiMissing(self):
2369 """Test that binman still produces an image if ifwitool is missing"""
2370 self._SetupIfwi('fitimage.bin')
2371 with test_util.capture_sys_output() as (_, stderr):
2372 self._DoTestFile('111_x86_rom_ifwi.dts',
2373 force_missing_bintools='ifwitool')
2374 err = stderr.getvalue()
2375 self.assertRegex(err,
2376 "Image 'main-section'.*missing bintools.*: ifwitool")
2377
Simon Glassc2f1aed2019-07-08 13:18:56 -06002378 def testCbfsOffset(self):
2379 """Test a CBFS with files at particular offsets
2380
2381 Like all CFBS tests, this is just checking the logic that calls
2382 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2383 """
2384 data = self._DoReadFile('114_cbfs_offset.dts')
2385 size = 0x200
2386
2387 cbfs = cbfs_util.CbfsReader(data)
2388 self.assertEqual(size, cbfs.rom_size)
2389
2390 self.assertIn('u-boot', cbfs.files)
2391 cfile = cbfs.files['u-boot']
2392 self.assertEqual(U_BOOT_DATA, cfile.data)
2393 self.assertEqual(0x40, cfile.cbfs_offset)
2394
2395 self.assertIn('u-boot-dtb', cbfs.files)
2396 cfile2 = cbfs.files['u-boot-dtb']
2397 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2398 self.assertEqual(0x140, cfile2.cbfs_offset)
2399
Simon Glass0f621332019-07-08 14:25:27 -06002400 def testFdtmap(self):
2401 """Test an FDT map can be inserted in the image"""
2402 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2403 fdtmap_data = data[len(U_BOOT_DATA):]
2404 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002405 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002406 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002407
2408 fdt_data = fdtmap_data[16:]
2409 dtb = fdt.Fdt.FromData(fdt_data)
2410 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002411 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002412 self.assertEqual({
2413 'image-pos': 0,
2414 'offset': 0,
2415 'u-boot:offset': 0,
2416 'u-boot:size': len(U_BOOT_DATA),
2417 'u-boot:image-pos': 0,
2418 'fdtmap:image-pos': 4,
2419 'fdtmap:offset': 4,
2420 'fdtmap:size': len(fdtmap_data),
2421 'size': len(data),
2422 }, props)
2423
2424 def testFdtmapNoMatch(self):
2425 """Check handling of an FDT map when the section cannot be found"""
2426 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2427
2428 # Mangle the section name, which should cause a mismatch between the
2429 # correct FDT path and the one expected by the section
2430 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002431 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002432 entries = image.GetEntries()
2433 fdtmap = entries['fdtmap']
2434 with self.assertRaises(ValueError) as e:
2435 fdtmap._GetFdtmap()
2436 self.assertIn("Cannot locate node for path '/binman-suffix'",
2437 str(e.exception))
2438
Simon Glasscec34ba2019-07-08 14:25:28 -06002439 def testFdtmapHeader(self):
2440 """Test an FDT map and image header can be inserted in the image"""
2441 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2442 fdtmap_pos = len(U_BOOT_DATA)
2443 fdtmap_data = data[fdtmap_pos:]
2444 fdt_data = fdtmap_data[16:]
2445 dtb = fdt.Fdt.FromData(fdt_data)
2446 fdt_size = dtb.GetFdtObj().totalsize()
2447 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002448 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002449 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2450 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2451
2452 def testFdtmapHeaderStart(self):
2453 """Test an image header can be inserted at the image start"""
2454 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2455 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2456 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002457 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002458 offset = struct.unpack('<I', hdr_data[4:])[0]
2459 self.assertEqual(fdtmap_pos, offset)
2460
2461 def testFdtmapHeaderPos(self):
2462 """Test an image header can be inserted at a chosen position"""
2463 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2464 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2465 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002466 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002467 offset = struct.unpack('<I', hdr_data[4:])[0]
2468 self.assertEqual(fdtmap_pos, offset)
2469
2470 def testHeaderMissingFdtmap(self):
2471 """Test an image header requires an fdtmap"""
2472 with self.assertRaises(ValueError) as e:
2473 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2474 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2475 str(e.exception))
2476
2477 def testHeaderNoLocation(self):
2478 """Test an image header with a no specified location is detected"""
2479 with self.assertRaises(ValueError) as e:
2480 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2481 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2482 str(e.exception))
2483
Simon Glasse61b6f62019-07-08 14:25:37 -06002484 def testEntryExpand(self):
2485 """Test expanding an entry after it is packed"""
2486 data = self._DoReadFile('121_entry_expand.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002487 self.assertEqual(b'aaa', data[:3])
2488 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2489 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002490
2491 def testEntryExpandBad(self):
2492 """Test expanding an entry after it is packed, twice"""
2493 with self.assertRaises(ValueError) as e:
2494 self._DoReadFile('122_entry_expand_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002495 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002496 str(e.exception))
2497
2498 def testEntryExpandSection(self):
2499 """Test expanding an entry within a section after it is packed"""
2500 data = self._DoReadFile('123_entry_expand_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002501 self.assertEqual(b'aaa', data[:3])
2502 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2503 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002504
Simon Glass90d29682019-07-08 14:25:38 -06002505 def testCompressDtb(self):
2506 """Test that compress of device-tree files is supported"""
2507 self._CheckLz4()
2508 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2509 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2510 comp_data = data[len(U_BOOT_DATA):]
2511 orig = self._decompress(comp_data)
2512 dtb = fdt.Fdt.FromData(orig)
2513 dtb.Scan()
2514 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2515 expected = {
2516 'u-boot:size': len(U_BOOT_DATA),
2517 'u-boot-dtb:uncomp-size': len(orig),
2518 'u-boot-dtb:size': len(comp_data),
2519 'size': len(data),
2520 }
2521 self.assertEqual(expected, props)
2522
Simon Glass151bbbf2019-07-08 14:25:41 -06002523 def testCbfsUpdateFdt(self):
2524 """Test that we can update the device tree with CBFS offset/size info"""
2525 self._CheckLz4()
2526 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2527 update_dtb=True)
2528 dtb = fdt.Fdt(out_dtb_fname)
2529 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002530 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002531 del props['cbfs/u-boot:size']
2532 self.assertEqual({
2533 'offset': 0,
2534 'size': len(data),
2535 'image-pos': 0,
2536 'cbfs:offset': 0,
2537 'cbfs:size': len(data),
2538 'cbfs:image-pos': 0,
2539 'cbfs/u-boot:offset': 0x38,
2540 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2541 'cbfs/u-boot:image-pos': 0x38,
2542 'cbfs/u-boot-dtb:offset': 0xb8,
2543 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2544 'cbfs/u-boot-dtb:image-pos': 0xb8,
2545 }, props)
2546
Simon Glass3c9b4f22019-07-08 14:25:42 -06002547 def testCbfsBadType(self):
2548 """Test an image header with a no specified location is detected"""
2549 with self.assertRaises(ValueError) as e:
2550 self._DoReadFile('126_cbfs_bad_type.dts')
2551 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2552
Simon Glass6b156f82019-07-08 14:25:43 -06002553 def testList(self):
2554 """Test listing the files in an image"""
2555 self._CheckLz4()
2556 data = self._DoReadFile('127_list.dts')
2557 image = control.images['image']
2558 entries = image.BuildEntryList()
2559 self.assertEqual(7, len(entries))
2560
2561 ent = entries[0]
2562 self.assertEqual(0, ent.indent)
2563 self.assertEqual('main-section', ent.name)
2564 self.assertEqual('section', ent.etype)
2565 self.assertEqual(len(data), ent.size)
2566 self.assertEqual(0, ent.image_pos)
2567 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002568 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002569
2570 ent = entries[1]
2571 self.assertEqual(1, ent.indent)
2572 self.assertEqual('u-boot', ent.name)
2573 self.assertEqual('u-boot', ent.etype)
2574 self.assertEqual(len(U_BOOT_DATA), ent.size)
2575 self.assertEqual(0, ent.image_pos)
2576 self.assertEqual(None, ent.uncomp_size)
2577 self.assertEqual(0, ent.offset)
2578
2579 ent = entries[2]
2580 self.assertEqual(1, ent.indent)
2581 self.assertEqual('section', ent.name)
2582 self.assertEqual('section', ent.etype)
2583 section_size = ent.size
2584 self.assertEqual(0x100, ent.image_pos)
2585 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002586 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002587
2588 ent = entries[3]
2589 self.assertEqual(2, ent.indent)
2590 self.assertEqual('cbfs', ent.name)
2591 self.assertEqual('cbfs', ent.etype)
2592 self.assertEqual(0x400, ent.size)
2593 self.assertEqual(0x100, ent.image_pos)
2594 self.assertEqual(None, ent.uncomp_size)
2595 self.assertEqual(0, ent.offset)
2596
2597 ent = entries[4]
2598 self.assertEqual(3, ent.indent)
2599 self.assertEqual('u-boot', ent.name)
2600 self.assertEqual('u-boot', ent.etype)
2601 self.assertEqual(len(U_BOOT_DATA), ent.size)
2602 self.assertEqual(0x138, ent.image_pos)
2603 self.assertEqual(None, ent.uncomp_size)
2604 self.assertEqual(0x38, ent.offset)
2605
2606 ent = entries[5]
2607 self.assertEqual(3, ent.indent)
2608 self.assertEqual('u-boot-dtb', ent.name)
2609 self.assertEqual('text', ent.etype)
2610 self.assertGreater(len(COMPRESS_DATA), ent.size)
2611 self.assertEqual(0x178, ent.image_pos)
2612 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2613 self.assertEqual(0x78, ent.offset)
2614
2615 ent = entries[6]
2616 self.assertEqual(2, ent.indent)
2617 self.assertEqual('u-boot-dtb', ent.name)
2618 self.assertEqual('u-boot-dtb', ent.etype)
2619 self.assertEqual(0x500, ent.image_pos)
2620 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2621 dtb_size = ent.size
2622 # Compressing this data expands it since headers are added
2623 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2624 self.assertEqual(0x400, ent.offset)
2625
2626 self.assertEqual(len(data), 0x100 + section_size)
2627 self.assertEqual(section_size, 0x400 + dtb_size)
2628
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002629 def testFindFdtmap(self):
2630 """Test locating an FDT map in an image"""
2631 self._CheckLz4()
2632 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2633 image = control.images['image']
2634 entries = image.GetEntries()
2635 entry = entries['fdtmap']
2636 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2637
2638 def testFindFdtmapMissing(self):
2639 """Test failing to locate an FDP map"""
2640 data = self._DoReadFile('005_simple.dts')
2641 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2642
Simon Glassed39a3c2019-07-08 14:25:45 -06002643 def testFindImageHeader(self):
2644 """Test locating a image header"""
2645 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002646 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002647 image = control.images['image']
2648 entries = image.GetEntries()
2649 entry = entries['fdtmap']
2650 # The header should point to the FDT map
2651 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2652
2653 def testFindImageHeaderStart(self):
2654 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002655 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002656 image = control.images['image']
2657 entries = image.GetEntries()
2658 entry = entries['fdtmap']
2659 # The header should point to the FDT map
2660 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2661
2662 def testFindImageHeaderMissing(self):
2663 """Test failing to locate an image header"""
2664 data = self._DoReadFile('005_simple.dts')
2665 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2666
Simon Glassb8424fa2019-07-08 14:25:46 -06002667 def testReadImage(self):
2668 """Test reading an image and accessing its FDT map"""
2669 self._CheckLz4()
2670 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002671 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002672 orig_image = control.images['image']
2673 image = Image.FromFile(image_fname)
2674 self.assertEqual(orig_image.GetEntries().keys(),
2675 image.GetEntries().keys())
2676
2677 orig_entry = orig_image.GetEntries()['fdtmap']
2678 entry = image.GetEntries()['fdtmap']
2679 self.assertEquals(orig_entry.offset, entry.offset)
2680 self.assertEquals(orig_entry.size, entry.size)
2681 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2682
2683 def testReadImageNoHeader(self):
2684 """Test accessing an image's FDT map without an image header"""
2685 self._CheckLz4()
2686 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002687 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002688 image = Image.FromFile(image_fname)
2689 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002690 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002691
2692 def testReadImageFail(self):
2693 """Test failing to read an image image's FDT map"""
2694 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002695 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002696 with self.assertRaises(ValueError) as e:
2697 image = Image.FromFile(image_fname)
2698 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002699
Simon Glassb2fd11d2019-07-08 14:25:48 -06002700 def testListCmd(self):
2701 """Test listing the files in an image using an Fdtmap"""
2702 self._CheckLz4()
2703 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2704
2705 # lz4 compression size differs depending on the version
2706 image = control.images['image']
2707 entries = image.GetEntries()
2708 section_size = entries['section'].size
2709 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2710 fdtmap_offset = entries['fdtmap'].offset
2711
Simon Glassb3d6fc72019-07-20 12:24:10 -06002712 try:
2713 tmpdir, updated_fname = self._SetupImageInTmpdir()
2714 with test_util.capture_sys_output() as (stdout, stderr):
2715 self._DoBinman('ls', '-i', updated_fname)
2716 finally:
2717 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002718 lines = stdout.getvalue().splitlines()
2719 expected = [
2720'Name Image-pos Size Entry-type Offset Uncomp-size',
2721'----------------------------------------------------------------------',
2722'main-section 0 c00 section 0',
2723' u-boot 0 4 u-boot 0',
2724' section 100 %x section 100' % section_size,
2725' cbfs 100 400 cbfs 0',
2726' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002727' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002728' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002729' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002730 (fdtmap_offset, fdtmap_offset),
2731' image-header bf8 8 image-header bf8',
2732 ]
2733 self.assertEqual(expected, lines)
2734
2735 def testListCmdFail(self):
2736 """Test failing to list an image"""
2737 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002738 try:
2739 tmpdir, updated_fname = self._SetupImageInTmpdir()
2740 with self.assertRaises(ValueError) as e:
2741 self._DoBinman('ls', '-i', updated_fname)
2742 finally:
2743 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002744 self.assertIn("Cannot find FDT map in image", str(e.exception))
2745
2746 def _RunListCmd(self, paths, expected):
2747 """List out entries and check the result
2748
2749 Args:
2750 paths: List of paths to pass to the list command
2751 expected: Expected list of filenames to be returned, in order
2752 """
2753 self._CheckLz4()
2754 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002755 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002756 image = Image.FromFile(image_fname)
2757 lines = image.GetListEntries(paths)[1]
2758 files = [line[0].strip() for line in lines[1:]]
2759 self.assertEqual(expected, files)
2760
2761 def testListCmdSection(self):
2762 """Test listing the files in a section"""
2763 self._RunListCmd(['section'],
2764 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2765
2766 def testListCmdFile(self):
2767 """Test listing a particular file"""
2768 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2769
2770 def testListCmdWildcard(self):
2771 """Test listing a wildcarded file"""
2772 self._RunListCmd(['*boot*'],
2773 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2774
2775 def testListCmdWildcardMulti(self):
2776 """Test listing a wildcarded file"""
2777 self._RunListCmd(['*cb*', '*head*'],
2778 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2779
2780 def testListCmdEmpty(self):
2781 """Test listing a wildcarded file"""
2782 self._RunListCmd(['nothing'], [])
2783
2784 def testListCmdPath(self):
2785 """Test listing the files in a sub-entry of a section"""
2786 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2787
Simon Glass4c613bf2019-07-08 14:25:50 -06002788 def _RunExtractCmd(self, entry_name, decomp=True):
2789 """Extract an entry from an image
2790
2791 Args:
2792 entry_name: Entry name to extract
2793 decomp: True to decompress the data if compressed, False to leave
2794 it in its raw uncompressed format
2795
2796 Returns:
2797 data from entry
2798 """
2799 self._CheckLz4()
2800 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002801 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002802 return control.ReadEntry(image_fname, entry_name, decomp)
2803
2804 def testExtractSimple(self):
2805 """Test extracting a single file"""
2806 data = self._RunExtractCmd('u-boot')
2807 self.assertEqual(U_BOOT_DATA, data)
2808
Simon Glass980a2842019-07-08 14:25:52 -06002809 def testExtractSection(self):
2810 """Test extracting the files in a section"""
2811 data = self._RunExtractCmd('section')
2812 cbfs_data = data[:0x400]
2813 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002814 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002815 dtb_data = data[0x400:]
2816 dtb = self._decompress(dtb_data)
2817 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2818
2819 def testExtractCompressed(self):
2820 """Test extracting compressed data"""
2821 data = self._RunExtractCmd('section/u-boot-dtb')
2822 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2823
2824 def testExtractRaw(self):
2825 """Test extracting compressed data without decompressing it"""
2826 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2827 dtb = self._decompress(data)
2828 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2829
2830 def testExtractCbfs(self):
2831 """Test extracting CBFS data"""
2832 data = self._RunExtractCmd('section/cbfs/u-boot')
2833 self.assertEqual(U_BOOT_DATA, data)
2834
2835 def testExtractCbfsCompressed(self):
2836 """Test extracting CBFS compressed data"""
2837 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2838 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2839
2840 def testExtractCbfsRaw(self):
2841 """Test extracting CBFS compressed data without decompressing it"""
2842 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07002843 dtb = comp_util.decompress(data, 'lzma', with_header=False)
Simon Glass980a2842019-07-08 14:25:52 -06002844 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2845
Simon Glass4c613bf2019-07-08 14:25:50 -06002846 def testExtractBadEntry(self):
2847 """Test extracting a bad section path"""
2848 with self.assertRaises(ValueError) as e:
2849 self._RunExtractCmd('section/does-not-exist')
2850 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2851 str(e.exception))
2852
2853 def testExtractMissingFile(self):
2854 """Test extracting file that does not exist"""
2855 with self.assertRaises(IOError) as e:
2856 control.ReadEntry('missing-file', 'name')
2857
2858 def testExtractBadFile(self):
2859 """Test extracting an invalid file"""
2860 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002861 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002862 with self.assertRaises(ValueError) as e:
2863 control.ReadEntry(fname, 'name')
2864
Simon Glass980a2842019-07-08 14:25:52 -06002865 def testExtractCmd(self):
2866 """Test extracting a file fron an image on the command line"""
2867 self._CheckLz4()
2868 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002869 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002870 try:
2871 tmpdir, updated_fname = self._SetupImageInTmpdir()
2872 with test_util.capture_sys_output() as (stdout, stderr):
2873 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2874 '-f', fname)
2875 finally:
2876 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07002877 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002878 self.assertEqual(U_BOOT_DATA, data)
2879
2880 def testExtractOneEntry(self):
2881 """Test extracting a single entry fron an image """
2882 self._CheckLz4()
2883 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002884 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002885 fname = os.path.join(self._indir, 'output.extact')
2886 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07002887 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002888 self.assertEqual(U_BOOT_DATA, data)
2889
2890 def _CheckExtractOutput(self, decomp):
2891 """Helper to test file output with and without decompression
2892
2893 Args:
2894 decomp: True to decompress entry data, False to output it raw
2895 """
2896 def _CheckPresent(entry_path, expect_data, expect_size=None):
2897 """Check and remove expected file
2898
2899 This checks the data/size of a file and removes the file both from
2900 the outfiles set and from the output directory. Once all files are
2901 processed, both the set and directory should be empty.
2902
2903 Args:
2904 entry_path: Entry path
2905 expect_data: Data to expect in file, or None to skip check
2906 expect_size: Size of data to expect in file, or None to skip
2907 """
2908 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07002909 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06002910 os.remove(path)
2911 if expect_data:
2912 self.assertEqual(expect_data, data)
2913 elif expect_size:
2914 self.assertEqual(expect_size, len(data))
2915 outfiles.remove(path)
2916
2917 def _CheckDirPresent(name):
2918 """Remove expected directory
2919
2920 This gives an error if the directory does not exist as expected
2921
2922 Args:
2923 name: Name of directory to remove
2924 """
2925 path = os.path.join(outdir, name)
2926 os.rmdir(path)
2927
2928 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002929 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002930 outdir = os.path.join(self._indir, 'extract')
2931 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2932
2933 # Create a set of all file that were output (should be 9)
2934 outfiles = set()
2935 for root, dirs, files in os.walk(outdir):
2936 outfiles |= set([os.path.join(root, fname) for fname in files])
2937 self.assertEqual(9, len(outfiles))
2938 self.assertEqual(9, len(einfos))
2939
2940 image = control.images['image']
2941 entries = image.GetEntries()
2942
2943 # Check the 9 files in various ways
2944 section = entries['section']
2945 section_entries = section.GetEntries()
2946 cbfs_entries = section_entries['cbfs'].GetEntries()
2947 _CheckPresent('u-boot', U_BOOT_DATA)
2948 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2949 dtb_len = EXTRACT_DTB_SIZE
2950 if not decomp:
2951 dtb_len = cbfs_entries['u-boot-dtb'].size
2952 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2953 if not decomp:
2954 dtb_len = section_entries['u-boot-dtb'].size
2955 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2956
2957 fdtmap = entries['fdtmap']
2958 _CheckPresent('fdtmap', fdtmap.data)
2959 hdr = entries['image-header']
2960 _CheckPresent('image-header', hdr.data)
2961
2962 _CheckPresent('section/root', section.data)
2963 cbfs = section_entries['cbfs']
2964 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07002965 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06002966 _CheckPresent('root', data)
2967
2968 # There should be no files left. Remove all the directories to check.
2969 # If there are any files/dirs remaining, one of these checks will fail.
2970 self.assertEqual(0, len(outfiles))
2971 _CheckDirPresent('section/cbfs')
2972 _CheckDirPresent('section')
2973 _CheckDirPresent('')
2974 self.assertFalse(os.path.exists(outdir))
2975
2976 def testExtractAllEntries(self):
2977 """Test extracting all entries"""
2978 self._CheckLz4()
2979 self._CheckExtractOutput(decomp=True)
2980
2981 def testExtractAllEntriesRaw(self):
2982 """Test extracting all entries without decompressing them"""
2983 self._CheckLz4()
2984 self._CheckExtractOutput(decomp=False)
2985
2986 def testExtractSelectedEntries(self):
2987 """Test extracting some entries"""
2988 self._CheckLz4()
2989 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002990 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002991 outdir = os.path.join(self._indir, 'extract')
2992 einfos = control.ExtractEntries(image_fname, None, outdir,
2993 ['*cb*', '*head*'])
2994
2995 # File output is tested by testExtractAllEntries(), so just check that
2996 # the expected entries are selected
2997 names = [einfo.name for einfo in einfos]
2998 self.assertEqual(names,
2999 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3000
3001 def testExtractNoEntryPaths(self):
3002 """Test extracting some entries"""
3003 self._CheckLz4()
3004 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003005 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003006 with self.assertRaises(ValueError) as e:
3007 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003008 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003009 str(e.exception))
3010
3011 def testExtractTooManyEntryPaths(self):
3012 """Test extracting some entries"""
3013 self._CheckLz4()
3014 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003015 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003016 with self.assertRaises(ValueError) as e:
3017 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003018 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003019 str(e.exception))
3020
Simon Glass52d06212019-07-08 14:25:53 -06003021 def testPackAlignSection(self):
3022 """Test that sections can have alignment"""
3023 self._DoReadFile('131_pack_align_section.dts')
3024
3025 self.assertIn('image', control.images)
3026 image = control.images['image']
3027 entries = image.GetEntries()
3028 self.assertEqual(3, len(entries))
3029
3030 # First u-boot
3031 self.assertIn('u-boot', entries)
3032 entry = entries['u-boot']
3033 self.assertEqual(0, entry.offset)
3034 self.assertEqual(0, entry.image_pos)
3035 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3036 self.assertEqual(len(U_BOOT_DATA), entry.size)
3037
3038 # Section0
3039 self.assertIn('section0', entries)
3040 section0 = entries['section0']
3041 self.assertEqual(0x10, section0.offset)
3042 self.assertEqual(0x10, section0.image_pos)
3043 self.assertEqual(len(U_BOOT_DATA), section0.size)
3044
3045 # Second u-boot
3046 section_entries = section0.GetEntries()
3047 self.assertIn('u-boot', section_entries)
3048 entry = section_entries['u-boot']
3049 self.assertEqual(0, entry.offset)
3050 self.assertEqual(0x10, entry.image_pos)
3051 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3052 self.assertEqual(len(U_BOOT_DATA), entry.size)
3053
3054 # Section1
3055 self.assertIn('section1', entries)
3056 section1 = entries['section1']
3057 self.assertEqual(0x14, section1.offset)
3058 self.assertEqual(0x14, section1.image_pos)
3059 self.assertEqual(0x20, section1.size)
3060
3061 # Second u-boot
3062 section_entries = section1.GetEntries()
3063 self.assertIn('u-boot', section_entries)
3064 entry = section_entries['u-boot']
3065 self.assertEqual(0, entry.offset)
3066 self.assertEqual(0x14, entry.image_pos)
3067 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3068 self.assertEqual(len(U_BOOT_DATA), entry.size)
3069
3070 # Section2
3071 self.assertIn('section2', section_entries)
3072 section2 = section_entries['section2']
3073 self.assertEqual(0x4, section2.offset)
3074 self.assertEqual(0x18, section2.image_pos)
3075 self.assertEqual(4, section2.size)
3076
3077 # Third u-boot
3078 section_entries = section2.GetEntries()
3079 self.assertIn('u-boot', section_entries)
3080 entry = section_entries['u-boot']
3081 self.assertEqual(0, entry.offset)
3082 self.assertEqual(0x18, entry.image_pos)
3083 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3084 self.assertEqual(len(U_BOOT_DATA), entry.size)
3085
Simon Glassf8a54bc2019-07-20 12:23:56 -06003086 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3087 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003088 """Replace an entry in an image
3089
3090 This writes the entry data to update it, then opens the updated file and
3091 returns the value that it now finds there.
3092
3093 Args:
3094 entry_name: Entry name to replace
3095 data: Data to replace it with
3096 decomp: True to compress the data if needed, False if data is
3097 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003098 allow_resize: True to allow entries to change size, False to raise
3099 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003100
3101 Returns:
3102 Tuple:
3103 data from entry
3104 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003105 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003106 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003107 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003108 update_dtb=True)[1]
3109
3110 self.assertIn('image', control.images)
3111 image = control.images['image']
3112 entries = image.GetEntries()
3113 orig_dtb_data = entries['u-boot-dtb'].data
3114 orig_fdtmap_data = entries['fdtmap'].data
3115
Simon Glass80025522022-01-29 14:14:04 -07003116 image_fname = tools.get_output_filename('image.bin')
3117 updated_fname = tools.get_output_filename('image-updated.bin')
3118 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003119 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3120 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003121 data = control.ReadEntry(updated_fname, entry_name, decomp)
3122
Simon Glassf8a54bc2019-07-20 12:23:56 -06003123 # The DT data should not change unless resized:
3124 if not allow_resize:
3125 new_dtb_data = entries['u-boot-dtb'].data
3126 self.assertEqual(new_dtb_data, orig_dtb_data)
3127 new_fdtmap_data = entries['fdtmap'].data
3128 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003129
Simon Glassf8a54bc2019-07-20 12:23:56 -06003130 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003131
3132 def testReplaceSimple(self):
3133 """Test replacing a single file"""
3134 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003135 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3136 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003137 self.assertEqual(expected, data)
3138
3139 # Test that the state looks right. There should be an FDT for the fdtmap
3140 # that we jsut read back in, and it should match what we find in the
3141 # 'control' tables. Checking for an FDT that does not exist should
3142 # return None.
3143 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003144 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003145 self.assertEqual(expected_fdtmap, fdtmap)
3146
3147 dtb = state.GetFdtForEtype('fdtmap')
3148 self.assertEqual(dtb.GetContents(), fdtmap)
3149
3150 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3151 self.assertIsNone(missing_path)
3152 self.assertIsNone(missing_fdtmap)
3153
3154 missing_dtb = state.GetFdtForEtype('missing')
3155 self.assertIsNone(missing_dtb)
3156
3157 self.assertEqual('/binman', state.fdt_path_prefix)
3158
3159 def testReplaceResizeFail(self):
3160 """Test replacing a file by something larger"""
3161 expected = U_BOOT_DATA + b'x'
3162 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003163 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3164 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003165 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3166 str(e.exception))
3167
3168 def testReplaceMulti(self):
3169 """Test replacing entry data where multiple images are generated"""
3170 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3171 update_dtb=True)[0]
3172 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003173 updated_fname = tools.get_output_filename('image-updated.bin')
3174 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003175 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003176 control.WriteEntry(updated_fname, entry_name, expected,
3177 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003178 data = control.ReadEntry(updated_fname, entry_name)
3179 self.assertEqual(expected, data)
3180
3181 # Check the state looks right.
3182 self.assertEqual('/binman/image', state.fdt_path_prefix)
3183
3184 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003185 image_fname = tools.get_output_filename('first-image.bin')
3186 updated_fname = tools.get_output_filename('first-updated.bin')
3187 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003188 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003189 control.WriteEntry(updated_fname, entry_name, expected,
3190 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003191 data = control.ReadEntry(updated_fname, entry_name)
3192 self.assertEqual(expected, data)
3193
3194 # Check the state looks right.
3195 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003196
Simon Glassfb30e292019-07-20 12:23:51 -06003197 def testUpdateFdtAllRepack(self):
3198 """Test that all device trees are updated with offset/size info"""
3199 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3200 SECTION_SIZE = 0x300
3201 DTB_SIZE = 602
3202 FDTMAP_SIZE = 608
3203 base_expected = {
3204 'offset': 0,
3205 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3206 'image-pos': 0,
3207 'section:offset': 0,
3208 'section:size': SECTION_SIZE,
3209 'section:image-pos': 0,
3210 'section/u-boot-dtb:offset': 4,
3211 'section/u-boot-dtb:size': 636,
3212 'section/u-boot-dtb:image-pos': 4,
3213 'u-boot-spl-dtb:offset': SECTION_SIZE,
3214 'u-boot-spl-dtb:size': DTB_SIZE,
3215 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3216 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3217 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3218 'u-boot-tpl-dtb:size': DTB_SIZE,
3219 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3220 'fdtmap:size': FDTMAP_SIZE,
3221 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3222 }
3223 main_expected = {
3224 'section:orig-size': SECTION_SIZE,
3225 'section/u-boot-dtb:orig-offset': 4,
3226 }
3227
3228 # We expect three device-tree files in the output, with the first one
3229 # within a fixed-size section.
3230 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3231 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3232 # main U-Boot tree. All three should have the same positions and offset
3233 # except that the main tree should include the main_expected properties
3234 start = 4
3235 for item in ['', 'spl', 'tpl', None]:
3236 if item is None:
3237 start += 16 # Move past fdtmap header
3238 dtb = fdt.Fdt.FromData(data[start:])
3239 dtb.Scan()
3240 props = self._GetPropTree(dtb,
3241 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3242 prefix='/' if item is None else '/binman/')
3243 expected = dict(base_expected)
3244 if item:
3245 expected[item] = 0
3246 else:
3247 # Main DTB and fdtdec should include the 'orig-' properties
3248 expected.update(main_expected)
3249 # Helpful for debugging:
3250 #for prop in sorted(props):
3251 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3252 self.assertEqual(expected, props)
3253 if item == '':
3254 start = SECTION_SIZE
3255 else:
3256 start += dtb._fdt_obj.totalsize()
3257
Simon Glass11453762019-07-20 12:23:55 -06003258 def testFdtmapHeaderMiddle(self):
3259 """Test an FDT map in the middle of an image when it should be at end"""
3260 with self.assertRaises(ValueError) as e:
3261 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3262 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3263 str(e.exception))
3264
3265 def testFdtmapHeaderStartBad(self):
3266 """Test an FDT map in middle of an image when it should be at start"""
3267 with self.assertRaises(ValueError) as e:
3268 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3269 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3270 str(e.exception))
3271
3272 def testFdtmapHeaderEndBad(self):
3273 """Test an FDT map at the start of an image when it should be at end"""
3274 with self.assertRaises(ValueError) as e:
3275 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3276 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3277 str(e.exception))
3278
3279 def testFdtmapHeaderNoSize(self):
3280 """Test an image header at the end of an image with undefined size"""
3281 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3282
Simon Glassf8a54bc2019-07-20 12:23:56 -06003283 def testReplaceResize(self):
3284 """Test replacing a single file in an entry with a larger file"""
3285 expected = U_BOOT_DATA + b'x'
3286 data, _, image = self._RunReplaceCmd('u-boot', expected,
3287 dts='139_replace_repack.dts')
3288 self.assertEqual(expected, data)
3289
3290 entries = image.GetEntries()
3291 dtb_data = entries['u-boot-dtb'].data
3292 dtb = fdt.Fdt.FromData(dtb_data)
3293 dtb.Scan()
3294
3295 # The u-boot section should now be larger in the dtb
3296 node = dtb.GetNode('/binman/u-boot')
3297 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3298
3299 # Same for the fdtmap
3300 fdata = entries['fdtmap'].data
3301 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3302 fdtb.Scan()
3303 fnode = fdtb.GetNode('/u-boot')
3304 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3305
3306 def testReplaceResizeNoRepack(self):
3307 """Test replacing an entry with a larger file when not allowed"""
3308 expected = U_BOOT_DATA + b'x'
3309 with self.assertRaises(ValueError) as e:
3310 self._RunReplaceCmd('u-boot', expected)
3311 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3312 str(e.exception))
3313
Simon Glass9d8ee322019-07-20 12:23:58 -06003314 def testEntryShrink(self):
3315 """Test contracting an entry after it is packed"""
3316 try:
3317 state.SetAllowEntryContraction(True)
3318 data = self._DoReadFileDtb('140_entry_shrink.dts',
3319 update_dtb=True)[0]
3320 finally:
3321 state.SetAllowEntryContraction(False)
3322 self.assertEqual(b'a', data[:1])
3323 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3324 self.assertEqual(b'a', data[-1:])
3325
3326 def testEntryShrinkFail(self):
3327 """Test not being allowed to contract an entry after it is packed"""
3328 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3329
3330 # In this case there is a spare byte at the end of the data. The size of
3331 # the contents is only 1 byte but we still have the size before it
3332 # shrunk.
3333 self.assertEqual(b'a\0', data[:2])
3334 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3335 self.assertEqual(b'a\0', data[-2:])
3336
Simon Glass70e32982019-07-20 12:24:01 -06003337 def testDescriptorOffset(self):
3338 """Test that the Intel descriptor is always placed at at the start"""
3339 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3340 image = control.images['image']
3341 entries = image.GetEntries()
3342 desc = entries['intel-descriptor']
3343 self.assertEqual(0xff800000, desc.offset);
3344 self.assertEqual(0xff800000, desc.image_pos);
3345
Simon Glass37fdd142019-07-20 12:24:06 -06003346 def testReplaceCbfs(self):
3347 """Test replacing a single file in CBFS without changing the size"""
3348 self._CheckLz4()
3349 expected = b'x' * len(U_BOOT_DATA)
3350 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003351 updated_fname = tools.get_output_filename('image-updated.bin')
3352 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003353 entry_name = 'section/cbfs/u-boot'
3354 control.WriteEntry(updated_fname, entry_name, expected,
3355 allow_resize=True)
3356 data = control.ReadEntry(updated_fname, entry_name)
3357 self.assertEqual(expected, data)
3358
3359 def testReplaceResizeCbfs(self):
3360 """Test replacing a single file in CBFS with one of a different size"""
3361 self._CheckLz4()
3362 expected = U_BOOT_DATA + b'x'
3363 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003364 updated_fname = tools.get_output_filename('image-updated.bin')
3365 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003366 entry_name = 'section/cbfs/u-boot'
3367 control.WriteEntry(updated_fname, entry_name, expected,
3368 allow_resize=True)
3369 data = control.ReadEntry(updated_fname, entry_name)
3370 self.assertEqual(expected, data)
3371
Simon Glass30033c22019-07-20 12:24:15 -06003372 def _SetupForReplace(self):
3373 """Set up some files to use to replace entries
3374
3375 This generates an image, copies it to a new file, extracts all the files
3376 in it and updates some of them
3377
3378 Returns:
3379 List
3380 Image filename
3381 Output directory
3382 Expected values for updated entries, each a string
3383 """
3384 data = self._DoReadFileRealDtb('143_replace_all.dts')
3385
Simon Glass80025522022-01-29 14:14:04 -07003386 updated_fname = tools.get_output_filename('image-updated.bin')
3387 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003388
3389 outdir = os.path.join(self._indir, 'extract')
3390 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3391
3392 expected1 = b'x' + U_BOOT_DATA + b'y'
3393 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003394 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003395
3396 expected2 = b'a' + U_BOOT_DATA + b'b'
3397 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003398 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003399
3400 expected_text = b'not the same text'
3401 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003402 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003403
3404 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3405 dtb = fdt.FdtScan(dtb_fname)
3406 node = dtb.GetNode('/binman/text')
3407 node.AddString('my-property', 'the value')
3408 dtb.Sync(auto_resize=True)
3409 dtb.Flush()
3410
3411 return updated_fname, outdir, expected1, expected2, expected_text
3412
3413 def _CheckReplaceMultiple(self, entry_paths):
3414 """Handle replacing the contents of multiple entries
3415
3416 Args:
3417 entry_paths: List of entry paths to replace
3418
3419 Returns:
3420 List
3421 Dict of entries in the image:
3422 key: Entry name
3423 Value: Entry object
3424 Expected values for updated entries, each a string
3425 """
3426 updated_fname, outdir, expected1, expected2, expected_text = (
3427 self._SetupForReplace())
3428 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3429
3430 image = Image.FromFile(updated_fname)
3431 image.LoadData()
3432 return image.GetEntries(), expected1, expected2, expected_text
3433
3434 def testReplaceAll(self):
3435 """Test replacing the contents of all entries"""
3436 entries, expected1, expected2, expected_text = (
3437 self._CheckReplaceMultiple([]))
3438 data = entries['u-boot'].data
3439 self.assertEqual(expected1, data)
3440
3441 data = entries['u-boot2'].data
3442 self.assertEqual(expected2, data)
3443
3444 data = entries['text'].data
3445 self.assertEqual(expected_text, data)
3446
3447 # Check that the device tree is updated
3448 data = entries['u-boot-dtb'].data
3449 dtb = fdt.Fdt.FromData(data)
3450 dtb.Scan()
3451 node = dtb.GetNode('/binman/text')
3452 self.assertEqual('the value', node.props['my-property'].value)
3453
3454 def testReplaceSome(self):
3455 """Test replacing the contents of a few entries"""
3456 entries, expected1, expected2, expected_text = (
3457 self._CheckReplaceMultiple(['u-boot2', 'text']))
3458
3459 # This one should not change
3460 data = entries['u-boot'].data
3461 self.assertEqual(U_BOOT_DATA, data)
3462
3463 data = entries['u-boot2'].data
3464 self.assertEqual(expected2, data)
3465
3466 data = entries['text'].data
3467 self.assertEqual(expected_text, data)
3468
3469 def testReplaceCmd(self):
3470 """Test replacing a file fron an image on the command line"""
3471 self._DoReadFileRealDtb('143_replace_all.dts')
3472
3473 try:
3474 tmpdir, updated_fname = self._SetupImageInTmpdir()
3475
3476 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3477 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003478 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003479
3480 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003481 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003482 self.assertEqual(expected, data[:len(expected)])
3483 map_fname = os.path.join(tmpdir, 'image-updated.map')
3484 self.assertFalse(os.path.exists(map_fname))
3485 finally:
3486 shutil.rmtree(tmpdir)
3487
3488 def testReplaceCmdSome(self):
3489 """Test replacing some files fron an image on the command line"""
3490 updated_fname, outdir, expected1, expected2, expected_text = (
3491 self._SetupForReplace())
3492
3493 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3494 'u-boot2', 'text')
3495
Simon Glass80025522022-01-29 14:14:04 -07003496 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003497 image = Image.FromFile(updated_fname)
3498 image.LoadData()
3499 entries = image.GetEntries()
3500
3501 # This one should not change
3502 data = entries['u-boot'].data
3503 self.assertEqual(U_BOOT_DATA, data)
3504
3505 data = entries['u-boot2'].data
3506 self.assertEqual(expected2, data)
3507
3508 data = entries['text'].data
3509 self.assertEqual(expected_text, data)
3510
3511 def testReplaceMissing(self):
3512 """Test replacing entries where the file is missing"""
3513 updated_fname, outdir, expected1, expected2, expected_text = (
3514 self._SetupForReplace())
3515
3516 # Remove one of the files, to generate a warning
3517 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3518 os.remove(u_boot_fname1)
3519
3520 with test_util.capture_sys_output() as (stdout, stderr):
3521 control.ReplaceEntries(updated_fname, None, outdir, [])
3522 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003523 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003524
3525 def testReplaceCmdMap(self):
3526 """Test replacing a file fron an image on the command line"""
3527 self._DoReadFileRealDtb('143_replace_all.dts')
3528
3529 try:
3530 tmpdir, updated_fname = self._SetupImageInTmpdir()
3531
3532 fname = os.path.join(self._indir, 'update-u-boot.bin')
3533 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003534 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003535
3536 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3537 '-f', fname, '-m')
3538 map_fname = os.path.join(tmpdir, 'image-updated.map')
3539 self.assertTrue(os.path.exists(map_fname))
3540 finally:
3541 shutil.rmtree(tmpdir)
3542
3543 def testReplaceNoEntryPaths(self):
3544 """Test replacing an entry without an entry path"""
3545 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003546 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003547 with self.assertRaises(ValueError) as e:
3548 control.ReplaceEntries(image_fname, 'fname', None, [])
3549 self.assertIn('Must specify an entry path to read with -f',
3550 str(e.exception))
3551
3552 def testReplaceTooManyEntryPaths(self):
3553 """Test extracting some entries"""
3554 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003555 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003556 with self.assertRaises(ValueError) as e:
3557 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3558 self.assertIn('Must specify exactly one entry path to write with -f',
3559 str(e.exception))
3560
Simon Glass0b074d62019-08-24 07:22:48 -06003561 def testPackReset16(self):
3562 """Test that an image with an x86 reset16 region can be created"""
3563 data = self._DoReadFile('144_x86_reset16.dts')
3564 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3565
3566 def testPackReset16Spl(self):
3567 """Test that an image with an x86 reset16-spl region can be created"""
3568 data = self._DoReadFile('145_x86_reset16_spl.dts')
3569 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3570
3571 def testPackReset16Tpl(self):
3572 """Test that an image with an x86 reset16-tpl region can be created"""
3573 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3574 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3575
Simon Glass232f90c2019-08-24 07:22:50 -06003576 def testPackIntelFit(self):
3577 """Test that an image with an Intel FIT and pointer can be created"""
3578 data = self._DoReadFile('147_intel_fit.dts')
3579 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3580 fit = data[16:32];
3581 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3582 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3583
3584 image = control.images['image']
3585 entries = image.GetEntries()
3586 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3587 self.assertEqual(expected_ptr, ptr)
3588
3589 def testPackIntelFitMissing(self):
3590 """Test detection of a FIT pointer with not FIT region"""
3591 with self.assertRaises(ValueError) as e:
3592 self._DoReadFile('148_intel_fit_missing.dts')
3593 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3594 str(e.exception))
3595
Simon Glass72555fa2019-11-06 17:22:44 -07003596 def _CheckSymbolsTplSection(self, dts, expected_vals):
3597 data = self._DoReadFile(dts)
3598 sym_values = struct.pack('<LQLL', *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003599 upto1 = 4 + len(U_BOOT_SPL_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003600 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003601 self.assertEqual(expected1, data[:upto1])
3602
3603 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003604 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[20:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003605 self.assertEqual(expected2, data[upto1:upto2])
3606
Simon Glass4e353e22019-08-24 07:23:04 -06003607 upto3 = 0x34 + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003608 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003609 self.assertEqual(expected3, data[upto2:upto3])
3610
Simon Glass3f8ff012019-08-24 07:23:05 -06003611 expected4 = sym_values + U_BOOT_TPL_DATA[20:]
Simon Glass72555fa2019-11-06 17:22:44 -07003612 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3613
3614 def testSymbolsTplSection(self):
3615 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3616 self._SetupSplElf('u_boot_binman_syms')
3617 self._SetupTplElf('u_boot_binman_syms')
3618 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
3619 [0x04, 0x1c, 0x10 + 0x34, 0x04])
3620
3621 def testSymbolsTplSectionX86(self):
3622 """Test binman can assign symbols in a section with end-at-4gb"""
3623 self._SetupSplElf('u_boot_binman_syms_x86')
3624 self._SetupTplElf('u_boot_binman_syms_x86')
3625 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
3626 [0xffffff04, 0xffffff1c, 0xffffff34,
3627 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003628
Simon Glass98c59572019-08-24 07:23:03 -06003629 def testPackX86RomIfwiSectiom(self):
3630 """Test that a section can be placed in an IFWI region"""
3631 self._SetupIfwi('fitimage.bin')
3632 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3633 self._CheckIfwi(data)
3634
Simon Glassba7985d2019-08-24 07:23:07 -06003635 def testPackFspM(self):
3636 """Test that an image with a FSP memory-init binary can be created"""
3637 data = self._DoReadFile('152_intel_fsp_m.dts')
3638 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3639
Simon Glass4d9086d2019-10-20 21:31:35 -06003640 def testPackFspS(self):
3641 """Test that an image with a FSP silicon-init binary can be created"""
3642 data = self._DoReadFile('153_intel_fsp_s.dts')
3643 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003644
Simon Glass9ea87b22019-10-20 21:31:36 -06003645 def testPackFspT(self):
3646 """Test that an image with a FSP temp-ram-init binary can be created"""
3647 data = self._DoReadFile('154_intel_fsp_t.dts')
3648 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3649
Simon Glass48f3aad2020-07-09 18:39:31 -06003650 def testMkimage(self):
3651 """Test using mkimage to build an image"""
3652 data = self._DoReadFile('156_mkimage.dts')
3653
3654 # Just check that the data appears in the file somewhere
3655 self.assertIn(U_BOOT_SPL_DATA, data)
3656
Simon Glass66152ce2022-01-09 20:14:09 -07003657 def testMkimageMissing(self):
3658 """Test that binman still produces an image if mkimage is missing"""
3659 with test_util.capture_sys_output() as (_, stderr):
3660 self._DoTestFile('156_mkimage.dts',
3661 force_missing_bintools='mkimage')
3662 err = stderr.getvalue()
3663 self.assertRegex(err,
3664 "Image 'main-section'.*missing bintools.*: mkimage")
3665
Simon Glass5e560182020-07-09 18:39:36 -06003666 def testExtblob(self):
3667 """Test an image with an external blob"""
3668 data = self._DoReadFile('157_blob_ext.dts')
3669 self.assertEqual(REFCODE_DATA, data)
3670
3671 def testExtblobMissing(self):
3672 """Test an image with a missing external blob"""
3673 with self.assertRaises(ValueError) as e:
3674 self._DoReadFile('158_blob_ext_missing.dts')
3675 self.assertIn("Filename 'missing-file' not found in input path",
3676 str(e.exception))
3677
Simon Glass5d94cc62020-07-09 18:39:38 -06003678 def testExtblobMissingOk(self):
3679 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003680 with test_util.capture_sys_output() as (stdout, stderr):
3681 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3682 err = stderr.getvalue()
3683 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3684
3685 def testExtblobMissingOkSect(self):
3686 """Test an image with an missing external blob that is allowed"""
3687 with test_util.capture_sys_output() as (stdout, stderr):
3688 self._DoTestFile('159_blob_ext_missing_sect.dts',
3689 allow_missing=True)
3690 err = stderr.getvalue()
3691 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3692 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003693
Simon Glasse88cef92020-07-09 18:39:41 -06003694 def testPackX86RomMeMissingDesc(self):
3695 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003696 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003697 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003698 err = stderr.getvalue()
3699 self.assertRegex(err,
3700 "Image 'main-section'.*missing.*: intel-descriptor")
3701
3702 def testPackX86RomMissingIfwi(self):
3703 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3704 self._SetupIfwi('fitimage.bin')
3705 pathname = os.path.join(self._indir, 'fitimage.bin')
3706 os.remove(pathname)
3707 with test_util.capture_sys_output() as (stdout, stderr):
3708 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3709 err = stderr.getvalue()
3710 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3711
Simon Glassd70829a2020-07-09 18:39:42 -06003712 def testPackOverlap(self):
3713 """Test that zero-size overlapping regions are ignored"""
3714 self._DoTestFile('160_pack_overlap_zero.dts')
3715
Simon Glass45d556d2020-07-09 18:39:45 -06003716 def testSimpleFit(self):
3717 """Test an image with a FIT inside"""
3718 data = self._DoReadFile('161_fit.dts')
3719 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3720 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3721 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3722
3723 # The data should be inside the FIT
3724 dtb = fdt.Fdt.FromData(fit_data)
3725 dtb.Scan()
3726 fnode = dtb.GetNode('/images/kernel')
3727 self.assertIn('data', fnode.props)
3728
3729 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003730 tools.write_file(fname, fit_data)
3731 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003732
3733 # Check a few features to make sure the plumbing works. We don't need
3734 # to test the operation of mkimage or dumpimage here. First convert the
3735 # output into a dict where the keys are the fields printed by dumpimage
3736 # and the values are a list of values for each field
3737 lines = out.splitlines()
3738
3739 # Converts "Compression: gzip compressed" into two groups:
3740 # 'Compression' and 'gzip compressed'
3741 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3742 vals = collections.defaultdict(list)
3743 for line in lines:
3744 mat = re_line.match(line)
3745 vals[mat.group(1)].append(mat.group(2))
3746
3747 self.assertEquals('FIT description: test-desc', lines[0])
3748 self.assertIn('Created:', lines[1])
3749 self.assertIn('Image 0 (kernel)', vals)
3750 self.assertIn('Hash value', vals)
3751 data_sizes = vals.get('Data Size')
3752 self.assertIsNotNone(data_sizes)
3753 self.assertEqual(2, len(data_sizes))
3754 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
3755 self.assertEqual(len(U_BOOT_DATA), int(data_sizes[0].split()[0]))
3756 self.assertEqual(len(U_BOOT_SPL_DTB_DATA), int(data_sizes[1].split()[0]))
3757
3758 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003759 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003760 data = self._DoReadFile('162_fit_external.dts')
3761 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3762
Simon Glass7932c882022-01-09 20:13:39 -07003763 # Size of the external-data region as set up by mkimage
3764 external_data_size = len(U_BOOT_DATA) + 2
3765 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003766 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003767 len(U_BOOT_NODTB_DATA))
3768
Simon Glass45d556d2020-07-09 18:39:45 -06003769 # The data should be outside the FIT
3770 dtb = fdt.Fdt.FromData(fit_data)
3771 dtb.Scan()
3772 fnode = dtb.GetNode('/images/kernel')
3773 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003774 self.assertEqual(len(U_BOOT_DATA),
3775 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3776 fit_pos = 0x400;
3777 self.assertEqual(
3778 fit_pos,
3779 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3780
3781 self.assertEquals(expected_size, len(data))
3782 actual_pos = len(U_BOOT_DATA) + fit_pos
3783 self.assertEqual(U_BOOT_DATA + b'aa',
3784 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003785
Simon Glass66152ce2022-01-09 20:14:09 -07003786 def testFitMissing(self):
3787 """Test that binman still produces a FIT image if mkimage is missing"""
3788 with test_util.capture_sys_output() as (_, stderr):
3789 self._DoTestFile('162_fit_external.dts',
3790 force_missing_bintools='mkimage')
3791 err = stderr.getvalue()
3792 self.assertRegex(err,
3793 "Image 'main-section'.*missing bintools.*: mkimage")
3794
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003795 def testSectionIgnoreHashSignature(self):
3796 """Test that sections ignore hash, signature nodes for its data"""
3797 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3798 expected = (U_BOOT_DATA + U_BOOT_DATA)
3799 self.assertEqual(expected, data)
3800
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003801 def testPadInSections(self):
3802 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06003803 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3804 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07003805 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
3806 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003807 U_BOOT_DATA)
3808 self.assertEqual(expected, data)
3809
Simon Glassd12599d2020-10-26 17:40:09 -06003810 dtb = fdt.Fdt(out_dtb_fname)
3811 dtb.Scan()
3812 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3813 expected = {
3814 'image-pos': 0,
3815 'offset': 0,
3816 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3817
3818 'section:image-pos': 0,
3819 'section:offset': 0,
3820 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3821
3822 'section/before:image-pos': 0,
3823 'section/before:offset': 0,
3824 'section/before:size': len(U_BOOT_DATA),
3825
3826 'section/u-boot:image-pos': 4,
3827 'section/u-boot:offset': 4,
3828 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3829
3830 'section/after:image-pos': 26,
3831 'section/after:offset': 26,
3832 'section/after:size': len(U_BOOT_DATA),
3833 }
3834 self.assertEqual(expected, props)
3835
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003836 def testFitImageSubentryAlignment(self):
3837 """Test relative alignability of FIT image subentries"""
3838 entry_args = {
3839 'test-id': TEXT_DATA,
3840 }
3841 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3842 entry_args=entry_args)
3843 dtb = fdt.Fdt.FromData(data)
3844 dtb.Scan()
3845
3846 node = dtb.GetNode('/images/kernel')
3847 data = dtb.GetProps(node)["data"].bytes
3848 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07003849 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
3850 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003851 self.assertEqual(expected, data)
3852
3853 node = dtb.GetNode('/images/fdt-1')
3854 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07003855 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
3856 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003857 U_BOOT_DTB_DATA)
3858 self.assertEqual(expected, data)
3859
3860 def testFitExtblobMissingOk(self):
3861 """Test a FIT with a missing external blob that is allowed"""
3862 with test_util.capture_sys_output() as (stdout, stderr):
3863 self._DoTestFile('168_fit_missing_blob.dts',
3864 allow_missing=True)
3865 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06003866 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003867
Simon Glass21db0ff2020-09-01 05:13:54 -06003868 def testBlobNamedByArgMissing(self):
3869 """Test handling of a missing entry arg"""
3870 with self.assertRaises(ValueError) as e:
3871 self._DoReadFile('068_blob_named_by_arg.dts')
3872 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
3873 str(e.exception))
3874
Simon Glass559c4de2020-09-01 05:13:58 -06003875 def testPackBl31(self):
3876 """Test that an image with an ATF BL31 binary can be created"""
3877 data = self._DoReadFile('169_atf_bl31.dts')
3878 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
3879
Samuel Holland9d8cc632020-10-21 21:12:15 -05003880 def testPackScp(self):
3881 """Test that an image with an SCP binary can be created"""
3882 data = self._DoReadFile('172_scp.dts')
3883 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
3884
Simon Glassa435cd12020-09-01 05:13:59 -06003885 def testFitFdt(self):
3886 """Test an image with an FIT with multiple FDT images"""
3887 def _CheckFdt(seq, expected_data):
3888 """Check the FDT nodes
3889
3890 Args:
3891 seq: Sequence number to check (0 or 1)
3892 expected_data: Expected contents of 'data' property
3893 """
3894 name = 'fdt-%d' % seq
3895 fnode = dtb.GetNode('/images/%s' % name)
3896 self.assertIsNotNone(fnode)
3897 self.assertEqual({'description','type', 'compression', 'data'},
3898 set(fnode.props.keys()))
3899 self.assertEqual(expected_data, fnode.props['data'].bytes)
3900 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
3901 fnode.props['description'].value)
3902
3903 def _CheckConfig(seq, expected_data):
3904 """Check the configuration nodes
3905
3906 Args:
3907 seq: Sequence number to check (0 or 1)
3908 expected_data: Expected contents of 'data' property
3909 """
3910 cnode = dtb.GetNode('/configurations')
3911 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06003912 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06003913
3914 name = 'config-%d' % seq
3915 fnode = dtb.GetNode('/configurations/%s' % name)
3916 self.assertIsNotNone(fnode)
3917 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
3918 set(fnode.props.keys()))
3919 self.assertEqual('conf-test-fdt%d.dtb' % seq,
3920 fnode.props['description'].value)
3921 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
3922
3923 entry_args = {
3924 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06003925 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06003926 }
3927 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08003928 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06003929 entry_args=entry_args,
3930 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3931 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3932 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3933
3934 dtb = fdt.Fdt.FromData(fit_data)
3935 dtb.Scan()
3936 fnode = dtb.GetNode('/images/kernel')
3937 self.assertIn('data', fnode.props)
3938
3939 # Check all the properties in fdt-1 and fdt-2
3940 _CheckFdt(1, TEST_FDT1_DATA)
3941 _CheckFdt(2, TEST_FDT2_DATA)
3942
3943 # Check configurations
3944 _CheckConfig(1, TEST_FDT1_DATA)
3945 _CheckConfig(2, TEST_FDT2_DATA)
3946
3947 def testFitFdtMissingList(self):
3948 """Test handling of a missing 'of-list' entry arg"""
3949 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08003950 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06003951 self.assertIn("Generator node requires 'of-list' entry argument",
3952 str(e.exception))
3953
3954 def testFitFdtEmptyList(self):
3955 """Test handling of an empty 'of-list' entry arg"""
3956 entry_args = {
3957 'of-list': '',
3958 }
3959 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
3960
3961 def testFitFdtMissingProp(self):
3962 """Test handling of a missing 'fit,fdt-list' property"""
3963 with self.assertRaises(ValueError) as e:
3964 self._DoReadFile('171_fit_fdt_missing_prop.dts')
3965 self.assertIn("Generator node requires 'fit,fdt-list' property",
3966 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06003967
Simon Glass1032acc2020-09-06 10:39:08 -06003968 def testFitFdtEmptyList(self):
3969 """Test handling of an empty 'of-list' entry arg"""
3970 entry_args = {
3971 'of-list': '',
3972 }
Bin Meng16cf5662021-05-10 20:23:32 +08003973 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
Simon Glass1032acc2020-09-06 10:39:08 -06003974
3975 def testFitFdtMissing(self):
3976 """Test handling of a missing 'default-dt' entry arg"""
3977 entry_args = {
3978 'of-list': 'test-fdt1 test-fdt2',
3979 }
3980 with self.assertRaises(ValueError) as e:
3981 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08003982 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06003983 entry_args=entry_args,
3984 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3985 self.assertIn("Generated 'default' node requires default-dt entry argument",
3986 str(e.exception))
3987
3988 def testFitFdtNotInList(self):
3989 """Test handling of a default-dt that is not in the of-list"""
3990 entry_args = {
3991 'of-list': 'test-fdt1 test-fdt2',
3992 'default-dt': 'test-fdt3',
3993 }
3994 with self.assertRaises(ValueError) as e:
3995 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08003996 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06003997 entry_args=entry_args,
3998 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
3999 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4000 str(e.exception))
4001
Simon Glassa820af72020-09-06 10:39:09 -06004002 def testFitExtblobMissingHelp(self):
4003 """Test display of help messages when an external blob is missing"""
4004 control.missing_blob_help = control._ReadMissingBlobHelp()
4005 control.missing_blob_help['wibble'] = 'Wibble test'
4006 control.missing_blob_help['another'] = 'Another test'
4007 with test_util.capture_sys_output() as (stdout, stderr):
4008 self._DoTestFile('168_fit_missing_blob.dts',
4009 allow_missing=True)
4010 err = stderr.getvalue()
4011
4012 # We can get the tag from the name, the type or the missing-msg
4013 # property. Check all three.
4014 self.assertIn('You may need to build ARM Trusted', err)
4015 self.assertIn('Wibble test', err)
4016 self.assertIn('Another test', err)
4017
Simon Glass6f1f4d42020-09-06 10:35:32 -06004018 def testMissingBlob(self):
4019 """Test handling of a blob containing a missing file"""
4020 with self.assertRaises(ValueError) as e:
4021 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4022 self.assertIn("Filename 'missing' not found in input path",
4023 str(e.exception))
4024
Simon Glassa0729502020-09-06 10:35:33 -06004025 def testEnvironment(self):
4026 """Test adding a U-Boot environment"""
4027 data = self._DoReadFile('174_env.dts')
4028 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4029 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4030 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4031 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4032 env)
4033
4034 def testEnvironmentNoSize(self):
4035 """Test that a missing 'size' property is detected"""
4036 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004037 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004038 self.assertIn("'u-boot-env' entry must have a size property",
4039 str(e.exception))
4040
4041 def testEnvironmentTooSmall(self):
4042 """Test handling of an environment that does not fit"""
4043 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004044 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004045
4046 # checksum, start byte, environment with \0 terminator, final \0
4047 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4048 short = need - 0x8
4049 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4050 str(e.exception))
4051
Simon Glassd1fdf752020-10-26 17:40:01 -06004052 def testSkipAtStart(self):
4053 """Test handling of skip-at-start section"""
4054 data = self._DoReadFile('177_skip_at_start.dts')
4055 self.assertEqual(U_BOOT_DATA, data)
4056
4057 image = control.images['image']
4058 entries = image.GetEntries()
4059 section = entries['section']
4060 self.assertEqual(0, section.offset)
4061 self.assertEqual(len(U_BOOT_DATA), section.size)
4062 self.assertEqual(U_BOOT_DATA, section.GetData())
4063
4064 entry = section.GetEntries()['u-boot']
4065 self.assertEqual(16, entry.offset)
4066 self.assertEqual(len(U_BOOT_DATA), entry.size)
4067 self.assertEqual(U_BOOT_DATA, entry.data)
4068
4069 def testSkipAtStartPad(self):
4070 """Test handling of skip-at-start section with padded entry"""
4071 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004072 before = tools.get_bytes(0, 8)
4073 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004074 all = before + U_BOOT_DATA + after
4075 self.assertEqual(all, data)
4076
4077 image = control.images['image']
4078 entries = image.GetEntries()
4079 section = entries['section']
4080 self.assertEqual(0, section.offset)
4081 self.assertEqual(len(all), section.size)
4082 self.assertEqual(all, section.GetData())
4083
4084 entry = section.GetEntries()['u-boot']
4085 self.assertEqual(16, entry.offset)
4086 self.assertEqual(len(all), entry.size)
4087 self.assertEqual(U_BOOT_DATA, entry.data)
4088
4089 def testSkipAtStartSectionPad(self):
4090 """Test handling of skip-at-start section with padding"""
4091 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004092 before = tools.get_bytes(0, 8)
4093 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004094 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004095 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004096
4097 image = control.images['image']
4098 entries = image.GetEntries()
4099 section = entries['section']
4100 self.assertEqual(0, section.offset)
4101 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004102 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004103 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004104
4105 entry = section.GetEntries()['u-boot']
4106 self.assertEqual(16, entry.offset)
4107 self.assertEqual(len(U_BOOT_DATA), entry.size)
4108 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004109
Simon Glassbb395742020-10-26 17:40:14 -06004110 def testSectionPad(self):
4111 """Testing padding with sections"""
4112 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004113 expected = (tools.get_bytes(ord('&'), 3) +
4114 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004115 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004116 tools.get_bytes(ord('!'), 1) +
4117 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004118 self.assertEqual(expected, data)
4119
4120 def testSectionAlign(self):
4121 """Testing alignment with sections"""
4122 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4123 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004124 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004125 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004126 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004127 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004128 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4129 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004130 self.assertEqual(expected, data)
4131
Simon Glassd92c8362020-10-26 17:40:25 -06004132 def testCompressImage(self):
4133 """Test compression of the entire image"""
4134 self._CheckLz4()
4135 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4136 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4137 dtb = fdt.Fdt(out_dtb_fname)
4138 dtb.Scan()
4139 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4140 'uncomp-size'])
4141 orig = self._decompress(data)
4142 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4143
4144 # Do a sanity check on various fields
4145 image = control.images['image']
4146 entries = image.GetEntries()
4147 self.assertEqual(2, len(entries))
4148
4149 entry = entries['blob']
4150 self.assertEqual(COMPRESS_DATA, entry.data)
4151 self.assertEqual(len(COMPRESS_DATA), entry.size)
4152
4153 entry = entries['u-boot']
4154 self.assertEqual(U_BOOT_DATA, entry.data)
4155 self.assertEqual(len(U_BOOT_DATA), entry.size)
4156
4157 self.assertEqual(len(data), image.size)
4158 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4159 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4160 orig = self._decompress(image.data)
4161 self.assertEqual(orig, image.uncomp_data)
4162
4163 expected = {
4164 'blob:offset': 0,
4165 'blob:size': len(COMPRESS_DATA),
4166 'u-boot:offset': len(COMPRESS_DATA),
4167 'u-boot:size': len(U_BOOT_DATA),
4168 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4169 'offset': 0,
4170 'image-pos': 0,
4171 'size': len(data),
4172 }
4173 self.assertEqual(expected, props)
4174
4175 def testCompressImageLess(self):
4176 """Test compression where compression reduces the image size"""
4177 self._CheckLz4()
4178 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4179 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4180 dtb = fdt.Fdt(out_dtb_fname)
4181 dtb.Scan()
4182 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4183 'uncomp-size'])
4184 orig = self._decompress(data)
4185
4186 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4187
4188 # Do a sanity check on various fields
4189 image = control.images['image']
4190 entries = image.GetEntries()
4191 self.assertEqual(2, len(entries))
4192
4193 entry = entries['blob']
4194 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4195 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4196
4197 entry = entries['u-boot']
4198 self.assertEqual(U_BOOT_DATA, entry.data)
4199 self.assertEqual(len(U_BOOT_DATA), entry.size)
4200
4201 self.assertEqual(len(data), image.size)
4202 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4203 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4204 image.uncomp_size)
4205 orig = self._decompress(image.data)
4206 self.assertEqual(orig, image.uncomp_data)
4207
4208 expected = {
4209 'blob:offset': 0,
4210 'blob:size': len(COMPRESS_DATA_BIG),
4211 'u-boot:offset': len(COMPRESS_DATA_BIG),
4212 'u-boot:size': len(U_BOOT_DATA),
4213 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4214 'offset': 0,
4215 'image-pos': 0,
4216 'size': len(data),
4217 }
4218 self.assertEqual(expected, props)
4219
4220 def testCompressSectionSize(self):
4221 """Test compression of a section with a fixed size"""
4222 self._CheckLz4()
4223 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4224 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4225 dtb = fdt.Fdt(out_dtb_fname)
4226 dtb.Scan()
4227 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4228 'uncomp-size'])
4229 orig = self._decompress(data)
4230 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4231 expected = {
4232 'section/blob:offset': 0,
4233 'section/blob:size': len(COMPRESS_DATA),
4234 'section/u-boot:offset': len(COMPRESS_DATA),
4235 'section/u-boot:size': len(U_BOOT_DATA),
4236 'section:offset': 0,
4237 'section:image-pos': 0,
4238 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4239 'section:size': 0x30,
4240 'offset': 0,
4241 'image-pos': 0,
4242 'size': 0x30,
4243 }
4244 self.assertEqual(expected, props)
4245
4246 def testCompressSection(self):
4247 """Test compression of a section with no fixed size"""
4248 self._CheckLz4()
4249 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4250 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4251 dtb = fdt.Fdt(out_dtb_fname)
4252 dtb.Scan()
4253 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4254 'uncomp-size'])
4255 orig = self._decompress(data)
4256 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4257 expected = {
4258 'section/blob:offset': 0,
4259 'section/blob:size': len(COMPRESS_DATA),
4260 'section/u-boot:offset': len(COMPRESS_DATA),
4261 'section/u-boot:size': len(U_BOOT_DATA),
4262 'section:offset': 0,
4263 'section:image-pos': 0,
4264 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4265 'section:size': len(data),
4266 'offset': 0,
4267 'image-pos': 0,
4268 'size': len(data),
4269 }
4270 self.assertEqual(expected, props)
4271
4272 def testCompressExtra(self):
4273 """Test compression of a section with no fixed size"""
4274 self._CheckLz4()
4275 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4276 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4277 dtb = fdt.Fdt(out_dtb_fname)
4278 dtb.Scan()
4279 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4280 'uncomp-size'])
4281
4282 base = data[len(U_BOOT_DATA):]
4283 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4284 rest = base[len(U_BOOT_DATA):]
4285
4286 # Check compressed data
4287 section1 = self._decompress(rest)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07004288 expect1 = comp_util.compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
Simon Glassd92c8362020-10-26 17:40:25 -06004289 self.assertEquals(expect1, rest[:len(expect1)])
4290 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4291 rest1 = rest[len(expect1):]
4292
4293 section2 = self._decompress(rest1)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07004294 expect2 = comp_util.compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
Simon Glassd92c8362020-10-26 17:40:25 -06004295 self.assertEquals(expect2, rest1[:len(expect2)])
4296 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4297 rest2 = rest1[len(expect2):]
4298
4299 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4300 len(expect2) + len(U_BOOT_DATA))
4301 #self.assertEquals(expect_size, len(data))
4302
4303 #self.assertEquals(U_BOOT_DATA, rest2)
4304
4305 self.maxDiff = None
4306 expected = {
4307 'u-boot:offset': 0,
4308 'u-boot:image-pos': 0,
4309 'u-boot:size': len(U_BOOT_DATA),
4310
4311 'base:offset': len(U_BOOT_DATA),
4312 'base:image-pos': len(U_BOOT_DATA),
4313 'base:size': len(data) - len(U_BOOT_DATA),
4314 'base/u-boot:offset': 0,
4315 'base/u-boot:image-pos': len(U_BOOT_DATA),
4316 'base/u-boot:size': len(U_BOOT_DATA),
4317 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4318 len(expect2),
4319 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4320 len(expect2),
4321 'base/u-boot2:size': len(U_BOOT_DATA),
4322
4323 'base/section:offset': len(U_BOOT_DATA),
4324 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4325 'base/section:size': len(expect1),
4326 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4327 'base/section/blob:offset': 0,
4328 'base/section/blob:size': len(COMPRESS_DATA),
4329 'base/section/u-boot:offset': len(COMPRESS_DATA),
4330 'base/section/u-boot:size': len(U_BOOT_DATA),
4331
4332 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4333 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4334 'base/section2:size': len(expect2),
4335 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4336 'base/section2/blob:offset': 0,
4337 'base/section2/blob:size': len(COMPRESS_DATA),
4338 'base/section2/blob2:offset': len(COMPRESS_DATA),
4339 'base/section2/blob2:size': len(COMPRESS_DATA),
4340
4341 'offset': 0,
4342 'image-pos': 0,
4343 'size': len(data),
4344 }
4345 self.assertEqual(expected, props)
4346
Simon Glassecbe4732021-01-06 21:35:15 -07004347 def testSymbolsSubsection(self):
4348 """Test binman can assign symbols from a subsection"""
Simon Glass31e04cb2021-03-18 20:24:56 +13004349 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x18)
Simon Glassecbe4732021-01-06 21:35:15 -07004350
Simon Glass3fb25402021-01-06 21:35:16 -07004351 def testReadImageEntryArg(self):
4352 """Test reading an image that would need an entry arg to generate"""
4353 entry_args = {
4354 'cros-ec-rw-path': 'ecrw.bin',
4355 }
4356 data = self.data = self._DoReadFileDtb(
4357 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4358 entry_args=entry_args)
4359
Simon Glass80025522022-01-29 14:14:04 -07004360 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004361 orig_image = control.images['image']
4362
4363 # This should not generate an error about the missing 'cros-ec-rw-path'
4364 # since we are reading the image from a file. Compare with
4365 # testEntryArgsRequired()
4366 image = Image.FromFile(image_fname)
4367 self.assertEqual(orig_image.GetEntries().keys(),
4368 image.GetEntries().keys())
4369
Simon Glassa2af7302021-01-06 21:35:18 -07004370 def testFilesAlign(self):
4371 """Test alignment with files"""
4372 data = self._DoReadFile('190_files_align.dts')
4373
4374 # The first string is 15 bytes so will align to 16
4375 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4376 self.assertEqual(expect, data)
4377
Simon Glassdb84b562021-01-06 21:35:19 -07004378 def testReadImageSkip(self):
4379 """Test reading an image and accessing its FDT map"""
4380 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004381 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004382 orig_image = control.images['image']
4383 image = Image.FromFile(image_fname)
4384 self.assertEqual(orig_image.GetEntries().keys(),
4385 image.GetEntries().keys())
4386
4387 orig_entry = orig_image.GetEntries()['fdtmap']
4388 entry = image.GetEntries()['fdtmap']
4389 self.assertEqual(orig_entry.offset, entry.offset)
4390 self.assertEqual(orig_entry.size, entry.size)
4391 self.assertEqual(16, entry.image_pos)
4392
4393 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4394
4395 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4396
Simon Glassc98de972021-03-18 20:24:57 +13004397 def testTplNoDtb(self):
4398 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004399 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004400 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4401 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4402 data[:len(U_BOOT_TPL_NODTB_DATA)])
4403
Simon Glass63f41d42021-03-18 20:24:58 +13004404 def testTplBssPad(self):
4405 """Test that we can pad TPL's BSS with zeros"""
4406 # ELF file with a '__bss_size' symbol
4407 self._SetupTplElf()
4408 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004409 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004410 data)
4411
4412 def testTplBssPadMissing(self):
4413 """Test that a missing symbol is detected"""
4414 self._SetupTplElf('u_boot_ucode_ptr')
4415 with self.assertRaises(ValueError) as e:
4416 self._DoReadFile('193_tpl_bss_pad.dts')
4417 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4418 str(e.exception))
4419
Simon Glass718b5292021-03-18 20:25:07 +13004420 def checkDtbSizes(self, data, pad_len, start):
4421 """Check the size arguments in a dtb embedded in an image
4422
4423 Args:
4424 data: The image data
4425 pad_len: Length of the pad section in the image, in bytes
4426 start: Start offset of the devicetree to examine, within the image
4427
4428 Returns:
4429 Size of the devicetree in bytes
4430 """
4431 dtb_data = data[start:]
4432 dtb = fdt.Fdt.FromData(dtb_data)
4433 fdt_size = dtb.GetFdtObj().totalsize()
4434 dtb.Scan()
4435 props = self._GetPropTree(dtb, 'size')
4436 self.assertEqual({
4437 'size': len(data),
4438 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4439 'u-boot-spl/u-boot-spl-dtb:size': 801,
4440 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4441 'u-boot-spl:size': 860,
4442 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4443 'u-boot/u-boot-dtb:size': 781,
4444 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4445 'u-boot:size': 827,
4446 }, props)
4447 return fdt_size
4448
4449 def testExpanded(self):
4450 """Test that an expanded entry type is selected when needed"""
4451 self._SetupSplElf()
4452 self._SetupTplElf()
4453
4454 # SPL has a devicetree, TPL does not
4455 entry_args = {
4456 'spl-dtb': '1',
4457 'spl-bss-pad': 'y',
4458 'tpl-dtb': '',
4459 }
4460 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4461 entry_args=entry_args)
4462 image = control.images['image']
4463 entries = image.GetEntries()
4464 self.assertEqual(3, len(entries))
4465
4466 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4467 self.assertIn('u-boot', entries)
4468 entry = entries['u-boot']
4469 self.assertEqual('u-boot-expanded', entry.etype)
4470 subent = entry.GetEntries()
4471 self.assertEqual(2, len(subent))
4472 self.assertIn('u-boot-nodtb', subent)
4473 self.assertIn('u-boot-dtb', subent)
4474
4475 # Second, u-boot-spl, which should be expanded into three parts
4476 self.assertIn('u-boot-spl', entries)
4477 entry = entries['u-boot-spl']
4478 self.assertEqual('u-boot-spl-expanded', entry.etype)
4479 subent = entry.GetEntries()
4480 self.assertEqual(3, len(subent))
4481 self.assertIn('u-boot-spl-nodtb', subent)
4482 self.assertIn('u-boot-spl-bss-pad', subent)
4483 self.assertIn('u-boot-spl-dtb', subent)
4484
4485 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4486 # devicetree
4487 self.assertIn('u-boot-tpl', entries)
4488 entry = entries['u-boot-tpl']
4489 self.assertEqual('u-boot-tpl', entry.etype)
4490 self.assertEqual(None, entry.GetEntries())
4491
4492 def testExpandedTpl(self):
4493 """Test that an expanded entry type is selected for TPL when needed"""
4494 self._SetupTplElf()
4495
4496 entry_args = {
4497 'tpl-bss-pad': 'y',
4498 'tpl-dtb': 'y',
4499 }
4500 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4501 entry_args=entry_args)
4502 image = control.images['image']
4503 entries = image.GetEntries()
4504 self.assertEqual(1, len(entries))
4505
4506 # We only have u-boot-tpl, which be expanded
4507 self.assertIn('u-boot-tpl', entries)
4508 entry = entries['u-boot-tpl']
4509 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4510 subent = entry.GetEntries()
4511 self.assertEqual(3, len(subent))
4512 self.assertIn('u-boot-tpl-nodtb', subent)
4513 self.assertIn('u-boot-tpl-bss-pad', subent)
4514 self.assertIn('u-boot-tpl-dtb', subent)
4515
4516 def testExpandedNoPad(self):
4517 """Test an expanded entry without BSS pad enabled"""
4518 self._SetupSplElf()
4519 self._SetupTplElf()
4520
4521 # SPL has a devicetree, TPL does not
4522 entry_args = {
4523 'spl-dtb': 'something',
4524 'spl-bss-pad': 'n',
4525 'tpl-dtb': '',
4526 }
4527 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4528 entry_args=entry_args)
4529 image = control.images['image']
4530 entries = image.GetEntries()
4531
4532 # Just check u-boot-spl, which should be expanded into two parts
4533 self.assertIn('u-boot-spl', entries)
4534 entry = entries['u-boot-spl']
4535 self.assertEqual('u-boot-spl-expanded', entry.etype)
4536 subent = entry.GetEntries()
4537 self.assertEqual(2, len(subent))
4538 self.assertIn('u-boot-spl-nodtb', subent)
4539 self.assertIn('u-boot-spl-dtb', subent)
4540
4541 def testExpandedTplNoPad(self):
4542 """Test that an expanded entry type with padding disabled in TPL"""
4543 self._SetupTplElf()
4544
4545 entry_args = {
4546 'tpl-bss-pad': '',
4547 'tpl-dtb': 'y',
4548 }
4549 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4550 entry_args=entry_args)
4551 image = control.images['image']
4552 entries = image.GetEntries()
4553 self.assertEqual(1, len(entries))
4554
4555 # We only have u-boot-tpl, which be expanded
4556 self.assertIn('u-boot-tpl', entries)
4557 entry = entries['u-boot-tpl']
4558 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4559 subent = entry.GetEntries()
4560 self.assertEqual(2, len(subent))
4561 self.assertIn('u-boot-tpl-nodtb', subent)
4562 self.assertIn('u-boot-tpl-dtb', subent)
4563
4564 def testFdtInclude(self):
4565 """Test that an Fdt is update within all binaries"""
4566 self._SetupSplElf()
4567 self._SetupTplElf()
4568
4569 # SPL has a devicetree, TPL does not
4570 self.maxDiff = None
4571 entry_args = {
4572 'spl-dtb': '1',
4573 'spl-bss-pad': 'y',
4574 'tpl-dtb': '',
4575 }
4576 # Build the image. It includes two separate devicetree binaries, each
4577 # with their own contents, but all contain the binman definition.
4578 data = self._DoReadFileDtb(
4579 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4580 update_dtb=True, entry_args=entry_args)[0]
4581 pad_len = 10
4582
4583 # Check the U-Boot dtb
4584 start = len(U_BOOT_NODTB_DATA)
4585 fdt_size = self.checkDtbSizes(data, pad_len, start)
4586
4587 # Now check SPL
4588 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4589 fdt_size = self.checkDtbSizes(data, pad_len, start)
4590
4591 # TPL has no devicetree
4592 start += fdt_size + len(U_BOOT_TPL_DATA)
4593 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004594
Simon Glass7098b7f2021-03-21 18:24:30 +13004595 def testSymbolsExpanded(self):
4596 """Test binman can assign symbols in expanded entries"""
4597 entry_args = {
4598 'spl-dtb': '1',
4599 }
4600 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4601 U_BOOT_SPL_DTB_DATA, 0x38,
4602 entry_args=entry_args, use_expanded=True)
4603
Simon Glasse1915782021-03-21 18:24:31 +13004604 def testCollection(self):
4605 """Test a collection"""
4606 data = self._DoReadFile('198_collection.dts')
4607 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004608 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4609 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004610 data)
4611
Simon Glass27a7f772021-03-21 18:24:32 +13004612 def testCollectionSection(self):
4613 """Test a collection where a section must be built first"""
4614 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004615 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004616 # building the contents, producing an error is anything is still
4617 # missing.
4618 data = self._DoReadFile('199_collection_section.dts')
4619 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004620 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4621 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004622 data)
4623
Simon Glassf427c5f2021-03-21 18:24:33 +13004624 def testAlignDefault(self):
4625 """Test that default alignment works on sections"""
4626 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004627 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004628 U_BOOT_DATA)
4629 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004630 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004631 # No alignment within the nested section
4632 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4633 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004634 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004635 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004636
Bin Mengc0b15742021-05-10 20:23:33 +08004637 def testPackOpenSBI(self):
4638 """Test that an image with an OpenSBI binary can be created"""
4639 data = self._DoReadFile('201_opensbi.dts')
4640 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4641
Simon Glass76f496d2021-07-06 10:36:37 -06004642 def testSectionsSingleThread(self):
4643 """Test sections without multithreading"""
4644 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004645 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4646 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4647 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004648 self.assertEqual(expected, data)
4649
4650 def testThreadTimeout(self):
4651 """Test handling a thread that takes too long"""
4652 with self.assertRaises(ValueError) as e:
4653 self._DoTestFile('202_section_timeout.dts',
4654 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004655 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004656
Simon Glass748a1d42021-07-06 10:36:41 -06004657 def testTiming(self):
4658 """Test output of timing information"""
4659 data = self._DoReadFile('055_sections.dts')
4660 with test_util.capture_sys_output() as (stdout, stderr):
4661 state.TimingShow()
4662 self.assertIn('read:', stdout.getvalue())
4663 self.assertIn('compress:', stdout.getvalue())
4664
Simon Glassadfb8492021-11-03 21:09:18 -06004665 def testUpdateFdtInElf(self):
4666 """Test that we can update the devicetree in an ELF file"""
4667 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4668 outfile = os.path.join(self._indir, 'u-boot.out')
4669 begin_sym = 'dtb_embed_begin'
4670 end_sym = 'dtb_embed_end'
4671 retcode = self._DoTestFile(
4672 '060_fdt_update.dts', update_dtb=True,
4673 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4674 self.assertEqual(0, retcode)
4675
4676 # Check that the output file does in fact contact a dtb with the binman
4677 # definition in the correct place
4678 syms = elf.GetSymbolFileOffset(infile,
4679 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004680 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004681 dtb_data = data[syms['dtb_embed_begin'].offset:
4682 syms['dtb_embed_end'].offset]
4683
4684 dtb = fdt.Fdt.FromData(dtb_data)
4685 dtb.Scan()
4686 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4687 self.assertEqual({
4688 'image-pos': 0,
4689 'offset': 0,
4690 '_testing:offset': 32,
4691 '_testing:size': 2,
4692 '_testing:image-pos': 32,
4693 'section@0/u-boot:offset': 0,
4694 'section@0/u-boot:size': len(U_BOOT_DATA),
4695 'section@0/u-boot:image-pos': 0,
4696 'section@0:offset': 0,
4697 'section@0:size': 16,
4698 'section@0:image-pos': 0,
4699
4700 'section@1/u-boot:offset': 0,
4701 'section@1/u-boot:size': len(U_BOOT_DATA),
4702 'section@1/u-boot:image-pos': 16,
4703 'section@1:offset': 16,
4704 'section@1:size': 16,
4705 'section@1:image-pos': 16,
4706 'size': 40
4707 }, props)
4708
4709 def testUpdateFdtInElfInvalid(self):
4710 """Test that invalid args are detected with --update-fdt-in-elf"""
4711 with self.assertRaises(ValueError) as e:
4712 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4713 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4714 str(e.exception))
4715
4716 def testUpdateFdtInElfNoSyms(self):
4717 """Test that missing symbols are detected with --update-fdt-in-elf"""
4718 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4719 outfile = ''
4720 begin_sym = 'wrong_begin'
4721 end_sym = 'wrong_end'
4722 with self.assertRaises(ValueError) as e:
4723 self._DoTestFile(
4724 '060_fdt_update.dts',
4725 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4726 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4727 str(e.exception))
4728
4729 def testUpdateFdtInElfTooSmall(self):
4730 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
4731 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4732 outfile = os.path.join(self._indir, 'u-boot.out')
4733 begin_sym = 'dtb_embed_begin'
4734 end_sym = 'dtb_embed_end'
4735 with self.assertRaises(ValueError) as e:
4736 self._DoTestFile(
4737 '060_fdt_update.dts', update_dtb=True,
4738 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4739 self.assertRegex(
4740 str(e.exception),
4741 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4742
Simon Glass88e04da2021-11-23 11:03:42 -07004743 def testVersion(self):
4744 """Test we can get the binman version"""
4745 version = '(unreleased)'
4746 self.assertEqual(version, state.GetVersion(self._indir))
4747
4748 with self.assertRaises(SystemExit):
4749 with test_util.capture_sys_output() as (_, stderr):
4750 self._DoBinman('-V')
4751 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4752
4753 # Try running the tool too, just to be safe
4754 result = self._RunBinman('-V')
4755 self.assertEqual('Binman %s\n' % version, result.stderr)
4756
4757 # Set up a version file to make sure that works
4758 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07004759 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07004760 binary=False)
4761 self.assertEqual(version, state.GetVersion(self._indir))
4762
Simon Glass637958f2021-11-23 21:09:50 -07004763 def testAltFormat(self):
4764 """Test that alternative formats can be used to extract"""
4765 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4766
4767 try:
4768 tmpdir, updated_fname = self._SetupImageInTmpdir()
4769 with test_util.capture_sys_output() as (stdout, _):
4770 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4771 self.assertEqual(
4772 '''Flag (-F) Entry type Description
4773fdt fdtmap Extract the devicetree blob from the fdtmap
4774''',
4775 stdout.getvalue())
4776
4777 dtb = os.path.join(tmpdir, 'fdt.dtb')
4778 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4779 dtb, 'fdtmap')
4780
4781 # Check that we can read it and it can be scanning, meaning it does
4782 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07004783 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07004784 dtb = fdt.Fdt.FromData(data)
4785 dtb.Scan()
4786
4787 # Now check u-boot which has no alt_format
4788 fname = os.path.join(tmpdir, 'fdt.dtb')
4789 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4790 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07004791 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07004792 self.assertEqual(U_BOOT_DATA, data)
4793
4794 finally:
4795 shutil.rmtree(tmpdir)
4796
Simon Glass0b00ae62021-11-23 21:09:52 -07004797 def testExtblobList(self):
4798 """Test an image with an external blob list"""
4799 data = self._DoReadFile('215_blob_ext_list.dts')
4800 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4801
4802 def testExtblobListMissing(self):
4803 """Test an image with a missing external blob"""
4804 with self.assertRaises(ValueError) as e:
4805 self._DoReadFile('216_blob_ext_list_missing.dts')
4806 self.assertIn("Filename 'missing-file' not found in input path",
4807 str(e.exception))
4808
4809 def testExtblobListMissingOk(self):
4810 """Test an image with an missing external blob that is allowed"""
4811 with test_util.capture_sys_output() as (stdout, stderr):
4812 self._DoTestFile('216_blob_ext_list_missing.dts',
4813 allow_missing=True)
4814 err = stderr.getvalue()
4815 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4816
Simon Glass3efb2972021-11-23 21:08:59 -07004817 def testFip(self):
4818 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4819 data = self._DoReadFile('203_fip.dts')
4820 hdr, fents = fip_util.decode_fip(data)
4821 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4822 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4823 self.assertEqual(0x123, hdr.flags)
4824
4825 self.assertEqual(2, len(fents))
4826
4827 fent = fents[0]
4828 self.assertEqual(
4829 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4830 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4831 self.assertEqual('soc-fw', fent.fip_type)
4832 self.assertEqual(0x88, fent.offset)
4833 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4834 self.assertEqual(0x123456789abcdef, fent.flags)
4835 self.assertEqual(ATF_BL31_DATA, fent.data)
4836 self.assertEqual(True, fent.valid)
4837
4838 fent = fents[1]
4839 self.assertEqual(
4840 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4841 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4842 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4843 self.assertEqual(0x8c, fent.offset)
4844 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4845 self.assertEqual(0, fent.flags)
4846 self.assertEqual(ATF_BL2U_DATA, fent.data)
4847 self.assertEqual(True, fent.valid)
4848
4849 def testFipOther(self):
4850 """Basic FIP with something that isn't a external blob"""
4851 data = self._DoReadFile('204_fip_other.dts')
4852 hdr, fents = fip_util.decode_fip(data)
4853
4854 self.assertEqual(2, len(fents))
4855 fent = fents[1]
4856 self.assertEqual('rot-cert', fent.fip_type)
4857 self.assertEqual(b'aa', fent.data)
4858
4859 def testFipOther(self):
4860 """Basic FIP with something that isn't a external blob"""
4861 data = self._DoReadFile('204_fip_other.dts')
4862 hdr, fents = fip_util.decode_fip(data)
4863
4864 self.assertEqual(2, len(fents))
4865 fent = fents[1]
4866 self.assertEqual('rot-cert', fent.fip_type)
4867 self.assertEqual(b'aa', fent.data)
4868
4869 def testFipNoType(self):
4870 """FIP with an entry of an unknown type"""
4871 with self.assertRaises(ValueError) as e:
4872 self._DoReadFile('205_fip_no_type.dts')
4873 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
4874 str(e.exception))
4875
4876 def testFipUuid(self):
4877 """Basic FIP with a manual uuid"""
4878 data = self._DoReadFile('206_fip_uuid.dts')
4879 hdr, fents = fip_util.decode_fip(data)
4880
4881 self.assertEqual(2, len(fents))
4882 fent = fents[1]
4883 self.assertEqual(None, fent.fip_type)
4884 self.assertEqual(
4885 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
4886 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
4887 fent.uuid)
4888 self.assertEqual(U_BOOT_DATA, fent.data)
4889
4890 def testFipLs(self):
4891 """Test listing a FIP"""
4892 data = self._DoReadFileRealDtb('207_fip_ls.dts')
4893 hdr, fents = fip_util.decode_fip(data)
4894
4895 try:
4896 tmpdir, updated_fname = self._SetupImageInTmpdir()
4897 with test_util.capture_sys_output() as (stdout, stderr):
4898 self._DoBinman('ls', '-i', updated_fname)
4899 finally:
4900 shutil.rmtree(tmpdir)
4901 lines = stdout.getvalue().splitlines()
4902 expected = [
4903'Name Image-pos Size Entry-type Offset Uncomp-size',
4904'----------------------------------------------------------------',
4905'main-section 0 2d3 section 0',
4906' atf-fip 0 90 atf-fip 0',
4907' soc-fw 88 4 blob-ext 88',
4908' u-boot 8c 4 u-boot 8c',
4909' fdtmap 90 243 fdtmap 90',
4910]
4911 self.assertEqual(expected, lines)
4912
4913 image = control.images['image']
4914 entries = image.GetEntries()
4915 fdtmap = entries['fdtmap']
4916
4917 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
4918 magic = fdtmap_data[:8]
4919 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07004920 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07004921
4922 fdt_data = fdtmap_data[16:]
4923 dtb = fdt.Fdt.FromData(fdt_data)
4924 dtb.Scan()
4925 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
4926 self.assertEqual({
4927 'atf-fip/soc-fw:image-pos': 136,
4928 'atf-fip/soc-fw:offset': 136,
4929 'atf-fip/soc-fw:size': 4,
4930 'atf-fip/u-boot:image-pos': 140,
4931 'atf-fip/u-boot:offset': 140,
4932 'atf-fip/u-boot:size': 4,
4933 'atf-fip:image-pos': 0,
4934 'atf-fip:offset': 0,
4935 'atf-fip:size': 144,
4936 'image-pos': 0,
4937 'offset': 0,
4938 'fdtmap:image-pos': fdtmap.image_pos,
4939 'fdtmap:offset': fdtmap.offset,
4940 'fdtmap:size': len(fdtmap_data),
4941 'size': len(data),
4942 }, props)
4943
4944 def testFipExtractOneEntry(self):
4945 """Test extracting a single entry fron an FIP"""
4946 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07004947 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07004948 fname = os.path.join(self._indir, 'output.extact')
4949 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07004950 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07004951 self.assertEqual(U_BOOT_DATA, data)
4952
4953 def testFipReplace(self):
4954 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07004955 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07004956 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07004957 updated_fname = tools.get_output_filename('image-updated.bin')
4958 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07004959 entry_name = 'atf-fip/u-boot'
4960 control.WriteEntry(updated_fname, entry_name, expected,
4961 allow_resize=True)
4962 actual = control.ReadEntry(updated_fname, entry_name)
4963 self.assertEqual(expected, actual)
4964
Simon Glass80025522022-01-29 14:14:04 -07004965 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07004966 hdr, fents = fip_util.decode_fip(new_data)
4967
4968 self.assertEqual(2, len(fents))
4969
4970 # Check that the FIP entry is updated
4971 fent = fents[1]
4972 self.assertEqual(0x8c, fent.offset)
4973 self.assertEqual(len(expected), fent.size)
4974 self.assertEqual(0, fent.flags)
4975 self.assertEqual(expected, fent.data)
4976 self.assertEqual(True, fent.valid)
4977
4978 def testFipMissing(self):
4979 with test_util.capture_sys_output() as (stdout, stderr):
4980 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
4981 err = stderr.getvalue()
4982 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
4983
4984 def testFipSize(self):
4985 """Test a FIP with a size property"""
4986 data = self._DoReadFile('210_fip_size.dts')
4987 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
4988 hdr, fents = fip_util.decode_fip(data)
4989 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4990 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4991
4992 self.assertEqual(1, len(fents))
4993
4994 fent = fents[0]
4995 self.assertEqual('soc-fw', fent.fip_type)
4996 self.assertEqual(0x60, fent.offset)
4997 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4998 self.assertEqual(ATF_BL31_DATA, fent.data)
4999 self.assertEqual(True, fent.valid)
5000
5001 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005002 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005003
5004 def testFipBadAlign(self):
5005 """Test that an invalid alignment value in a FIP is detected"""
5006 with self.assertRaises(ValueError) as e:
5007 self._DoTestFile('211_fip_bad_align.dts')
5008 self.assertIn(
5009 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5010 str(e.exception))
5011
5012 def testFipCollection(self):
5013 """Test using a FIP in a collection"""
5014 data = self._DoReadFile('212_fip_collection.dts')
5015 entry1 = control.images['image'].GetEntries()['collection']
5016 data1 = data[:entry1.size]
5017 hdr1, fents2 = fip_util.decode_fip(data1)
5018
5019 entry2 = control.images['image'].GetEntries()['atf-fip']
5020 data2 = data[entry2.offset:entry2.offset + entry2.size]
5021 hdr1, fents2 = fip_util.decode_fip(data2)
5022
5023 # The 'collection' entry should have U-Boot included at the end
5024 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5025 self.assertEqual(data1, data2 + U_BOOT_DATA)
5026 self.assertEqual(U_BOOT_DATA, data1[-4:])
5027
5028 # There should be a U-Boot after the final FIP
5029 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005030
Simon Glassccae6862022-01-12 13:10:35 -07005031 def testFakeBlob(self):
5032 """Test handling of faking an external blob"""
5033 with test_util.capture_sys_output() as (stdout, stderr):
5034 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5035 allow_fake_blobs=True)
5036 err = stderr.getvalue()
5037 self.assertRegex(
5038 err,
5039 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005040
Simon Glassceb5f912022-01-09 20:13:46 -07005041 def testExtblobListFaked(self):
5042 """Test an extblob with missing external blob that are faked"""
5043 with test_util.capture_sys_output() as (stdout, stderr):
5044 self._DoTestFile('216_blob_ext_list_missing.dts',
5045 allow_fake_blobs=True)
5046 err = stderr.getvalue()
5047 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
5048
Simon Glass162017b2022-01-09 20:13:57 -07005049 def testListBintools(self):
5050 args = ['tool', '--list']
5051 with test_util.capture_sys_output() as (stdout, _):
5052 self._DoBinman(*args)
5053 out = stdout.getvalue().splitlines()
5054 self.assertTrue(len(out) >= 2)
5055
5056 def testFetchBintools(self):
5057 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005058 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005059 raise urllib.error.URLError('my error')
5060
5061 args = ['tool']
5062 with self.assertRaises(ValueError) as e:
5063 self._DoBinman(*args)
5064 self.assertIn("Invalid arguments to 'tool' subcommand",
5065 str(e.exception))
5066
5067 args = ['tool', '--fetch']
5068 with self.assertRaises(ValueError) as e:
5069 self._DoBinman(*args)
5070 self.assertIn('Please specify bintools to fetch', str(e.exception))
5071
5072 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005073 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005074 side_effect=fail_download):
5075 with test_util.capture_sys_output() as (stdout, _):
5076 self._DoBinman(*args)
5077 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5078
Simon Glassdab7c142022-01-09 20:14:10 -07005079 def testInvalidCompress(self):
5080 with self.assertRaises(ValueError) as e:
5081 comp_util.compress(b'', 'invalid')
5082 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5083
5084 with self.assertRaises(ValueError) as e:
5085 comp_util.decompress(b'1234', 'invalid')
5086 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5087
Simon Glass620c4462022-01-09 20:14:11 -07005088 def testBintoolDocs(self):
5089 """Test for creation of bintool documentation"""
5090 with test_util.capture_sys_output() as (stdout, stderr):
5091 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5092 self.assertTrue(len(stdout.getvalue()) > 0)
5093
5094 def testBintoolDocsMissing(self):
5095 """Test handling of missing bintool documentation"""
5096 with self.assertRaises(ValueError) as e:
5097 with test_util.capture_sys_output() as (stdout, stderr):
5098 control.write_bintool_docs(
5099 control.bintool.Bintool.get_tool_list(), 'mkimage')
5100 self.assertIn('Documentation is missing for modules: mkimage',
5101 str(e.exception))
5102
Jan Kiszka58c407f2022-01-28 20:37:53 +01005103 def testListWithGenNode(self):
5104 """Check handling of an FDT map when the section cannot be found"""
5105 entry_args = {
5106 'of-list': 'test-fdt1 test-fdt2',
5107 }
5108 data = self._DoReadFileDtb(
5109 '219_fit_gennode.dts',
5110 entry_args=entry_args,
5111 use_real_dtb=True,
5112 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5113
5114 try:
5115 tmpdir, updated_fname = self._SetupImageInTmpdir()
5116 with test_util.capture_sys_output() as (stdout, stderr):
5117 self._RunBinman('ls', '-i', updated_fname)
5118 finally:
5119 shutil.rmtree(tmpdir)
5120
Simon Glassccae6862022-01-12 13:10:35 -07005121
Simon Glassac599912017-11-12 21:52:22 -07005122if __name__ == "__main__":
5123 unittest.main()