blob: 5a3226e3cb08cbcef065311be07d6d43b9b246cf [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
26from binman import control
27from binman import elf
28from binman import elf_test
Simon Glass3efb2972021-11-23 21:08:59 -070029from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060030from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060031from binman import state
32from dtoc import fdt
33from dtoc import fdt_util
34from binman.etype import fdtmap
35from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060036from binman.image import Image
Simon Glass131444f2023-02-23 18:18:04 -070037from u_boot_pylib import command
38from u_boot_pylib import test_util
39from u_boot_pylib import tools
40from u_boot_pylib import tout
Simon Glass57454f42016-11-25 20:15:52 -070041
42# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060043U_BOOT_DATA = b'1234'
44U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +030045U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
46U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass56d05412022-02-28 07:16:54 -070047U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
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'
Simon Glass56d05412022-02-28 07:16:54 -070054U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glass303f62f2019-05-17 22:00:46 -060055X86_START16_DATA = b'start16'
56X86_START16_SPL_DATA = b'start16spl'
57X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060058X86_RESET16_DATA = b'reset16'
59X86_RESET16_SPL_DATA = b'reset16spl'
60X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060061PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
62U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
63U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
64U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass56d05412022-02-28 07:16:54 -070065U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +030066U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
67U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
68U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glass303f62f2019-05-17 22:00:46 -060069FSP_DATA = b'fsp'
70CMC_DATA = b'cmc'
71VBT_DATA = b'vbt'
72MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060073TEXT_DATA = 'text'
74TEXT_DATA2 = 'text2'
75TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060076CROS_EC_RW_DATA = b'ecrw'
77GBB_DATA = b'gbbd'
78BMPBLK_DATA = b'bmp'
79VBLOCK_DATA = b'vblk'
80FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
81 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060082COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060083COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060084REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060085FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060086FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060087FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060088ATF_BL31_DATA = b'bl31'
Roger Quadros5cdcea02022-02-19 20:50:04 +020089TEE_OS_DATA = b'this is some tee OS data'
Simon Glass3efb2972021-11-23 21:08:59 -070090ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080091OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050092SCP_DATA = b'scp'
Jonas Karlman35305492023-02-25 19:01:33 +000093ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glassa435cd12020-09-01 05:13:59 -060094TEST_FDT1_DATA = b'fdt1'
95TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060096ENV_DATA = b'var1=1\nvar2="2"'
Philippe Reynesebe96cb2022-03-28 22:57:04 +020097PRE_LOAD_MAGIC = b'UBSH'
98PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
99PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530100TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Simon Glassa435cd12020-09-01 05:13:59 -0600101
102# Subdirectory of the input dir to use to put test FDTs
103TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600104
Simon Glass2c6adba2019-07-20 12:23:47 -0600105# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600106EXTRACT_DTB_SIZE = 0x3c9
107
Simon Glass2c6adba2019-07-20 12:23:47 -0600108# Properties expected to be in the device tree when update_dtb is used
109BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
110
Simon Glassfb30e292019-07-20 12:23:51 -0600111# Extra properties expected to be in the device tree when allow-repack is used
112REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
113
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200114# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200115COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700116
Simon Glassad5cfe12023-01-07 14:07:14 -0700117TEE_ADDR = 0x5678
118
Simon Glass57454f42016-11-25 20:15:52 -0700119class TestFunctional(unittest.TestCase):
120 """Functional tests for binman
121
122 Most of these use a sample .dts file to build an image and then check
123 that it looks correct. The sample files are in the test/ subdirectory
124 and are numbered.
125
126 For each entry type a very small test file is created using fixed
127 string contents. This makes it easy to test that things look right, and
128 debug problems.
129
130 In some cases a 'real' file must be used - these are also supplied in
131 the test/ diurectory.
132 """
133 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600134 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700135 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600136 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700137
Simon Glass57454f42016-11-25 20:15:52 -0700138 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600139 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
140 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700141
142 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600143 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700144
145 # Create some test files
146 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
147 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
148 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600149 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700150 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700151 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700152 TestFunctional._MakeInputFile('me.bin', ME_DATA)
153 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600154 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600155
Jagdish Gediya311d4842018-09-03 21:35:08 +0530156 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600157
Simon Glassabab18c2019-08-24 07:22:49 -0600158 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
159 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700160 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600161 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600162 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600163
164 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
165 X86_RESET16_DATA)
166 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
167 X86_RESET16_SPL_DATA)
168 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
169 X86_RESET16_TPL_DATA)
170
Simon Glass57454f42016-11-25 20:15:52 -0700171 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700172 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
173 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600174 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
175 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700176 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
177 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700178 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
179 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700180 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700181 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600182 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600183 TestFunctional._MakeInputDir('devkeys')
184 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600185 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600186 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600187 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600188 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700189
Simon Glassf6290892019-08-24 07:22:53 -0600190 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
191 elf_test.BuildElfTestFiles(cls._elf_testdir)
192
Simon Glass72232452016-11-25 20:15:53 -0700193 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600194 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700195 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700196
197 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600198 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700199
Simon Glass862f8e22019-08-24 07:22:43 -0600200 shutil.copytree(cls.TestFile('files'),
201 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600202
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530203 shutil.copytree(cls.TestFile('yaml'),
204 os.path.join(cls._indir, 'yaml'))
205
Simon Glass7ba33592018-09-14 04:57:26 -0600206 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600207 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600208 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200209 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700210 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800211 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500212 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman35305492023-02-25 19:01:33 +0000213 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600214
Simon Glassa435cd12020-09-01 05:13:59 -0600215 # Add a few .dtb files for testing
216 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
217 TEST_FDT1_DATA)
218 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
219 TEST_FDT2_DATA)
220
Simon Glassa0729502020-09-06 10:35:33 -0600221 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
222
Simon Glass5f423422022-03-05 20:19:12 -0700223 # ELF file with two sections in different parts of memory, used for both
224 # ATF and OP_TEE
225 TestFunctional._MakeInputFile('bl31.elf',
226 tools.read_file(cls.ElfTestFile('elf_sections')))
227 TestFunctional._MakeInputFile('tee.elf',
228 tools.read_file(cls.ElfTestFile('elf_sections')))
229
Simon Glassad5cfe12023-01-07 14:07:14 -0700230 # Newer OP_TEE file in v1 binary format
231 cls.make_tee_bin('tee.bin')
232
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200233 cls.comp_bintools = {}
234 for name in COMP_BINTOOLS:
235 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600236
Simon Glass57454f42016-11-25 20:15:52 -0700237 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600238 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700239 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600240 if cls.preserve_indir:
241 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600242 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600243 if cls._indir:
244 shutil.rmtree(cls._indir)
245 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700246
Simon Glass1c420c92019-07-08 13:18:49 -0600247 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600248 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600249 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600250 """Accept arguments controlling test execution
251
252 Args:
253 preserve_indir: Preserve the shared input directory used by all
254 tests in this class.
255 preserve_outdir: Preserve the output directories used by tests. Each
256 test has its own, so this is normally only useful when running a
257 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600258 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600259 """
260 cls.preserve_indir = preserve_indir
261 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600262 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600263 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600264
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200265 def _CheckBintool(self, bintool):
266 if not bintool.is_present():
267 self.skipTest('%s not available' % bintool.name)
268
Simon Glass1de34482019-07-08 13:18:53 -0600269 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200270 bintool = self.comp_bintools['lz4']
271 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600272
Simon Glassee9d10d2019-07-20 12:24:09 -0600273 def _CleanupOutputDir(self):
274 """Remove the temporary output directory"""
275 if self.preserve_outdirs:
276 print('Preserving output dir: %s' % tools.outdir)
277 else:
Simon Glass80025522022-01-29 14:14:04 -0700278 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600279
Simon Glass57454f42016-11-25 20:15:52 -0700280 def setUp(self):
281 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700282 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700283 command.test_result = None
284
285 def tearDown(self):
286 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600287 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700288
Simon Glassb3d6fc72019-07-20 12:24:10 -0600289 def _SetupImageInTmpdir(self):
290 """Set up the output image in a new temporary directory
291
292 This is used when an image has been generated in the output directory,
293 but we want to run binman again. This will create a new output
294 directory and fail to delete the original one.
295
296 This creates a new temporary directory, copies the image to it (with a
297 new name) and removes the old output directory.
298
299 Returns:
300 Tuple:
301 Temporary directory to use
302 New image filename
303 """
Simon Glass80025522022-01-29 14:14:04 -0700304 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600305 tmpdir = tempfile.mkdtemp(prefix='binman.')
306 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700307 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600308 self._CleanupOutputDir()
309 return tmpdir, updated_fname
310
Simon Glass8425a1f2018-07-17 13:25:48 -0600311 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600312 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600313 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
314 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
315 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700316 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600317
Simon Glass57454f42016-11-25 20:15:52 -0700318 def _RunBinman(self, *args, **kwargs):
319 """Run binman using the command line
320
321 Args:
322 Arguments to pass, as a list of strings
323 kwargs: Arguments to pass to Command.RunPipe()
324 """
Simon Glass840be732022-01-29 14:14:05 -0700325 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700326 capture=True, capture_stderr=True, raise_on_error=False)
327 if result.return_code and kwargs.get('raise_on_error', True):
328 raise Exception("Error running '%s': %s" % (' '.join(args),
329 result.stdout + result.stderr))
330 return result
331
Simon Glassf46732a2019-07-08 14:25:29 -0600332 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700333 """Run binman using directly (in the same process)
334
335 Args:
336 Arguments to pass, as a list of strings
337 Returns:
338 Return value (0 for success)
339 """
Simon Glassf46732a2019-07-08 14:25:29 -0600340 argv = list(argv)
341 args = cmdline.ParseArgs(argv)
342 args.pager = 'binman-invalid-pager'
343 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700344
345 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600346 # args.verbosity = tout.DEBUG
347 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700348
Simon Glass91710b32018-07-17 13:25:32 -0600349 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600350 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300351 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100352 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700353 test_section_timeout=False, update_fdt_in_elf=None,
Simon Glass6bce5dc2022-11-09 19:14:42 -0700354 force_missing_bintools='', ignore_missing=False):
Simon Glass57454f42016-11-25 20:15:52 -0700355 """Run binman with a given test file
356
357 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600358 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600359 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600360 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600361 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600362 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600363 entry_args: Dict of entry args to supply to binman
364 key: arg name
365 value: value of that arg
366 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600367 use_real_dtb: True to use the test file as the contents of
368 the u-boot-dtb entry. Normally this is not needed and the
369 test contents (the U_BOOT_DTB_DATA string) can be used.
370 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300371 use_expanded: True to use expanded entries where available, e.g.
372 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600373 verbosity: Verbosity level to use (0-3, None=don't set it)
374 allow_missing: Set the '--allow-missing' flag so that missing
375 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100376 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600377 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600378 threads: Number of threads to use (None for default, 0 for
379 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600380 test_section_timeout: True to force the first time to timeout, as
381 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600382 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass66152ce2022-01-09 20:14:09 -0700383 force_missing_tools (str): comma-separated list of bintools to
384 regard as missing
Simon Glass9a798402021-11-03 21:09:17 -0600385
386 Returns:
387 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700388 """
Simon Glassf46732a2019-07-08 14:25:29 -0600389 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700390 if debug:
391 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600392 if verbosity is not None:
393 args.append('-v%d' % verbosity)
394 elif self.verbosity:
395 args.append('-v%d' % self.verbosity)
396 if self.toolpath:
397 for path in self.toolpath:
398 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600399 if threads is not None:
400 args.append('-T%d' % threads)
401 if test_section_timeout:
402 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600403 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600404 if map:
405 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600406 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600407 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600408 if not use_real_dtb:
409 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300410 if not use_expanded:
411 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600412 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600413 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600414 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600415 if allow_missing:
416 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700417 if ignore_missing:
418 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100419 if allow_fake_blobs:
420 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700421 if force_missing_bintools:
422 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600423 if update_fdt_in_elf:
424 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600425 if images:
426 for image in images:
427 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600428 if extra_indirs:
429 for indir in extra_indirs:
430 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700431 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700432
433 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700434 """Set up a new test device-tree file
435
436 The given file is compiled and set up as the device tree to be used
437 for ths test.
438
439 Args:
440 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600441 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700442
443 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600444 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700445 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600446 tmpdir = tempfile.mkdtemp(prefix='binmant.')
447 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600448 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700449 data = fd.read()
450 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600451 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600452 return data
Simon Glass57454f42016-11-25 20:15:52 -0700453
Simon Glass56d05412022-02-28 07:16:54 -0700454 def _GetDtbContentsForSpls(self, dtb_data, name):
455 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600456
457 For testing we don't actually have different versions of the DTB. With
458 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
459 we don't normally have any unwanted nodes.
460
461 We still want the DTBs for SPL and TPL to be different though, since
462 otherwise it is confusing to know which one we are looking at. So add
463 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600464
465 Args:
466 dtb_data: dtb data to modify (this should be a value devicetree)
467 name: Name of a new property to add
468
469 Returns:
470 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600471 """
472 dtb = fdt.Fdt.FromData(dtb_data)
473 dtb.Scan()
474 dtb.GetNode('/binman').AddZeroProp(name)
475 dtb.Sync(auto_resize=True)
476 dtb.Pack()
477 return dtb.GetContents()
478
Simon Glassed930672021-03-18 20:25:05 +1300479 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
480 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600481 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700482 """Run binman and return the resulting image
483
484 This runs binman with a given test file and then reads the resulting
485 output file. It is a shortcut function since most tests need to do
486 these steps.
487
488 Raises an assertion failure if binman returns a non-zero exit code.
489
490 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600491 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700492 use_real_dtb: True to use the test file as the contents of
493 the u-boot-dtb entry. Normally this is not needed and the
494 test contents (the U_BOOT_DTB_DATA string) can be used.
495 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300496 use_expanded: True to use expanded entries where available, e.g.
497 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600498 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600499 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600500 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600501 entry_args: Dict of entry args to supply to binman
502 key: arg name
503 value: value of that arg
504 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
505 function. If reset_dtbs is True, then the original test dtb
506 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600507 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600508 threads: Number of threads to use (None for default, 0 for
509 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700510
511 Returns:
512 Tuple:
513 Resulting image contents
514 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600515 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600516 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700517 """
Simon Glass72232452016-11-25 20:15:53 -0700518 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700519 # Use the compiled test file as the u-boot-dtb input
520 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700521 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600522
523 # For testing purposes, make a copy of the DT for SPL and TPL. Add
524 # a node indicating which it is, so aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700525 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600526 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
527 outfile = os.path.join(self._indir, dtb_fname)
528 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700529 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700530
531 try:
Simon Glass91710b32018-07-17 13:25:32 -0600532 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600533 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600534 use_expanded=use_expanded, extra_indirs=extra_indirs,
535 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700536 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700537 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700538
539 # Find the (only) image, read it and return its contents
540 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700541 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600542 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600543 if map:
Simon Glass80025522022-01-29 14:14:04 -0700544 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600545 with open(map_fname) as fd:
546 map_data = fd.read()
547 else:
548 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600549 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600550 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700551 finally:
552 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600553 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600554 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700555
Simon Glass5b4bce32019-07-08 14:25:26 -0600556 def _DoReadFileRealDtb(self, fname):
557 """Run binman with a real .dtb file and return the resulting data
558
559 Args:
560 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
561
562 Returns:
563 Resulting image contents
564 """
565 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
566
Simon Glass72232452016-11-25 20:15:53 -0700567 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600568 """Helper function which discards the device-tree binary
569
570 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600571 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600572 use_real_dtb: True to use the test file as the contents of
573 the u-boot-dtb entry. Normally this is not needed and the
574 test contents (the U_BOOT_DTB_DATA string) can be used.
575 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600576
577 Returns:
578 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600579 """
Simon Glass72232452016-11-25 20:15:53 -0700580 return self._DoReadFileDtb(fname, use_real_dtb)[0]
581
Simon Glass57454f42016-11-25 20:15:52 -0700582 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600583 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700584 """Create a new test input file, creating directories as needed
585
586 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600587 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700588 contents: File contents to write in to the file
589 Returns:
590 Full pathname of file created
591 """
Simon Glass862f8e22019-08-24 07:22:43 -0600592 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700593 dirname = os.path.dirname(pathname)
594 if dirname and not os.path.exists(dirname):
595 os.makedirs(dirname)
596 with open(pathname, 'wb') as fd:
597 fd.write(contents)
598 return pathname
599
600 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600601 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600602 """Create a new test input directory, creating directories as needed
603
604 Args:
605 dirname: Directory name to create
606
607 Returns:
608 Full pathname of directory created
609 """
Simon Glass862f8e22019-08-24 07:22:43 -0600610 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600611 if not os.path.exists(pathname):
612 os.makedirs(pathname)
613 return pathname
614
615 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600616 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600617 """Set up an ELF file with a '_dt_ucode_base_size' symbol
618
619 Args:
620 Filename of ELF file to use as SPL
621 """
Simon Glass93a806f2019-08-24 07:22:59 -0600622 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700623 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600624
625 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600626 def _SetupTplElf(cls, src_fname='bss_data'):
627 """Set up an ELF file with a '_dt_ucode_base_size' symbol
628
629 Args:
630 Filename of ELF file to use as TPL
631 """
632 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700633 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600634
635 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700636 def _SetupVplElf(cls, src_fname='bss_data'):
637 """Set up an ELF file with a '_dt_ucode_base_size' symbol
638
639 Args:
640 Filename of ELF file to use as VPL
641 """
642 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
643 tools.read_file(cls.ElfTestFile(src_fname)))
644
645 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600646 def _SetupDescriptor(cls):
647 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
648 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
649
650 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600651 def TestFile(cls, fname):
652 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700653
Simon Glassf6290892019-08-24 07:22:53 -0600654 @classmethod
655 def ElfTestFile(cls, fname):
656 return os.path.join(cls._elf_testdir, fname)
657
Simon Glassad5cfe12023-01-07 14:07:14 -0700658 @classmethod
659 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
660 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
661 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
662 dummy, paged_sz) + U_BOOT_DATA
663 data += extra_data
664 TestFunctional._MakeInputFile(fname, data)
665
Simon Glass57454f42016-11-25 20:15:52 -0700666 def AssertInList(self, grep_list, target):
667 """Assert that at least one of a list of things is in a target
668
669 Args:
670 grep_list: List of strings to check
671 target: Target string
672 """
673 for grep in grep_list:
674 if grep in target:
675 return
Simon Glass848cdb52019-05-17 22:00:50 -0600676 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700677
678 def CheckNoGaps(self, entries):
679 """Check that all entries fit together without gaps
680
681 Args:
682 entries: List of entries to check
683 """
Simon Glasse8561af2018-08-01 15:22:37 -0600684 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700685 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600686 self.assertEqual(offset, entry.offset)
687 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700688
Simon Glass72232452016-11-25 20:15:53 -0700689 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600690 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700691
692 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600693 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700694
695 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600696 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700697 """
698 return struct.unpack('>L', dtb[4:8])[0]
699
Simon Glass0f621332019-07-08 14:25:27 -0600700 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600701 def AddNode(node, path):
702 if node.name != '/':
703 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600704 for prop in node.props.values():
705 if prop.name in prop_names:
706 prop_path = path + ':' + prop.name
707 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
708 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600709 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600710 AddNode(subnode, path)
711
712 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600713 AddNode(dtb.GetRoot(), '')
714 return tree
715
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000716 def _CheckSign(self, fit, key):
717 try:
718 tools.run('fit_check_sign', '-k', key, '-f', fit)
719 except:
720 self.fail('Expected signed FIT container')
721 return False
722 return True
723
Simon Glass57454f42016-11-25 20:15:52 -0700724 def testRun(self):
725 """Test a basic run with valid args"""
726 result = self._RunBinman('-h')
727
728 def testFullHelp(self):
729 """Test that the full help is displayed with -H"""
730 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300731 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500732 # Remove possible extraneous strings
733 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
734 gothelp = result.stdout.replace(extra, '')
735 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700736 self.assertEqual(0, len(result.stderr))
737 self.assertEqual(0, result.return_code)
738
739 def testFullHelpInternal(self):
740 """Test that the full help is displayed with -H"""
741 try:
742 command.test_result = command.CommandResult()
743 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300744 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700745 finally:
746 command.test_result = None
747
748 def testHelp(self):
749 """Test that the basic help is displayed with -h"""
750 result = self._RunBinman('-h')
751 self.assertTrue(len(result.stdout) > 200)
752 self.assertEqual(0, len(result.stderr))
753 self.assertEqual(0, result.return_code)
754
Simon Glass57454f42016-11-25 20:15:52 -0700755 def testBoard(self):
756 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600757 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700758 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300759 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700760 self.assertEqual(0, result)
761
762 def testNeedBoard(self):
763 """Test that we get an error when no board ius supplied"""
764 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600765 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700766 self.assertIn("Must provide a board to process (use -b <board>)",
767 str(e.exception))
768
769 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600770 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700771 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600772 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700773 # We get one error from libfdt, and a different one from fdtget.
774 self.AssertInList(["Couldn't open blob from 'missing_file'",
775 'No such file or directory'], str(e.exception))
776
777 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600778 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700779
780 Since this is a source file it should be compiled and the error
781 will come from the device-tree compiler (dtc).
782 """
783 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600784 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700785 self.assertIn("FATAL ERROR: Unable to parse input tree",
786 str(e.exception))
787
788 def testMissingNode(self):
789 """Test that a device tree without a 'binman' node generates an error"""
790 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600791 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700792 self.assertIn("does not have a 'binman' node", str(e.exception))
793
794 def testEmpty(self):
795 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600796 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700797 self.assertEqual(0, len(result.stderr))
798 self.assertEqual(0, result.return_code)
799
800 def testInvalidEntry(self):
801 """Test that an invalid entry is flagged"""
802 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600803 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600804 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700805 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
806 "'/binman/not-a-valid-type'", str(e.exception))
807
808 def testSimple(self):
809 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600810 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700811 self.assertEqual(U_BOOT_DATA, data)
812
Simon Glass075a45c2017-11-13 18:55:00 -0700813 def testSimpleDebug(self):
814 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600815 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700816
Simon Glass57454f42016-11-25 20:15:52 -0700817 def testDual(self):
818 """Test that we can handle creating two images
819
820 This also tests image padding.
821 """
Simon Glass511f6582018-10-01 12:22:30 -0600822 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700823 self.assertEqual(0, retcode)
824
825 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600826 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700827 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700828 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600829 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700830 data = fd.read()
831 self.assertEqual(U_BOOT_DATA, data)
832
833 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600834 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700835 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700836 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600837 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700838 data = fd.read()
839 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700840 self.assertEqual(tools.get_bytes(0, 3), data[:3])
841 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700842
843 def testBadAlign(self):
844 """Test that an invalid alignment value is detected"""
845 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600846 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700847 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
848 "of two", str(e.exception))
849
850 def testPackSimple(self):
851 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600852 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700853 self.assertEqual(0, retcode)
854 self.assertIn('image', control.images)
855 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600856 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700857 self.assertEqual(5, len(entries))
858
859 # First u-boot
860 self.assertIn('u-boot', entries)
861 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600862 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700863 self.assertEqual(len(U_BOOT_DATA), entry.size)
864
865 # Second u-boot, aligned to 16-byte boundary
866 self.assertIn('u-boot-align', entries)
867 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600868 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700869 self.assertEqual(len(U_BOOT_DATA), entry.size)
870
871 # Third u-boot, size 23 bytes
872 self.assertIn('u-boot-size', entries)
873 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600874 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700875 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
876 self.assertEqual(23, entry.size)
877
878 # Fourth u-boot, placed immediate after the above
879 self.assertIn('u-boot-next', entries)
880 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600881 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700882 self.assertEqual(len(U_BOOT_DATA), entry.size)
883
Simon Glasse8561af2018-08-01 15:22:37 -0600884 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700885 self.assertIn('u-boot-fixed', entries)
886 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600887 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700888 self.assertEqual(len(U_BOOT_DATA), entry.size)
889
Simon Glass39dd2152019-07-08 14:25:47 -0600890 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700891
892 def testPackExtra(self):
893 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600894 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
895 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700896
Simon Glass57454f42016-11-25 20:15:52 -0700897 self.assertIn('image', control.images)
898 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600899 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600900 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700901
Samuel Hollande2574022023-01-21 17:25:16 -0600902 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700903 self.assertIn('u-boot', entries)
904 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600905 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700906 self.assertEqual(3, entry.pad_before)
907 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600908 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700909 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
910 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600911 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700912
913 # Second u-boot has an aligned size, but it has no effect
914 self.assertIn('u-boot-align-size-nop', entries)
915 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600916 self.assertEqual(pos, entry.offset)
917 self.assertEqual(len(U_BOOT_DATA), entry.size)
918 self.assertEqual(U_BOOT_DATA, entry.data)
919 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
920 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700921
922 # Third u-boot has an aligned size too
923 self.assertIn('u-boot-align-size', entries)
924 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600925 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700926 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600927 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700928 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600929 data[pos:pos + entry.size])
930 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700931
932 # Fourth u-boot has an aligned end
933 self.assertIn('u-boot-align-end', entries)
934 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600935 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700936 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600937 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700938 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600939 data[pos:pos + entry.size])
940 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700941
942 # Fifth u-boot immediately afterwards
943 self.assertIn('u-boot-align-both', entries)
944 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600945 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700946 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600947 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700948 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600949 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700950
Samuel Hollande2574022023-01-21 17:25:16 -0600951 # Sixth u-boot with both minimum size and aligned size
952 self.assertIn('u-boot-min-size', entries)
953 entry = entries['u-boot-min-size']
954 self.assertEqual(128, entry.offset)
955 self.assertEqual(32, entry.size)
956 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
957 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
958 data[pos:pos + entry.size])
959
Simon Glass57454f42016-11-25 20:15:52 -0700960 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -0600961 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700962
Simon Glassafb9caa2020-10-26 17:40:10 -0600963 dtb = fdt.Fdt(out_dtb_fname)
964 dtb.Scan()
965 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
966 expected = {
967 'image-pos': 0,
968 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -0600969 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -0600970
971 'u-boot:image-pos': 0,
972 'u-boot:offset': 0,
973 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
974
975 'u-boot-align-size-nop:image-pos': 12,
976 'u-boot-align-size-nop:offset': 12,
977 'u-boot-align-size-nop:size': 4,
978
979 'u-boot-align-size:image-pos': 16,
980 'u-boot-align-size:offset': 16,
981 'u-boot-align-size:size': 32,
982
983 'u-boot-align-end:image-pos': 48,
984 'u-boot-align-end:offset': 48,
985 'u-boot-align-end:size': 16,
986
987 'u-boot-align-both:image-pos': 64,
988 'u-boot-align-both:offset': 64,
989 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -0600990
991 'u-boot-min-size:image-pos': 128,
992 'u-boot-min-size:offset': 128,
993 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -0600994 }
995 self.assertEqual(expected, props)
996
Simon Glass57454f42016-11-25 20:15:52 -0700997 def testPackAlignPowerOf2(self):
998 """Test that invalid entry alignment is detected"""
999 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001000 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001001 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1002 "of two", str(e.exception))
1003
1004 def testPackAlignSizePowerOf2(self):
1005 """Test that invalid entry size alignment is detected"""
1006 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001007 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001008 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1009 "power of two", str(e.exception))
1010
1011 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001012 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001013 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001014 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001015 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001016 "align 0x4 (4)", str(e.exception))
1017
1018 def testPackInvalidSizeAlign(self):
1019 """Test that invalid entry size alignment is detected"""
1020 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001021 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001022 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1023 "align-size 0x4 (4)", str(e.exception))
1024
1025 def testPackOverlap(self):
1026 """Test that overlapping regions are detected"""
1027 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001028 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001029 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001030 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1031 str(e.exception))
1032
1033 def testPackEntryOverflow(self):
1034 """Test that entries that overflow their size are detected"""
1035 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001036 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001037 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1038 "but entry size is 0x3 (3)", str(e.exception))
1039
1040 def testPackImageOverflow(self):
1041 """Test that entries which overflow the image size are detected"""
1042 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001043 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001044 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001045 "size 0x3 (3)", str(e.exception))
1046
1047 def testPackImageSize(self):
1048 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001049 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001050 self.assertEqual(0, retcode)
1051 self.assertIn('image', control.images)
1052 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001053 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001054
1055 def testPackImageSizeAlign(self):
1056 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001057 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001058 self.assertEqual(0, retcode)
1059 self.assertIn('image', control.images)
1060 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001061 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001062
1063 def testPackInvalidImageAlign(self):
1064 """Test that invalid image alignment is detected"""
1065 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001066 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001067 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001068 "align-size 0x8 (8)", str(e.exception))
1069
Simon Glass2a0fa982022-02-11 13:23:21 -07001070 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001071 """Test that invalid image alignment is detected"""
1072 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001073 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001074 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001075 "two", str(e.exception))
1076
1077 def testImagePadByte(self):
1078 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001079 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001080 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001081 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001082 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001083
1084 def testImageName(self):
1085 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001086 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001087 self.assertEqual(0, retcode)
1088 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001089 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001090 self.assertTrue(os.path.exists(fname))
1091
1092 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001093 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001094 self.assertTrue(os.path.exists(fname))
1095
1096 def testBlobFilename(self):
1097 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001098 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001099 self.assertEqual(BLOB_DATA, data)
1100
1101 def testPackSorted(self):
1102 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001103 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001104 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001105 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1106 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001107
Simon Glasse8561af2018-08-01 15:22:37 -06001108 def testPackZeroOffset(self):
1109 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001110 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001111 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001112 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001113 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001114 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1115 str(e.exception))
1116
1117 def testPackUbootDtb(self):
1118 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001119 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001120 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001121
1122 def testPackX86RomNoSize(self):
1123 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001124 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001125 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001126 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001127 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001128 "using end-at-4gb", str(e.exception))
1129
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301130 def test4gbAndSkipAtStartTogether(self):
1131 """Test that the end-at-4gb and skip-at-size property can't be used
1132 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001133 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301134 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001135 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001136 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301137 "'skip-at-start'", str(e.exception))
1138
Simon Glass72232452016-11-25 20:15:53 -07001139 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001140 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001141 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001142 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001143 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001144 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1145 "is outside the section '/binman' starting at "
1146 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001147 str(e.exception))
1148
1149 def testPackX86Rom(self):
1150 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001151 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001152 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001153 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1154 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001155
1156 def testPackX86RomMeNoDesc(self):
1157 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001158 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001159 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001160 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001161 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001162 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1163 str(e.exception))
1164 finally:
1165 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001166
1167 def testPackX86RomBadDesc(self):
1168 """Test that the Intel requires a descriptor entry"""
1169 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001170 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001171 self.assertIn("Node '/binman/intel-me': No offset set with "
1172 "offset-unset: should another entry provide this correct "
1173 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001174
1175 def testPackX86RomMe(self):
1176 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001177 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001178 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001179 if data[:0x1000] != expected_desc:
1180 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001181 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1182
1183 def testPackVga(self):
1184 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001185 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001186 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1187
1188 def testPackStart16(self):
1189 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001190 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001191 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1192
Jagdish Gediya311d4842018-09-03 21:35:08 +05301193 def testPackPowerpcMpc85xxBootpgResetvec(self):
1194 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1195 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001196 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301197 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1198
Simon Glass6ba679c2018-07-06 10:27:17 -06001199 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001200 """Handle running a test for insertion of microcode
1201
1202 Args:
1203 dts_fname: Name of test .dts file
1204 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001205 ucode_second: True if the microsecond entry is second instead of
1206 third
Simon Glass820af1d2018-07-06 10:27:16 -06001207
1208 Returns:
1209 Tuple:
1210 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001211 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001212 in the above (two 4-byte words)
1213 """
Simon Glass3d274232017-11-12 21:52:27 -07001214 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001215
1216 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001217 if ucode_second:
1218 ucode_content = data[len(nodtb_data):]
1219 ucode_pos = len(nodtb_data)
1220 dtb_with_ucode = ucode_content[16:]
1221 fdt_len = self.GetFdtLen(dtb_with_ucode)
1222 else:
1223 dtb_with_ucode = data[len(nodtb_data):]
1224 fdt_len = self.GetFdtLen(dtb_with_ucode)
1225 ucode_content = dtb_with_ucode[fdt_len:]
1226 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001227 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001228 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001229 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001230 dtb = fdt.FdtScan(fname)
1231 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001232 self.assertTrue(ucode)
1233 for node in ucode.subnodes:
1234 self.assertFalse(node.props.get('data'))
1235
Simon Glass72232452016-11-25 20:15:53 -07001236 # Check that the microcode appears immediately after the Fdt
1237 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001238 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001239 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1240 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001241 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001242
1243 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001244 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001245 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1246 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001247 u_boot = data[:len(nodtb_data)]
1248 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001249
1250 def testPackUbootMicrocode(self):
1251 """Test that x86 microcode can be handled correctly
1252
1253 We expect to see the following in the image, in order:
1254 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1255 place
1256 u-boot.dtb with the microcode removed
1257 the microcode
1258 """
Simon Glass511f6582018-10-01 12:22:30 -06001259 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001260 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001261 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1262 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001263
Simon Glassbac25c82017-05-27 07:38:26 -06001264 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001265 """Test that x86 microcode can be handled correctly
1266
1267 We expect to see the following in the image, in order:
1268 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1269 place
1270 u-boot.dtb with the microcode
1271 an empty microcode region
1272 """
1273 # We need the libfdt library to run this test since only that allows
1274 # finding the offset of a property. This is required by
1275 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001276 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001277
1278 second = data[len(U_BOOT_NODTB_DATA):]
1279
1280 fdt_len = self.GetFdtLen(second)
1281 third = second[fdt_len:]
1282 second = second[:fdt_len]
1283
Simon Glassbac25c82017-05-27 07:38:26 -06001284 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1285 self.assertIn(ucode_data, second)
1286 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001287
Simon Glassbac25c82017-05-27 07:38:26 -06001288 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001289 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001290 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1291 len(ucode_data))
1292 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001293 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1294 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001295
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001296 def testPackUbootSingleMicrocode(self):
1297 """Test that x86 microcode can be handled correctly with fdt_normal.
1298 """
Simon Glassbac25c82017-05-27 07:38:26 -06001299 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001300
Simon Glass996021e2016-11-25 20:15:54 -07001301 def testUBootImg(self):
1302 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001303 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001304 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001305
1306 def testNoMicrocode(self):
1307 """Test that a missing microcode region is detected"""
1308 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001309 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001310 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1311 "node found in ", str(e.exception))
1312
1313 def testMicrocodeWithoutNode(self):
1314 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1315 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001316 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001317 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1318 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1319
1320 def testMicrocodeWithoutNode2(self):
1321 """Test that a missing u-boot-ucode node is detected"""
1322 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001323 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001324 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1325 "microcode region u-boot-ucode", str(e.exception))
1326
1327 def testMicrocodeWithoutPtrInElf(self):
1328 """Test that a U-Boot binary without the microcode symbol is detected"""
1329 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001330 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001331 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001332 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001333
1334 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001335 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001336 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1337 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1338
1339 finally:
1340 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001341 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001342 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001343
1344 def testMicrocodeNotInImage(self):
1345 """Test that microcode must be placed within the image"""
1346 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001347 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001348 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1349 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001350 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001351
1352 def testWithoutMicrocode(self):
1353 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001354 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001355 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001356 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001357
1358 # Now check the device tree has no microcode
1359 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1360 second = data[len(U_BOOT_NODTB_DATA):]
1361
1362 fdt_len = self.GetFdtLen(second)
1363 self.assertEqual(dtb, second[:fdt_len])
1364
1365 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1366 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001367 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001368
1369 def testUnknownPosSize(self):
1370 """Test that microcode must be placed within the image"""
1371 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001372 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001373 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001374 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001375
1376 def testPackFsp(self):
1377 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001378 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001379 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1380
1381 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001382 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001383 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001384 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001385
1386 def testPackVbt(self):
1387 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001388 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001389 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001390
Simon Glass7f94e832017-11-12 21:52:25 -07001391 def testSplBssPad(self):
1392 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001393 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001394 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001395 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001396 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001397 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001398
Simon Glass04cda032018-10-01 21:12:42 -06001399 def testSplBssPadMissing(self):
1400 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001401 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001402 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001403 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001404 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1405 str(e.exception))
1406
Simon Glasse83679d2017-11-12 21:52:26 -07001407 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001408 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001409 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001410 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1411
Simon Glass6ba679c2018-07-06 10:27:17 -06001412 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1413 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001414
1415 We expect to see the following in the image, in order:
1416 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1417 correct place
1418 u-boot.dtb with the microcode removed
1419 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001420
1421 Args:
1422 dts: Device tree file to use for test
1423 ucode_second: True if the microsecond entry is second instead of
1424 third
Simon Glass3d274232017-11-12 21:52:27 -07001425 """
Simon Glass7057d022018-10-01 21:12:47 -06001426 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001427 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1428 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001429 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1430 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001431
Simon Glass6ba679c2018-07-06 10:27:17 -06001432 def testPackUbootSplMicrocode(self):
1433 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001434 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001435 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001436
1437 def testPackUbootSplMicrocodeReorder(self):
1438 """Test that order doesn't matter for microcode entries
1439
1440 This is the same as testPackUbootSplMicrocode but when we process the
1441 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1442 entry, so we reply on binman to try later.
1443 """
Simon Glass511f6582018-10-01 12:22:30 -06001444 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001445 ucode_second=True)
1446
Simon Glassa409c932017-11-12 21:52:28 -07001447 def testPackMrc(self):
1448 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001449 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001450 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1451
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001452 def testSplDtb(self):
1453 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001454 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001455 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001456 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1457
Simon Glass0a6da312017-11-13 18:54:56 -07001458 def testSplNoDtb(self):
1459 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001460 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001461 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001462 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1463
Simon Glass7098b7f2021-03-21 18:24:30 +13001464 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4abf7842023-07-18 07:23:54 -06001465 use_expanded=False, no_write_symbols=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001466 """Check the image contains the expected symbol values
1467
1468 Args:
1469 dts: Device tree file to use for test
1470 base_data: Data before and after 'u-boot' section
1471 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001472 entry_args: Dict of entry args to supply to binman
1473 key: arg name
1474 value: value of that arg
1475 use_expanded: True to use expanded entries where available, e.g.
1476 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001477 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001478 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001479 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1480 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001481 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001482 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001483 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001484
Simon Glass7057d022018-10-01 21:12:47 -06001485 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001486 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1487 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001488 # The image should contain the symbols from u_boot_binman_syms.c
1489 # Note that image_pos is adjusted by the base address of the image,
1490 # which is 0x10 in our test image
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001491 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1492 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glass31e04cb2021-03-18 20:24:56 +13001493 0x10 + u_boot_offset, 0x04)
Simon Glass4abf7842023-07-18 07:23:54 -06001494 if no_write_symbols:
1495 expected = (base_data +
1496 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1497 U_BOOT_DATA + base_data)
1498 else:
1499 expected = (sym_values + base_data[24:] +
1500 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1501 base_data[24:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001502 self.assertEqual(expected, data)
1503
Simon Glass31e04cb2021-03-18 20:24:56 +13001504 def testSymbols(self):
1505 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001506 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001507
1508 def testSymbolsNoDtb(self):
1509 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001510 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001511 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1512 0x38)
1513
Simon Glasse76a3e62018-06-01 09:38:11 -06001514 def testPackUnitAddress(self):
1515 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001516 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001517 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1518
Simon Glassa91e1152018-06-01 09:38:16 -06001519 def testSections(self):
1520 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001521 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001522 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1523 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1524 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001525 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001526
Simon Glass30732662018-06-01 09:38:20 -06001527 def testMap(self):
1528 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001529 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001530 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700153100000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600153200000000 00000000 00000010 section@0
153300000000 00000000 00000004 u-boot
153400000010 00000010 00000010 section@1
153500000010 00000000 00000004 u-boot
153600000020 00000020 00000004 section@2
153700000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001538''', map_data)
1539
Simon Glass3b78d532018-06-01 09:38:21 -06001540 def testNamePrefix(self):
1541 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001542 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001543 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700154400000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600154500000000 00000000 00000010 section@0
154600000000 00000000 00000004 ro-u-boot
154700000010 00000010 00000010 section@1
154800000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001549''', map_data)
1550
Simon Glass6ba679c2018-07-06 10:27:17 -06001551 def testUnknownContents(self):
1552 """Test that obtaining the contents works as expected"""
1553 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001554 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001555 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001556 "processing of contents: remaining ["
1557 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001558
Simon Glass2e1169f2018-07-06 10:27:19 -06001559 def testBadChangeSize(self):
1560 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001561 try:
1562 state.SetAllowEntryExpansion(False)
1563 with self.assertRaises(ValueError) as e:
1564 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001565 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001566 str(e.exception))
1567 finally:
1568 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001569
Simon Glassa87014e2018-07-06 10:27:42 -06001570 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001571 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001572 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001573 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001574 dtb = fdt.Fdt(out_dtb_fname)
1575 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001576 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001577 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001578 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001579 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001580 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001581 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001582 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001583 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001584 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001585 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001586 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001587 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001588 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001589
Simon Glasse8561af2018-08-01 15:22:37 -06001590 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001591 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001592 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001593 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001594 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001595 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001596 'size': 40
1597 }, props)
1598
1599 def testUpdateFdtBad(self):
1600 """Test that we detect when ProcessFdt never completes"""
1601 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001602 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001603 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001604 '[<binman.etype._testing.Entry__testing',
1605 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001606
Simon Glass91710b32018-07-17 13:25:32 -06001607 def testEntryArgs(self):
1608 """Test passing arguments to entries from the command line"""
1609 entry_args = {
1610 'test-str-arg': 'test1',
1611 'test-int-arg': '456',
1612 }
Simon Glass511f6582018-10-01 12:22:30 -06001613 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001614 self.assertIn('image', control.images)
1615 entry = control.images['image'].GetEntries()['_testing']
1616 self.assertEqual('test0', entry.test_str_fdt)
1617 self.assertEqual('test1', entry.test_str_arg)
1618 self.assertEqual(123, entry.test_int_fdt)
1619 self.assertEqual(456, entry.test_int_arg)
1620
1621 def testEntryArgsMissing(self):
1622 """Test missing arguments and properties"""
1623 entry_args = {
1624 'test-int-arg': '456',
1625 }
Simon Glass511f6582018-10-01 12:22:30 -06001626 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001627 entry = control.images['image'].GetEntries()['_testing']
1628 self.assertEqual('test0', entry.test_str_fdt)
1629 self.assertEqual(None, entry.test_str_arg)
1630 self.assertEqual(None, entry.test_int_fdt)
1631 self.assertEqual(456, entry.test_int_arg)
1632
1633 def testEntryArgsRequired(self):
1634 """Test missing arguments and properties"""
1635 entry_args = {
1636 'test-int-arg': '456',
1637 }
1638 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001639 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001640 self.assertIn("Node '/binman/_testing': "
1641 'Missing required properties/entry args: test-str-arg, '
1642 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001643 str(e.exception))
1644
1645 def testEntryArgsInvalidFormat(self):
1646 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001647 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1648 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001649 with self.assertRaises(ValueError) as e:
1650 self._DoBinman(*args)
1651 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1652
1653 def testEntryArgsInvalidInteger(self):
1654 """Test that an invalid entry-argument integer is detected"""
1655 entry_args = {
1656 'test-int-arg': 'abc',
1657 }
1658 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001659 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001660 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1661 "'test-int-arg' (value 'abc') to integer",
1662 str(e.exception))
1663
1664 def testEntryArgsInvalidDatatype(self):
1665 """Test that an invalid entry-argument datatype is detected
1666
1667 This test could be written in entry_test.py except that it needs
1668 access to control.entry_args, which seems more than that module should
1669 be able to see.
1670 """
1671 entry_args = {
1672 'test-bad-datatype-arg': '12',
1673 }
1674 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001675 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001676 entry_args=entry_args)
1677 self.assertIn('GetArg() internal error: Unknown data type ',
1678 str(e.exception))
1679
Simon Glass2ca52032018-07-17 13:25:33 -06001680 def testText(self):
1681 """Test for a text entry type"""
1682 entry_args = {
1683 'test-id': TEXT_DATA,
1684 'test-id2': TEXT_DATA2,
1685 'test-id3': TEXT_DATA3,
1686 }
Simon Glass511f6582018-10-01 12:22:30 -06001687 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001688 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001689 expected = (tools.to_bytes(TEXT_DATA) +
1690 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1691 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001692 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001693 self.assertEqual(expected, data)
1694
Simon Glass969616c2018-07-17 13:25:36 -06001695 def testEntryDocs(self):
1696 """Test for creation of entry documentation"""
1697 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001698 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001699 self.assertTrue(len(stdout.getvalue()) > 0)
1700
1701 def testEntryDocsMissing(self):
1702 """Test handling of missing entry documentation"""
1703 with self.assertRaises(ValueError) as e:
1704 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001705 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001706 self.assertIn('Documentation is missing for modules: u_boot',
1707 str(e.exception))
1708
Simon Glass704784b2018-07-17 13:25:38 -06001709 def testFmap(self):
1710 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001711 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001712 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001713 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1714 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001715 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001716 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001717 self.assertEqual(1, fhdr.ver_major)
1718 self.assertEqual(0, fhdr.ver_minor)
1719 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001720 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001721 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001722 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001723 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001724 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001725
Simon Glass82059c22021-04-03 11:05:09 +13001726 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001727 self.assertEqual(b'SECTION0', fentry.name)
1728 self.assertEqual(0, fentry.offset)
1729 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001730 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001731
1732 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001733 self.assertEqual(b'RO_U_BOOT', fentry.name)
1734 self.assertEqual(0, fentry.offset)
1735 self.assertEqual(4, fentry.size)
1736 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001737
Simon Glass82059c22021-04-03 11:05:09 +13001738 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001739 self.assertEqual(b'SECTION1', fentry.name)
1740 self.assertEqual(16, fentry.offset)
1741 self.assertEqual(16, fentry.size)
1742 self.assertEqual(0, fentry.flags)
1743
1744 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001745 self.assertEqual(b'RW_U_BOOT', fentry.name)
1746 self.assertEqual(16, fentry.offset)
1747 self.assertEqual(4, fentry.size)
1748 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001749
Simon Glass82059c22021-04-03 11:05:09 +13001750 fentry = next(fiter)
1751 self.assertEqual(b'FMAP', fentry.name)
1752 self.assertEqual(32, fentry.offset)
1753 self.assertEqual(expect_size, fentry.size)
1754 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001755
Simon Glassdb168d42018-07-17 13:25:39 -06001756 def testBlobNamedByArg(self):
1757 """Test we can add a blob with the filename coming from an entry arg"""
1758 entry_args = {
1759 'cros-ec-rw-path': 'ecrw.bin',
1760 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001761 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001762
Simon Glass53f53992018-07-17 13:25:40 -06001763 def testFill(self):
1764 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001765 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001766 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001767 self.assertEqual(expected, data)
1768
1769 def testFillNoSize(self):
1770 """Test for an fill entry type with no size"""
1771 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001772 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001773 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001774 str(e.exception))
1775
Simon Glassc1ae83c2018-07-17 13:25:44 -06001776 def _HandleGbbCommand(self, pipe_list):
1777 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001778 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001779 fname = pipe_list[0][-1]
1780 # Append our GBB data to the file, which will happen every time the
1781 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001782 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001783 fd.write(GBB_DATA)
1784 return command.CommandResult()
1785
1786 def testGbb(self):
1787 """Test for the Chromium OS Google Binary Block"""
1788 command.test_result = self._HandleGbbCommand
1789 entry_args = {
1790 'keydir': 'devkeys',
1791 'bmpblk': 'bmpblk.bin',
1792 }
Simon Glass511f6582018-10-01 12:22:30 -06001793 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001794
1795 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001796 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1797 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001798 self.assertEqual(expected, data)
1799
1800 def testGbbTooSmall(self):
1801 """Test for the Chromium OS Google Binary Block being large enough"""
1802 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001803 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001804 self.assertIn("Node '/binman/gbb': GBB is too small",
1805 str(e.exception))
1806
1807 def testGbbNoSize(self):
1808 """Test for the Chromium OS Google Binary Block having a size"""
1809 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001810 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001811 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1812 str(e.exception))
1813
Simon Glass66152ce2022-01-09 20:14:09 -07001814 def testGbbMissing(self):
1815 """Test that binman still produces an image if futility is missing"""
1816 entry_args = {
1817 'keydir': 'devkeys',
1818 }
1819 with test_util.capture_sys_output() as (_, stderr):
1820 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1821 entry_args=entry_args)
1822 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001823 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001824
Simon Glass5c350162018-07-17 13:25:47 -06001825 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001826 """Fake calls to the futility utility
1827
1828 The expected pipe is:
1829
1830 [('futility', 'vbutil_firmware', '--vblock',
1831 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1832 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1833 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1834 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1835
1836 This writes to the output file (here, 'vblock.vblock'). If
1837 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1838 of the input data (here, 'input.vblock').
1839 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001840 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001841 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001842 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001843 if self._hash_data:
1844 infile = pipe_list[0][11]
1845 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001846 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001847 m.update(data)
1848 fd.write(m.digest())
1849 else:
1850 fd.write(VBLOCK_DATA)
1851
Simon Glass5c350162018-07-17 13:25:47 -06001852 return command.CommandResult()
1853
1854 def testVblock(self):
1855 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001856 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001857 command.test_result = self._HandleVblockCommand
1858 entry_args = {
1859 'keydir': 'devkeys',
1860 }
Simon Glass511f6582018-10-01 12:22:30 -06001861 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001862 entry_args=entry_args)
1863 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1864 self.assertEqual(expected, data)
1865
1866 def testVblockNoContent(self):
1867 """Test we detect a vblock which has no content to sign"""
1868 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001869 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001870 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001871 'property', str(e.exception))
1872
1873 def testVblockBadPhandle(self):
1874 """Test that we detect a vblock with an invalid phandle in contents"""
1875 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001876 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001877 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1878 '1000', str(e.exception))
1879
1880 def testVblockBadEntry(self):
1881 """Test that we detect an entry that points to a non-entry"""
1882 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001883 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001884 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1885 "'other'", str(e.exception))
1886
Simon Glass220c6222021-01-06 21:35:17 -07001887 def testVblockContent(self):
1888 """Test that the vblock signs the right data"""
1889 self._hash_data = True
1890 command.test_result = self._HandleVblockCommand
1891 entry_args = {
1892 'keydir': 'devkeys',
1893 }
1894 data = self._DoReadFileDtb(
1895 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1896 entry_args=entry_args)[0]
1897 hashlen = 32 # SHA256 hash is 32 bytes
1898 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1899 hashval = data[-hashlen:]
1900 dtb = data[len(U_BOOT_DATA):-hashlen]
1901
1902 expected_data = U_BOOT_DATA + dtb
1903
1904 # The hashval should be a hash of the dtb
1905 m = hashlib.sha256()
1906 m.update(expected_data)
1907 expected_hashval = m.digest()
1908 self.assertEqual(expected_hashval, hashval)
1909
Simon Glass66152ce2022-01-09 20:14:09 -07001910 def testVblockMissing(self):
1911 """Test that binman still produces an image if futility is missing"""
1912 entry_args = {
1913 'keydir': 'devkeys',
1914 }
1915 with test_util.capture_sys_output() as (_, stderr):
1916 self._DoTestFile('074_vblock.dts',
1917 force_missing_bintools='futility',
1918 entry_args=entry_args)
1919 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001920 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001921
Simon Glass8425a1f2018-07-17 13:25:48 -06001922 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001923 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001924 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001925 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001926 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001927 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1928
Simon Glass24b97442018-07-17 13:25:51 -06001929 def testUsesPos(self):
1930 """Test that the 'pos' property cannot be used anymore"""
1931 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001932 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001933 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1934 "'pos'", str(e.exception))
1935
Simon Glass274bf092018-09-14 04:57:08 -06001936 def testFillZero(self):
1937 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001938 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001939 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001940
Simon Glass267de432018-09-14 04:57:09 -06001941 def testTextMissing(self):
1942 """Test for a text entry type where there is no text"""
1943 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001944 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001945 self.assertIn("Node '/binman/text': No value provided for text label "
1946 "'test-id'", str(e.exception))
1947
Simon Glassed40e962018-09-14 04:57:10 -06001948 def testPackStart16Tpl(self):
1949 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001950 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001951 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1952
Simon Glass3b376c32018-09-14 04:57:12 -06001953 def testSelectImage(self):
1954 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001955 expected = 'Skipping images: image1'
1956
1957 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001958 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001959 with test_util.capture_sys_output() as (stdout, stderr):
1960 retcode = self._DoTestFile('006_dual_image.dts',
1961 verbosity=verbosity,
1962 images=['image2'])
1963 self.assertEqual(0, retcode)
1964 if verbosity:
1965 self.assertIn(expected, stdout.getvalue())
1966 else:
1967 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001968
Simon Glass80025522022-01-29 14:14:04 -07001969 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1970 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001971 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001972
Simon Glasse219aa42018-09-14 04:57:24 -06001973 def testUpdateFdtAll(self):
1974 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001975 self._SetupSplElf()
1976 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06001977 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001978
1979 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06001980 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001981 'image-pos': 0,
1982 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06001983 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001984 'section:image-pos': 0,
1985 'section:size': 565,
1986 'section/u-boot-dtb:offset': 0,
1987 'section/u-boot-dtb:image-pos': 0,
1988 'section/u-boot-dtb:size': 565,
1989 'u-boot-spl-dtb:offset': 565,
1990 'u-boot-spl-dtb:image-pos': 565,
1991 'u-boot-spl-dtb:size': 585,
1992 'u-boot-tpl-dtb:offset': 1150,
1993 'u-boot-tpl-dtb:image-pos': 1150,
1994 'u-boot-tpl-dtb:size': 585,
1995 'u-boot-vpl-dtb:image-pos': 1735,
1996 'u-boot-vpl-dtb:offset': 1735,
1997 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06001998 }
1999
2000 # We expect three device-tree files in the output, one after the other.
2001 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2002 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2003 # main U-Boot tree. All three should have the same postions and offset.
2004 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002005 self.maxDiff = None
2006 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002007 dtb = fdt.Fdt.FromData(data[start:])
2008 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002009 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002010 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002011 expected = dict(base_expected)
2012 if item:
2013 expected[item] = 0
2014 self.assertEqual(expected, props)
2015 start += dtb._fdt_obj.totalsize()
2016
2017 def testUpdateFdtOutput(self):
2018 """Test that output DTB files are updated"""
2019 try:
Simon Glass511f6582018-10-01 12:22:30 -06002020 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002021 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2022
2023 # Unfortunately, compiling a source file always results in a file
2024 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002025 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002026 # binman as a file called u-boot.dtb. To fix this, copy the file
2027 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002028 start = 0
2029 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002030 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002031 dtb = fdt.Fdt.FromData(data[start:])
2032 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002033 pathname = tools.get_output_filename(os.path.split(fname)[1])
2034 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002035 name = os.path.split(fname)[0]
2036
2037 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002038 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002039 else:
2040 orig_indata = dtb_data
2041 self.assertNotEqual(outdata, orig_indata,
2042 "Expected output file '%s' be updated" % pathname)
2043 self.assertEqual(outdata, data[start:start + size],
2044 "Expected output file '%s' to match output image" %
2045 pathname)
2046 start += size
2047 finally:
2048 self._ResetDtbs()
2049
Simon Glass7ba33592018-09-14 04:57:26 -06002050 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002051 bintool = self.comp_bintools['lz4']
2052 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002053
2054 def testCompress(self):
2055 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002056 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002057 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002058 use_real_dtb=True, update_dtb=True)
2059 dtb = fdt.Fdt(out_dtb_fname)
2060 dtb.Scan()
2061 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2062 orig = self._decompress(data)
2063 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002064
2065 # Do a sanity check on various fields
2066 image = control.images['image']
2067 entries = image.GetEntries()
2068 self.assertEqual(1, len(entries))
2069
2070 entry = entries['blob']
2071 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2072 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2073 orig = self._decompress(entry.data)
2074 self.assertEqual(orig, entry.uncomp_data)
2075
Simon Glass72eeff12020-10-26 17:40:16 -06002076 self.assertEqual(image.data, entry.data)
2077
Simon Glass7ba33592018-09-14 04:57:26 -06002078 expected = {
2079 'blob:uncomp-size': len(COMPRESS_DATA),
2080 'blob:size': len(data),
2081 'size': len(data),
2082 }
2083 self.assertEqual(expected, props)
2084
Simon Glassac6328c2018-09-14 04:57:28 -06002085 def testFiles(self):
2086 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002087 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002088 self.assertEqual(FILES_DATA, data)
2089
2090 def testFilesCompress(self):
2091 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002092 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002093 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002094
2095 image = control.images['image']
2096 entries = image.GetEntries()
2097 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002098 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002099
Simon Glass303f62f2019-05-17 22:00:46 -06002100 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002101 for i in range(1, 3):
2102 key = '%d.dat' % i
2103 start = entries[key].image_pos
2104 len = entries[key].size
2105 chunk = data[start:start + len]
2106 orig += self._decompress(chunk)
2107
2108 self.assertEqual(FILES_DATA, orig)
2109
2110 def testFilesMissing(self):
2111 """Test missing files"""
2112 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002113 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002114 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2115 'no files', str(e.exception))
2116
2117 def testFilesNoPattern(self):
2118 """Test missing files"""
2119 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002120 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002121 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2122 str(e.exception))
2123
Simon Glassdd156a42022-03-05 20:18:59 -07002124 def testExtendSize(self):
2125 """Test an extending entry"""
2126 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002127 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002128 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2129 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2130 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2131 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002132 self.assertEqual(expect, data)
2133 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700213400000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600213500000000 00000000 00000008 fill
213600000008 00000008 00000004 u-boot
21370000000c 0000000c 00000004 section
21380000000c 00000000 00000003 intel-mrc
213900000010 00000010 00000004 u-boot2
214000000014 00000014 0000000c section2
214100000014 00000000 00000008 fill
21420000001c 00000008 00000004 u-boot
214300000020 00000020 00000008 fill2
2144''', map_data)
2145
Simon Glassdd156a42022-03-05 20:18:59 -07002146 def testExtendSizeBad(self):
2147 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002148 with test_util.capture_sys_output() as (stdout, stderr):
2149 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002150 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002151 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2152 'expanding entry', str(e.exception))
2153
Simon Glassae7cf032018-09-14 04:57:31 -06002154 def testHash(self):
2155 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002156 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002157 use_real_dtb=True, update_dtb=True)
2158 dtb = fdt.Fdt(out_dtb_fname)
2159 dtb.Scan()
2160 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2161 m = hashlib.sha256()
2162 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002163 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002164
2165 def testHashNoAlgo(self):
2166 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002167 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002168 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2169 'hash node', str(e.exception))
2170
2171 def testHashBadAlgo(self):
2172 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002173 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002174 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002175 str(e.exception))
2176
2177 def testHashSection(self):
2178 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002179 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002180 use_real_dtb=True, update_dtb=True)
2181 dtb = fdt.Fdt(out_dtb_fname)
2182 dtb.Scan()
2183 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2184 m = hashlib.sha256()
2185 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002186 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002187 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002188
Simon Glass3fb4f422018-09-14 04:57:32 -06002189 def testPackUBootTplMicrocode(self):
2190 """Test that x86 microcode can be handled correctly in TPL
2191
2192 We expect to see the following in the image, in order:
2193 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2194 place
2195 u-boot-tpl.dtb with the microcode removed
2196 the microcode
2197 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002198 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002199 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002200 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002201 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2202 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002203
Simon Glassc64aea52018-09-14 04:57:34 -06002204 def testFmapX86(self):
2205 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002206 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002207 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002208 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002209 self.assertEqual(expected, data[:32])
2210 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2211
2212 self.assertEqual(0x100, fhdr.image_size)
2213
2214 self.assertEqual(0, fentries[0].offset)
2215 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002216 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002217
2218 self.assertEqual(4, fentries[1].offset)
2219 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002220 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002221
2222 self.assertEqual(32, fentries[2].offset)
2223 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2224 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002225 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002226
2227 def testFmapX86Section(self):
2228 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002229 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002230 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002231 self.assertEqual(expected, data[:32])
2232 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2233
Simon Glassb1d414c2021-04-03 11:05:10 +13002234 self.assertEqual(0x180, fhdr.image_size)
2235 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002236 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002237
Simon Glass82059c22021-04-03 11:05:09 +13002238 fentry = next(fiter)
2239 self.assertEqual(b'U_BOOT', fentry.name)
2240 self.assertEqual(0, fentry.offset)
2241 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002242
Simon Glass82059c22021-04-03 11:05:09 +13002243 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002244 self.assertEqual(b'SECTION', fentry.name)
2245 self.assertEqual(4, fentry.offset)
2246 self.assertEqual(0x20 + expect_size, fentry.size)
2247
2248 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002249 self.assertEqual(b'INTEL_MRC', fentry.name)
2250 self.assertEqual(4, fentry.offset)
2251 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002252
Simon Glass82059c22021-04-03 11:05:09 +13002253 fentry = next(fiter)
2254 self.assertEqual(b'FMAP', fentry.name)
2255 self.assertEqual(36, fentry.offset)
2256 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002257
Simon Glassb1714232018-09-14 04:57:35 -06002258 def testElf(self):
2259 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002260 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002261 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002262 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002263 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002264 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002265
Simon Glass0d673792019-07-08 13:18:25 -06002266 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002267 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002268 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002269 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002270 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002271 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002272
Simon Glasscd817d52018-09-14 04:57:36 -06002273 def testPackOverlapMap(self):
2274 """Test that overlapping regions are detected"""
2275 with test_util.capture_sys_output() as (stdout, stderr):
2276 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002277 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002278 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002279 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2280 stdout.getvalue())
2281
2282 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002283 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002284 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002285 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002286 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002287<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002288<none> 00000000 00000004 u-boot
2289<none> 00000003 00000004 u-boot-align
2290''', map_data)
2291
Simon Glass0d673792019-07-08 13:18:25 -06002292 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002293 """Test that an image with an Intel Reference code binary works"""
2294 data = self._DoReadFile('100_intel_refcode.dts')
2295 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2296
Simon Glasseb023b32019-04-25 21:58:39 -06002297 def testSectionOffset(self):
2298 """Tests use of a section with an offset"""
2299 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2300 map=True)
2301 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700230200000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600230300000004 00000004 00000010 section@0
230400000004 00000000 00000004 u-boot
230500000018 00000018 00000010 section@1
230600000018 00000000 00000004 u-boot
23070000002c 0000002c 00000004 section@2
23080000002c 00000000 00000004 u-boot
2309''', map_data)
2310 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002311 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2312 tools.get_bytes(0x21, 12) +
2313 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2314 tools.get_bytes(0x61, 12) +
2315 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2316 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002317
Simon Glass1de34482019-07-08 13:18:53 -06002318 def testCbfsRaw(self):
2319 """Test base handling of a Coreboot Filesystem (CBFS)
2320
2321 The exact contents of the CBFS is verified by similar tests in
2322 cbfs_util_test.py. The tests here merely check that the files added to
2323 the CBFS can be found in the final image.
2324 """
2325 data = self._DoReadFile('102_cbfs_raw.dts')
2326 size = 0xb0
2327
2328 cbfs = cbfs_util.CbfsReader(data)
2329 self.assertEqual(size, cbfs.rom_size)
2330
2331 self.assertIn('u-boot-dtb', cbfs.files)
2332 cfile = cbfs.files['u-boot-dtb']
2333 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2334
2335 def testCbfsArch(self):
2336 """Test on non-x86 architecture"""
2337 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2338 size = 0x100
2339
2340 cbfs = cbfs_util.CbfsReader(data)
2341 self.assertEqual(size, cbfs.rom_size)
2342
2343 self.assertIn('u-boot-dtb', cbfs.files)
2344 cfile = cbfs.files['u-boot-dtb']
2345 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2346
2347 def testCbfsStage(self):
2348 """Tests handling of a Coreboot Filesystem (CBFS)"""
2349 if not elf.ELF_TOOLS:
2350 self.skipTest('Python elftools not available')
2351 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2352 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2353 size = 0xb0
2354
2355 data = self._DoReadFile('104_cbfs_stage.dts')
2356 cbfs = cbfs_util.CbfsReader(data)
2357 self.assertEqual(size, cbfs.rom_size)
2358
2359 self.assertIn('u-boot', cbfs.files)
2360 cfile = cbfs.files['u-boot']
2361 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2362
2363 def testCbfsRawCompress(self):
2364 """Test handling of compressing raw files"""
2365 self._CheckLz4()
2366 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2367 size = 0x140
2368
2369 cbfs = cbfs_util.CbfsReader(data)
2370 self.assertIn('u-boot', cbfs.files)
2371 cfile = cbfs.files['u-boot']
2372 self.assertEqual(COMPRESS_DATA, cfile.data)
2373
2374 def testCbfsBadArch(self):
2375 """Test handling of a bad architecture"""
2376 with self.assertRaises(ValueError) as e:
2377 self._DoReadFile('106_cbfs_bad_arch.dts')
2378 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2379
2380 def testCbfsNoSize(self):
2381 """Test handling of a missing size property"""
2382 with self.assertRaises(ValueError) as e:
2383 self._DoReadFile('107_cbfs_no_size.dts')
2384 self.assertIn('entry must have a size property', str(e.exception))
2385
Simon Glass3e28f4f2021-11-23 11:03:54 -07002386 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002387 """Test handling of a CBFS entry which does not provide contentsy"""
2388 with self.assertRaises(ValueError) as e:
2389 self._DoReadFile('108_cbfs_no_contents.dts')
2390 self.assertIn('Could not complete processing of contents',
2391 str(e.exception))
2392
2393 def testCbfsBadCompress(self):
2394 """Test handling of a bad architecture"""
2395 with self.assertRaises(ValueError) as e:
2396 self._DoReadFile('109_cbfs_bad_compress.dts')
2397 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2398 str(e.exception))
2399
2400 def testCbfsNamedEntries(self):
2401 """Test handling of named entries"""
2402 data = self._DoReadFile('110_cbfs_name.dts')
2403
2404 cbfs = cbfs_util.CbfsReader(data)
2405 self.assertIn('FRED', cbfs.files)
2406 cfile1 = cbfs.files['FRED']
2407 self.assertEqual(U_BOOT_DATA, cfile1.data)
2408
2409 self.assertIn('hello', cbfs.files)
2410 cfile2 = cbfs.files['hello']
2411 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2412
Simon Glass759af872019-07-08 13:18:54 -06002413 def _SetupIfwi(self, fname):
2414 """Set up to run an IFWI test
2415
2416 Args:
2417 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2418 """
2419 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002420 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002421
2422 # Intel Integrated Firmware Image (IFWI) file
2423 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2424 data = fd.read()
2425 TestFunctional._MakeInputFile(fname,data)
2426
2427 def _CheckIfwi(self, data):
2428 """Check that an image with an IFWI contains the correct output
2429
2430 Args:
2431 data: Conents of output file
2432 """
Simon Glass80025522022-01-29 14:14:04 -07002433 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002434 if data[:0x1000] != expected_desc:
2435 self.fail('Expected descriptor binary at start of image')
2436
2437 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002438 image_fname = tools.get_output_filename('image.bin')
2439 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002440 ifwitool = bintool.Bintool.create('ifwitool')
2441 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002442
Simon Glass80025522022-01-29 14:14:04 -07002443 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002444 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002445
2446 def testPackX86RomIfwi(self):
2447 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2448 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002449 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002450 self._CheckIfwi(data)
2451
2452 def testPackX86RomIfwiNoDesc(self):
2453 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2454 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002455 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002456 self._CheckIfwi(data)
2457
2458 def testPackX86RomIfwiNoData(self):
2459 """Test that an x86 ROM with IFWI handles missing data"""
2460 self._SetupIfwi('ifwi.bin')
2461 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002462 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002463 self.assertIn('Could not complete processing of contents',
2464 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002465
Simon Glass66152ce2022-01-09 20:14:09 -07002466 def testIfwiMissing(self):
2467 """Test that binman still produces an image if ifwitool is missing"""
2468 self._SetupIfwi('fitimage.bin')
2469 with test_util.capture_sys_output() as (_, stderr):
2470 self._DoTestFile('111_x86_rom_ifwi.dts',
2471 force_missing_bintools='ifwitool')
2472 err = stderr.getvalue()
2473 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002474 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002475
Simon Glassc2f1aed2019-07-08 13:18:56 -06002476 def testCbfsOffset(self):
2477 """Test a CBFS with files at particular offsets
2478
2479 Like all CFBS tests, this is just checking the logic that calls
2480 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2481 """
2482 data = self._DoReadFile('114_cbfs_offset.dts')
2483 size = 0x200
2484
2485 cbfs = cbfs_util.CbfsReader(data)
2486 self.assertEqual(size, cbfs.rom_size)
2487
2488 self.assertIn('u-boot', cbfs.files)
2489 cfile = cbfs.files['u-boot']
2490 self.assertEqual(U_BOOT_DATA, cfile.data)
2491 self.assertEqual(0x40, cfile.cbfs_offset)
2492
2493 self.assertIn('u-boot-dtb', cbfs.files)
2494 cfile2 = cbfs.files['u-boot-dtb']
2495 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2496 self.assertEqual(0x140, cfile2.cbfs_offset)
2497
Simon Glass0f621332019-07-08 14:25:27 -06002498 def testFdtmap(self):
2499 """Test an FDT map can be inserted in the image"""
2500 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2501 fdtmap_data = data[len(U_BOOT_DATA):]
2502 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002503 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002504 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002505
2506 fdt_data = fdtmap_data[16:]
2507 dtb = fdt.Fdt.FromData(fdt_data)
2508 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002509 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002510 self.assertEqual({
2511 'image-pos': 0,
2512 'offset': 0,
2513 'u-boot:offset': 0,
2514 'u-boot:size': len(U_BOOT_DATA),
2515 'u-boot:image-pos': 0,
2516 'fdtmap:image-pos': 4,
2517 'fdtmap:offset': 4,
2518 'fdtmap:size': len(fdtmap_data),
2519 'size': len(data),
2520 }, props)
2521
2522 def testFdtmapNoMatch(self):
2523 """Check handling of an FDT map when the section cannot be found"""
2524 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2525
2526 # Mangle the section name, which should cause a mismatch between the
2527 # correct FDT path and the one expected by the section
2528 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002529 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002530 entries = image.GetEntries()
2531 fdtmap = entries['fdtmap']
2532 with self.assertRaises(ValueError) as e:
2533 fdtmap._GetFdtmap()
2534 self.assertIn("Cannot locate node for path '/binman-suffix'",
2535 str(e.exception))
2536
Simon Glasscec34ba2019-07-08 14:25:28 -06002537 def testFdtmapHeader(self):
2538 """Test an FDT map and image header can be inserted in the image"""
2539 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2540 fdtmap_pos = len(U_BOOT_DATA)
2541 fdtmap_data = data[fdtmap_pos:]
2542 fdt_data = fdtmap_data[16:]
2543 dtb = fdt.Fdt.FromData(fdt_data)
2544 fdt_size = dtb.GetFdtObj().totalsize()
2545 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002546 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002547 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2548 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2549
2550 def testFdtmapHeaderStart(self):
2551 """Test an image header can be inserted at the image start"""
2552 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2553 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2554 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002555 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002556 offset = struct.unpack('<I', hdr_data[4:])[0]
2557 self.assertEqual(fdtmap_pos, offset)
2558
2559 def testFdtmapHeaderPos(self):
2560 """Test an image header can be inserted at a chosen position"""
2561 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2562 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2563 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002564 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002565 offset = struct.unpack('<I', hdr_data[4:])[0]
2566 self.assertEqual(fdtmap_pos, offset)
2567
2568 def testHeaderMissingFdtmap(self):
2569 """Test an image header requires an fdtmap"""
2570 with self.assertRaises(ValueError) as e:
2571 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2572 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2573 str(e.exception))
2574
2575 def testHeaderNoLocation(self):
2576 """Test an image header with a no specified location is detected"""
2577 with self.assertRaises(ValueError) as e:
2578 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2579 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2580 str(e.exception))
2581
Simon Glasse61b6f62019-07-08 14:25:37 -06002582 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002583 """Test extending an entry after it is packed"""
2584 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002585 self.assertEqual(b'aaa', data[:3])
2586 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2587 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002588
Simon Glassdd156a42022-03-05 20:18:59 -07002589 def testEntryExtendBad(self):
2590 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002591 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002592 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002593 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002594 str(e.exception))
2595
Simon Glassdd156a42022-03-05 20:18:59 -07002596 def testEntryExtendSection(self):
2597 """Test extending an entry within a section after it is packed"""
2598 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002599 self.assertEqual(b'aaa', data[:3])
2600 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2601 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002602
Simon Glass90d29682019-07-08 14:25:38 -06002603 def testCompressDtb(self):
2604 """Test that compress of device-tree files is supported"""
2605 self._CheckLz4()
2606 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2607 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2608 comp_data = data[len(U_BOOT_DATA):]
2609 orig = self._decompress(comp_data)
2610 dtb = fdt.Fdt.FromData(orig)
2611 dtb.Scan()
2612 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2613 expected = {
2614 'u-boot:size': len(U_BOOT_DATA),
2615 'u-boot-dtb:uncomp-size': len(orig),
2616 'u-boot-dtb:size': len(comp_data),
2617 'size': len(data),
2618 }
2619 self.assertEqual(expected, props)
2620
Simon Glass151bbbf2019-07-08 14:25:41 -06002621 def testCbfsUpdateFdt(self):
2622 """Test that we can update the device tree with CBFS offset/size info"""
2623 self._CheckLz4()
2624 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2625 update_dtb=True)
2626 dtb = fdt.Fdt(out_dtb_fname)
2627 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002628 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002629 del props['cbfs/u-boot:size']
2630 self.assertEqual({
2631 'offset': 0,
2632 'size': len(data),
2633 'image-pos': 0,
2634 'cbfs:offset': 0,
2635 'cbfs:size': len(data),
2636 'cbfs:image-pos': 0,
2637 'cbfs/u-boot:offset': 0x38,
2638 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2639 'cbfs/u-boot:image-pos': 0x38,
2640 'cbfs/u-boot-dtb:offset': 0xb8,
2641 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2642 'cbfs/u-boot-dtb:image-pos': 0xb8,
2643 }, props)
2644
Simon Glass3c9b4f22019-07-08 14:25:42 -06002645 def testCbfsBadType(self):
2646 """Test an image header with a no specified location is detected"""
2647 with self.assertRaises(ValueError) as e:
2648 self._DoReadFile('126_cbfs_bad_type.dts')
2649 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2650
Simon Glass6b156f82019-07-08 14:25:43 -06002651 def testList(self):
2652 """Test listing the files in an image"""
2653 self._CheckLz4()
2654 data = self._DoReadFile('127_list.dts')
2655 image = control.images['image']
2656 entries = image.BuildEntryList()
2657 self.assertEqual(7, len(entries))
2658
2659 ent = entries[0]
2660 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002661 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002662 self.assertEqual('section', ent.etype)
2663 self.assertEqual(len(data), ent.size)
2664 self.assertEqual(0, ent.image_pos)
2665 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002666 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002667
2668 ent = entries[1]
2669 self.assertEqual(1, ent.indent)
2670 self.assertEqual('u-boot', ent.name)
2671 self.assertEqual('u-boot', ent.etype)
2672 self.assertEqual(len(U_BOOT_DATA), ent.size)
2673 self.assertEqual(0, ent.image_pos)
2674 self.assertEqual(None, ent.uncomp_size)
2675 self.assertEqual(0, ent.offset)
2676
2677 ent = entries[2]
2678 self.assertEqual(1, ent.indent)
2679 self.assertEqual('section', ent.name)
2680 self.assertEqual('section', ent.etype)
2681 section_size = ent.size
2682 self.assertEqual(0x100, ent.image_pos)
2683 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002684 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002685
2686 ent = entries[3]
2687 self.assertEqual(2, ent.indent)
2688 self.assertEqual('cbfs', ent.name)
2689 self.assertEqual('cbfs', ent.etype)
2690 self.assertEqual(0x400, ent.size)
2691 self.assertEqual(0x100, ent.image_pos)
2692 self.assertEqual(None, ent.uncomp_size)
2693 self.assertEqual(0, ent.offset)
2694
2695 ent = entries[4]
2696 self.assertEqual(3, ent.indent)
2697 self.assertEqual('u-boot', ent.name)
2698 self.assertEqual('u-boot', ent.etype)
2699 self.assertEqual(len(U_BOOT_DATA), ent.size)
2700 self.assertEqual(0x138, ent.image_pos)
2701 self.assertEqual(None, ent.uncomp_size)
2702 self.assertEqual(0x38, ent.offset)
2703
2704 ent = entries[5]
2705 self.assertEqual(3, ent.indent)
2706 self.assertEqual('u-boot-dtb', ent.name)
2707 self.assertEqual('text', ent.etype)
2708 self.assertGreater(len(COMPRESS_DATA), ent.size)
2709 self.assertEqual(0x178, ent.image_pos)
2710 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2711 self.assertEqual(0x78, ent.offset)
2712
2713 ent = entries[6]
2714 self.assertEqual(2, ent.indent)
2715 self.assertEqual('u-boot-dtb', ent.name)
2716 self.assertEqual('u-boot-dtb', ent.etype)
2717 self.assertEqual(0x500, ent.image_pos)
2718 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2719 dtb_size = ent.size
2720 # Compressing this data expands it since headers are added
2721 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2722 self.assertEqual(0x400, ent.offset)
2723
2724 self.assertEqual(len(data), 0x100 + section_size)
2725 self.assertEqual(section_size, 0x400 + dtb_size)
2726
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002727 def testFindFdtmap(self):
2728 """Test locating an FDT map in an image"""
2729 self._CheckLz4()
2730 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2731 image = control.images['image']
2732 entries = image.GetEntries()
2733 entry = entries['fdtmap']
2734 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2735
2736 def testFindFdtmapMissing(self):
2737 """Test failing to locate an FDP map"""
2738 data = self._DoReadFile('005_simple.dts')
2739 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2740
Simon Glassed39a3c2019-07-08 14:25:45 -06002741 def testFindImageHeader(self):
2742 """Test locating a image header"""
2743 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002744 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002745 image = control.images['image']
2746 entries = image.GetEntries()
2747 entry = entries['fdtmap']
2748 # The header should point to the FDT map
2749 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2750
2751 def testFindImageHeaderStart(self):
2752 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002753 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002754 image = control.images['image']
2755 entries = image.GetEntries()
2756 entry = entries['fdtmap']
2757 # The header should point to the FDT map
2758 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2759
2760 def testFindImageHeaderMissing(self):
2761 """Test failing to locate an image header"""
2762 data = self._DoReadFile('005_simple.dts')
2763 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2764
Simon Glassb8424fa2019-07-08 14:25:46 -06002765 def testReadImage(self):
2766 """Test reading an image and accessing its FDT map"""
2767 self._CheckLz4()
2768 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002769 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002770 orig_image = control.images['image']
2771 image = Image.FromFile(image_fname)
2772 self.assertEqual(orig_image.GetEntries().keys(),
2773 image.GetEntries().keys())
2774
2775 orig_entry = orig_image.GetEntries()['fdtmap']
2776 entry = image.GetEntries()['fdtmap']
2777 self.assertEquals(orig_entry.offset, entry.offset)
2778 self.assertEquals(orig_entry.size, entry.size)
2779 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2780
2781 def testReadImageNoHeader(self):
2782 """Test accessing an image's FDT map without an image header"""
2783 self._CheckLz4()
2784 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002785 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002786 image = Image.FromFile(image_fname)
2787 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002788 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002789
2790 def testReadImageFail(self):
2791 """Test failing to read an image image's FDT map"""
2792 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002793 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002794 with self.assertRaises(ValueError) as e:
2795 image = Image.FromFile(image_fname)
2796 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002797
Simon Glassb2fd11d2019-07-08 14:25:48 -06002798 def testListCmd(self):
2799 """Test listing the files in an image using an Fdtmap"""
2800 self._CheckLz4()
2801 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2802
2803 # lz4 compression size differs depending on the version
2804 image = control.images['image']
2805 entries = image.GetEntries()
2806 section_size = entries['section'].size
2807 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2808 fdtmap_offset = entries['fdtmap'].offset
2809
Simon Glassb3d6fc72019-07-20 12:24:10 -06002810 try:
2811 tmpdir, updated_fname = self._SetupImageInTmpdir()
2812 with test_util.capture_sys_output() as (stdout, stderr):
2813 self._DoBinman('ls', '-i', updated_fname)
2814 finally:
2815 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002816 lines = stdout.getvalue().splitlines()
2817 expected = [
2818'Name Image-pos Size Entry-type Offset Uncomp-size',
2819'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002820'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002821' u-boot 0 4 u-boot 0',
2822' section 100 %x section 100' % section_size,
2823' cbfs 100 400 cbfs 0',
2824' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002825' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002826' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002827' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002828 (fdtmap_offset, fdtmap_offset),
2829' image-header bf8 8 image-header bf8',
2830 ]
2831 self.assertEqual(expected, lines)
2832
2833 def testListCmdFail(self):
2834 """Test failing to list an image"""
2835 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002836 try:
2837 tmpdir, updated_fname = self._SetupImageInTmpdir()
2838 with self.assertRaises(ValueError) as e:
2839 self._DoBinman('ls', '-i', updated_fname)
2840 finally:
2841 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002842 self.assertIn("Cannot find FDT map in image", str(e.exception))
2843
2844 def _RunListCmd(self, paths, expected):
2845 """List out entries and check the result
2846
2847 Args:
2848 paths: List of paths to pass to the list command
2849 expected: Expected list of filenames to be returned, in order
2850 """
2851 self._CheckLz4()
2852 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002853 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002854 image = Image.FromFile(image_fname)
2855 lines = image.GetListEntries(paths)[1]
2856 files = [line[0].strip() for line in lines[1:]]
2857 self.assertEqual(expected, files)
2858
2859 def testListCmdSection(self):
2860 """Test listing the files in a section"""
2861 self._RunListCmd(['section'],
2862 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2863
2864 def testListCmdFile(self):
2865 """Test listing a particular file"""
2866 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2867
2868 def testListCmdWildcard(self):
2869 """Test listing a wildcarded file"""
2870 self._RunListCmd(['*boot*'],
2871 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2872
2873 def testListCmdWildcardMulti(self):
2874 """Test listing a wildcarded file"""
2875 self._RunListCmd(['*cb*', '*head*'],
2876 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2877
2878 def testListCmdEmpty(self):
2879 """Test listing a wildcarded file"""
2880 self._RunListCmd(['nothing'], [])
2881
2882 def testListCmdPath(self):
2883 """Test listing the files in a sub-entry of a section"""
2884 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2885
Simon Glass4c613bf2019-07-08 14:25:50 -06002886 def _RunExtractCmd(self, entry_name, decomp=True):
2887 """Extract an entry from an image
2888
2889 Args:
2890 entry_name: Entry name to extract
2891 decomp: True to decompress the data if compressed, False to leave
2892 it in its raw uncompressed format
2893
2894 Returns:
2895 data from entry
2896 """
2897 self._CheckLz4()
2898 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002899 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002900 return control.ReadEntry(image_fname, entry_name, decomp)
2901
2902 def testExtractSimple(self):
2903 """Test extracting a single file"""
2904 data = self._RunExtractCmd('u-boot')
2905 self.assertEqual(U_BOOT_DATA, data)
2906
Simon Glass980a2842019-07-08 14:25:52 -06002907 def testExtractSection(self):
2908 """Test extracting the files in a section"""
2909 data = self._RunExtractCmd('section')
2910 cbfs_data = data[:0x400]
2911 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002912 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002913 dtb_data = data[0x400:]
2914 dtb = self._decompress(dtb_data)
2915 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2916
2917 def testExtractCompressed(self):
2918 """Test extracting compressed data"""
2919 data = self._RunExtractCmd('section/u-boot-dtb')
2920 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2921
2922 def testExtractRaw(self):
2923 """Test extracting compressed data without decompressing it"""
2924 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2925 dtb = self._decompress(data)
2926 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2927
2928 def testExtractCbfs(self):
2929 """Test extracting CBFS data"""
2930 data = self._RunExtractCmd('section/cbfs/u-boot')
2931 self.assertEqual(U_BOOT_DATA, data)
2932
2933 def testExtractCbfsCompressed(self):
2934 """Test extracting CBFS compressed data"""
2935 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2936 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2937
2938 def testExtractCbfsRaw(self):
2939 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002940 bintool = self.comp_bintools['lzma_alone']
2941 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06002942 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002943 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06002944 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2945
Simon Glass4c613bf2019-07-08 14:25:50 -06002946 def testExtractBadEntry(self):
2947 """Test extracting a bad section path"""
2948 with self.assertRaises(ValueError) as e:
2949 self._RunExtractCmd('section/does-not-exist')
2950 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2951 str(e.exception))
2952
2953 def testExtractMissingFile(self):
2954 """Test extracting file that does not exist"""
2955 with self.assertRaises(IOError) as e:
2956 control.ReadEntry('missing-file', 'name')
2957
2958 def testExtractBadFile(self):
2959 """Test extracting an invalid file"""
2960 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002961 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002962 with self.assertRaises(ValueError) as e:
2963 control.ReadEntry(fname, 'name')
2964
Simon Glass980a2842019-07-08 14:25:52 -06002965 def testExtractCmd(self):
2966 """Test extracting a file fron an image on the command line"""
2967 self._CheckLz4()
2968 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002969 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002970 try:
2971 tmpdir, updated_fname = self._SetupImageInTmpdir()
2972 with test_util.capture_sys_output() as (stdout, stderr):
2973 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2974 '-f', fname)
2975 finally:
2976 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07002977 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002978 self.assertEqual(U_BOOT_DATA, data)
2979
2980 def testExtractOneEntry(self):
2981 """Test extracting a single entry fron an image """
2982 self._CheckLz4()
2983 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002984 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002985 fname = os.path.join(self._indir, 'output.extact')
2986 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07002987 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002988 self.assertEqual(U_BOOT_DATA, data)
2989
2990 def _CheckExtractOutput(self, decomp):
2991 """Helper to test file output with and without decompression
2992
2993 Args:
2994 decomp: True to decompress entry data, False to output it raw
2995 """
2996 def _CheckPresent(entry_path, expect_data, expect_size=None):
2997 """Check and remove expected file
2998
2999 This checks the data/size of a file and removes the file both from
3000 the outfiles set and from the output directory. Once all files are
3001 processed, both the set and directory should be empty.
3002
3003 Args:
3004 entry_path: Entry path
3005 expect_data: Data to expect in file, or None to skip check
3006 expect_size: Size of data to expect in file, or None to skip
3007 """
3008 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003009 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003010 os.remove(path)
3011 if expect_data:
3012 self.assertEqual(expect_data, data)
3013 elif expect_size:
3014 self.assertEqual(expect_size, len(data))
3015 outfiles.remove(path)
3016
3017 def _CheckDirPresent(name):
3018 """Remove expected directory
3019
3020 This gives an error if the directory does not exist as expected
3021
3022 Args:
3023 name: Name of directory to remove
3024 """
3025 path = os.path.join(outdir, name)
3026 os.rmdir(path)
3027
3028 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003029 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003030 outdir = os.path.join(self._indir, 'extract')
3031 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3032
3033 # Create a set of all file that were output (should be 9)
3034 outfiles = set()
3035 for root, dirs, files in os.walk(outdir):
3036 outfiles |= set([os.path.join(root, fname) for fname in files])
3037 self.assertEqual(9, len(outfiles))
3038 self.assertEqual(9, len(einfos))
3039
3040 image = control.images['image']
3041 entries = image.GetEntries()
3042
3043 # Check the 9 files in various ways
3044 section = entries['section']
3045 section_entries = section.GetEntries()
3046 cbfs_entries = section_entries['cbfs'].GetEntries()
3047 _CheckPresent('u-boot', U_BOOT_DATA)
3048 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3049 dtb_len = EXTRACT_DTB_SIZE
3050 if not decomp:
3051 dtb_len = cbfs_entries['u-boot-dtb'].size
3052 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3053 if not decomp:
3054 dtb_len = section_entries['u-boot-dtb'].size
3055 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3056
3057 fdtmap = entries['fdtmap']
3058 _CheckPresent('fdtmap', fdtmap.data)
3059 hdr = entries['image-header']
3060 _CheckPresent('image-header', hdr.data)
3061
3062 _CheckPresent('section/root', section.data)
3063 cbfs = section_entries['cbfs']
3064 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003065 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003066 _CheckPresent('root', data)
3067
3068 # There should be no files left. Remove all the directories to check.
3069 # If there are any files/dirs remaining, one of these checks will fail.
3070 self.assertEqual(0, len(outfiles))
3071 _CheckDirPresent('section/cbfs')
3072 _CheckDirPresent('section')
3073 _CheckDirPresent('')
3074 self.assertFalse(os.path.exists(outdir))
3075
3076 def testExtractAllEntries(self):
3077 """Test extracting all entries"""
3078 self._CheckLz4()
3079 self._CheckExtractOutput(decomp=True)
3080
3081 def testExtractAllEntriesRaw(self):
3082 """Test extracting all entries without decompressing them"""
3083 self._CheckLz4()
3084 self._CheckExtractOutput(decomp=False)
3085
3086 def testExtractSelectedEntries(self):
3087 """Test extracting some entries"""
3088 self._CheckLz4()
3089 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003090 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003091 outdir = os.path.join(self._indir, 'extract')
3092 einfos = control.ExtractEntries(image_fname, None, outdir,
3093 ['*cb*', '*head*'])
3094
3095 # File output is tested by testExtractAllEntries(), so just check that
3096 # the expected entries are selected
3097 names = [einfo.name for einfo in einfos]
3098 self.assertEqual(names,
3099 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3100
3101 def testExtractNoEntryPaths(self):
3102 """Test extracting some entries"""
3103 self._CheckLz4()
3104 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003105 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003106 with self.assertRaises(ValueError) as e:
3107 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003108 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003109 str(e.exception))
3110
3111 def testExtractTooManyEntryPaths(self):
3112 """Test extracting some entries"""
3113 self._CheckLz4()
3114 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003115 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003116 with self.assertRaises(ValueError) as e:
3117 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003118 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003119 str(e.exception))
3120
Simon Glass52d06212019-07-08 14:25:53 -06003121 def testPackAlignSection(self):
3122 """Test that sections can have alignment"""
3123 self._DoReadFile('131_pack_align_section.dts')
3124
3125 self.assertIn('image', control.images)
3126 image = control.images['image']
3127 entries = image.GetEntries()
3128 self.assertEqual(3, len(entries))
3129
3130 # First u-boot
3131 self.assertIn('u-boot', entries)
3132 entry = entries['u-boot']
3133 self.assertEqual(0, entry.offset)
3134 self.assertEqual(0, entry.image_pos)
3135 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3136 self.assertEqual(len(U_BOOT_DATA), entry.size)
3137
3138 # Section0
3139 self.assertIn('section0', entries)
3140 section0 = entries['section0']
3141 self.assertEqual(0x10, section0.offset)
3142 self.assertEqual(0x10, section0.image_pos)
3143 self.assertEqual(len(U_BOOT_DATA), section0.size)
3144
3145 # Second u-boot
3146 section_entries = section0.GetEntries()
3147 self.assertIn('u-boot', section_entries)
3148 entry = section_entries['u-boot']
3149 self.assertEqual(0, entry.offset)
3150 self.assertEqual(0x10, entry.image_pos)
3151 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3152 self.assertEqual(len(U_BOOT_DATA), entry.size)
3153
3154 # Section1
3155 self.assertIn('section1', entries)
3156 section1 = entries['section1']
3157 self.assertEqual(0x14, section1.offset)
3158 self.assertEqual(0x14, section1.image_pos)
3159 self.assertEqual(0x20, section1.size)
3160
3161 # Second u-boot
3162 section_entries = section1.GetEntries()
3163 self.assertIn('u-boot', section_entries)
3164 entry = section_entries['u-boot']
3165 self.assertEqual(0, entry.offset)
3166 self.assertEqual(0x14, entry.image_pos)
3167 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3168 self.assertEqual(len(U_BOOT_DATA), entry.size)
3169
3170 # Section2
3171 self.assertIn('section2', section_entries)
3172 section2 = section_entries['section2']
3173 self.assertEqual(0x4, section2.offset)
3174 self.assertEqual(0x18, section2.image_pos)
3175 self.assertEqual(4, section2.size)
3176
3177 # Third u-boot
3178 section_entries = section2.GetEntries()
3179 self.assertIn('u-boot', section_entries)
3180 entry = section_entries['u-boot']
3181 self.assertEqual(0, entry.offset)
3182 self.assertEqual(0x18, entry.image_pos)
3183 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3184 self.assertEqual(len(U_BOOT_DATA), entry.size)
3185
Simon Glassf8a54bc2019-07-20 12:23:56 -06003186 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3187 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003188 """Replace an entry in an image
3189
3190 This writes the entry data to update it, then opens the updated file and
3191 returns the value that it now finds there.
3192
3193 Args:
3194 entry_name: Entry name to replace
3195 data: Data to replace it with
3196 decomp: True to compress the data if needed, False if data is
3197 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003198 allow_resize: True to allow entries to change size, False to raise
3199 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003200
3201 Returns:
3202 Tuple:
3203 data from entry
3204 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003205 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003206 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003207 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003208 update_dtb=True)[1]
3209
3210 self.assertIn('image', control.images)
3211 image = control.images['image']
3212 entries = image.GetEntries()
3213 orig_dtb_data = entries['u-boot-dtb'].data
3214 orig_fdtmap_data = entries['fdtmap'].data
3215
Simon Glass80025522022-01-29 14:14:04 -07003216 image_fname = tools.get_output_filename('image.bin')
3217 updated_fname = tools.get_output_filename('image-updated.bin')
3218 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003219 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3220 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003221 data = control.ReadEntry(updated_fname, entry_name, decomp)
3222
Simon Glassf8a54bc2019-07-20 12:23:56 -06003223 # The DT data should not change unless resized:
3224 if not allow_resize:
3225 new_dtb_data = entries['u-boot-dtb'].data
3226 self.assertEqual(new_dtb_data, orig_dtb_data)
3227 new_fdtmap_data = entries['fdtmap'].data
3228 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003229
Simon Glassf8a54bc2019-07-20 12:23:56 -06003230 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003231
3232 def testReplaceSimple(self):
3233 """Test replacing a single file"""
3234 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003235 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3236 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003237 self.assertEqual(expected, data)
3238
3239 # Test that the state looks right. There should be an FDT for the fdtmap
3240 # that we jsut read back in, and it should match what we find in the
3241 # 'control' tables. Checking for an FDT that does not exist should
3242 # return None.
3243 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003244 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003245 self.assertEqual(expected_fdtmap, fdtmap)
3246
3247 dtb = state.GetFdtForEtype('fdtmap')
3248 self.assertEqual(dtb.GetContents(), fdtmap)
3249
3250 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3251 self.assertIsNone(missing_path)
3252 self.assertIsNone(missing_fdtmap)
3253
3254 missing_dtb = state.GetFdtForEtype('missing')
3255 self.assertIsNone(missing_dtb)
3256
3257 self.assertEqual('/binman', state.fdt_path_prefix)
3258
3259 def testReplaceResizeFail(self):
3260 """Test replacing a file by something larger"""
3261 expected = U_BOOT_DATA + b'x'
3262 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003263 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3264 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003265 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3266 str(e.exception))
3267
3268 def testReplaceMulti(self):
3269 """Test replacing entry data where multiple images are generated"""
3270 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3271 update_dtb=True)[0]
3272 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003273 updated_fname = tools.get_output_filename('image-updated.bin')
3274 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003275 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003276 control.WriteEntry(updated_fname, entry_name, expected,
3277 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003278 data = control.ReadEntry(updated_fname, entry_name)
3279 self.assertEqual(expected, data)
3280
3281 # Check the state looks right.
3282 self.assertEqual('/binman/image', state.fdt_path_prefix)
3283
3284 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003285 image_fname = tools.get_output_filename('first-image.bin')
3286 updated_fname = tools.get_output_filename('first-updated.bin')
3287 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003288 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003289 control.WriteEntry(updated_fname, entry_name, expected,
3290 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003291 data = control.ReadEntry(updated_fname, entry_name)
3292 self.assertEqual(expected, data)
3293
3294 # Check the state looks right.
3295 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003296
Simon Glassfb30e292019-07-20 12:23:51 -06003297 def testUpdateFdtAllRepack(self):
3298 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003299 self._SetupSplElf()
3300 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003301 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3302 SECTION_SIZE = 0x300
3303 DTB_SIZE = 602
3304 FDTMAP_SIZE = 608
3305 base_expected = {
3306 'offset': 0,
3307 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3308 'image-pos': 0,
3309 'section:offset': 0,
3310 'section:size': SECTION_SIZE,
3311 'section:image-pos': 0,
3312 'section/u-boot-dtb:offset': 4,
3313 'section/u-boot-dtb:size': 636,
3314 'section/u-boot-dtb:image-pos': 4,
3315 'u-boot-spl-dtb:offset': SECTION_SIZE,
3316 'u-boot-spl-dtb:size': DTB_SIZE,
3317 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3318 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3319 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3320 'u-boot-tpl-dtb:size': DTB_SIZE,
3321 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3322 'fdtmap:size': FDTMAP_SIZE,
3323 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3324 }
3325 main_expected = {
3326 'section:orig-size': SECTION_SIZE,
3327 'section/u-boot-dtb:orig-offset': 4,
3328 }
3329
3330 # We expect three device-tree files in the output, with the first one
3331 # within a fixed-size section.
3332 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3333 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3334 # main U-Boot tree. All three should have the same positions and offset
3335 # except that the main tree should include the main_expected properties
3336 start = 4
3337 for item in ['', 'spl', 'tpl', None]:
3338 if item is None:
3339 start += 16 # Move past fdtmap header
3340 dtb = fdt.Fdt.FromData(data[start:])
3341 dtb.Scan()
3342 props = self._GetPropTree(dtb,
3343 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3344 prefix='/' if item is None else '/binman/')
3345 expected = dict(base_expected)
3346 if item:
3347 expected[item] = 0
3348 else:
3349 # Main DTB and fdtdec should include the 'orig-' properties
3350 expected.update(main_expected)
3351 # Helpful for debugging:
3352 #for prop in sorted(props):
3353 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3354 self.assertEqual(expected, props)
3355 if item == '':
3356 start = SECTION_SIZE
3357 else:
3358 start += dtb._fdt_obj.totalsize()
3359
Simon Glass11453762019-07-20 12:23:55 -06003360 def testFdtmapHeaderMiddle(self):
3361 """Test an FDT map in the middle of an image when it should be at end"""
3362 with self.assertRaises(ValueError) as e:
3363 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3364 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3365 str(e.exception))
3366
3367 def testFdtmapHeaderStartBad(self):
3368 """Test an FDT map in middle of an image when it should be at start"""
3369 with self.assertRaises(ValueError) as e:
3370 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3371 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3372 str(e.exception))
3373
3374 def testFdtmapHeaderEndBad(self):
3375 """Test an FDT map at the start of an image when it should be at end"""
3376 with self.assertRaises(ValueError) as e:
3377 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3378 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3379 str(e.exception))
3380
3381 def testFdtmapHeaderNoSize(self):
3382 """Test an image header at the end of an image with undefined size"""
3383 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3384
Simon Glassf8a54bc2019-07-20 12:23:56 -06003385 def testReplaceResize(self):
3386 """Test replacing a single file in an entry with a larger file"""
3387 expected = U_BOOT_DATA + b'x'
3388 data, _, image = self._RunReplaceCmd('u-boot', expected,
3389 dts='139_replace_repack.dts')
3390 self.assertEqual(expected, data)
3391
3392 entries = image.GetEntries()
3393 dtb_data = entries['u-boot-dtb'].data
3394 dtb = fdt.Fdt.FromData(dtb_data)
3395 dtb.Scan()
3396
3397 # The u-boot section should now be larger in the dtb
3398 node = dtb.GetNode('/binman/u-boot')
3399 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3400
3401 # Same for the fdtmap
3402 fdata = entries['fdtmap'].data
3403 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3404 fdtb.Scan()
3405 fnode = fdtb.GetNode('/u-boot')
3406 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3407
3408 def testReplaceResizeNoRepack(self):
3409 """Test replacing an entry with a larger file when not allowed"""
3410 expected = U_BOOT_DATA + b'x'
3411 with self.assertRaises(ValueError) as e:
3412 self._RunReplaceCmd('u-boot', expected)
3413 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3414 str(e.exception))
3415
Simon Glass9d8ee322019-07-20 12:23:58 -06003416 def testEntryShrink(self):
3417 """Test contracting an entry after it is packed"""
3418 try:
3419 state.SetAllowEntryContraction(True)
3420 data = self._DoReadFileDtb('140_entry_shrink.dts',
3421 update_dtb=True)[0]
3422 finally:
3423 state.SetAllowEntryContraction(False)
3424 self.assertEqual(b'a', data[:1])
3425 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3426 self.assertEqual(b'a', data[-1:])
3427
3428 def testEntryShrinkFail(self):
3429 """Test not being allowed to contract an entry after it is packed"""
3430 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3431
3432 # In this case there is a spare byte at the end of the data. The size of
3433 # the contents is only 1 byte but we still have the size before it
3434 # shrunk.
3435 self.assertEqual(b'a\0', data[:2])
3436 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3437 self.assertEqual(b'a\0', data[-2:])
3438
Simon Glass70e32982019-07-20 12:24:01 -06003439 def testDescriptorOffset(self):
3440 """Test that the Intel descriptor is always placed at at the start"""
3441 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3442 image = control.images['image']
3443 entries = image.GetEntries()
3444 desc = entries['intel-descriptor']
3445 self.assertEqual(0xff800000, desc.offset);
3446 self.assertEqual(0xff800000, desc.image_pos);
3447
Simon Glass37fdd142019-07-20 12:24:06 -06003448 def testReplaceCbfs(self):
3449 """Test replacing a single file in CBFS without changing the size"""
3450 self._CheckLz4()
3451 expected = b'x' * len(U_BOOT_DATA)
3452 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003453 updated_fname = tools.get_output_filename('image-updated.bin')
3454 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003455 entry_name = 'section/cbfs/u-boot'
3456 control.WriteEntry(updated_fname, entry_name, expected,
3457 allow_resize=True)
3458 data = control.ReadEntry(updated_fname, entry_name)
3459 self.assertEqual(expected, data)
3460
3461 def testReplaceResizeCbfs(self):
3462 """Test replacing a single file in CBFS with one of a different size"""
3463 self._CheckLz4()
3464 expected = U_BOOT_DATA + b'x'
3465 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003466 updated_fname = tools.get_output_filename('image-updated.bin')
3467 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003468 entry_name = 'section/cbfs/u-boot'
3469 control.WriteEntry(updated_fname, entry_name, expected,
3470 allow_resize=True)
3471 data = control.ReadEntry(updated_fname, entry_name)
3472 self.assertEqual(expected, data)
3473
Simon Glass30033c22019-07-20 12:24:15 -06003474 def _SetupForReplace(self):
3475 """Set up some files to use to replace entries
3476
3477 This generates an image, copies it to a new file, extracts all the files
3478 in it and updates some of them
3479
3480 Returns:
3481 List
3482 Image filename
3483 Output directory
3484 Expected values for updated entries, each a string
3485 """
3486 data = self._DoReadFileRealDtb('143_replace_all.dts')
3487
Simon Glass80025522022-01-29 14:14:04 -07003488 updated_fname = tools.get_output_filename('image-updated.bin')
3489 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003490
3491 outdir = os.path.join(self._indir, 'extract')
3492 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3493
3494 expected1 = b'x' + U_BOOT_DATA + b'y'
3495 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003496 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003497
3498 expected2 = b'a' + U_BOOT_DATA + b'b'
3499 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003500 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003501
3502 expected_text = b'not the same text'
3503 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003504 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003505
3506 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3507 dtb = fdt.FdtScan(dtb_fname)
3508 node = dtb.GetNode('/binman/text')
3509 node.AddString('my-property', 'the value')
3510 dtb.Sync(auto_resize=True)
3511 dtb.Flush()
3512
3513 return updated_fname, outdir, expected1, expected2, expected_text
3514
3515 def _CheckReplaceMultiple(self, entry_paths):
3516 """Handle replacing the contents of multiple entries
3517
3518 Args:
3519 entry_paths: List of entry paths to replace
3520
3521 Returns:
3522 List
3523 Dict of entries in the image:
3524 key: Entry name
3525 Value: Entry object
3526 Expected values for updated entries, each a string
3527 """
3528 updated_fname, outdir, expected1, expected2, expected_text = (
3529 self._SetupForReplace())
3530 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3531
3532 image = Image.FromFile(updated_fname)
3533 image.LoadData()
3534 return image.GetEntries(), expected1, expected2, expected_text
3535
3536 def testReplaceAll(self):
3537 """Test replacing the contents of all entries"""
3538 entries, expected1, expected2, expected_text = (
3539 self._CheckReplaceMultiple([]))
3540 data = entries['u-boot'].data
3541 self.assertEqual(expected1, data)
3542
3543 data = entries['u-boot2'].data
3544 self.assertEqual(expected2, data)
3545
3546 data = entries['text'].data
3547 self.assertEqual(expected_text, data)
3548
3549 # Check that the device tree is updated
3550 data = entries['u-boot-dtb'].data
3551 dtb = fdt.Fdt.FromData(data)
3552 dtb.Scan()
3553 node = dtb.GetNode('/binman/text')
3554 self.assertEqual('the value', node.props['my-property'].value)
3555
3556 def testReplaceSome(self):
3557 """Test replacing the contents of a few entries"""
3558 entries, expected1, expected2, expected_text = (
3559 self._CheckReplaceMultiple(['u-boot2', 'text']))
3560
3561 # This one should not change
3562 data = entries['u-boot'].data
3563 self.assertEqual(U_BOOT_DATA, data)
3564
3565 data = entries['u-boot2'].data
3566 self.assertEqual(expected2, data)
3567
3568 data = entries['text'].data
3569 self.assertEqual(expected_text, data)
3570
3571 def testReplaceCmd(self):
3572 """Test replacing a file fron an image on the command line"""
3573 self._DoReadFileRealDtb('143_replace_all.dts')
3574
3575 try:
3576 tmpdir, updated_fname = self._SetupImageInTmpdir()
3577
3578 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3579 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003580 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003581
3582 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003583 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003584 self.assertEqual(expected, data[:len(expected)])
3585 map_fname = os.path.join(tmpdir, 'image-updated.map')
3586 self.assertFalse(os.path.exists(map_fname))
3587 finally:
3588 shutil.rmtree(tmpdir)
3589
3590 def testReplaceCmdSome(self):
3591 """Test replacing some files fron an image on the command line"""
3592 updated_fname, outdir, expected1, expected2, expected_text = (
3593 self._SetupForReplace())
3594
3595 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3596 'u-boot2', 'text')
3597
Simon Glass80025522022-01-29 14:14:04 -07003598 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003599 image = Image.FromFile(updated_fname)
3600 image.LoadData()
3601 entries = image.GetEntries()
3602
3603 # This one should not change
3604 data = entries['u-boot'].data
3605 self.assertEqual(U_BOOT_DATA, data)
3606
3607 data = entries['u-boot2'].data
3608 self.assertEqual(expected2, data)
3609
3610 data = entries['text'].data
3611 self.assertEqual(expected_text, data)
3612
3613 def testReplaceMissing(self):
3614 """Test replacing entries where the file is missing"""
3615 updated_fname, outdir, expected1, expected2, expected_text = (
3616 self._SetupForReplace())
3617
3618 # Remove one of the files, to generate a warning
3619 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3620 os.remove(u_boot_fname1)
3621
3622 with test_util.capture_sys_output() as (stdout, stderr):
3623 control.ReplaceEntries(updated_fname, None, outdir, [])
3624 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003625 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003626
3627 def testReplaceCmdMap(self):
3628 """Test replacing a file fron an image on the command line"""
3629 self._DoReadFileRealDtb('143_replace_all.dts')
3630
3631 try:
3632 tmpdir, updated_fname = self._SetupImageInTmpdir()
3633
3634 fname = os.path.join(self._indir, 'update-u-boot.bin')
3635 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003636 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003637
3638 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3639 '-f', fname, '-m')
3640 map_fname = os.path.join(tmpdir, 'image-updated.map')
3641 self.assertTrue(os.path.exists(map_fname))
3642 finally:
3643 shutil.rmtree(tmpdir)
3644
3645 def testReplaceNoEntryPaths(self):
3646 """Test replacing an entry without an entry path"""
3647 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003648 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003649 with self.assertRaises(ValueError) as e:
3650 control.ReplaceEntries(image_fname, 'fname', None, [])
3651 self.assertIn('Must specify an entry path to read with -f',
3652 str(e.exception))
3653
3654 def testReplaceTooManyEntryPaths(self):
3655 """Test extracting some entries"""
3656 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003657 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003658 with self.assertRaises(ValueError) as e:
3659 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3660 self.assertIn('Must specify exactly one entry path to write with -f',
3661 str(e.exception))
3662
Simon Glass0b074d62019-08-24 07:22:48 -06003663 def testPackReset16(self):
3664 """Test that an image with an x86 reset16 region can be created"""
3665 data = self._DoReadFile('144_x86_reset16.dts')
3666 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3667
3668 def testPackReset16Spl(self):
3669 """Test that an image with an x86 reset16-spl region can be created"""
3670 data = self._DoReadFile('145_x86_reset16_spl.dts')
3671 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3672
3673 def testPackReset16Tpl(self):
3674 """Test that an image with an x86 reset16-tpl region can be created"""
3675 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3676 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3677
Simon Glass232f90c2019-08-24 07:22:50 -06003678 def testPackIntelFit(self):
3679 """Test that an image with an Intel FIT and pointer can be created"""
3680 data = self._DoReadFile('147_intel_fit.dts')
3681 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3682 fit = data[16:32];
3683 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3684 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3685
3686 image = control.images['image']
3687 entries = image.GetEntries()
3688 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3689 self.assertEqual(expected_ptr, ptr)
3690
3691 def testPackIntelFitMissing(self):
3692 """Test detection of a FIT pointer with not FIT region"""
3693 with self.assertRaises(ValueError) as e:
3694 self._DoReadFile('148_intel_fit_missing.dts')
3695 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3696 str(e.exception))
3697
Simon Glass72555fa2019-11-06 17:22:44 -07003698 def _CheckSymbolsTplSection(self, dts, expected_vals):
3699 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003700 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003701 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003702 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003703 self.assertEqual(expected1, data[:upto1])
3704
3705 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003706 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003707 self.assertEqual(expected2, data[upto1:upto2])
3708
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003709 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003710 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003711 self.assertEqual(expected3, data[upto2:upto3])
3712
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003713 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003714 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3715
3716 def testSymbolsTplSection(self):
3717 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3718 self._SetupSplElf('u_boot_binman_syms')
3719 self._SetupTplElf('u_boot_binman_syms')
3720 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003721 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003722
3723 def testSymbolsTplSectionX86(self):
3724 """Test binman can assign symbols in a section with end-at-4gb"""
3725 self._SetupSplElf('u_boot_binman_syms_x86')
3726 self._SetupTplElf('u_boot_binman_syms_x86')
3727 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003728 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003729 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003730
Simon Glass98c59572019-08-24 07:23:03 -06003731 def testPackX86RomIfwiSectiom(self):
3732 """Test that a section can be placed in an IFWI region"""
3733 self._SetupIfwi('fitimage.bin')
3734 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3735 self._CheckIfwi(data)
3736
Simon Glassba7985d2019-08-24 07:23:07 -06003737 def testPackFspM(self):
3738 """Test that an image with a FSP memory-init binary can be created"""
3739 data = self._DoReadFile('152_intel_fsp_m.dts')
3740 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3741
Simon Glass4d9086d2019-10-20 21:31:35 -06003742 def testPackFspS(self):
3743 """Test that an image with a FSP silicon-init binary can be created"""
3744 data = self._DoReadFile('153_intel_fsp_s.dts')
3745 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003746
Simon Glass9ea87b22019-10-20 21:31:36 -06003747 def testPackFspT(self):
3748 """Test that an image with a FSP temp-ram-init binary can be created"""
3749 data = self._DoReadFile('154_intel_fsp_t.dts')
3750 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3751
Simon Glass48f3aad2020-07-09 18:39:31 -06003752 def testMkimage(self):
3753 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003754 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003755 data = self._DoReadFile('156_mkimage.dts')
3756
3757 # Just check that the data appears in the file somewhere
3758 self.assertIn(U_BOOT_SPL_DATA, data)
3759
Simon Glass66152ce2022-01-09 20:14:09 -07003760 def testMkimageMissing(self):
3761 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003762 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003763 with test_util.capture_sys_output() as (_, stderr):
3764 self._DoTestFile('156_mkimage.dts',
3765 force_missing_bintools='mkimage')
3766 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003767 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003768
Simon Glass5e560182020-07-09 18:39:36 -06003769 def testExtblob(self):
3770 """Test an image with an external blob"""
3771 data = self._DoReadFile('157_blob_ext.dts')
3772 self.assertEqual(REFCODE_DATA, data)
3773
3774 def testExtblobMissing(self):
3775 """Test an image with a missing external blob"""
3776 with self.assertRaises(ValueError) as e:
3777 self._DoReadFile('158_blob_ext_missing.dts')
3778 self.assertIn("Filename 'missing-file' not found in input path",
3779 str(e.exception))
3780
Simon Glass5d94cc62020-07-09 18:39:38 -06003781 def testExtblobMissingOk(self):
3782 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003783 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003784 ret = self._DoTestFile('158_blob_ext_missing.dts',
3785 allow_missing=True)
3786 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003787 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003788 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003789 self.assertIn('Some images are invalid', err)
3790
3791 def testExtblobMissingOkFlag(self):
3792 """Test an image with an missing external blob allowed with -W"""
3793 with test_util.capture_sys_output() as (stdout, stderr):
3794 ret = self._DoTestFile('158_blob_ext_missing.dts',
3795 allow_missing=True, ignore_missing=True)
3796 self.assertEqual(0, ret)
3797 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003798 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003799 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003800
3801 def testExtblobMissingOkSect(self):
3802 """Test an image with an missing external blob that is allowed"""
3803 with test_util.capture_sys_output() as (stdout, stderr):
3804 self._DoTestFile('159_blob_ext_missing_sect.dts',
3805 allow_missing=True)
3806 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003807 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003808
Simon Glasse88cef92020-07-09 18:39:41 -06003809 def testPackX86RomMeMissingDesc(self):
3810 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003811 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003812 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003813 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003814 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003815
3816 def testPackX86RomMissingIfwi(self):
3817 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3818 self._SetupIfwi('fitimage.bin')
3819 pathname = os.path.join(self._indir, 'fitimage.bin')
3820 os.remove(pathname)
3821 with test_util.capture_sys_output() as (stdout, stderr):
3822 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3823 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003824 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003825
Simon Glass2a0fa982022-02-11 13:23:21 -07003826 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003827 """Test that zero-size overlapping regions are ignored"""
3828 self._DoTestFile('160_pack_overlap_zero.dts')
3829
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003830 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003831 # The data should be inside the FIT
3832 dtb = fdt.Fdt.FromData(fit_data)
3833 dtb.Scan()
3834 fnode = dtb.GetNode('/images/kernel')
3835 self.assertIn('data', fnode.props)
3836
3837 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003838 tools.write_file(fname, fit_data)
3839 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003840
3841 # Check a few features to make sure the plumbing works. We don't need
3842 # to test the operation of mkimage or dumpimage here. First convert the
3843 # output into a dict where the keys are the fields printed by dumpimage
3844 # and the values are a list of values for each field
3845 lines = out.splitlines()
3846
3847 # Converts "Compression: gzip compressed" into two groups:
3848 # 'Compression' and 'gzip compressed'
3849 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3850 vals = collections.defaultdict(list)
3851 for line in lines:
3852 mat = re_line.match(line)
3853 vals[mat.group(1)].append(mat.group(2))
3854
3855 self.assertEquals('FIT description: test-desc', lines[0])
3856 self.assertIn('Created:', lines[1])
3857 self.assertIn('Image 0 (kernel)', vals)
3858 self.assertIn('Hash value', vals)
3859 data_sizes = vals.get('Data Size')
3860 self.assertIsNotNone(data_sizes)
3861 self.assertEqual(2, len(data_sizes))
3862 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003863 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3864 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3865
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003866 # Check if entry listing correctly omits /images/
3867 image = control.images['image']
3868 fit_entry = image.GetEntries()['fit']
3869 subentries = list(fit_entry.GetEntries().keys())
3870 expected = ['kernel', 'fdt-1']
3871 self.assertEqual(expected, subentries)
3872
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003873 def testSimpleFit(self):
3874 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003875 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003876 data = self._DoReadFile('161_fit.dts')
3877 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3878 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3879 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3880
3881 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3882
3883 def testSimpleFitExpandsSubentries(self):
3884 """Test that FIT images expand their subentries"""
3885 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3886 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3887 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3888 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3889
3890 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003891
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003892 def testSimpleFitImagePos(self):
3893 """Test that we have correct image-pos for FIT subentries"""
3894 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3895 update_dtb=True)
3896 dtb = fdt.Fdt(out_dtb_fname)
3897 dtb.Scan()
3898 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3899
Simon Glassb7bad182022-03-05 20:19:01 -07003900 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003901 self.assertEqual({
3902 'image-pos': 0,
3903 'offset': 0,
3904 'size': 1890,
3905
3906 'u-boot:image-pos': 0,
3907 'u-boot:offset': 0,
3908 'u-boot:size': 4,
3909
3910 'fit:image-pos': 4,
3911 'fit:offset': 4,
3912 'fit:size': 1840,
3913
Simon Glassb7bad182022-03-05 20:19:01 -07003914 'fit/images/kernel:image-pos': 304,
3915 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003916 'fit/images/kernel:size': 4,
3917
Simon Glassb7bad182022-03-05 20:19:01 -07003918 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003919 'fit/images/kernel/u-boot:offset': 0,
3920 'fit/images/kernel/u-boot:size': 4,
3921
Simon Glassb7bad182022-03-05 20:19:01 -07003922 'fit/images/fdt-1:image-pos': 552,
3923 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003924 'fit/images/fdt-1:size': 6,
3925
Simon Glassb7bad182022-03-05 20:19:01 -07003926 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003927 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3928 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3929
3930 'u-boot-nodtb:image-pos': 1844,
3931 'u-boot-nodtb:offset': 1844,
3932 'u-boot-nodtb:size': 46,
3933 }, props)
3934
3935 # Actually check the data is where we think it is
3936 for node, expected in [
3937 ("u-boot", U_BOOT_DATA),
3938 ("fit/images/kernel", U_BOOT_DATA),
3939 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3940 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3941 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3942 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3943 ]:
3944 image_pos = props[f"{node}:image-pos"]
3945 size = props[f"{node}:size"]
3946 self.assertEqual(len(expected), size)
3947 self.assertEqual(expected, data[image_pos:image_pos+size])
3948
Simon Glass45d556d2020-07-09 18:39:45 -06003949 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003950 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003951 data = self._DoReadFile('162_fit_external.dts')
3952 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3953
Simon Glass7932c882022-01-09 20:13:39 -07003954 # Size of the external-data region as set up by mkimage
3955 external_data_size = len(U_BOOT_DATA) + 2
3956 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003957 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003958 len(U_BOOT_NODTB_DATA))
3959
Simon Glass45d556d2020-07-09 18:39:45 -06003960 # The data should be outside the FIT
3961 dtb = fdt.Fdt.FromData(fit_data)
3962 dtb.Scan()
3963 fnode = dtb.GetNode('/images/kernel')
3964 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003965 self.assertEqual(len(U_BOOT_DATA),
3966 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3967 fit_pos = 0x400;
3968 self.assertEqual(
3969 fit_pos,
3970 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3971
3972 self.assertEquals(expected_size, len(data))
3973 actual_pos = len(U_BOOT_DATA) + fit_pos
3974 self.assertEqual(U_BOOT_DATA + b'aa',
3975 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003976
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003977 def testFitExternalImagePos(self):
3978 """Test that we have correct image-pos for external FIT subentries"""
3979 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3980 update_dtb=True)
3981 dtb = fdt.Fdt(out_dtb_fname)
3982 dtb.Scan()
3983 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3984
3985 self.assertEqual({
3986 'image-pos': 0,
3987 'offset': 0,
3988 'size': 1082,
3989
3990 'u-boot:image-pos': 0,
3991 'u-boot:offset': 0,
3992 'u-boot:size': 4,
3993
3994 'fit:size': 1032,
3995 'fit:offset': 4,
3996 'fit:image-pos': 4,
3997
3998 'fit/images/kernel:size': 4,
3999 'fit/images/kernel:offset': 1024,
4000 'fit/images/kernel:image-pos': 1028,
4001
4002 'fit/images/kernel/u-boot:size': 4,
4003 'fit/images/kernel/u-boot:offset': 0,
4004 'fit/images/kernel/u-boot:image-pos': 1028,
4005
4006 'fit/images/fdt-1:size': 2,
4007 'fit/images/fdt-1:offset': 1028,
4008 'fit/images/fdt-1:image-pos': 1032,
4009
4010 'fit/images/fdt-1/_testing:size': 2,
4011 'fit/images/fdt-1/_testing:offset': 0,
4012 'fit/images/fdt-1/_testing:image-pos': 1032,
4013
4014 'u-boot-nodtb:image-pos': 1036,
4015 'u-boot-nodtb:offset': 1036,
4016 'u-boot-nodtb:size': 46,
4017 }, props)
4018
4019 # Actually check the data is where we think it is
4020 for node, expected in [
4021 ("u-boot", U_BOOT_DATA),
4022 ("fit/images/kernel", U_BOOT_DATA),
4023 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4024 ("fit/images/fdt-1", b'aa'),
4025 ("fit/images/fdt-1/_testing", b'aa'),
4026 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4027 ]:
4028 image_pos = props[f"{node}:image-pos"]
4029 size = props[f"{node}:size"]
4030 self.assertEqual(len(expected), size)
4031 self.assertEqual(expected, data[image_pos:image_pos+size])
4032
Simon Glass66152ce2022-01-09 20:14:09 -07004033 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004034 """Test that binman complains if mkimage is missing"""
4035 with self.assertRaises(ValueError) as e:
4036 self._DoTestFile('162_fit_external.dts',
4037 force_missing_bintools='mkimage')
4038 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4039 str(e.exception))
4040
4041 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004042 """Test that binman still produces a FIT image if mkimage is missing"""
4043 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004044 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004045 force_missing_bintools='mkimage')
4046 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004047 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004048
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004049 def testSectionIgnoreHashSignature(self):
4050 """Test that sections ignore hash, signature nodes for its data"""
4051 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4052 expected = (U_BOOT_DATA + U_BOOT_DATA)
4053 self.assertEqual(expected, data)
4054
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004055 def testPadInSections(self):
4056 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004057 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4058 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004059 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4060 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004061 U_BOOT_DATA)
4062 self.assertEqual(expected, data)
4063
Simon Glassd12599d2020-10-26 17:40:09 -06004064 dtb = fdt.Fdt(out_dtb_fname)
4065 dtb.Scan()
4066 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4067 expected = {
4068 'image-pos': 0,
4069 'offset': 0,
4070 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4071
4072 'section:image-pos': 0,
4073 'section:offset': 0,
4074 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4075
4076 'section/before:image-pos': 0,
4077 'section/before:offset': 0,
4078 'section/before:size': len(U_BOOT_DATA),
4079
4080 'section/u-boot:image-pos': 4,
4081 'section/u-boot:offset': 4,
4082 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4083
4084 'section/after:image-pos': 26,
4085 'section/after:offset': 26,
4086 'section/after:size': len(U_BOOT_DATA),
4087 }
4088 self.assertEqual(expected, props)
4089
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004090 def testFitImageSubentryAlignment(self):
4091 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004092 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004093 entry_args = {
4094 'test-id': TEXT_DATA,
4095 }
4096 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4097 entry_args=entry_args)
4098 dtb = fdt.Fdt.FromData(data)
4099 dtb.Scan()
4100
4101 node = dtb.GetNode('/images/kernel')
4102 data = dtb.GetProps(node)["data"].bytes
4103 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004104 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4105 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004106 self.assertEqual(expected, data)
4107
4108 node = dtb.GetNode('/images/fdt-1')
4109 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004110 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4111 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004112 U_BOOT_DTB_DATA)
4113 self.assertEqual(expected, data)
4114
4115 def testFitExtblobMissingOk(self):
4116 """Test a FIT with a missing external blob that is allowed"""
4117 with test_util.capture_sys_output() as (stdout, stderr):
4118 self._DoTestFile('168_fit_missing_blob.dts',
4119 allow_missing=True)
4120 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004121 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004122
Simon Glass21db0ff2020-09-01 05:13:54 -06004123 def testBlobNamedByArgMissing(self):
4124 """Test handling of a missing entry arg"""
4125 with self.assertRaises(ValueError) as e:
4126 self._DoReadFile('068_blob_named_by_arg.dts')
4127 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4128 str(e.exception))
4129
Simon Glass559c4de2020-09-01 05:13:58 -06004130 def testPackBl31(self):
4131 """Test that an image with an ATF BL31 binary can be created"""
4132 data = self._DoReadFile('169_atf_bl31.dts')
4133 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4134
Samuel Holland9d8cc632020-10-21 21:12:15 -05004135 def testPackScp(self):
4136 """Test that an image with an SCP binary can be created"""
4137 data = self._DoReadFile('172_scp.dts')
4138 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4139
Simon Glassa435cd12020-09-01 05:13:59 -06004140 def testFitFdt(self):
4141 """Test an image with an FIT with multiple FDT images"""
4142 def _CheckFdt(seq, expected_data):
4143 """Check the FDT nodes
4144
4145 Args:
4146 seq: Sequence number to check (0 or 1)
4147 expected_data: Expected contents of 'data' property
4148 """
4149 name = 'fdt-%d' % seq
4150 fnode = dtb.GetNode('/images/%s' % name)
4151 self.assertIsNotNone(fnode)
4152 self.assertEqual({'description','type', 'compression', 'data'},
4153 set(fnode.props.keys()))
4154 self.assertEqual(expected_data, fnode.props['data'].bytes)
4155 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4156 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004157 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004158
4159 def _CheckConfig(seq, expected_data):
4160 """Check the configuration nodes
4161
4162 Args:
4163 seq: Sequence number to check (0 or 1)
4164 expected_data: Expected contents of 'data' property
4165 """
4166 cnode = dtb.GetNode('/configurations')
4167 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004168 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004169
4170 name = 'config-%d' % seq
4171 fnode = dtb.GetNode('/configurations/%s' % name)
4172 self.assertIsNotNone(fnode)
4173 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4174 set(fnode.props.keys()))
4175 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4176 fnode.props['description'].value)
4177 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4178
4179 entry_args = {
4180 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004181 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004182 }
4183 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004184 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004185 entry_args=entry_args,
4186 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4187 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4188 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4189
4190 dtb = fdt.Fdt.FromData(fit_data)
4191 dtb.Scan()
4192 fnode = dtb.GetNode('/images/kernel')
4193 self.assertIn('data', fnode.props)
4194
4195 # Check all the properties in fdt-1 and fdt-2
4196 _CheckFdt(1, TEST_FDT1_DATA)
4197 _CheckFdt(2, TEST_FDT2_DATA)
4198
4199 # Check configurations
4200 _CheckConfig(1, TEST_FDT1_DATA)
4201 _CheckConfig(2, TEST_FDT2_DATA)
4202
4203 def testFitFdtMissingList(self):
4204 """Test handling of a missing 'of-list' entry arg"""
4205 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004206 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004207 self.assertIn("Generator node requires 'of-list' entry argument",
4208 str(e.exception))
4209
4210 def testFitFdtEmptyList(self):
4211 """Test handling of an empty 'of-list' entry arg"""
4212 entry_args = {
4213 'of-list': '',
4214 }
4215 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4216
4217 def testFitFdtMissingProp(self):
4218 """Test handling of a missing 'fit,fdt-list' property"""
4219 with self.assertRaises(ValueError) as e:
4220 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4221 self.assertIn("Generator node requires 'fit,fdt-list' property",
4222 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004223
Simon Glass1032acc2020-09-06 10:39:08 -06004224 def testFitFdtMissing(self):
4225 """Test handling of a missing 'default-dt' entry arg"""
4226 entry_args = {
4227 'of-list': 'test-fdt1 test-fdt2',
4228 }
4229 with self.assertRaises(ValueError) as e:
4230 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004231 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004232 entry_args=entry_args,
4233 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4234 self.assertIn("Generated 'default' node requires default-dt entry argument",
4235 str(e.exception))
4236
4237 def testFitFdtNotInList(self):
4238 """Test handling of a default-dt that is not in the of-list"""
4239 entry_args = {
4240 'of-list': 'test-fdt1 test-fdt2',
4241 'default-dt': 'test-fdt3',
4242 }
4243 with self.assertRaises(ValueError) as e:
4244 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004245 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004246 entry_args=entry_args,
4247 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4248 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4249 str(e.exception))
4250
Simon Glassa820af72020-09-06 10:39:09 -06004251 def testFitExtblobMissingHelp(self):
4252 """Test display of help messages when an external blob is missing"""
4253 control.missing_blob_help = control._ReadMissingBlobHelp()
4254 control.missing_blob_help['wibble'] = 'Wibble test'
4255 control.missing_blob_help['another'] = 'Another test'
4256 with test_util.capture_sys_output() as (stdout, stderr):
4257 self._DoTestFile('168_fit_missing_blob.dts',
4258 allow_missing=True)
4259 err = stderr.getvalue()
4260
4261 # We can get the tag from the name, the type or the missing-msg
4262 # property. Check all three.
4263 self.assertIn('You may need to build ARM Trusted', err)
4264 self.assertIn('Wibble test', err)
4265 self.assertIn('Another test', err)
4266
Simon Glass6f1f4d42020-09-06 10:35:32 -06004267 def testMissingBlob(self):
4268 """Test handling of a blob containing a missing file"""
4269 with self.assertRaises(ValueError) as e:
4270 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4271 self.assertIn("Filename 'missing' not found in input path",
4272 str(e.exception))
4273
Simon Glassa0729502020-09-06 10:35:33 -06004274 def testEnvironment(self):
4275 """Test adding a U-Boot environment"""
4276 data = self._DoReadFile('174_env.dts')
4277 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4278 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4279 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4280 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4281 env)
4282
4283 def testEnvironmentNoSize(self):
4284 """Test that a missing 'size' property is detected"""
4285 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004286 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004287 self.assertIn("'u-boot-env' entry must have a size property",
4288 str(e.exception))
4289
4290 def testEnvironmentTooSmall(self):
4291 """Test handling of an environment that does not fit"""
4292 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004293 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004294
4295 # checksum, start byte, environment with \0 terminator, final \0
4296 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4297 short = need - 0x8
4298 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4299 str(e.exception))
4300
Simon Glassd1fdf752020-10-26 17:40:01 -06004301 def testSkipAtStart(self):
4302 """Test handling of skip-at-start section"""
4303 data = self._DoReadFile('177_skip_at_start.dts')
4304 self.assertEqual(U_BOOT_DATA, data)
4305
4306 image = control.images['image']
4307 entries = image.GetEntries()
4308 section = entries['section']
4309 self.assertEqual(0, section.offset)
4310 self.assertEqual(len(U_BOOT_DATA), section.size)
4311 self.assertEqual(U_BOOT_DATA, section.GetData())
4312
4313 entry = section.GetEntries()['u-boot']
4314 self.assertEqual(16, entry.offset)
4315 self.assertEqual(len(U_BOOT_DATA), entry.size)
4316 self.assertEqual(U_BOOT_DATA, entry.data)
4317
4318 def testSkipAtStartPad(self):
4319 """Test handling of skip-at-start section with padded entry"""
4320 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004321 before = tools.get_bytes(0, 8)
4322 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004323 all = before + U_BOOT_DATA + after
4324 self.assertEqual(all, data)
4325
4326 image = control.images['image']
4327 entries = image.GetEntries()
4328 section = entries['section']
4329 self.assertEqual(0, section.offset)
4330 self.assertEqual(len(all), section.size)
4331 self.assertEqual(all, section.GetData())
4332
4333 entry = section.GetEntries()['u-boot']
4334 self.assertEqual(16, entry.offset)
4335 self.assertEqual(len(all), entry.size)
4336 self.assertEqual(U_BOOT_DATA, entry.data)
4337
4338 def testSkipAtStartSectionPad(self):
4339 """Test handling of skip-at-start section with padding"""
4340 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004341 before = tools.get_bytes(0, 8)
4342 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004343 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004344 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004345
4346 image = control.images['image']
4347 entries = image.GetEntries()
4348 section = entries['section']
4349 self.assertEqual(0, section.offset)
4350 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004351 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004352 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004353
4354 entry = section.GetEntries()['u-boot']
4355 self.assertEqual(16, entry.offset)
4356 self.assertEqual(len(U_BOOT_DATA), entry.size)
4357 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004358
Simon Glassbb395742020-10-26 17:40:14 -06004359 def testSectionPad(self):
4360 """Testing padding with sections"""
4361 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004362 expected = (tools.get_bytes(ord('&'), 3) +
4363 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004364 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004365 tools.get_bytes(ord('!'), 1) +
4366 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004367 self.assertEqual(expected, data)
4368
4369 def testSectionAlign(self):
4370 """Testing alignment with sections"""
4371 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4372 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004373 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004374 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004375 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004376 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004377 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4378 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004379 self.assertEqual(expected, data)
4380
Simon Glassd92c8362020-10-26 17:40:25 -06004381 def testCompressImage(self):
4382 """Test compression of the entire image"""
4383 self._CheckLz4()
4384 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4385 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4386 dtb = fdt.Fdt(out_dtb_fname)
4387 dtb.Scan()
4388 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4389 'uncomp-size'])
4390 orig = self._decompress(data)
4391 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4392
4393 # Do a sanity check on various fields
4394 image = control.images['image']
4395 entries = image.GetEntries()
4396 self.assertEqual(2, len(entries))
4397
4398 entry = entries['blob']
4399 self.assertEqual(COMPRESS_DATA, entry.data)
4400 self.assertEqual(len(COMPRESS_DATA), entry.size)
4401
4402 entry = entries['u-boot']
4403 self.assertEqual(U_BOOT_DATA, entry.data)
4404 self.assertEqual(len(U_BOOT_DATA), entry.size)
4405
4406 self.assertEqual(len(data), image.size)
4407 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4408 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4409 orig = self._decompress(image.data)
4410 self.assertEqual(orig, image.uncomp_data)
4411
4412 expected = {
4413 'blob:offset': 0,
4414 'blob:size': len(COMPRESS_DATA),
4415 'u-boot:offset': len(COMPRESS_DATA),
4416 'u-boot:size': len(U_BOOT_DATA),
4417 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4418 'offset': 0,
4419 'image-pos': 0,
4420 'size': len(data),
4421 }
4422 self.assertEqual(expected, props)
4423
4424 def testCompressImageLess(self):
4425 """Test compression where compression reduces the image size"""
4426 self._CheckLz4()
4427 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4428 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4429 dtb = fdt.Fdt(out_dtb_fname)
4430 dtb.Scan()
4431 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4432 'uncomp-size'])
4433 orig = self._decompress(data)
4434
4435 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4436
4437 # Do a sanity check on various fields
4438 image = control.images['image']
4439 entries = image.GetEntries()
4440 self.assertEqual(2, len(entries))
4441
4442 entry = entries['blob']
4443 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4444 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4445
4446 entry = entries['u-boot']
4447 self.assertEqual(U_BOOT_DATA, entry.data)
4448 self.assertEqual(len(U_BOOT_DATA), entry.size)
4449
4450 self.assertEqual(len(data), image.size)
4451 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4452 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4453 image.uncomp_size)
4454 orig = self._decompress(image.data)
4455 self.assertEqual(orig, image.uncomp_data)
4456
4457 expected = {
4458 'blob:offset': 0,
4459 'blob:size': len(COMPRESS_DATA_BIG),
4460 'u-boot:offset': len(COMPRESS_DATA_BIG),
4461 'u-boot:size': len(U_BOOT_DATA),
4462 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4463 'offset': 0,
4464 'image-pos': 0,
4465 'size': len(data),
4466 }
4467 self.assertEqual(expected, props)
4468
4469 def testCompressSectionSize(self):
4470 """Test compression of a section with a fixed size"""
4471 self._CheckLz4()
4472 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4473 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4474 dtb = fdt.Fdt(out_dtb_fname)
4475 dtb.Scan()
4476 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4477 'uncomp-size'])
4478 orig = self._decompress(data)
4479 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4480 expected = {
4481 'section/blob:offset': 0,
4482 'section/blob:size': len(COMPRESS_DATA),
4483 'section/u-boot:offset': len(COMPRESS_DATA),
4484 'section/u-boot:size': len(U_BOOT_DATA),
4485 'section:offset': 0,
4486 'section:image-pos': 0,
4487 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4488 'section:size': 0x30,
4489 'offset': 0,
4490 'image-pos': 0,
4491 'size': 0x30,
4492 }
4493 self.assertEqual(expected, props)
4494
4495 def testCompressSection(self):
4496 """Test compression of a section with no fixed size"""
4497 self._CheckLz4()
4498 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4499 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4500 dtb = fdt.Fdt(out_dtb_fname)
4501 dtb.Scan()
4502 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4503 'uncomp-size'])
4504 orig = self._decompress(data)
4505 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4506 expected = {
4507 'section/blob:offset': 0,
4508 'section/blob:size': len(COMPRESS_DATA),
4509 'section/u-boot:offset': len(COMPRESS_DATA),
4510 'section/u-boot:size': len(U_BOOT_DATA),
4511 'section:offset': 0,
4512 'section:image-pos': 0,
4513 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4514 'section:size': len(data),
4515 'offset': 0,
4516 'image-pos': 0,
4517 'size': len(data),
4518 }
4519 self.assertEqual(expected, props)
4520
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004521 def testLz4Missing(self):
4522 """Test that binman still produces an image if lz4 is missing"""
4523 with test_util.capture_sys_output() as (_, stderr):
4524 self._DoTestFile('185_compress_section.dts',
4525 force_missing_bintools='lz4')
4526 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004527 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004528
Simon Glassd92c8362020-10-26 17:40:25 -06004529 def testCompressExtra(self):
4530 """Test compression of a section with no fixed size"""
4531 self._CheckLz4()
4532 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4533 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4534 dtb = fdt.Fdt(out_dtb_fname)
4535 dtb.Scan()
4536 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4537 'uncomp-size'])
4538
4539 base = data[len(U_BOOT_DATA):]
4540 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4541 rest = base[len(U_BOOT_DATA):]
4542
4543 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004544 bintool = self.comp_bintools['lz4']
4545 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004546 data1 = rest[:len(expect1)]
4547 section1 = self._decompress(data1)
4548 self.assertEquals(expect1, data1)
Simon Glassd92c8362020-10-26 17:40:25 -06004549 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4550 rest1 = rest[len(expect1):]
4551
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004552 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004553 data2 = rest1[:len(expect2)]
4554 section2 = self._decompress(data2)
4555 self.assertEquals(expect2, data2)
Simon Glassd92c8362020-10-26 17:40:25 -06004556 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4557 rest2 = rest1[len(expect2):]
4558
4559 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4560 len(expect2) + len(U_BOOT_DATA))
4561 #self.assertEquals(expect_size, len(data))
4562
4563 #self.assertEquals(U_BOOT_DATA, rest2)
4564
4565 self.maxDiff = None
4566 expected = {
4567 'u-boot:offset': 0,
4568 'u-boot:image-pos': 0,
4569 'u-boot:size': len(U_BOOT_DATA),
4570
4571 'base:offset': len(U_BOOT_DATA),
4572 'base:image-pos': len(U_BOOT_DATA),
4573 'base:size': len(data) - len(U_BOOT_DATA),
4574 'base/u-boot:offset': 0,
4575 'base/u-boot:image-pos': len(U_BOOT_DATA),
4576 'base/u-boot:size': len(U_BOOT_DATA),
4577 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4578 len(expect2),
4579 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4580 len(expect2),
4581 'base/u-boot2:size': len(U_BOOT_DATA),
4582
4583 'base/section:offset': len(U_BOOT_DATA),
4584 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4585 'base/section:size': len(expect1),
4586 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4587 'base/section/blob:offset': 0,
4588 'base/section/blob:size': len(COMPRESS_DATA),
4589 'base/section/u-boot:offset': len(COMPRESS_DATA),
4590 'base/section/u-boot:size': len(U_BOOT_DATA),
4591
4592 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4593 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4594 'base/section2:size': len(expect2),
4595 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4596 'base/section2/blob:offset': 0,
4597 'base/section2/blob:size': len(COMPRESS_DATA),
4598 'base/section2/blob2:offset': len(COMPRESS_DATA),
4599 'base/section2/blob2:size': len(COMPRESS_DATA),
4600
4601 'offset': 0,
4602 'image-pos': 0,
4603 'size': len(data),
4604 }
4605 self.assertEqual(expected, props)
4606
Simon Glassecbe4732021-01-06 21:35:15 -07004607 def testSymbolsSubsection(self):
4608 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004609 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004610
Simon Glass3fb25402021-01-06 21:35:16 -07004611 def testReadImageEntryArg(self):
4612 """Test reading an image that would need an entry arg to generate"""
4613 entry_args = {
4614 'cros-ec-rw-path': 'ecrw.bin',
4615 }
4616 data = self.data = self._DoReadFileDtb(
4617 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4618 entry_args=entry_args)
4619
Simon Glass80025522022-01-29 14:14:04 -07004620 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004621 orig_image = control.images['image']
4622
4623 # This should not generate an error about the missing 'cros-ec-rw-path'
4624 # since we are reading the image from a file. Compare with
4625 # testEntryArgsRequired()
4626 image = Image.FromFile(image_fname)
4627 self.assertEqual(orig_image.GetEntries().keys(),
4628 image.GetEntries().keys())
4629
Simon Glassa2af7302021-01-06 21:35:18 -07004630 def testFilesAlign(self):
4631 """Test alignment with files"""
4632 data = self._DoReadFile('190_files_align.dts')
4633
4634 # The first string is 15 bytes so will align to 16
4635 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4636 self.assertEqual(expect, data)
4637
Simon Glassdb84b562021-01-06 21:35:19 -07004638 def testReadImageSkip(self):
4639 """Test reading an image and accessing its FDT map"""
4640 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004641 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004642 orig_image = control.images['image']
4643 image = Image.FromFile(image_fname)
4644 self.assertEqual(orig_image.GetEntries().keys(),
4645 image.GetEntries().keys())
4646
4647 orig_entry = orig_image.GetEntries()['fdtmap']
4648 entry = image.GetEntries()['fdtmap']
4649 self.assertEqual(orig_entry.offset, entry.offset)
4650 self.assertEqual(orig_entry.size, entry.size)
4651 self.assertEqual(16, entry.image_pos)
4652
4653 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4654
4655 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4656
Simon Glassc98de972021-03-18 20:24:57 +13004657 def testTplNoDtb(self):
4658 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004659 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004660 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4661 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4662 data[:len(U_BOOT_TPL_NODTB_DATA)])
4663
Simon Glass63f41d42021-03-18 20:24:58 +13004664 def testTplBssPad(self):
4665 """Test that we can pad TPL's BSS with zeros"""
4666 # ELF file with a '__bss_size' symbol
4667 self._SetupTplElf()
4668 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004669 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004670 data)
4671
4672 def testTplBssPadMissing(self):
4673 """Test that a missing symbol is detected"""
4674 self._SetupTplElf('u_boot_ucode_ptr')
4675 with self.assertRaises(ValueError) as e:
4676 self._DoReadFile('193_tpl_bss_pad.dts')
4677 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4678 str(e.exception))
4679
Simon Glass718b5292021-03-18 20:25:07 +13004680 def checkDtbSizes(self, data, pad_len, start):
4681 """Check the size arguments in a dtb embedded in an image
4682
4683 Args:
4684 data: The image data
4685 pad_len: Length of the pad section in the image, in bytes
4686 start: Start offset of the devicetree to examine, within the image
4687
4688 Returns:
4689 Size of the devicetree in bytes
4690 """
4691 dtb_data = data[start:]
4692 dtb = fdt.Fdt.FromData(dtb_data)
4693 fdt_size = dtb.GetFdtObj().totalsize()
4694 dtb.Scan()
4695 props = self._GetPropTree(dtb, 'size')
4696 self.assertEqual({
4697 'size': len(data),
4698 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4699 'u-boot-spl/u-boot-spl-dtb:size': 801,
4700 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4701 'u-boot-spl:size': 860,
4702 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4703 'u-boot/u-boot-dtb:size': 781,
4704 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4705 'u-boot:size': 827,
4706 }, props)
4707 return fdt_size
4708
4709 def testExpanded(self):
4710 """Test that an expanded entry type is selected when needed"""
4711 self._SetupSplElf()
4712 self._SetupTplElf()
4713
4714 # SPL has a devicetree, TPL does not
4715 entry_args = {
4716 'spl-dtb': '1',
4717 'spl-bss-pad': 'y',
4718 'tpl-dtb': '',
4719 }
4720 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4721 entry_args=entry_args)
4722 image = control.images['image']
4723 entries = image.GetEntries()
4724 self.assertEqual(3, len(entries))
4725
4726 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4727 self.assertIn('u-boot', entries)
4728 entry = entries['u-boot']
4729 self.assertEqual('u-boot-expanded', entry.etype)
4730 subent = entry.GetEntries()
4731 self.assertEqual(2, len(subent))
4732 self.assertIn('u-boot-nodtb', subent)
4733 self.assertIn('u-boot-dtb', subent)
4734
4735 # Second, u-boot-spl, which should be expanded into three parts
4736 self.assertIn('u-boot-spl', entries)
4737 entry = entries['u-boot-spl']
4738 self.assertEqual('u-boot-spl-expanded', entry.etype)
4739 subent = entry.GetEntries()
4740 self.assertEqual(3, len(subent))
4741 self.assertIn('u-boot-spl-nodtb', subent)
4742 self.assertIn('u-boot-spl-bss-pad', subent)
4743 self.assertIn('u-boot-spl-dtb', subent)
4744
4745 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4746 # devicetree
4747 self.assertIn('u-boot-tpl', entries)
4748 entry = entries['u-boot-tpl']
4749 self.assertEqual('u-boot-tpl', entry.etype)
4750 self.assertEqual(None, entry.GetEntries())
4751
4752 def testExpandedTpl(self):
4753 """Test that an expanded entry type is selected for TPL when needed"""
4754 self._SetupTplElf()
4755
4756 entry_args = {
4757 'tpl-bss-pad': 'y',
4758 'tpl-dtb': 'y',
4759 }
4760 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4761 entry_args=entry_args)
4762 image = control.images['image']
4763 entries = image.GetEntries()
4764 self.assertEqual(1, len(entries))
4765
4766 # We only have u-boot-tpl, which be expanded
4767 self.assertIn('u-boot-tpl', entries)
4768 entry = entries['u-boot-tpl']
4769 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4770 subent = entry.GetEntries()
4771 self.assertEqual(3, len(subent))
4772 self.assertIn('u-boot-tpl-nodtb', subent)
4773 self.assertIn('u-boot-tpl-bss-pad', subent)
4774 self.assertIn('u-boot-tpl-dtb', subent)
4775
4776 def testExpandedNoPad(self):
4777 """Test an expanded entry without BSS pad enabled"""
4778 self._SetupSplElf()
4779 self._SetupTplElf()
4780
4781 # SPL has a devicetree, TPL does not
4782 entry_args = {
4783 'spl-dtb': 'something',
4784 'spl-bss-pad': 'n',
4785 'tpl-dtb': '',
4786 }
4787 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4788 entry_args=entry_args)
4789 image = control.images['image']
4790 entries = image.GetEntries()
4791
4792 # Just check u-boot-spl, which should be expanded into two parts
4793 self.assertIn('u-boot-spl', entries)
4794 entry = entries['u-boot-spl']
4795 self.assertEqual('u-boot-spl-expanded', entry.etype)
4796 subent = entry.GetEntries()
4797 self.assertEqual(2, len(subent))
4798 self.assertIn('u-boot-spl-nodtb', subent)
4799 self.assertIn('u-boot-spl-dtb', subent)
4800
4801 def testExpandedTplNoPad(self):
4802 """Test that an expanded entry type with padding disabled in TPL"""
4803 self._SetupTplElf()
4804
4805 entry_args = {
4806 'tpl-bss-pad': '',
4807 'tpl-dtb': 'y',
4808 }
4809 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4810 entry_args=entry_args)
4811 image = control.images['image']
4812 entries = image.GetEntries()
4813 self.assertEqual(1, len(entries))
4814
4815 # We only have u-boot-tpl, which be expanded
4816 self.assertIn('u-boot-tpl', entries)
4817 entry = entries['u-boot-tpl']
4818 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4819 subent = entry.GetEntries()
4820 self.assertEqual(2, len(subent))
4821 self.assertIn('u-boot-tpl-nodtb', subent)
4822 self.assertIn('u-boot-tpl-dtb', subent)
4823
4824 def testFdtInclude(self):
4825 """Test that an Fdt is update within all binaries"""
4826 self._SetupSplElf()
4827 self._SetupTplElf()
4828
4829 # SPL has a devicetree, TPL does not
4830 self.maxDiff = None
4831 entry_args = {
4832 'spl-dtb': '1',
4833 'spl-bss-pad': 'y',
4834 'tpl-dtb': '',
4835 }
4836 # Build the image. It includes two separate devicetree binaries, each
4837 # with their own contents, but all contain the binman definition.
4838 data = self._DoReadFileDtb(
4839 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4840 update_dtb=True, entry_args=entry_args)[0]
4841 pad_len = 10
4842
4843 # Check the U-Boot dtb
4844 start = len(U_BOOT_NODTB_DATA)
4845 fdt_size = self.checkDtbSizes(data, pad_len, start)
4846
4847 # Now check SPL
4848 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4849 fdt_size = self.checkDtbSizes(data, pad_len, start)
4850
4851 # TPL has no devicetree
4852 start += fdt_size + len(U_BOOT_TPL_DATA)
4853 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004854
Simon Glass7098b7f2021-03-21 18:24:30 +13004855 def testSymbolsExpanded(self):
4856 """Test binman can assign symbols in expanded entries"""
4857 entry_args = {
4858 'spl-dtb': '1',
4859 }
4860 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4861 U_BOOT_SPL_DTB_DATA, 0x38,
4862 entry_args=entry_args, use_expanded=True)
4863
Simon Glasse1915782021-03-21 18:24:31 +13004864 def testCollection(self):
4865 """Test a collection"""
4866 data = self._DoReadFile('198_collection.dts')
4867 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004868 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4869 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004870 data)
4871
Simon Glass27a7f772021-03-21 18:24:32 +13004872 def testCollectionSection(self):
4873 """Test a collection where a section must be built first"""
4874 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004875 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004876 # building the contents, producing an error is anything is still
4877 # missing.
4878 data = self._DoReadFile('199_collection_section.dts')
4879 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004880 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4881 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004882 data)
4883
Simon Glassf427c5f2021-03-21 18:24:33 +13004884 def testAlignDefault(self):
4885 """Test that default alignment works on sections"""
4886 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004887 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004888 U_BOOT_DATA)
4889 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004890 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004891 # No alignment within the nested section
4892 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4893 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004894 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004895 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004896
Bin Mengc0b15742021-05-10 20:23:33 +08004897 def testPackOpenSBI(self):
4898 """Test that an image with an OpenSBI binary can be created"""
4899 data = self._DoReadFile('201_opensbi.dts')
4900 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4901
Simon Glass76f496d2021-07-06 10:36:37 -06004902 def testSectionsSingleThread(self):
4903 """Test sections without multithreading"""
4904 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004905 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4906 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4907 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004908 self.assertEqual(expected, data)
4909
4910 def testThreadTimeout(self):
4911 """Test handling a thread that takes too long"""
4912 with self.assertRaises(ValueError) as e:
4913 self._DoTestFile('202_section_timeout.dts',
4914 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004915 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004916
Simon Glass748a1d42021-07-06 10:36:41 -06004917 def testTiming(self):
4918 """Test output of timing information"""
4919 data = self._DoReadFile('055_sections.dts')
4920 with test_util.capture_sys_output() as (stdout, stderr):
4921 state.TimingShow()
4922 self.assertIn('read:', stdout.getvalue())
4923 self.assertIn('compress:', stdout.getvalue())
4924
Simon Glassadfb8492021-11-03 21:09:18 -06004925 def testUpdateFdtInElf(self):
4926 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004927 if not elf.ELF_TOOLS:
4928 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004929 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4930 outfile = os.path.join(self._indir, 'u-boot.out')
4931 begin_sym = 'dtb_embed_begin'
4932 end_sym = 'dtb_embed_end'
4933 retcode = self._DoTestFile(
4934 '060_fdt_update.dts', update_dtb=True,
4935 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4936 self.assertEqual(0, retcode)
4937
4938 # Check that the output file does in fact contact a dtb with the binman
4939 # definition in the correct place
4940 syms = elf.GetSymbolFileOffset(infile,
4941 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004942 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004943 dtb_data = data[syms['dtb_embed_begin'].offset:
4944 syms['dtb_embed_end'].offset]
4945
4946 dtb = fdt.Fdt.FromData(dtb_data)
4947 dtb.Scan()
4948 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4949 self.assertEqual({
4950 'image-pos': 0,
4951 'offset': 0,
4952 '_testing:offset': 32,
4953 '_testing:size': 2,
4954 '_testing:image-pos': 32,
4955 'section@0/u-boot:offset': 0,
4956 'section@0/u-boot:size': len(U_BOOT_DATA),
4957 'section@0/u-boot:image-pos': 0,
4958 'section@0:offset': 0,
4959 'section@0:size': 16,
4960 'section@0:image-pos': 0,
4961
4962 'section@1/u-boot:offset': 0,
4963 'section@1/u-boot:size': len(U_BOOT_DATA),
4964 'section@1/u-boot:image-pos': 16,
4965 'section@1:offset': 16,
4966 'section@1:size': 16,
4967 'section@1:image-pos': 16,
4968 'size': 40
4969 }, props)
4970
4971 def testUpdateFdtInElfInvalid(self):
4972 """Test that invalid args are detected with --update-fdt-in-elf"""
4973 with self.assertRaises(ValueError) as e:
4974 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4975 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4976 str(e.exception))
4977
4978 def testUpdateFdtInElfNoSyms(self):
4979 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004980 if not elf.ELF_TOOLS:
4981 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004982 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4983 outfile = ''
4984 begin_sym = 'wrong_begin'
4985 end_sym = 'wrong_end'
4986 with self.assertRaises(ValueError) as e:
4987 self._DoTestFile(
4988 '060_fdt_update.dts',
4989 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4990 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4991 str(e.exception))
4992
4993 def testUpdateFdtInElfTooSmall(self):
4994 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004995 if not elf.ELF_TOOLS:
4996 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004997 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4998 outfile = os.path.join(self._indir, 'u-boot.out')
4999 begin_sym = 'dtb_embed_begin'
5000 end_sym = 'dtb_embed_end'
5001 with self.assertRaises(ValueError) as e:
5002 self._DoTestFile(
5003 '060_fdt_update.dts', update_dtb=True,
5004 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5005 self.assertRegex(
5006 str(e.exception),
5007 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5008
Simon Glass88e04da2021-11-23 11:03:42 -07005009 def testVersion(self):
5010 """Test we can get the binman version"""
5011 version = '(unreleased)'
5012 self.assertEqual(version, state.GetVersion(self._indir))
5013
5014 with self.assertRaises(SystemExit):
5015 with test_util.capture_sys_output() as (_, stderr):
5016 self._DoBinman('-V')
5017 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5018
5019 # Try running the tool too, just to be safe
5020 result = self._RunBinman('-V')
5021 self.assertEqual('Binman %s\n' % version, result.stderr)
5022
5023 # Set up a version file to make sure that works
5024 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005025 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005026 binary=False)
5027 self.assertEqual(version, state.GetVersion(self._indir))
5028
Simon Glass637958f2021-11-23 21:09:50 -07005029 def testAltFormat(self):
5030 """Test that alternative formats can be used to extract"""
5031 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5032
5033 try:
5034 tmpdir, updated_fname = self._SetupImageInTmpdir()
5035 with test_util.capture_sys_output() as (stdout, _):
5036 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5037 self.assertEqual(
5038 '''Flag (-F) Entry type Description
5039fdt fdtmap Extract the devicetree blob from the fdtmap
5040''',
5041 stdout.getvalue())
5042
5043 dtb = os.path.join(tmpdir, 'fdt.dtb')
5044 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5045 dtb, 'fdtmap')
5046
5047 # Check that we can read it and it can be scanning, meaning it does
5048 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005049 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005050 dtb = fdt.Fdt.FromData(data)
5051 dtb.Scan()
5052
5053 # Now check u-boot which has no alt_format
5054 fname = os.path.join(tmpdir, 'fdt.dtb')
5055 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5056 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005057 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005058 self.assertEqual(U_BOOT_DATA, data)
5059
5060 finally:
5061 shutil.rmtree(tmpdir)
5062
Simon Glass0b00ae62021-11-23 21:09:52 -07005063 def testExtblobList(self):
5064 """Test an image with an external blob list"""
5065 data = self._DoReadFile('215_blob_ext_list.dts')
5066 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5067
5068 def testExtblobListMissing(self):
5069 """Test an image with a missing external blob"""
5070 with self.assertRaises(ValueError) as e:
5071 self._DoReadFile('216_blob_ext_list_missing.dts')
5072 self.assertIn("Filename 'missing-file' not found in input path",
5073 str(e.exception))
5074
5075 def testExtblobListMissingOk(self):
5076 """Test an image with an missing external blob that is allowed"""
5077 with test_util.capture_sys_output() as (stdout, stderr):
5078 self._DoTestFile('216_blob_ext_list_missing.dts',
5079 allow_missing=True)
5080 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005081 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005082
Simon Glass3efb2972021-11-23 21:08:59 -07005083 def testFip(self):
5084 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5085 data = self._DoReadFile('203_fip.dts')
5086 hdr, fents = fip_util.decode_fip(data)
5087 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5088 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5089 self.assertEqual(0x123, hdr.flags)
5090
5091 self.assertEqual(2, len(fents))
5092
5093 fent = fents[0]
5094 self.assertEqual(
5095 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5096 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5097 self.assertEqual('soc-fw', fent.fip_type)
5098 self.assertEqual(0x88, fent.offset)
5099 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5100 self.assertEqual(0x123456789abcdef, fent.flags)
5101 self.assertEqual(ATF_BL31_DATA, fent.data)
5102 self.assertEqual(True, fent.valid)
5103
5104 fent = fents[1]
5105 self.assertEqual(
5106 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5107 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5108 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5109 self.assertEqual(0x8c, fent.offset)
5110 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5111 self.assertEqual(0, fent.flags)
5112 self.assertEqual(ATF_BL2U_DATA, fent.data)
5113 self.assertEqual(True, fent.valid)
5114
5115 def testFipOther(self):
5116 """Basic FIP with something that isn't a external blob"""
5117 data = self._DoReadFile('204_fip_other.dts')
5118 hdr, fents = fip_util.decode_fip(data)
5119
5120 self.assertEqual(2, len(fents))
5121 fent = fents[1]
5122 self.assertEqual('rot-cert', fent.fip_type)
5123 self.assertEqual(b'aa', fent.data)
5124
Simon Glass3efb2972021-11-23 21:08:59 -07005125 def testFipNoType(self):
5126 """FIP with an entry of an unknown type"""
5127 with self.assertRaises(ValueError) as e:
5128 self._DoReadFile('205_fip_no_type.dts')
5129 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5130 str(e.exception))
5131
5132 def testFipUuid(self):
5133 """Basic FIP with a manual uuid"""
5134 data = self._DoReadFile('206_fip_uuid.dts')
5135 hdr, fents = fip_util.decode_fip(data)
5136
5137 self.assertEqual(2, len(fents))
5138 fent = fents[1]
5139 self.assertEqual(None, fent.fip_type)
5140 self.assertEqual(
5141 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5142 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5143 fent.uuid)
5144 self.assertEqual(U_BOOT_DATA, fent.data)
5145
5146 def testFipLs(self):
5147 """Test listing a FIP"""
5148 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5149 hdr, fents = fip_util.decode_fip(data)
5150
5151 try:
5152 tmpdir, updated_fname = self._SetupImageInTmpdir()
5153 with test_util.capture_sys_output() as (stdout, stderr):
5154 self._DoBinman('ls', '-i', updated_fname)
5155 finally:
5156 shutil.rmtree(tmpdir)
5157 lines = stdout.getvalue().splitlines()
5158 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005159'Name Image-pos Size Entry-type Offset Uncomp-size',
5160'--------------------------------------------------------------',
5161'image 0 2d3 section 0',
5162' atf-fip 0 90 atf-fip 0',
5163' soc-fw 88 4 blob-ext 88',
5164' u-boot 8c 4 u-boot 8c',
5165' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005166]
5167 self.assertEqual(expected, lines)
5168
5169 image = control.images['image']
5170 entries = image.GetEntries()
5171 fdtmap = entries['fdtmap']
5172
5173 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5174 magic = fdtmap_data[:8]
5175 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005176 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005177
5178 fdt_data = fdtmap_data[16:]
5179 dtb = fdt.Fdt.FromData(fdt_data)
5180 dtb.Scan()
5181 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5182 self.assertEqual({
5183 'atf-fip/soc-fw:image-pos': 136,
5184 'atf-fip/soc-fw:offset': 136,
5185 'atf-fip/soc-fw:size': 4,
5186 'atf-fip/u-boot:image-pos': 140,
5187 'atf-fip/u-boot:offset': 140,
5188 'atf-fip/u-boot:size': 4,
5189 'atf-fip:image-pos': 0,
5190 'atf-fip:offset': 0,
5191 'atf-fip:size': 144,
5192 'image-pos': 0,
5193 'offset': 0,
5194 'fdtmap:image-pos': fdtmap.image_pos,
5195 'fdtmap:offset': fdtmap.offset,
5196 'fdtmap:size': len(fdtmap_data),
5197 'size': len(data),
5198 }, props)
5199
5200 def testFipExtractOneEntry(self):
5201 """Test extracting a single entry fron an FIP"""
5202 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005203 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005204 fname = os.path.join(self._indir, 'output.extact')
5205 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005206 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005207 self.assertEqual(U_BOOT_DATA, data)
5208
5209 def testFipReplace(self):
5210 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005211 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005212 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005213 updated_fname = tools.get_output_filename('image-updated.bin')
5214 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005215 entry_name = 'atf-fip/u-boot'
5216 control.WriteEntry(updated_fname, entry_name, expected,
5217 allow_resize=True)
5218 actual = control.ReadEntry(updated_fname, entry_name)
5219 self.assertEqual(expected, actual)
5220
Simon Glass80025522022-01-29 14:14:04 -07005221 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005222 hdr, fents = fip_util.decode_fip(new_data)
5223
5224 self.assertEqual(2, len(fents))
5225
5226 # Check that the FIP entry is updated
5227 fent = fents[1]
5228 self.assertEqual(0x8c, fent.offset)
5229 self.assertEqual(len(expected), fent.size)
5230 self.assertEqual(0, fent.flags)
5231 self.assertEqual(expected, fent.data)
5232 self.assertEqual(True, fent.valid)
5233
5234 def testFipMissing(self):
5235 with test_util.capture_sys_output() as (stdout, stderr):
5236 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5237 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005238 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005239
5240 def testFipSize(self):
5241 """Test a FIP with a size property"""
5242 data = self._DoReadFile('210_fip_size.dts')
5243 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5244 hdr, fents = fip_util.decode_fip(data)
5245 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5246 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5247
5248 self.assertEqual(1, len(fents))
5249
5250 fent = fents[0]
5251 self.assertEqual('soc-fw', fent.fip_type)
5252 self.assertEqual(0x60, fent.offset)
5253 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5254 self.assertEqual(ATF_BL31_DATA, fent.data)
5255 self.assertEqual(True, fent.valid)
5256
5257 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005258 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005259
5260 def testFipBadAlign(self):
5261 """Test that an invalid alignment value in a FIP is detected"""
5262 with self.assertRaises(ValueError) as e:
5263 self._DoTestFile('211_fip_bad_align.dts')
5264 self.assertIn(
5265 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5266 str(e.exception))
5267
5268 def testFipCollection(self):
5269 """Test using a FIP in a collection"""
5270 data = self._DoReadFile('212_fip_collection.dts')
5271 entry1 = control.images['image'].GetEntries()['collection']
5272 data1 = data[:entry1.size]
5273 hdr1, fents2 = fip_util.decode_fip(data1)
5274
5275 entry2 = control.images['image'].GetEntries()['atf-fip']
5276 data2 = data[entry2.offset:entry2.offset + entry2.size]
5277 hdr1, fents2 = fip_util.decode_fip(data2)
5278
5279 # The 'collection' entry should have U-Boot included at the end
5280 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5281 self.assertEqual(data1, data2 + U_BOOT_DATA)
5282 self.assertEqual(U_BOOT_DATA, data1[-4:])
5283
5284 # There should be a U-Boot after the final FIP
5285 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005286
Simon Glassccae6862022-01-12 13:10:35 -07005287 def testFakeBlob(self):
5288 """Test handling of faking an external blob"""
5289 with test_util.capture_sys_output() as (stdout, stderr):
5290 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5291 allow_fake_blobs=True)
5292 err = stderr.getvalue()
5293 self.assertRegex(
5294 err,
5295 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005296
Simon Glassceb5f912022-01-09 20:13:46 -07005297 def testExtblobListFaked(self):
5298 """Test an extblob with missing external blob that are faked"""
5299 with test_util.capture_sys_output() as (stdout, stderr):
5300 self._DoTestFile('216_blob_ext_list_missing.dts',
5301 allow_fake_blobs=True)
5302 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005303 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005304
Simon Glass162017b2022-01-09 20:13:57 -07005305 def testListBintools(self):
5306 args = ['tool', '--list']
5307 with test_util.capture_sys_output() as (stdout, _):
5308 self._DoBinman(*args)
5309 out = stdout.getvalue().splitlines()
5310 self.assertTrue(len(out) >= 2)
5311
5312 def testFetchBintools(self):
5313 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005314 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005315 raise urllib.error.URLError('my error')
5316
5317 args = ['tool']
5318 with self.assertRaises(ValueError) as e:
5319 self._DoBinman(*args)
5320 self.assertIn("Invalid arguments to 'tool' subcommand",
5321 str(e.exception))
5322
5323 args = ['tool', '--fetch']
5324 with self.assertRaises(ValueError) as e:
5325 self._DoBinman(*args)
5326 self.assertIn('Please specify bintools to fetch', str(e.exception))
5327
5328 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005329 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005330 side_effect=fail_download):
5331 with test_util.capture_sys_output() as (stdout, _):
5332 self._DoBinman(*args)
5333 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5334
Simon Glass620c4462022-01-09 20:14:11 -07005335 def testBintoolDocs(self):
5336 """Test for creation of bintool documentation"""
5337 with test_util.capture_sys_output() as (stdout, stderr):
5338 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5339 self.assertTrue(len(stdout.getvalue()) > 0)
5340
5341 def testBintoolDocsMissing(self):
5342 """Test handling of missing bintool documentation"""
5343 with self.assertRaises(ValueError) as e:
5344 with test_util.capture_sys_output() as (stdout, stderr):
5345 control.write_bintool_docs(
5346 control.bintool.Bintool.get_tool_list(), 'mkimage')
5347 self.assertIn('Documentation is missing for modules: mkimage',
5348 str(e.exception))
5349
Jan Kiszka58c407f2022-01-28 20:37:53 +01005350 def testListWithGenNode(self):
5351 """Check handling of an FDT map when the section cannot be found"""
5352 entry_args = {
5353 'of-list': 'test-fdt1 test-fdt2',
5354 }
5355 data = self._DoReadFileDtb(
5356 '219_fit_gennode.dts',
5357 entry_args=entry_args,
5358 use_real_dtb=True,
5359 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5360
5361 try:
5362 tmpdir, updated_fname = self._SetupImageInTmpdir()
5363 with test_util.capture_sys_output() as (stdout, stderr):
5364 self._RunBinman('ls', '-i', updated_fname)
5365 finally:
5366 shutil.rmtree(tmpdir)
5367
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005368 def testFitSubentryUsesBintool(self):
5369 """Test that binman FIT subentries can use bintools"""
5370 command.test_result = self._HandleGbbCommand
5371 entry_args = {
5372 'keydir': 'devkeys',
5373 'bmpblk': 'bmpblk.bin',
5374 }
5375 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5376 entry_args=entry_args)
5377
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005378 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5379 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005380 self.assertIn(expected, data)
5381
5382 def testFitSubentryMissingBintool(self):
5383 """Test that binman reports missing bintools for FIT subentries"""
5384 entry_args = {
5385 'keydir': 'devkeys',
5386 }
5387 with test_util.capture_sys_output() as (_, stderr):
5388 self._DoTestFile('220_fit_subentry_bintool.dts',
5389 force_missing_bintools='futility', entry_args=entry_args)
5390 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005391 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005392
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005393 def testFitSubentryHashSubnode(self):
5394 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005395 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005396 data, _, _, out_dtb_name = self._DoReadFileDtb(
5397 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5398
5399 mkimage_dtb = fdt.Fdt.FromData(data)
5400 mkimage_dtb.Scan()
5401 binman_dtb = fdt.Fdt(out_dtb_name)
5402 binman_dtb.Scan()
5403
5404 # Check that binman didn't add hash values
5405 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5406 self.assertNotIn('value', fnode.props)
5407
5408 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5409 self.assertNotIn('value', fnode.props)
5410
5411 # Check that mkimage added hash values
5412 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5413 self.assertIn('value', fnode.props)
5414
5415 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5416 self.assertIn('value', fnode.props)
5417
Roger Quadros5cdcea02022-02-19 20:50:04 +02005418 def testPackTeeOs(self):
5419 """Test that an image with an TEE binary can be created"""
5420 data = self._DoReadFile('222_tee_os.dts')
5421 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5422
Simon Glass912339f2022-02-08 11:50:03 -07005423 def testFitFdtOper(self):
5424 """Check handling of a specified FIT operation"""
5425 entry_args = {
5426 'of-list': 'test-fdt1 test-fdt2',
5427 'default-dt': 'test-fdt2',
5428 }
5429 self._DoReadFileDtb(
5430 '223_fit_fdt_oper.dts',
5431 entry_args=entry_args,
5432 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5433
5434 def testFitFdtBadOper(self):
5435 """Check handling of an FDT map when the section cannot be found"""
5436 with self.assertRaises(ValueError) as exc:
5437 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005438 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005439 str(exc.exception))
5440
Simon Glassdd156a42022-03-05 20:18:59 -07005441 def test_uses_expand_size(self):
5442 """Test that the 'expand-size' property cannot be used anymore"""
5443 with self.assertRaises(ValueError) as e:
5444 data = self._DoReadFile('225_expand_size_bad.dts')
5445 self.assertIn(
5446 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5447 str(e.exception))
5448
Simon Glass5f423422022-03-05 20:19:12 -07005449 def testFitSplitElf(self):
5450 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005451 if not elf.ELF_TOOLS:
5452 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005453 entry_args = {
5454 'of-list': 'test-fdt1 test-fdt2',
5455 'default-dt': 'test-fdt2',
5456 'atf-bl31-path': 'bl31.elf',
5457 'tee-os-path': 'tee.elf',
5458 }
5459 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5460 data = self._DoReadFileDtb(
5461 '226_fit_split_elf.dts',
5462 entry_args=entry_args,
5463 extra_indirs=[test_subdir])[0]
5464
5465 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5466 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5467
5468 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5469 'data', 'load'}
5470 dtb = fdt.Fdt.FromData(fit_data)
5471 dtb.Scan()
5472
5473 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5474 segments, entry = elf.read_loadable_segments(elf_data)
5475
5476 # We assume there are two segments
5477 self.assertEquals(2, len(segments))
5478
5479 atf1 = dtb.GetNode('/images/atf-1')
5480 _, start, data = segments[0]
5481 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5482 self.assertEqual(entry,
5483 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5484 self.assertEqual(start,
5485 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5486 self.assertEqual(data, atf1.props['data'].bytes)
5487
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005488 hash_node = atf1.FindNode('hash')
5489 self.assertIsNotNone(hash_node)
5490 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5491
Simon Glass5f423422022-03-05 20:19:12 -07005492 atf2 = dtb.GetNode('/images/atf-2')
5493 self.assertEqual(base_keys, atf2.props.keys())
5494 _, start, data = segments[1]
5495 self.assertEqual(start,
5496 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5497 self.assertEqual(data, atf2.props['data'].bytes)
5498
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005499 hash_node = atf2.FindNode('hash')
5500 self.assertIsNotNone(hash_node)
5501 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5502
5503 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5504 self.assertIsNotNone(hash_node)
5505 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5506
Simon Glass5f423422022-03-05 20:19:12 -07005507 conf = dtb.GetNode('/configurations')
5508 self.assertEqual({'default'}, conf.props.keys())
5509
5510 for subnode in conf.subnodes:
5511 self.assertEqual({'description', 'fdt', 'loadables'},
5512 subnode.props.keys())
5513 self.assertEqual(
5514 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5515 fdt_util.GetStringList(subnode, 'loadables'))
5516
5517 def _check_bad_fit(self, dts):
5518 """Check a bad FIT
5519
5520 This runs with the given dts and returns the assertion raised
5521
5522 Args:
5523 dts (str): dts filename to use
5524
5525 Returns:
5526 str: Assertion string raised
5527 """
5528 entry_args = {
5529 'of-list': 'test-fdt1 test-fdt2',
5530 'default-dt': 'test-fdt2',
5531 'atf-bl31-path': 'bl31.elf',
5532 'tee-os-path': 'tee.elf',
5533 }
5534 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5535 with self.assertRaises(ValueError) as exc:
5536 self._DoReadFileDtb(dts, entry_args=entry_args,
5537 extra_indirs=[test_subdir])[0]
5538 return str(exc.exception)
5539
5540 def testFitSplitElfBadElf(self):
5541 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005542 if not elf.ELF_TOOLS:
5543 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005544 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5545 entry_args = {
5546 'of-list': 'test-fdt1 test-fdt2',
5547 'default-dt': 'test-fdt2',
5548 'atf-bl31-path': 'bad.elf',
5549 'tee-os-path': 'tee.elf',
5550 }
5551 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5552 with self.assertRaises(ValueError) as exc:
5553 self._DoReadFileDtb(
5554 '226_fit_split_elf.dts',
5555 entry_args=entry_args,
5556 extra_indirs=[test_subdir])[0]
5557 self.assertIn(
5558 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5559 str(exc.exception))
5560
Simon Glass5f423422022-03-05 20:19:12 -07005561 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005562 """Test an split-elf FIT with a missing ELF file
5563
5564 Args:
5565 kwargs (dict of str): Arguments to pass to _DoTestFile()
5566
5567 Returns:
5568 tuple:
5569 str: stdout result
5570 str: stderr result
5571 """
Simon Glass5f423422022-03-05 20:19:12 -07005572 entry_args = {
5573 'of-list': 'test-fdt1 test-fdt2',
5574 'default-dt': 'test-fdt2',
5575 'atf-bl31-path': 'bl31.elf',
5576 'tee-os-path': 'missing.elf',
5577 }
5578 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5579 with test_util.capture_sys_output() as (stdout, stderr):
5580 self._DoTestFile(
5581 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005582 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5583 out = stdout.getvalue()
5584 err = stderr.getvalue()
5585 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005586
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005587 def testFitSplitElfBadDirective(self):
5588 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5589 if not elf.ELF_TOOLS:
5590 self.skipTest('Python elftools not available')
5591 err = self._check_bad_fit('227_fit_bad_dir.dts')
5592 self.assertIn(
5593 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5594 err)
5595
5596 def testFitSplitElfBadDirectiveConfig(self):
5597 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5598 if not elf.ELF_TOOLS:
5599 self.skipTest('Python elftools not available')
5600 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5601 self.assertEqual(
5602 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5603 err)
5604
5605
Simon Glass5f423422022-03-05 20:19:12 -07005606 def testFitSplitElfMissing(self):
5607 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005608 if not elf.ELF_TOOLS:
5609 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005610 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005611 self.assertRegex(
5612 err,
5613 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005614 self.assertNotRegex(out, '.*Faked blob.*')
5615 fname = tools.get_output_filename('binman-fake/missing.elf')
5616 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005617
5618 def testFitSplitElfFaked(self):
5619 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005620 if not elf.ELF_TOOLS:
5621 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005622 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005623 self.assertRegex(
5624 err,
5625 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005626 self.assertRegex(
5627 out,
5628 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5629 fname = tools.get_output_filename('binman-fake/missing.elf')
5630 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005631
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005632 def testMkimageMissingBlob(self):
5633 """Test using mkimage to build an image"""
5634 with test_util.capture_sys_output() as (stdout, stderr):
5635 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5636 allow_fake_blobs=True)
5637 err = stderr.getvalue()
5638 self.assertRegex(
5639 err,
5640 "Image '.*' has faked external blobs and is non-functional: .*")
5641
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005642 def testPreLoad(self):
5643 """Test an image with a pre-load header"""
5644 entry_args = {
5645 'pre-load-key-path': '.',
5646 }
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005647 data, _, _, _ = self._DoReadFileDtb('230_pre_load.dts',
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005648 entry_args=entry_args)
5649 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5650 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5651 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005652 data = self._DoReadFile('230_pre_load.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005653 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5654 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5655 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5656
5657 def testPreLoadPkcs(self):
5658 """Test an image with a pre-load header with padding pkcs"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005659 data = self._DoReadFile('231_pre_load_pkcs.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005660 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5661 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5662 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5663
5664 def testPreLoadPss(self):
5665 """Test an image with a pre-load header with padding pss"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005666 data = self._DoReadFile('232_pre_load_pss.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005667 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5668 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5669 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5670
5671 def testPreLoadInvalidPadding(self):
5672 """Test an image with a pre-load header with an invalid padding"""
5673 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005674 data = self._DoReadFile('233_pre_load_invalid_padding.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005675
5676 def testPreLoadInvalidSha(self):
5677 """Test an image with a pre-load header with an invalid hash"""
5678 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005679 data = self._DoReadFile('234_pre_load_invalid_sha.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005680
5681 def testPreLoadInvalidAlgo(self):
5682 """Test an image with a pre-load header with an invalid algo"""
5683 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005684 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005685
5686 def testPreLoadInvalidKey(self):
5687 """Test an image with a pre-load header with an invalid key"""
5688 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005689 data = self._DoReadFile('236_pre_load_invalid_key.dts')
Roger Quadros5cdcea02022-02-19 20:50:04 +02005690
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005691 def _CheckSafeUniqueNames(self, *images):
5692 """Check all entries of given images for unsafe unique names"""
5693 for image in images:
5694 entries = {}
5695 image._CollectEntries(entries, {}, image)
5696 for entry in entries.values():
5697 uniq = entry.GetUniqueName()
5698
5699 # Used as part of a filename, so must not be absolute paths.
5700 self.assertFalse(os.path.isabs(uniq))
5701
5702 def testSafeUniqueNames(self):
5703 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005704 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005705
5706 orig_image = control.images['image']
5707 image_fname = tools.get_output_filename('image.bin')
5708 image = Image.FromFile(image_fname)
5709
5710 self._CheckSafeUniqueNames(orig_image, image)
5711
5712 def testSafeUniqueNamesMulti(self):
5713 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005714 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005715
5716 orig_image = control.images['image']
5717 image_fname = tools.get_output_filename('image.bin')
5718 image = Image.FromFile(image_fname)
5719
5720 self._CheckSafeUniqueNames(orig_image, image)
5721
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005722 def testReplaceCmdWithBintool(self):
5723 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005724 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005725 expected = U_BOOT_DATA + b'aa'
5726 self.assertEqual(expected, data[:len(expected)])
5727
5728 try:
5729 tmpdir, updated_fname = self._SetupImageInTmpdir()
5730 fname = os.path.join(tmpdir, 'update-testing.bin')
5731 tools.write_file(fname, b'zz')
5732 self._DoBinman('replace', '-i', updated_fname,
5733 '_testing', '-f', fname)
5734
5735 data = tools.read_file(updated_fname)
5736 expected = U_BOOT_DATA + b'zz'
5737 self.assertEqual(expected, data[:len(expected)])
5738 finally:
5739 shutil.rmtree(tmpdir)
5740
5741 def testReplaceCmdOtherWithBintool(self):
5742 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005743 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005744 expected = U_BOOT_DATA + b'aa'
5745 self.assertEqual(expected, data[:len(expected)])
5746
5747 try:
5748 tmpdir, updated_fname = self._SetupImageInTmpdir()
5749 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5750 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5751 self._DoBinman('replace', '-i', updated_fname,
5752 'u-boot', '-f', fname)
5753
5754 data = tools.read_file(updated_fname)
5755 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5756 self.assertEqual(expected, data[:len(expected)])
5757 finally:
5758 shutil.rmtree(tmpdir)
5759
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005760 def testReplaceResizeNoRepackSameSize(self):
5761 """Test replacing entries with same-size data without repacking"""
5762 expected = b'x' * len(U_BOOT_DATA)
5763 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5764 self.assertEqual(expected, data)
5765
5766 path, fdtmap = state.GetFdtContents('fdtmap')
5767 self.assertIsNotNone(path)
5768 self.assertEqual(expected_fdtmap, fdtmap)
5769
5770 def testReplaceResizeNoRepackSmallerSize(self):
5771 """Test replacing entries with smaller-size data without repacking"""
5772 new_data = b'x'
5773 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5774 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5775 self.assertEqual(expected, data)
5776
5777 path, fdtmap = state.GetFdtContents('fdtmap')
5778 self.assertIsNotNone(path)
5779 self.assertEqual(expected_fdtmap, fdtmap)
5780
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005781 def testExtractFit(self):
5782 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005783 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005784 image_fname = tools.get_output_filename('image.bin')
5785
5786 fit_data = control.ReadEntry(image_fname, 'fit')
5787 fit = fdt.Fdt.FromData(fit_data)
5788 fit.Scan()
5789
5790 # Check subentry data inside the extracted fit
5791 for node_path, expected in [
5792 ('/images/kernel', U_BOOT_DATA),
5793 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5794 ('/images/scr-1', COMPRESS_DATA),
5795 ]:
5796 node = fit.GetNode(node_path)
5797 data = fit.GetProps(node)['data'].bytes
5798 self.assertEqual(expected, data)
5799
5800 def testExtractFitSubentries(self):
5801 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005802 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005803 image_fname = tools.get_output_filename('image.bin')
5804
5805 for entry_path, expected in [
5806 ('fit/kernel', U_BOOT_DATA),
5807 ('fit/kernel/u-boot', U_BOOT_DATA),
5808 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5809 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5810 ('fit/scr-1', COMPRESS_DATA),
5811 ('fit/scr-1/blob', COMPRESS_DATA),
5812 ]:
5813 data = control.ReadEntry(image_fname, entry_path)
5814 self.assertEqual(expected, data)
5815
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005816 def testReplaceFitSubentryLeafSameSize(self):
5817 """Test replacing a FIT leaf subentry with same-size data"""
5818 new_data = b'x' * len(U_BOOT_DATA)
5819 data, expected_fdtmap, _ = self._RunReplaceCmd(
5820 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005821 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005822 self.assertEqual(new_data, data)
5823
5824 path, fdtmap = state.GetFdtContents('fdtmap')
5825 self.assertIsNotNone(path)
5826 self.assertEqual(expected_fdtmap, fdtmap)
5827
5828 def testReplaceFitSubentryLeafBiggerSize(self):
5829 """Test replacing a FIT leaf subentry with bigger-size data"""
5830 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5831 data, expected_fdtmap, _ = self._RunReplaceCmd(
5832 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005833 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005834 self.assertEqual(new_data, data)
5835
5836 # Will be repacked, so fdtmap must change
5837 path, fdtmap = state.GetFdtContents('fdtmap')
5838 self.assertIsNotNone(path)
5839 self.assertNotEqual(expected_fdtmap, fdtmap)
5840
5841 def testReplaceFitSubentryLeafSmallerSize(self):
5842 """Test replacing a FIT leaf subentry with smaller-size data"""
5843 new_data = b'x'
5844 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5845 data, expected_fdtmap, _ = self._RunReplaceCmd(
5846 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005847 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005848 self.assertEqual(expected, data)
5849
5850 path, fdtmap = state.GetFdtContents('fdtmap')
5851 self.assertIsNotNone(path)
5852 self.assertEqual(expected_fdtmap, fdtmap)
5853
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005854 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005855 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005856 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005857 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5858 new_data, dts='241_replace_section_simple.dts')
5859 self.assertEqual(new_data, data)
5860
5861 entries = image.GetEntries()
5862 self.assertIn('section', entries)
5863 entry = entries['section']
5864 self.assertEqual(len(new_data), entry.size)
5865
5866 def testReplaceSectionLarger(self):
5867 """Test replacing a simple section with larger data"""
5868 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5869 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5870 new_data, dts='241_replace_section_simple.dts')
5871 self.assertEqual(new_data, data)
5872
5873 entries = image.GetEntries()
5874 self.assertIn('section', entries)
5875 entry = entries['section']
5876 self.assertEqual(len(new_data), entry.size)
5877 fentry = entries['fdtmap']
5878 self.assertEqual(entry.offset + entry.size, fentry.offset)
5879
5880 def testReplaceSectionSmaller(self):
5881 """Test replacing a simple section with smaller data"""
5882 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5883 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5884 new_data, dts='241_replace_section_simple.dts')
5885 self.assertEqual(new_data, data)
5886
5887 # The new size is the same as the old, just with a pad byte at the end
5888 entries = image.GetEntries()
5889 self.assertIn('section', entries)
5890 entry = entries['section']
5891 self.assertEqual(len(new_data), entry.size)
5892
5893 def testReplaceSectionSmallerAllow(self):
5894 """Test failing to replace a simple section with smaller data"""
5895 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5896 try:
5897 state.SetAllowEntryContraction(True)
5898 with self.assertRaises(ValueError) as exc:
5899 self._RunReplaceCmd('section', new_data,
5900 dts='241_replace_section_simple.dts')
5901 finally:
5902 state.SetAllowEntryContraction(False)
5903
5904 # Since we have no information about the position of things within the
5905 # section, we cannot adjust the position of /section-u-boot so it ends
5906 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06005907 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07005908 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5909 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06005910 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005911
Simon Glass8fbca772022-08-13 11:40:48 -06005912 def testMkimageImagename(self):
5913 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005914 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005915 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005916
5917 # Check that the data appears in the file somewhere
5918 self.assertIn(U_BOOT_SPL_DATA, data)
5919
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005920 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005921 name = data[0x20:0x40]
5922
5923 # Build the filename that we expect to be placed in there, by virtue of
5924 # the -n paraameter
5925 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5926
5927 # Check that the image name is set to the temporary filename used
5928 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5929
Simon Glassb1669752022-08-13 11:40:49 -06005930 def testMkimageImage(self):
5931 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005932 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005933 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005934
5935 # Check that the data appears in the file somewhere
5936 self.assertIn(U_BOOT_SPL_DATA, data)
5937
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005938 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06005939 name = data[0x20:0x40]
5940
5941 # Build the filename that we expect to be placed in there, by virtue of
5942 # the -n paraameter
5943 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5944
5945 # Check that the image name is set to the temporary filename used
5946 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5947
5948 # Check the corect data is in the imagename file
5949 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5950
5951 def testMkimageImageNoContent(self):
5952 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005953 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06005954 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005955 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005956 self.assertIn('Could not complete processing of contents',
5957 str(exc.exception))
5958
5959 def testMkimageImageBad(self):
5960 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005961 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06005962 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005963 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005964 self.assertIn('Cannot use both imagename node and data-to-imagename',
5965 str(exc.exception))
5966
Simon Glassbd5cd882022-08-13 11:40:50 -06005967 def testCollectionOther(self):
5968 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005969 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005970 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5971 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5972 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5973 data)
5974
5975 def testMkimageCollection(self):
5976 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005977 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005978 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005979 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5980 self.assertEqual(expect, data[:len(expect)])
5981
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005982 def testCompressDtbPrependInvalid(self):
5983 """Test that invalid header is detected"""
5984 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005985 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005986 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5987 "'u-boot-dtb': 'invalid'", str(e.exception))
5988
5989 def testCompressDtbPrependLength(self):
5990 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005991 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005992 image = control.images['image']
5993 entries = image.GetEntries()
5994 self.assertIn('u-boot-dtb', entries)
5995 u_boot_dtb = entries['u-boot-dtb']
5996 self.assertIn('fdtmap', entries)
5997 fdtmap = entries['fdtmap']
5998
5999 image_fname = tools.get_output_filename('image.bin')
6000 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6001 dtb = fdt.Fdt.FromData(orig)
6002 dtb.Scan()
6003 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6004 expected = {
6005 'u-boot:size': len(U_BOOT_DATA),
6006 'u-boot-dtb:uncomp-size': len(orig),
6007 'u-boot-dtb:size': u_boot_dtb.size,
6008 'fdtmap:size': fdtmap.size,
6009 'size': len(data),
6010 }
6011 self.assertEqual(expected, props)
6012
6013 # Check implementation
6014 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6015 rest = data[len(U_BOOT_DATA):]
6016 comp_data_len = struct.unpack('<I', rest[:4])[0]
6017 comp_data = rest[4:4 + comp_data_len]
6018 orig2 = self._decompress(comp_data)
6019 self.assertEqual(orig, orig2)
6020
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006021 def testInvalidCompress(self):
6022 """Test that invalid compress algorithm is detected"""
6023 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006024 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006025 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6026
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006027 def testCompUtilCompressions(self):
6028 """Test compression algorithms"""
6029 for bintool in self.comp_bintools.values():
6030 self._CheckBintool(bintool)
6031 data = bintool.compress(COMPRESS_DATA)
6032 self.assertNotEqual(COMPRESS_DATA, data)
6033 orig = bintool.decompress(data)
6034 self.assertEquals(COMPRESS_DATA, orig)
6035
6036 def testCompUtilVersions(self):
6037 """Test tool version of compression algorithms"""
6038 for bintool in self.comp_bintools.values():
6039 self._CheckBintool(bintool)
6040 version = bintool.version()
6041 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6042
6043 def testCompUtilPadding(self):
6044 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006045 # Skip zstd because it doesn't support padding
6046 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006047 self._CheckBintool(bintool)
6048 data = bintool.compress(COMPRESS_DATA)
6049 self.assertNotEqual(COMPRESS_DATA, data)
6050 data += tools.get_bytes(0, 64)
6051 orig = bintool.decompress(data)
6052 self.assertEquals(COMPRESS_DATA, orig)
6053
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006054 def testCompressDtbZstd(self):
6055 """Test that zstd compress of device-tree files failed"""
6056 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006057 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006058 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6059 "requires a length header", str(e.exception))
6060
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006061 def testMkimageMultipleDataFiles(self):
6062 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006063 self._SetupSplElf()
6064 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006065 data = self._DoReadFile('252_mkimage_mult_data.dts')
6066 # Size of files are packed in their 4B big-endian format
6067 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6068 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6069 # Size info is always followed by a 4B zero value.
6070 expect += tools.get_bytes(0, 4)
6071 expect += U_BOOT_TPL_DATA
6072 # All but last files are 4B-aligned
6073 align_pad = len(U_BOOT_TPL_DATA) % 4
6074 if align_pad:
6075 expect += tools.get_bytes(0, align_pad)
6076 expect += U_BOOT_SPL_DATA
6077 self.assertEqual(expect, data[-len(expect):])
6078
Marek Vasutf7413f02023-07-18 07:23:58 -06006079 def testMkimageMultipleExpanded(self):
6080 """Test passing multiple files to mkimage in a mkimage entry"""
6081 self._SetupSplElf()
6082 self._SetupTplElf()
6083 entry_args = {
6084 'spl-bss-pad': 'y',
6085 'spl-dtb': 'y',
6086 }
6087 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6088 use_expanded=True, entry_args=entry_args)[0]
6089 pad_len = 10
6090 tpl_expect = U_BOOT_TPL_DATA
6091 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6092 spl_expect += U_BOOT_SPL_DTB_DATA
6093
6094 content = data[0x40:]
6095 lens = struct.unpack('>III', content[:12])
6096
6097 # Size of files are packed in their 4B big-endian format
6098 # Size info is always followed by a 4B zero value.
6099 self.assertEqual(len(tpl_expect), lens[0])
6100 self.assertEqual(len(spl_expect), lens[1])
6101 self.assertEqual(0, lens[2])
6102
6103 rest = content[12:]
6104 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6105
6106 rest = rest[len(tpl_expect):]
6107 align_pad = len(tpl_expect) % 4
6108 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6109 rest = rest[align_pad:]
6110 self.assertEqual(spl_expect, rest)
6111
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006112 def testMkimageMultipleNoContent(self):
6113 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006114 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006115 with self.assertRaises(ValueError) as exc:
6116 self._DoReadFile('253_mkimage_mult_no_content.dts')
6117 self.assertIn('Could not complete processing of contents',
6118 str(exc.exception))
6119
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006120 def testMkimageFilename(self):
6121 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006122 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006123 retcode = self._DoTestFile('254_mkimage_filename.dts')
6124 self.assertEqual(0, retcode)
6125 fname = tools.get_output_filename('mkimage-test.bin')
6126 self.assertTrue(os.path.exists(fname))
6127
Simon Glass56d05412022-02-28 07:16:54 -07006128 def testVpl(self):
6129 """Test that an image with VPL and its device tree can be created"""
6130 # ELF file with a '__bss_size' symbol
6131 self._SetupVplElf()
6132 data = self._DoReadFile('255_u_boot_vpl.dts')
6133 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6134
6135 def testVplNoDtb(self):
6136 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6137 self._SetupVplElf()
6138 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6139 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6140 data[:len(U_BOOT_VPL_NODTB_DATA)])
6141
6142 def testExpandedVpl(self):
6143 """Test that an expanded entry type is selected for TPL when needed"""
6144 self._SetupVplElf()
6145
6146 entry_args = {
6147 'vpl-bss-pad': 'y',
6148 'vpl-dtb': 'y',
6149 }
6150 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6151 entry_args=entry_args)
6152 image = control.images['image']
6153 entries = image.GetEntries()
6154 self.assertEqual(1, len(entries))
6155
6156 # We only have u-boot-vpl, which be expanded
6157 self.assertIn('u-boot-vpl', entries)
6158 entry = entries['u-boot-vpl']
6159 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6160 subent = entry.GetEntries()
6161 self.assertEqual(3, len(subent))
6162 self.assertIn('u-boot-vpl-nodtb', subent)
6163 self.assertIn('u-boot-vpl-bss-pad', subent)
6164 self.assertIn('u-boot-vpl-dtb', subent)
6165
6166 def testVplBssPadMissing(self):
6167 """Test that a missing symbol is detected"""
6168 self._SetupVplElf('u_boot_ucode_ptr')
6169 with self.assertRaises(ValueError) as e:
6170 self._DoReadFile('258_vpl_bss_pad.dts')
6171 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6172 str(e.exception))
6173
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306174 def testSymlink(self):
6175 """Test that image files can be named"""
6176 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6177 self.assertEqual(0, retcode)
6178 image = control.images['test_image']
6179 fname = tools.get_output_filename('test_image.bin')
6180 sname = tools.get_output_filename('symlink_to_test.bin')
6181 self.assertTrue(os.path.islink(sname))
6182 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006183
Simon Glass37f85de2022-10-20 18:22:47 -06006184 def testSymbolsElf(self):
6185 """Test binman can assign symbols embedded in an ELF file"""
6186 if not elf.ELF_TOOLS:
6187 self.skipTest('Python elftools not available')
6188 self._SetupTplElf('u_boot_binman_syms')
6189 self._SetupVplElf('u_boot_binman_syms')
6190 self._SetupSplElf('u_boot_binman_syms')
6191 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6192 image_fname = tools.get_output_filename('image.bin')
6193
6194 image = control.images['image']
6195 entries = image.GetEntries()
6196
6197 for entry in entries.values():
6198 # No symbols in u-boot and it has faked contents anyway
6199 if entry.name == 'u-boot':
6200 continue
6201 edata = data[entry.image_pos:entry.image_pos + entry.size]
6202 efname = tools.get_output_filename(f'edata-{entry.name}')
6203 tools.write_file(efname, edata)
6204
6205 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6206 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6207 for name, sym in syms.items():
6208 msg = 'test'
6209 val = elf.GetSymbolValue(sym, edata, msg)
6210 entry_m = re_name.match(name)
6211 if entry_m:
6212 ename, prop = entry_m.group(1), entry_m.group(3)
6213 entry, entry_name, prop_name = image.LookupEntry(entries,
6214 name, msg)
6215 if prop_name == 'offset':
6216 expect_val = entry.offset
6217 elif prop_name == 'image_pos':
6218 expect_val = entry.image_pos
6219 elif prop_name == 'size':
6220 expect_val = entry.size
6221 self.assertEqual(expect_val, val)
6222
6223 def testSymbolsElfBad(self):
6224 """Check error when trying to write symbols without the elftools lib"""
6225 if not elf.ELF_TOOLS:
6226 self.skipTest('Python elftools not available')
6227 self._SetupTplElf('u_boot_binman_syms')
6228 self._SetupVplElf('u_boot_binman_syms')
6229 self._SetupSplElf('u_boot_binman_syms')
6230 try:
6231 elf.ELF_TOOLS = False
6232 with self.assertRaises(ValueError) as exc:
6233 self._DoReadFileDtb('260_symbols_elf.dts')
6234 finally:
6235 elf.ELF_TOOLS = True
6236 self.assertIn(
6237 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6238 'Cannot write symbols to an ELF file without Python elftools',
6239 str(exc.exception))
6240
Simon Glassde244162023-01-07 14:07:08 -07006241 def testSectionFilename(self):
6242 """Check writing of section contents to a file"""
6243 data = self._DoReadFile('261_section_fname.dts')
6244 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6245 tools.get_bytes(ord('!'), 7) +
6246 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6247 self.assertEqual(expected, data)
6248
6249 sect_fname = tools.get_output_filename('outfile.bin')
6250 self.assertTrue(os.path.exists(sect_fname))
6251 sect_data = tools.read_file(sect_fname)
6252 self.assertEqual(U_BOOT_DATA, sect_data)
6253
Simon Glass1e9e61c2023-01-07 14:07:12 -07006254 def testAbsent(self):
6255 """Check handling of absent entries"""
6256 data = self._DoReadFile('262_absent.dts')
6257 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6258
Simon Glassad5cfe12023-01-07 14:07:14 -07006259 def testPackTeeOsOptional(self):
6260 """Test that an image with an optional TEE binary can be created"""
6261 entry_args = {
6262 'tee-os-path': 'tee.elf',
6263 }
6264 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6265 entry_args=entry_args)[0]
6266 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6267
6268 def checkFitTee(self, dts, tee_fname):
6269 """Check that a tee-os entry works and returns data
6270
6271 Args:
6272 dts (str): Device tree filename to use
6273 tee_fname (str): filename containing tee-os
6274
6275 Returns:
6276 bytes: Image contents
6277 """
6278 if not elf.ELF_TOOLS:
6279 self.skipTest('Python elftools not available')
6280 entry_args = {
6281 'of-list': 'test-fdt1 test-fdt2',
6282 'default-dt': 'test-fdt2',
6283 'tee-os-path': tee_fname,
6284 }
6285 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6286 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6287 extra_indirs=[test_subdir])[0]
6288 return data
6289
6290 def testFitTeeOsOptionalFit(self):
6291 """Test an image with a FIT with an optional OP-TEE binary"""
6292 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6293
6294 # There should be only one node, holding the data set up in SetUpClass()
6295 # for tee.bin
6296 dtb = fdt.Fdt.FromData(data)
6297 dtb.Scan()
6298 node = dtb.GetNode('/images/tee-1')
6299 self.assertEqual(TEE_ADDR,
6300 fdt_util.fdt32_to_cpu(node.props['load'].value))
6301 self.assertEqual(TEE_ADDR,
6302 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6303 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6304
6305 def testFitTeeOsOptionalFitBad(self):
6306 """Test an image with a FIT with an optional OP-TEE binary"""
6307 with self.assertRaises(ValueError) as exc:
6308 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6309 self.assertIn(
6310 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6311 str(exc.exception))
6312
6313 def testFitTeeOsBad(self):
6314 """Test an OP-TEE binary with wrong formats"""
6315 self.make_tee_bin('tee.bad1', 123)
6316 with self.assertRaises(ValueError) as exc:
6317 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6318 self.assertIn(
6319 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6320 str(exc.exception))
6321
6322 self.make_tee_bin('tee.bad2', 0, b'extra data')
6323 with self.assertRaises(ValueError) as exc:
6324 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6325 self.assertIn(
6326 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6327 str(exc.exception))
6328
Simon Glass63328f12023-01-07 14:07:15 -07006329 def testExtblobOptional(self):
6330 """Test an image with an external blob that is optional"""
6331 with test_util.capture_sys_output() as (stdout, stderr):
6332 data = self._DoReadFile('266_blob_ext_opt.dts')
6333 self.assertEqual(REFCODE_DATA, data)
6334 err = stderr.getvalue()
6335 self.assertRegex(
6336 err,
6337 "Image '.*' is missing external blobs but is still functional: missing")
6338
Simon Glass7447a9d2023-01-11 16:10:12 -07006339 def testSectionInner(self):
6340 """Test an inner section with a size"""
6341 data = self._DoReadFile('267_section_inner.dts')
6342 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6343 self.assertEqual(expected, data)
6344
Simon Glassa4948b22023-01-11 16:10:14 -07006345 def testNull(self):
6346 """Test an image with a null entry"""
6347 data = self._DoReadFile('268_null.dts')
6348 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6349
Simon Glassf1ee03b2023-01-11 16:10:16 -07006350 def testOverlap(self):
6351 """Test an image with a overlapping entry"""
6352 data = self._DoReadFile('269_overlap.dts')
6353 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6354
6355 image = control.images['image']
6356 entries = image.GetEntries()
6357
6358 self.assertIn('inset', entries)
6359 inset = entries['inset']
6360 self.assertEqual(1, inset.offset);
6361 self.assertEqual(1, inset.image_pos);
6362 self.assertEqual(2, inset.size);
6363
6364 def testOverlapNull(self):
6365 """Test an image with a null overlap"""
6366 data = self._DoReadFile('270_overlap_null.dts')
6367 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6368
6369 # Check the FMAP
6370 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6371 self.assertEqual(4, fhdr.nareas)
6372 fiter = iter(fentries)
6373
6374 fentry = next(fiter)
6375 self.assertEqual(b'SECTION', fentry.name)
6376 self.assertEqual(0, fentry.offset)
6377 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6378 self.assertEqual(0, fentry.flags)
6379
6380 fentry = next(fiter)
6381 self.assertEqual(b'U_BOOT', fentry.name)
6382 self.assertEqual(0, fentry.offset)
6383 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6384 self.assertEqual(0, fentry.flags)
6385
6386 # Make sure that the NULL entry appears in the FMAP
6387 fentry = next(fiter)
6388 self.assertEqual(b'NULL', fentry.name)
6389 self.assertEqual(1, fentry.offset)
6390 self.assertEqual(2, fentry.size)
6391 self.assertEqual(0, fentry.flags)
6392
6393 fentry = next(fiter)
6394 self.assertEqual(b'FMAP', fentry.name)
6395 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6396
6397 def testOverlapBad(self):
6398 """Test an image with a bad overlapping entry"""
6399 with self.assertRaises(ValueError) as exc:
6400 self._DoReadFile('271_overlap_bad.dts')
6401 self.assertIn(
6402 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6403 str(exc.exception))
6404
6405 def testOverlapNoOffset(self):
6406 """Test an image with a bad overlapping entry"""
6407 with self.assertRaises(ValueError) as exc:
6408 self._DoReadFile('272_overlap_no_size.dts')
6409 self.assertIn(
6410 "Node '/binman/inset': 'fill' entry is missing properties: size",
6411 str(exc.exception))
6412
Simon Glasse0035c92023-01-11 16:10:17 -07006413 def testBlobSymbol(self):
6414 """Test a blob with symbols read from an ELF file"""
6415 elf_fname = self.ElfTestFile('blob_syms')
6416 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6417 TestFunctional._MakeInputFile('blob_syms.bin',
6418 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6419
6420 data = self._DoReadFile('273_blob_symbol.dts')
6421
6422 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6423 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6424 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6425 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6426 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6427
6428 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6429 expected = sym_values
6430 self.assertEqual(expected, data[:len(expected)])
6431
Simon Glass49e9c002023-01-11 16:10:19 -07006432 def testOffsetFromElf(self):
6433 """Test a blob with symbols read from an ELF file"""
6434 elf_fname = self.ElfTestFile('blob_syms')
6435 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6436 TestFunctional._MakeInputFile('blob_syms.bin',
6437 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6438
6439 data = self._DoReadFile('274_offset_from_elf.dts')
6440
6441 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6442 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6443
6444 image = control.images['image']
6445 entries = image.GetEntries()
6446
6447 self.assertIn('inset', entries)
6448 inset = entries['inset']
6449
6450 self.assertEqual(base + 4, inset.offset);
6451 self.assertEqual(base + 4, inset.image_pos);
6452 self.assertEqual(4, inset.size);
6453
6454 self.assertIn('inset2', entries)
6455 inset = entries['inset2']
6456 self.assertEqual(base + 8, inset.offset);
6457 self.assertEqual(base + 8, inset.image_pos);
6458 self.assertEqual(4, inset.size);
6459
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006460 def testFitAlign(self):
6461 """Test an image with an FIT with aligned external data"""
6462 data = self._DoReadFile('275_fit_align.dts')
6463 self.assertEqual(4096, len(data))
6464
6465 dtb = fdt.Fdt.FromData(data)
6466 dtb.Scan()
6467
6468 props = self._GetPropTree(dtb, ['data-position'])
6469 expected = {
6470 'u-boot:data-position': 1024,
6471 'fdt-1:data-position': 2048,
6472 'fdt-2:data-position': 3072,
6473 }
6474 self.assertEqual(expected, props)
6475
Jonas Karlman490f73c2023-01-21 19:02:12 +00006476 def testFitFirmwareLoadables(self):
6477 """Test an image with an FIT that use fit,firmware"""
6478 if not elf.ELF_TOOLS:
6479 self.skipTest('Python elftools not available')
6480 entry_args = {
6481 'of-list': 'test-fdt1',
6482 'default-dt': 'test-fdt1',
6483 'atf-bl31-path': 'bl31.elf',
6484 'tee-os-path': 'missing.bin',
6485 }
6486 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006487 with test_util.capture_sys_output() as (stdout, stderr):
6488 data = self._DoReadFileDtb(
6489 '276_fit_firmware_loadables.dts',
6490 entry_args=entry_args,
6491 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006492
6493 dtb = fdt.Fdt.FromData(data)
6494 dtb.Scan()
6495
6496 node = dtb.GetNode('/configurations/conf-uboot-1')
6497 self.assertEqual('u-boot', node.props['firmware'].value)
6498 self.assertEqual(['atf-1', 'atf-2'],
6499 fdt_util.GetStringList(node, 'loadables'))
6500
6501 node = dtb.GetNode('/configurations/conf-atf-1')
6502 self.assertEqual('atf-1', node.props['firmware'].value)
6503 self.assertEqual(['u-boot', 'atf-2'],
6504 fdt_util.GetStringList(node, 'loadables'))
6505
6506 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6507 self.assertEqual('u-boot', node.props['firmware'].value)
6508 self.assertEqual(['atf-1', 'atf-2'],
6509 fdt_util.GetStringList(node, 'loadables'))
6510
6511 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6512 self.assertEqual('atf-1', node.props['firmware'].value)
6513 self.assertEqual(['u-boot', 'atf-2'],
6514 fdt_util.GetStringList(node, 'loadables'))
6515
6516 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6517 self.assertEqual('atf-1', node.props['firmware'].value)
6518 self.assertEqual(['u-boot', 'atf-2'],
6519 fdt_util.GetStringList(node, 'loadables'))
6520
Simon Glass9a1c7262023-02-22 12:14:49 -07006521 def testTooldir(self):
6522 """Test that we can specify the tooldir"""
6523 with test_util.capture_sys_output() as (stdout, stderr):
6524 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6525 'tool', '-l'))
6526 self.assertEqual('fred', bintool.Bintool.tooldir)
6527
6528 # Check that the toolpath is updated correctly
6529 self.assertEqual(['fred'], tools.tool_search_paths)
6530
6531 # Try with a few toolpaths; the tooldir should be at the end
6532 with test_util.capture_sys_output() as (stdout, stderr):
6533 self.assertEqual(0, self._DoBinman(
6534 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6535 'tool', '-l'))
6536 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6537
Simon Glass49b77e82023-03-02 17:02:44 -07006538 def testReplaceSectionEntry(self):
6539 """Test replacing an entry in a section"""
6540 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6541 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6542 expect_data, dts='241_replace_section_simple.dts')
6543 self.assertEqual(expect_data, entry_data)
6544
6545 entries = image.GetEntries()
6546 self.assertIn('section', entries)
6547 section = entries['section']
6548
6549 sect_entries = section.GetEntries()
6550 self.assertIn('blob', sect_entries)
6551 entry = sect_entries['blob']
6552 self.assertEqual(len(expect_data), entry.size)
6553
6554 fname = tools.get_output_filename('image-updated.bin')
6555 data = tools.read_file(fname)
6556
6557 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6558 self.assertEqual(expect_data, new_blob_data)
6559
6560 self.assertEqual(U_BOOT_DATA,
6561 data[entry.image_pos + len(expect_data):]
6562 [:len(U_BOOT_DATA)])
6563
6564 def testReplaceSectionDeep(self):
6565 """Test replacing an entry in two levels of sections"""
6566 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6567 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6568 'section/section/blob', expect_data,
6569 dts='278_replace_section_deep.dts')
6570 self.assertEqual(expect_data, entry_data)
6571
6572 entries = image.GetEntries()
6573 self.assertIn('section', entries)
6574 section = entries['section']
6575
6576 subentries = section.GetEntries()
6577 self.assertIn('section', subentries)
6578 section = subentries['section']
6579
6580 sect_entries = section.GetEntries()
6581 self.assertIn('blob', sect_entries)
6582 entry = sect_entries['blob']
6583 self.assertEqual(len(expect_data), entry.size)
6584
6585 fname = tools.get_output_filename('image-updated.bin')
6586 data = tools.read_file(fname)
6587
6588 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6589 self.assertEqual(expect_data, new_blob_data)
6590
6591 self.assertEqual(U_BOOT_DATA,
6592 data[entry.image_pos + len(expect_data):]
6593 [:len(U_BOOT_DATA)])
6594
6595 def testReplaceFitSibling(self):
6596 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006597 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006598 fname = TestFunctional._MakeInputFile('once', b'available once')
6599 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6600 os.remove(fname)
6601
6602 try:
6603 tmpdir, updated_fname = self._SetupImageInTmpdir()
6604
6605 fname = os.path.join(tmpdir, 'update-blob')
6606 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6607 tools.write_file(fname, expected)
6608
6609 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6610 data = tools.read_file(updated_fname)
6611 start = len(U_BOOT_DTB_DATA)
6612 self.assertEqual(expected, data[start:start + len(expected)])
6613 map_fname = os.path.join(tmpdir, 'image-updated.map')
6614 self.assertFalse(os.path.exists(map_fname))
6615 finally:
6616 shutil.rmtree(tmpdir)
6617
Simon Glassc3fe97f2023-03-02 17:02:45 -07006618 def testX509Cert(self):
6619 """Test creating an X509 certificate"""
6620 keyfile = self.TestFile('key.key')
6621 entry_args = {
6622 'keyfile': keyfile,
6623 }
6624 data = self._DoReadFileDtb('279_x509_cert.dts',
6625 entry_args=entry_args)[0]
6626 cert = data[:-4]
6627 self.assertEqual(U_BOOT_DATA, data[-4:])
6628
6629 # TODO: verify the signature
6630
6631 def testX509CertMissing(self):
6632 """Test that binman still produces an image if openssl is missing"""
6633 keyfile = self.TestFile('key.key')
6634 entry_args = {
6635 'keyfile': 'keyfile',
6636 }
6637 with test_util.capture_sys_output() as (_, stderr):
6638 self._DoTestFile('279_x509_cert.dts',
6639 force_missing_bintools='openssl',
6640 entry_args=entry_args)
6641 err = stderr.getvalue()
6642 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6643
Jonas Karlman35305492023-02-25 19:01:33 +00006644 def testPackRockchipTpl(self):
6645 """Test that an image with a Rockchip TPL binary can be created"""
6646 data = self._DoReadFile('277_rockchip_tpl.dts')
6647 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6648
Jonas Karlman1016ec72023-02-25 19:01:35 +00006649 def testMkimageMissingBlobMultiple(self):
6650 """Test missing blob with mkimage entry and multiple-data-files"""
6651 with test_util.capture_sys_output() as (stdout, stderr):
6652 self._DoTestFile('278_mkimage_missing_multiple.dts', allow_missing=True)
6653 err = stderr.getvalue()
6654 self.assertIn("is missing external blobs and is non-functional", err)
6655
6656 with self.assertRaises(ValueError) as e:
6657 self._DoTestFile('278_mkimage_missing_multiple.dts', allow_missing=False)
6658 self.assertIn("not found in input path", str(e.exception))
6659
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006660 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6661 """Prepare sign environment
6662
6663 Create private and public keys, add pubkey into dtb.
6664
6665 Returns:
6666 Tuple:
6667 FIT container
6668 Image name
6669 Private key
6670 DTB
6671 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006672 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006673 data = self._DoReadFileRealDtb(dts)
6674 updated_fname = tools.get_output_filename('image-updated.bin')
6675 tools.write_file(updated_fname, data)
6676 dtb = tools.get_output_filename('source.dtb')
6677 private_key = tools.get_output_filename('test_key.key')
6678 public_key = tools.get_output_filename('test_key.crt')
6679 fit = tools.get_output_filename('fit.fit')
6680 key_dir = tools.get_output_dir()
6681
6682 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6683 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6684 private_key, '-out', public_key)
6685 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6686 '-n', 'test_key', '-r', 'conf', dtb)
6687
6688 return fit, updated_fname, private_key, dtb
6689
6690 def testSignSimple(self):
6691 """Test that a FIT container can be signed in image"""
6692 is_signed = False
6693 fit, fname, private_key, dtb = self._PrepareSignEnv()
6694
6695 # do sign with private key
6696 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6697 ['fit'])
6698 is_signed = self._CheckSign(fit, dtb)
6699
6700 self.assertEqual(is_signed, True)
6701
6702 def testSignExactFIT(self):
6703 """Test that a FIT container can be signed and replaced in image"""
6704 is_signed = False
6705 fit, fname, private_key, dtb = self._PrepareSignEnv()
6706
6707 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6708 args = []
6709 if self.toolpath:
6710 for path in self.toolpath:
6711 args += ['--toolpath', path]
6712
6713 # do sign with private key
6714 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6715 'sha256,rsa4096', '-f', fit, 'fit')
6716 is_signed = self._CheckSign(fit, dtb)
6717
6718 self.assertEqual(is_signed, True)
6719
6720 def testSignNonFit(self):
6721 """Test a non-FIT entry cannot be signed"""
6722 is_signed = False
6723 fit, fname, private_key, _ = self._PrepareSignEnv(
6724 '281_sign_non_fit.dts')
6725
6726 # do sign with private key
6727 with self.assertRaises(ValueError) as e:
6728 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6729 'sha256,rsa4096', '-f', fit, 'u-boot')
6730 self.assertIn(
6731 "Node '/u-boot': Updating signatures is not supported with this entry type",
6732 str(e.exception))
6733
6734 def testSignMissingMkimage(self):
6735 """Test that FIT signing handles a missing mkimage tool"""
6736 fit, fname, private_key, _ = self._PrepareSignEnv()
6737
6738 # try to sign with a missing mkimage tool
6739 bintool.Bintool.set_missing_list(['mkimage'])
6740 with self.assertRaises(ValueError) as e:
6741 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6742 ['fit'])
6743 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6744
Simon Glass4abf7842023-07-18 07:23:54 -06006745 def testSymbolNoWrite(self):
6746 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006747 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006748 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6749 no_write_symbols=True)
6750
6751 def testSymbolNoWriteExpanded(self):
6752 """Test disabling of symbol writing in expanded entries"""
6753 entry_args = {
6754 'spl-dtb': '1',
6755 }
6756 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6757 U_BOOT_SPL_DTB_DATA, 0x38,
6758 entry_args=entry_args, use_expanded=True,
6759 no_write_symbols=True)
6760
Marek Vasutf7413f02023-07-18 07:23:58 -06006761 def testMkimageSpecial(self):
6762 """Test mkimage ignores special hash-1 node"""
6763 data = self._DoReadFile('283_mkimage_special.dts')
6764
6765 # Just check that the data appears in the file somewhere
6766 self.assertIn(U_BOOT_DATA, data)
6767
Simon Glass2d94c422023-07-18 07:23:59 -06006768 def testFitFdtList(self):
6769 """Test an image with an FIT with the fit,fdt-list-val option"""
6770 entry_args = {
6771 'default-dt': 'test-fdt2',
6772 }
6773 data = self._DoReadFileDtb(
6774 '284_fit_fdt_list.dts',
6775 entry_args=entry_args,
6776 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6777 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6778 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6779
Simon Glass83b8bfe2023-07-18 07:24:01 -06006780 def testSplEmptyBss(self):
6781 """Test an expanded SPL with a zero-size BSS"""
6782 # ELF file with a '__bss_size' symbol
6783 self._SetupSplElf(src_fname='bss_data_zero')
6784
6785 entry_args = {
6786 'spl-bss-pad': 'y',
6787 'spl-dtb': 'y',
6788 }
6789 data = self._DoReadFileDtb('285_spl_expand.dts',
6790 use_expanded=True, entry_args=entry_args)[0]
6791
Simon Glassfc792842023-07-18 07:24:04 -06006792 def testTemplate(self):
6793 """Test using a template"""
6794 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6795 data = self._DoReadFile('286_template.dts')
6796 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6797 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6798 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6799
Simon Glass9909c112023-07-18 07:24:05 -06006800 def testTemplateBlobMulti(self):
6801 """Test using a template with 'multiple-images' enabled"""
6802 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6803 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6804 retcode = self._DoTestFile('287_template_multi.dts')
6805
6806 self.assertEqual(0, retcode)
6807 image = control.images['image']
6808 image_fname = tools.get_output_filename('my-image.bin')
6809 data = tools.read_file(image_fname)
6810 self.assertEqual(b'blob@@@@other', data)
6811
Simon Glass5dc511b2023-07-18 07:24:06 -06006812 def testTemplateFit(self):
6813 """Test using a template in a FIT"""
6814 fit_data = self._DoReadFile('288_template_fit.dts')
6815 fname = os.path.join(self._indir, 'fit_data.fit')
6816 tools.write_file(fname, fit_data)
6817 out = tools.run('dumpimage', '-l', fname)
6818
Simon Glassaa6e0552023-07-18 07:24:07 -06006819 def testTemplateSection(self):
6820 """Test using a template in a section (not at top level)"""
6821 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6822 data = self._DoReadFile('289_template_section.dts')
6823 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6824 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6825 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6826
Simon Glassf53a7bc2023-07-18 07:24:08 -06006827 def testMkimageSymbols(self):
6828 """Test using mkimage to build an image with symbols in it"""
6829 self._SetupSplElf('u_boot_binman_syms')
6830 data = self._DoReadFile('290_mkimage_sym.dts')
6831
6832 image = control.images['image']
6833 entries = image.GetEntries()
6834 self.assertIn('u-boot', entries)
6835 u_boot = entries['u-boot']
6836
6837 mkim = entries['mkimage']
6838 mkim_entries = mkim.GetEntries()
6839 self.assertIn('u-boot-spl', mkim_entries)
6840 spl = mkim_entries['u-boot-spl']
6841 self.assertIn('u-boot-spl2', mkim_entries)
6842 spl2 = mkim_entries['u-boot-spl2']
6843
6844 # skip the mkimage header and the area sizes
6845 mk_data = data[mkim.offset + 0x40:]
6846 size, term = struct.unpack('>LL', mk_data[:8])
6847
6848 # There should be only one image, so check that the zero terminator is
6849 # present
6850 self.assertEqual(0, term)
6851
6852 content = mk_data[8:8 + size]
6853
6854 # The image should contain the symbols from u_boot_binman_syms.c
6855 # Note that image_pos is adjusted by the base address of the image,
6856 # which is 0x10 in our test image
6857 spl_data = content[:0x18]
6858 content = content[0x1b:]
6859
6860 # After the header is a table of offsets for each image. There should
6861 # only be one image, then a 0 terminator, so figure out the real start
6862 # of the image data
6863 base = 0x40 + 8
6864
6865 # Check symbols in both u-boot-spl and u-boot-spl2
6866 for i in range(2):
6867 vals = struct.unpack('<LLQLL', spl_data)
6868
6869 # The image should contain the symbols from u_boot_binman_syms.c
6870 # Note that image_pos is adjusted by the base address of the image,
6871 # which is 0x10 in our 'u_boot_binman_syms' test image
6872 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6873 self.assertEqual(base, vals[1])
6874 self.assertEqual(spl2.offset, vals[2])
6875 # figure out the internal positions of its components
6876 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6877
6878 # Check that spl and spl2 are actually at the indicated positions
6879 self.assertEqual(
6880 elf.BINMAN_SYM_MAGIC_VALUE,
6881 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6882 self.assertEqual(
6883 elf.BINMAN_SYM_MAGIC_VALUE,
6884 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6885
6886 self.assertEqual(len(U_BOOT_DATA), vals[4])
6887
6888 # Move to next
6889 spl_data = content[:0x18]
6890
Neha Malcom Francis3b788942023-07-22 00:14:24 +05306891 def testTIBoardConfig(self):
6892 """Test that a schema validated board config file can be generated"""
6893 data = self._DoReadFile('277_ti_board_cfg.dts')
6894 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
6895
6896 def testTIBoardConfigCombined(self):
6897 """Test that a schema validated combined board config file can be generated"""
6898 data = self._DoReadFile('278_ti_board_cfg_combined.dts')
6899 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
6900 self.assertGreater(data, configlen_noheader)
6901
6902 def testTIBoardConfigNoDataType(self):
6903 """Test that error is thrown when data type is not supported"""
6904 with self.assertRaises(ValueError) as e:
6905 data = self._DoReadFile('279_ti_board_cfg_no_type.dts')
6906 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07006907
Simon Glassac599912017-11-12 21:52:22 -07006908if __name__ == "__main__":
6909 unittest.main()