blob: ecada41833e3fbb8c8ea0c195e88efba7f244aac [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"'
Christian Taedcke62ac29a2023-07-17 09:05:54 +020097ENCRYPTED_IV_DATA = b'123456'
98ENCRYPTED_KEY_DATA = b'abcde'
Philippe Reynesebe96cb2022-03-28 22:57:04 +020099PRE_LOAD_MAGIC = b'UBSH'
100PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
101PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530102TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530103TI_UNSECURE_DATA = b'unsecuredata'
Simon Glassa435cd12020-09-01 05:13:59 -0600104
105# Subdirectory of the input dir to use to put test FDTs
106TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600107
Simon Glass2c6adba2019-07-20 12:23:47 -0600108# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600109EXTRACT_DTB_SIZE = 0x3c9
110
Simon Glass2c6adba2019-07-20 12:23:47 -0600111# Properties expected to be in the device tree when update_dtb is used
112BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
113
Simon Glassfb30e292019-07-20 12:23:51 -0600114# Extra properties expected to be in the device tree when allow-repack is used
115REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
116
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200117# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200118COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700119
Simon Glassad5cfe12023-01-07 14:07:14 -0700120TEE_ADDR = 0x5678
121
Simon Glass57454f42016-11-25 20:15:52 -0700122class TestFunctional(unittest.TestCase):
123 """Functional tests for binman
124
125 Most of these use a sample .dts file to build an image and then check
126 that it looks correct. The sample files are in the test/ subdirectory
127 and are numbered.
128
129 For each entry type a very small test file is created using fixed
130 string contents. This makes it easy to test that things look right, and
131 debug problems.
132
133 In some cases a 'real' file must be used - these are also supplied in
134 the test/ diurectory.
135 """
136 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600137 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700138 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600139 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700140
Simon Glass57454f42016-11-25 20:15:52 -0700141 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600142 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
143 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700144
145 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600146 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700147
148 # Create some test files
149 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
150 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
151 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600152 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700153 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700154 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700155 TestFunctional._MakeInputFile('me.bin', ME_DATA)
156 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600157 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600158
Jagdish Gediya311d4842018-09-03 21:35:08 +0530159 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600160
Simon Glassabab18c2019-08-24 07:22:49 -0600161 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
162 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700163 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600164 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600165 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600166
167 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
168 X86_RESET16_DATA)
169 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
170 X86_RESET16_SPL_DATA)
171 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
172 X86_RESET16_TPL_DATA)
173
Simon Glass57454f42016-11-25 20:15:52 -0700174 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700175 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
176 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600177 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
178 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700179 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
180 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700181 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
182 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700183 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700184 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600185 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600186 TestFunctional._MakeInputDir('devkeys')
187 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600188 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600189 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600190 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600191 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700192
Simon Glassf6290892019-08-24 07:22:53 -0600193 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
194 elf_test.BuildElfTestFiles(cls._elf_testdir)
195
Simon Glass72232452016-11-25 20:15:53 -0700196 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600197 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700198 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700199
200 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600201 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700202
Simon Glass862f8e22019-08-24 07:22:43 -0600203 shutil.copytree(cls.TestFile('files'),
204 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600205
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530206 shutil.copytree(cls.TestFile('yaml'),
207 os.path.join(cls._indir, 'yaml'))
208
Simon Glass7ba33592018-09-14 04:57:26 -0600209 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600210 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600211 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200212 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700213 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800214 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500215 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman35305492023-02-25 19:01:33 +0000216 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530217 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600218
Simon Glassa435cd12020-09-01 05:13:59 -0600219 # Add a few .dtb files for testing
220 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
221 TEST_FDT1_DATA)
222 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
223 TEST_FDT2_DATA)
224
Simon Glassa0729502020-09-06 10:35:33 -0600225 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
226
Simon Glass5f423422022-03-05 20:19:12 -0700227 # ELF file with two sections in different parts of memory, used for both
228 # ATF and OP_TEE
229 TestFunctional._MakeInputFile('bl31.elf',
230 tools.read_file(cls.ElfTestFile('elf_sections')))
231 TestFunctional._MakeInputFile('tee.elf',
232 tools.read_file(cls.ElfTestFile('elf_sections')))
233
Simon Glassad5cfe12023-01-07 14:07:14 -0700234 # Newer OP_TEE file in v1 binary format
235 cls.make_tee_bin('tee.bin')
236
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200237 # test files for encrypted tests
238 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
239 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
240
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200241 cls.comp_bintools = {}
242 for name in COMP_BINTOOLS:
243 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600244
Simon Glass57454f42016-11-25 20:15:52 -0700245 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600246 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700247 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600248 if cls.preserve_indir:
249 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600250 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600251 if cls._indir:
252 shutil.rmtree(cls._indir)
253 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700254
Simon Glass1c420c92019-07-08 13:18:49 -0600255 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600256 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600257 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600258 """Accept arguments controlling test execution
259
260 Args:
261 preserve_indir: Preserve the shared input directory used by all
262 tests in this class.
263 preserve_outdir: Preserve the output directories used by tests. Each
264 test has its own, so this is normally only useful when running a
265 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600266 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600267 """
268 cls.preserve_indir = preserve_indir
269 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600270 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600271 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600272
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200273 def _CheckBintool(self, bintool):
274 if not bintool.is_present():
275 self.skipTest('%s not available' % bintool.name)
276
Simon Glass1de34482019-07-08 13:18:53 -0600277 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200278 bintool = self.comp_bintools['lz4']
279 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600280
Simon Glassee9d10d2019-07-20 12:24:09 -0600281 def _CleanupOutputDir(self):
282 """Remove the temporary output directory"""
283 if self.preserve_outdirs:
284 print('Preserving output dir: %s' % tools.outdir)
285 else:
Simon Glass80025522022-01-29 14:14:04 -0700286 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600287
Simon Glass57454f42016-11-25 20:15:52 -0700288 def setUp(self):
289 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700290 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700291 command.test_result = None
292
293 def tearDown(self):
294 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600295 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700296
Simon Glassb3d6fc72019-07-20 12:24:10 -0600297 def _SetupImageInTmpdir(self):
298 """Set up the output image in a new temporary directory
299
300 This is used when an image has been generated in the output directory,
301 but we want to run binman again. This will create a new output
302 directory and fail to delete the original one.
303
304 This creates a new temporary directory, copies the image to it (with a
305 new name) and removes the old output directory.
306
307 Returns:
308 Tuple:
309 Temporary directory to use
310 New image filename
311 """
Simon Glass80025522022-01-29 14:14:04 -0700312 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600313 tmpdir = tempfile.mkdtemp(prefix='binman.')
314 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700315 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600316 self._CleanupOutputDir()
317 return tmpdir, updated_fname
318
Simon Glass8425a1f2018-07-17 13:25:48 -0600319 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600320 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600321 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
322 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
323 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700324 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600325
Simon Glass57454f42016-11-25 20:15:52 -0700326 def _RunBinman(self, *args, **kwargs):
327 """Run binman using the command line
328
329 Args:
330 Arguments to pass, as a list of strings
331 kwargs: Arguments to pass to Command.RunPipe()
332 """
Simon Glass840be732022-01-29 14:14:05 -0700333 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700334 capture=True, capture_stderr=True, raise_on_error=False)
335 if result.return_code and kwargs.get('raise_on_error', True):
336 raise Exception("Error running '%s': %s" % (' '.join(args),
337 result.stdout + result.stderr))
338 return result
339
Simon Glassf46732a2019-07-08 14:25:29 -0600340 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700341 """Run binman using directly (in the same process)
342
343 Args:
344 Arguments to pass, as a list of strings
345 Returns:
346 Return value (0 for success)
347 """
Simon Glassf46732a2019-07-08 14:25:29 -0600348 argv = list(argv)
349 args = cmdline.ParseArgs(argv)
350 args.pager = 'binman-invalid-pager'
351 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700352
353 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600354 # args.verbosity = tout.DEBUG
355 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700356
Simon Glass91710b32018-07-17 13:25:32 -0600357 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600358 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300359 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100360 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700361 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis6b463da2023-07-22 00:14:44 +0530362 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass57454f42016-11-25 20:15:52 -0700363 """Run binman with a given test file
364
365 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600366 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600367 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600368 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600369 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600370 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600371 entry_args: Dict of entry args to supply to binman
372 key: arg name
373 value: value of that arg
374 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600375 use_real_dtb: True to use the test file as the contents of
376 the u-boot-dtb entry. Normally this is not needed and the
377 test contents (the U_BOOT_DTB_DATA string) can be used.
378 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300379 use_expanded: True to use expanded entries where available, e.g.
380 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600381 verbosity: Verbosity level to use (0-3, None=don't set it)
382 allow_missing: Set the '--allow-missing' flag so that missing
383 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100384 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600385 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600386 threads: Number of threads to use (None for default, 0 for
387 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600388 test_section_timeout: True to force the first time to timeout, as
389 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600390 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass66152ce2022-01-09 20:14:09 -0700391 force_missing_tools (str): comma-separated list of bintools to
392 regard as missing
Andrew Davis6b463da2023-07-22 00:14:44 +0530393 output_dir: Specific output directory to use for image using -O
Simon Glass9a798402021-11-03 21:09:17 -0600394
395 Returns:
396 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700397 """
Simon Glassf46732a2019-07-08 14:25:29 -0600398 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700399 if debug:
400 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600401 if verbosity is not None:
402 args.append('-v%d' % verbosity)
403 elif self.verbosity:
404 args.append('-v%d' % self.verbosity)
405 if self.toolpath:
406 for path in self.toolpath:
407 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600408 if threads is not None:
409 args.append('-T%d' % threads)
410 if test_section_timeout:
411 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600412 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600413 if map:
414 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600415 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600416 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600417 if not use_real_dtb:
418 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300419 if not use_expanded:
420 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600421 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600422 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600423 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600424 if allow_missing:
425 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700426 if ignore_missing:
427 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100428 if allow_fake_blobs:
429 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700430 if force_missing_bintools:
431 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600432 if update_fdt_in_elf:
433 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600434 if images:
435 for image in images:
436 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600437 if extra_indirs:
438 for indir in extra_indirs:
439 args += ['-I', indir]
Andrew Davis6b463da2023-07-22 00:14:44 +0530440 if output_dir:
441 args += ['-O', output_dir]
Simon Glass075a45c2017-11-13 18:55:00 -0700442 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700443
444 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700445 """Set up a new test device-tree file
446
447 The given file is compiled and set up as the device tree to be used
448 for ths test.
449
450 Args:
451 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600452 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700453
454 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600455 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700456 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600457 tmpdir = tempfile.mkdtemp(prefix='binmant.')
458 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600459 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700460 data = fd.read()
461 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600462 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600463 return data
Simon Glass57454f42016-11-25 20:15:52 -0700464
Simon Glass56d05412022-02-28 07:16:54 -0700465 def _GetDtbContentsForSpls(self, dtb_data, name):
466 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600467
468 For testing we don't actually have different versions of the DTB. With
469 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
470 we don't normally have any unwanted nodes.
471
472 We still want the DTBs for SPL and TPL to be different though, since
473 otherwise it is confusing to know which one we are looking at. So add
474 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600475
476 Args:
477 dtb_data: dtb data to modify (this should be a value devicetree)
478 name: Name of a new property to add
479
480 Returns:
481 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600482 """
483 dtb = fdt.Fdt.FromData(dtb_data)
484 dtb.Scan()
485 dtb.GetNode('/binman').AddZeroProp(name)
486 dtb.Sync(auto_resize=True)
487 dtb.Pack()
488 return dtb.GetContents()
489
Simon Glassed930672021-03-18 20:25:05 +1300490 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
491 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600492 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700493 """Run binman and return the resulting image
494
495 This runs binman with a given test file and then reads the resulting
496 output file. It is a shortcut function since most tests need to do
497 these steps.
498
499 Raises an assertion failure if binman returns a non-zero exit code.
500
501 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600502 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700503 use_real_dtb: True to use the test file as the contents of
504 the u-boot-dtb entry. Normally this is not needed and the
505 test contents (the U_BOOT_DTB_DATA string) can be used.
506 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300507 use_expanded: True to use expanded entries where available, e.g.
508 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600509 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600510 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600511 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600512 entry_args: Dict of entry args to supply to binman
513 key: arg name
514 value: value of that arg
515 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
516 function. If reset_dtbs is True, then the original test dtb
517 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600518 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600519 threads: Number of threads to use (None for default, 0 for
520 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700521
522 Returns:
523 Tuple:
524 Resulting image contents
525 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600526 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600527 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700528 """
Simon Glass72232452016-11-25 20:15:53 -0700529 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700530 # Use the compiled test file as the u-boot-dtb input
531 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700532 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600533
534 # For testing purposes, make a copy of the DT for SPL and TPL. Add
535 # a node indicating which it is, so aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700536 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600537 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
538 outfile = os.path.join(self._indir, dtb_fname)
539 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700540 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700541
542 try:
Simon Glass91710b32018-07-17 13:25:32 -0600543 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600544 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600545 use_expanded=use_expanded, extra_indirs=extra_indirs,
546 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700547 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700548 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700549
550 # Find the (only) image, read it and return its contents
551 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700552 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600553 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600554 if map:
Simon Glass80025522022-01-29 14:14:04 -0700555 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600556 with open(map_fname) as fd:
557 map_data = fd.read()
558 else:
559 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600560 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600561 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700562 finally:
563 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600564 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600565 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700566
Simon Glass5b4bce32019-07-08 14:25:26 -0600567 def _DoReadFileRealDtb(self, fname):
568 """Run binman with a real .dtb file and return the resulting data
569
570 Args:
571 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
572
573 Returns:
574 Resulting image contents
575 """
576 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
577
Simon Glass72232452016-11-25 20:15:53 -0700578 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600579 """Helper function which discards the device-tree binary
580
581 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600582 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600583 use_real_dtb: True to use the test file as the contents of
584 the u-boot-dtb entry. Normally this is not needed and the
585 test contents (the U_BOOT_DTB_DATA string) can be used.
586 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600587
588 Returns:
589 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600590 """
Simon Glass72232452016-11-25 20:15:53 -0700591 return self._DoReadFileDtb(fname, use_real_dtb)[0]
592
Simon Glass57454f42016-11-25 20:15:52 -0700593 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600594 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700595 """Create a new test input file, creating directories as needed
596
597 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600598 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700599 contents: File contents to write in to the file
600 Returns:
601 Full pathname of file created
602 """
Simon Glass862f8e22019-08-24 07:22:43 -0600603 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700604 dirname = os.path.dirname(pathname)
605 if dirname and not os.path.exists(dirname):
606 os.makedirs(dirname)
607 with open(pathname, 'wb') as fd:
608 fd.write(contents)
609 return pathname
610
611 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600612 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600613 """Create a new test input directory, creating directories as needed
614
615 Args:
616 dirname: Directory name to create
617
618 Returns:
619 Full pathname of directory created
620 """
Simon Glass862f8e22019-08-24 07:22:43 -0600621 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600622 if not os.path.exists(pathname):
623 os.makedirs(pathname)
624 return pathname
625
626 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600627 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600628 """Set up an ELF file with a '_dt_ucode_base_size' symbol
629
630 Args:
631 Filename of ELF file to use as SPL
632 """
Simon Glass93a806f2019-08-24 07:22:59 -0600633 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700634 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600635
636 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600637 def _SetupTplElf(cls, src_fname='bss_data'):
638 """Set up an ELF file with a '_dt_ucode_base_size' symbol
639
640 Args:
641 Filename of ELF file to use as TPL
642 """
643 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700644 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600645
646 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700647 def _SetupVplElf(cls, src_fname='bss_data'):
648 """Set up an ELF file with a '_dt_ucode_base_size' symbol
649
650 Args:
651 Filename of ELF file to use as VPL
652 """
653 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
654 tools.read_file(cls.ElfTestFile(src_fname)))
655
656 @classmethod
Lukas Funkee901faf2023-07-18 13:53:13 +0200657 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
658 """Set up an ELF file with a '_dt_ucode_base_size' symbol
659
660 Args:
661 Filename of ELF file to use as VPL
662 """
663 TestFunctional._MakeInputFile('pmu-firmware.elf',
664 tools.read_file(cls.ElfTestFile(src_fname)))
665
666 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600667 def _SetupDescriptor(cls):
668 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
669 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
670
671 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600672 def TestFile(cls, fname):
673 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700674
Simon Glassf6290892019-08-24 07:22:53 -0600675 @classmethod
676 def ElfTestFile(cls, fname):
677 return os.path.join(cls._elf_testdir, fname)
678
Simon Glassad5cfe12023-01-07 14:07:14 -0700679 @classmethod
680 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
681 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
682 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
683 dummy, paged_sz) + U_BOOT_DATA
684 data += extra_data
685 TestFunctional._MakeInputFile(fname, data)
686
Simon Glass57454f42016-11-25 20:15:52 -0700687 def AssertInList(self, grep_list, target):
688 """Assert that at least one of a list of things is in a target
689
690 Args:
691 grep_list: List of strings to check
692 target: Target string
693 """
694 for grep in grep_list:
695 if grep in target:
696 return
Simon Glass848cdb52019-05-17 22:00:50 -0600697 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700698
699 def CheckNoGaps(self, entries):
700 """Check that all entries fit together without gaps
701
702 Args:
703 entries: List of entries to check
704 """
Simon Glasse8561af2018-08-01 15:22:37 -0600705 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700706 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600707 self.assertEqual(offset, entry.offset)
708 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700709
Simon Glass72232452016-11-25 20:15:53 -0700710 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600711 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700712
713 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600714 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700715
716 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600717 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700718 """
719 return struct.unpack('>L', dtb[4:8])[0]
720
Simon Glass0f621332019-07-08 14:25:27 -0600721 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600722 def AddNode(node, path):
723 if node.name != '/':
724 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600725 for prop in node.props.values():
726 if prop.name in prop_names:
727 prop_path = path + ':' + prop.name
728 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
729 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600730 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600731 AddNode(subnode, path)
732
733 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600734 AddNode(dtb.GetRoot(), '')
735 return tree
736
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000737 def _CheckSign(self, fit, key):
738 try:
739 tools.run('fit_check_sign', '-k', key, '-f', fit)
740 except:
741 self.fail('Expected signed FIT container')
742 return False
743 return True
744
Simon Glass57454f42016-11-25 20:15:52 -0700745 def testRun(self):
746 """Test a basic run with valid args"""
747 result = self._RunBinman('-h')
748
749 def testFullHelp(self):
750 """Test that the full help is displayed with -H"""
751 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300752 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500753 # Remove possible extraneous strings
754 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
755 gothelp = result.stdout.replace(extra, '')
756 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700757 self.assertEqual(0, len(result.stderr))
758 self.assertEqual(0, result.return_code)
759
760 def testFullHelpInternal(self):
761 """Test that the full help is displayed with -H"""
762 try:
763 command.test_result = command.CommandResult()
764 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300765 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700766 finally:
767 command.test_result = None
768
769 def testHelp(self):
770 """Test that the basic help is displayed with -h"""
771 result = self._RunBinman('-h')
772 self.assertTrue(len(result.stdout) > 200)
773 self.assertEqual(0, len(result.stderr))
774 self.assertEqual(0, result.return_code)
775
Simon Glass57454f42016-11-25 20:15:52 -0700776 def testBoard(self):
777 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600778 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700779 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300780 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700781 self.assertEqual(0, result)
782
783 def testNeedBoard(self):
784 """Test that we get an error when no board ius supplied"""
785 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600786 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700787 self.assertIn("Must provide a board to process (use -b <board>)",
788 str(e.exception))
789
790 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600791 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700792 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600793 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700794 # We get one error from libfdt, and a different one from fdtget.
795 self.AssertInList(["Couldn't open blob from 'missing_file'",
796 'No such file or directory'], str(e.exception))
797
798 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600799 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700800
801 Since this is a source file it should be compiled and the error
802 will come from the device-tree compiler (dtc).
803 """
804 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600805 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700806 self.assertIn("FATAL ERROR: Unable to parse input tree",
807 str(e.exception))
808
809 def testMissingNode(self):
810 """Test that a device tree without a 'binman' node generates an error"""
811 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600812 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700813 self.assertIn("does not have a 'binman' node", str(e.exception))
814
815 def testEmpty(self):
816 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600817 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700818 self.assertEqual(0, len(result.stderr))
819 self.assertEqual(0, result.return_code)
820
821 def testInvalidEntry(self):
822 """Test that an invalid entry is flagged"""
823 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600824 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600825 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700826 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
827 "'/binman/not-a-valid-type'", str(e.exception))
828
829 def testSimple(self):
830 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600831 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700832 self.assertEqual(U_BOOT_DATA, data)
833
Simon Glass075a45c2017-11-13 18:55:00 -0700834 def testSimpleDebug(self):
835 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600836 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700837
Simon Glass57454f42016-11-25 20:15:52 -0700838 def testDual(self):
839 """Test that we can handle creating two images
840
841 This also tests image padding.
842 """
Simon Glass511f6582018-10-01 12:22:30 -0600843 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700844 self.assertEqual(0, retcode)
845
846 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600847 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700848 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700849 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600850 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700851 data = fd.read()
852 self.assertEqual(U_BOOT_DATA, data)
853
854 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600855 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700856 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700857 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600858 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700859 data = fd.read()
860 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700861 self.assertEqual(tools.get_bytes(0, 3), data[:3])
862 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700863
864 def testBadAlign(self):
865 """Test that an invalid alignment value is detected"""
866 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600867 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700868 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
869 "of two", str(e.exception))
870
871 def testPackSimple(self):
872 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600873 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700874 self.assertEqual(0, retcode)
875 self.assertIn('image', control.images)
876 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600877 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700878 self.assertEqual(5, len(entries))
879
880 # First u-boot
881 self.assertIn('u-boot', entries)
882 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600883 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700884 self.assertEqual(len(U_BOOT_DATA), entry.size)
885
886 # Second u-boot, aligned to 16-byte boundary
887 self.assertIn('u-boot-align', entries)
888 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600889 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700890 self.assertEqual(len(U_BOOT_DATA), entry.size)
891
892 # Third u-boot, size 23 bytes
893 self.assertIn('u-boot-size', entries)
894 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600895 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700896 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
897 self.assertEqual(23, entry.size)
898
899 # Fourth u-boot, placed immediate after the above
900 self.assertIn('u-boot-next', entries)
901 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600902 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700903 self.assertEqual(len(U_BOOT_DATA), entry.size)
904
Simon Glasse8561af2018-08-01 15:22:37 -0600905 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700906 self.assertIn('u-boot-fixed', entries)
907 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600908 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700909 self.assertEqual(len(U_BOOT_DATA), entry.size)
910
Simon Glass39dd2152019-07-08 14:25:47 -0600911 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700912
913 def testPackExtra(self):
914 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600915 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
916 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700917
Simon Glass57454f42016-11-25 20:15:52 -0700918 self.assertIn('image', control.images)
919 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600920 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600921 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700922
Samuel Hollande2574022023-01-21 17:25:16 -0600923 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700924 self.assertIn('u-boot', entries)
925 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600926 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700927 self.assertEqual(3, entry.pad_before)
928 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600929 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700930 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
931 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600932 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700933
934 # Second u-boot has an aligned size, but it has no effect
935 self.assertIn('u-boot-align-size-nop', entries)
936 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600937 self.assertEqual(pos, entry.offset)
938 self.assertEqual(len(U_BOOT_DATA), entry.size)
939 self.assertEqual(U_BOOT_DATA, entry.data)
940 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
941 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700942
943 # Third u-boot has an aligned size too
944 self.assertIn('u-boot-align-size', entries)
945 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600946 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700947 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600948 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700949 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600950 data[pos:pos + entry.size])
951 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700952
953 # Fourth u-boot has an aligned end
954 self.assertIn('u-boot-align-end', entries)
955 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600956 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700957 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600958 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700959 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600960 data[pos:pos + entry.size])
961 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700962
963 # Fifth u-boot immediately afterwards
964 self.assertIn('u-boot-align-both', entries)
965 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600966 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700967 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600968 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700969 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600970 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700971
Samuel Hollande2574022023-01-21 17:25:16 -0600972 # Sixth u-boot with both minimum size and aligned size
973 self.assertIn('u-boot-min-size', entries)
974 entry = entries['u-boot-min-size']
975 self.assertEqual(128, entry.offset)
976 self.assertEqual(32, entry.size)
977 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
978 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
979 data[pos:pos + entry.size])
980
Simon Glass57454f42016-11-25 20:15:52 -0700981 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -0600982 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700983
Simon Glassafb9caa2020-10-26 17:40:10 -0600984 dtb = fdt.Fdt(out_dtb_fname)
985 dtb.Scan()
986 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
987 expected = {
988 'image-pos': 0,
989 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -0600990 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -0600991
992 'u-boot:image-pos': 0,
993 'u-boot:offset': 0,
994 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
995
996 'u-boot-align-size-nop:image-pos': 12,
997 'u-boot-align-size-nop:offset': 12,
998 'u-boot-align-size-nop:size': 4,
999
1000 'u-boot-align-size:image-pos': 16,
1001 'u-boot-align-size:offset': 16,
1002 'u-boot-align-size:size': 32,
1003
1004 'u-boot-align-end:image-pos': 48,
1005 'u-boot-align-end:offset': 48,
1006 'u-boot-align-end:size': 16,
1007
1008 'u-boot-align-both:image-pos': 64,
1009 'u-boot-align-both:offset': 64,
1010 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -06001011
1012 'u-boot-min-size:image-pos': 128,
1013 'u-boot-min-size:offset': 128,
1014 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -06001015 }
1016 self.assertEqual(expected, props)
1017
Simon Glass57454f42016-11-25 20:15:52 -07001018 def testPackAlignPowerOf2(self):
1019 """Test that invalid entry alignment is detected"""
1020 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001021 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001022 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1023 "of two", str(e.exception))
1024
1025 def testPackAlignSizePowerOf2(self):
1026 """Test that invalid entry size alignment is detected"""
1027 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001028 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001029 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1030 "power of two", str(e.exception))
1031
1032 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001033 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001034 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001035 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001036 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001037 "align 0x4 (4)", str(e.exception))
1038
1039 def testPackInvalidSizeAlign(self):
1040 """Test that invalid entry size alignment is detected"""
1041 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001042 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001043 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1044 "align-size 0x4 (4)", str(e.exception))
1045
1046 def testPackOverlap(self):
1047 """Test that overlapping regions are detected"""
1048 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001049 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001050 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001051 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1052 str(e.exception))
1053
1054 def testPackEntryOverflow(self):
1055 """Test that entries that overflow their size are detected"""
1056 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001057 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001058 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1059 "but entry size is 0x3 (3)", str(e.exception))
1060
1061 def testPackImageOverflow(self):
1062 """Test that entries which overflow the image size are detected"""
1063 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001064 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001065 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001066 "size 0x3 (3)", str(e.exception))
1067
1068 def testPackImageSize(self):
1069 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001070 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001071 self.assertEqual(0, retcode)
1072 self.assertIn('image', control.images)
1073 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001074 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001075
1076 def testPackImageSizeAlign(self):
1077 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001078 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001079 self.assertEqual(0, retcode)
1080 self.assertIn('image', control.images)
1081 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001082 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001083
1084 def testPackInvalidImageAlign(self):
1085 """Test that invalid image alignment is detected"""
1086 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001087 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001088 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001089 "align-size 0x8 (8)", str(e.exception))
1090
Simon Glass2a0fa982022-02-11 13:23:21 -07001091 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001092 """Test that invalid image alignment is detected"""
1093 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001094 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001095 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001096 "two", str(e.exception))
1097
1098 def testImagePadByte(self):
1099 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001100 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001101 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001102 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001103 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001104
1105 def testImageName(self):
1106 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001107 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001108 self.assertEqual(0, retcode)
1109 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001110 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001111 self.assertTrue(os.path.exists(fname))
1112
1113 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001114 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001115 self.assertTrue(os.path.exists(fname))
1116
1117 def testBlobFilename(self):
1118 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001119 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001120 self.assertEqual(BLOB_DATA, data)
1121
1122 def testPackSorted(self):
1123 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001124 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001125 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001126 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1127 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001128
Simon Glasse8561af2018-08-01 15:22:37 -06001129 def testPackZeroOffset(self):
1130 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001131 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001132 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001133 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001134 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001135 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1136 str(e.exception))
1137
1138 def testPackUbootDtb(self):
1139 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001140 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001141 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001142
1143 def testPackX86RomNoSize(self):
1144 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001145 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001146 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001147 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001148 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001149 "using end-at-4gb", str(e.exception))
1150
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301151 def test4gbAndSkipAtStartTogether(self):
1152 """Test that the end-at-4gb and skip-at-size property can't be used
1153 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001154 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301155 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001156 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001157 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301158 "'skip-at-start'", str(e.exception))
1159
Simon Glass72232452016-11-25 20:15:53 -07001160 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001161 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001162 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001163 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001164 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001165 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1166 "is outside the section '/binman' starting at "
1167 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001168 str(e.exception))
1169
1170 def testPackX86Rom(self):
1171 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001172 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001173 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001174 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1175 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001176
1177 def testPackX86RomMeNoDesc(self):
1178 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001179 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001180 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001181 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001182 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001183 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1184 str(e.exception))
1185 finally:
1186 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001187
1188 def testPackX86RomBadDesc(self):
1189 """Test that the Intel requires a descriptor entry"""
1190 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001191 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001192 self.assertIn("Node '/binman/intel-me': No offset set with "
1193 "offset-unset: should another entry provide this correct "
1194 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001195
1196 def testPackX86RomMe(self):
1197 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001198 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001199 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001200 if data[:0x1000] != expected_desc:
1201 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001202 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1203
1204 def testPackVga(self):
1205 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001206 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001207 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1208
1209 def testPackStart16(self):
1210 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001211 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001212 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1213
Jagdish Gediya311d4842018-09-03 21:35:08 +05301214 def testPackPowerpcMpc85xxBootpgResetvec(self):
1215 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1216 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001217 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301218 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1219
Simon Glass6ba679c2018-07-06 10:27:17 -06001220 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001221 """Handle running a test for insertion of microcode
1222
1223 Args:
1224 dts_fname: Name of test .dts file
1225 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001226 ucode_second: True if the microsecond entry is second instead of
1227 third
Simon Glass820af1d2018-07-06 10:27:16 -06001228
1229 Returns:
1230 Tuple:
1231 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001232 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001233 in the above (two 4-byte words)
1234 """
Simon Glass3d274232017-11-12 21:52:27 -07001235 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001236
1237 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001238 if ucode_second:
1239 ucode_content = data[len(nodtb_data):]
1240 ucode_pos = len(nodtb_data)
1241 dtb_with_ucode = ucode_content[16:]
1242 fdt_len = self.GetFdtLen(dtb_with_ucode)
1243 else:
1244 dtb_with_ucode = data[len(nodtb_data):]
1245 fdt_len = self.GetFdtLen(dtb_with_ucode)
1246 ucode_content = dtb_with_ucode[fdt_len:]
1247 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001248 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001249 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001250 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001251 dtb = fdt.FdtScan(fname)
1252 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001253 self.assertTrue(ucode)
1254 for node in ucode.subnodes:
1255 self.assertFalse(node.props.get('data'))
1256
Simon Glass72232452016-11-25 20:15:53 -07001257 # Check that the microcode appears immediately after the Fdt
1258 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001259 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001260 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1261 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001262 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001263
1264 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001265 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001266 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1267 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001268 u_boot = data[:len(nodtb_data)]
1269 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001270
1271 def testPackUbootMicrocode(self):
1272 """Test that x86 microcode can be handled correctly
1273
1274 We expect to see the following in the image, in order:
1275 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1276 place
1277 u-boot.dtb with the microcode removed
1278 the microcode
1279 """
Simon Glass511f6582018-10-01 12:22:30 -06001280 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001281 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001282 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1283 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001284
Simon Glassbac25c82017-05-27 07:38:26 -06001285 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001286 """Test that x86 microcode can be handled correctly
1287
1288 We expect to see the following in the image, in order:
1289 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1290 place
1291 u-boot.dtb with the microcode
1292 an empty microcode region
1293 """
1294 # We need the libfdt library to run this test since only that allows
1295 # finding the offset of a property. This is required by
1296 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001297 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001298
1299 second = data[len(U_BOOT_NODTB_DATA):]
1300
1301 fdt_len = self.GetFdtLen(second)
1302 third = second[fdt_len:]
1303 second = second[:fdt_len]
1304
Simon Glassbac25c82017-05-27 07:38:26 -06001305 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1306 self.assertIn(ucode_data, second)
1307 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001308
Simon Glassbac25c82017-05-27 07:38:26 -06001309 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001310 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001311 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1312 len(ucode_data))
1313 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001314 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1315 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001316
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001317 def testPackUbootSingleMicrocode(self):
1318 """Test that x86 microcode can be handled correctly with fdt_normal.
1319 """
Simon Glassbac25c82017-05-27 07:38:26 -06001320 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001321
Simon Glass996021e2016-11-25 20:15:54 -07001322 def testUBootImg(self):
1323 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001324 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001325 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001326
1327 def testNoMicrocode(self):
1328 """Test that a missing microcode region is detected"""
1329 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001330 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001331 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1332 "node found in ", str(e.exception))
1333
1334 def testMicrocodeWithoutNode(self):
1335 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1336 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001337 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001338 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1339 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1340
1341 def testMicrocodeWithoutNode2(self):
1342 """Test that a missing u-boot-ucode node is detected"""
1343 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001344 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001345 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1346 "microcode region u-boot-ucode", str(e.exception))
1347
1348 def testMicrocodeWithoutPtrInElf(self):
1349 """Test that a U-Boot binary without the microcode symbol is detected"""
1350 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001351 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001352 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001353 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001354
1355 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001356 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001357 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1358 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1359
1360 finally:
1361 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001362 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001363 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001364
1365 def testMicrocodeNotInImage(self):
1366 """Test that microcode must be placed within the image"""
1367 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001368 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001369 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1370 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001371 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001372
1373 def testWithoutMicrocode(self):
1374 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001375 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001376 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001377 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001378
1379 # Now check the device tree has no microcode
1380 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1381 second = data[len(U_BOOT_NODTB_DATA):]
1382
1383 fdt_len = self.GetFdtLen(second)
1384 self.assertEqual(dtb, second[:fdt_len])
1385
1386 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1387 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001388 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001389
1390 def testUnknownPosSize(self):
1391 """Test that microcode must be placed within the image"""
1392 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001393 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001394 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001395 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001396
1397 def testPackFsp(self):
1398 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001399 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001400 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1401
1402 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001403 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001404 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001405 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001406
1407 def testPackVbt(self):
1408 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001409 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001410 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001411
Simon Glass7f94e832017-11-12 21:52:25 -07001412 def testSplBssPad(self):
1413 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001414 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001415 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001416 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001417 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001418 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001419
Simon Glass04cda032018-10-01 21:12:42 -06001420 def testSplBssPadMissing(self):
1421 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001422 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001423 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001424 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001425 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1426 str(e.exception))
1427
Simon Glasse83679d2017-11-12 21:52:26 -07001428 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001429 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001430 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001431 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1432
Simon Glass6ba679c2018-07-06 10:27:17 -06001433 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1434 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001435
1436 We expect to see the following in the image, in order:
1437 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1438 correct place
1439 u-boot.dtb with the microcode removed
1440 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001441
1442 Args:
1443 dts: Device tree file to use for test
1444 ucode_second: True if the microsecond entry is second instead of
1445 third
Simon Glass3d274232017-11-12 21:52:27 -07001446 """
Simon Glass7057d022018-10-01 21:12:47 -06001447 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001448 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1449 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001450 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1451 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001452
Simon Glass6ba679c2018-07-06 10:27:17 -06001453 def testPackUbootSplMicrocode(self):
1454 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001455 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001456 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001457
1458 def testPackUbootSplMicrocodeReorder(self):
1459 """Test that order doesn't matter for microcode entries
1460
1461 This is the same as testPackUbootSplMicrocode but when we process the
1462 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1463 entry, so we reply on binman to try later.
1464 """
Simon Glass511f6582018-10-01 12:22:30 -06001465 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001466 ucode_second=True)
1467
Simon Glassa409c932017-11-12 21:52:28 -07001468 def testPackMrc(self):
1469 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001470 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001471 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1472
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001473 def testSplDtb(self):
1474 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001475 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001476 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001477 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1478
Simon Glass0a6da312017-11-13 18:54:56 -07001479 def testSplNoDtb(self):
1480 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001481 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001482 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001483 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1484
Simon Glass7098b7f2021-03-21 18:24:30 +13001485 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4abf7842023-07-18 07:23:54 -06001486 use_expanded=False, no_write_symbols=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001487 """Check the image contains the expected symbol values
1488
1489 Args:
1490 dts: Device tree file to use for test
1491 base_data: Data before and after 'u-boot' section
1492 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001493 entry_args: Dict of entry args to supply to binman
1494 key: arg name
1495 value: value of that arg
1496 use_expanded: True to use expanded entries where available, e.g.
1497 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001498 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001499 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001500 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1501 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001502 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001503 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001504 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001505
Simon Glass7057d022018-10-01 21:12:47 -06001506 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001507 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1508 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001509 # The image should contain the symbols from u_boot_binman_syms.c
1510 # Note that image_pos is adjusted by the base address of the image,
1511 # which is 0x10 in our test image
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001512 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1513 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glass31e04cb2021-03-18 20:24:56 +13001514 0x10 + u_boot_offset, 0x04)
Simon Glass4abf7842023-07-18 07:23:54 -06001515 if no_write_symbols:
1516 expected = (base_data +
1517 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1518 U_BOOT_DATA + base_data)
1519 else:
1520 expected = (sym_values + base_data[24:] +
1521 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1522 base_data[24:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001523 self.assertEqual(expected, data)
1524
Simon Glass31e04cb2021-03-18 20:24:56 +13001525 def testSymbols(self):
1526 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001527 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001528
1529 def testSymbolsNoDtb(self):
1530 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001531 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001532 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1533 0x38)
1534
Simon Glasse76a3e62018-06-01 09:38:11 -06001535 def testPackUnitAddress(self):
1536 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001537 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001538 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1539
Simon Glassa91e1152018-06-01 09:38:16 -06001540 def testSections(self):
1541 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001542 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001543 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1544 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1545 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001546 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001547
Simon Glass30732662018-06-01 09:38:20 -06001548 def testMap(self):
1549 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001550 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001551 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700155200000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600155300000000 00000000 00000010 section@0
155400000000 00000000 00000004 u-boot
155500000010 00000010 00000010 section@1
155600000010 00000000 00000004 u-boot
155700000020 00000020 00000004 section@2
155800000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001559''', map_data)
1560
Simon Glass3b78d532018-06-01 09:38:21 -06001561 def testNamePrefix(self):
1562 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001563 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001564 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700156500000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600156600000000 00000000 00000010 section@0
156700000000 00000000 00000004 ro-u-boot
156800000010 00000010 00000010 section@1
156900000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001570''', map_data)
1571
Simon Glass6ba679c2018-07-06 10:27:17 -06001572 def testUnknownContents(self):
1573 """Test that obtaining the contents works as expected"""
1574 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001575 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001576 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001577 "processing of contents: remaining ["
1578 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001579
Simon Glass2e1169f2018-07-06 10:27:19 -06001580 def testBadChangeSize(self):
1581 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001582 try:
1583 state.SetAllowEntryExpansion(False)
1584 with self.assertRaises(ValueError) as e:
1585 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001586 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001587 str(e.exception))
1588 finally:
1589 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001590
Simon Glassa87014e2018-07-06 10:27:42 -06001591 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001592 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001593 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001594 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001595 dtb = fdt.Fdt(out_dtb_fname)
1596 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001597 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001598 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001599 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001600 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001601 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001602 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001603 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001604 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001605 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001606 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001607 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001608 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001609 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001610
Simon Glasse8561af2018-08-01 15:22:37 -06001611 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001612 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001613 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001614 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001615 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001616 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001617 'size': 40
1618 }, props)
1619
1620 def testUpdateFdtBad(self):
1621 """Test that we detect when ProcessFdt never completes"""
1622 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001623 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001624 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001625 '[<binman.etype._testing.Entry__testing',
1626 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001627
Simon Glass91710b32018-07-17 13:25:32 -06001628 def testEntryArgs(self):
1629 """Test passing arguments to entries from the command line"""
1630 entry_args = {
1631 'test-str-arg': 'test1',
1632 'test-int-arg': '456',
1633 }
Simon Glass511f6582018-10-01 12:22:30 -06001634 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001635 self.assertIn('image', control.images)
1636 entry = control.images['image'].GetEntries()['_testing']
1637 self.assertEqual('test0', entry.test_str_fdt)
1638 self.assertEqual('test1', entry.test_str_arg)
1639 self.assertEqual(123, entry.test_int_fdt)
1640 self.assertEqual(456, entry.test_int_arg)
1641
1642 def testEntryArgsMissing(self):
1643 """Test missing arguments and properties"""
1644 entry_args = {
1645 'test-int-arg': '456',
1646 }
Simon Glass511f6582018-10-01 12:22:30 -06001647 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001648 entry = control.images['image'].GetEntries()['_testing']
1649 self.assertEqual('test0', entry.test_str_fdt)
1650 self.assertEqual(None, entry.test_str_arg)
1651 self.assertEqual(None, entry.test_int_fdt)
1652 self.assertEqual(456, entry.test_int_arg)
1653
1654 def testEntryArgsRequired(self):
1655 """Test missing arguments and properties"""
1656 entry_args = {
1657 'test-int-arg': '456',
1658 }
1659 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001660 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001661 self.assertIn("Node '/binman/_testing': "
1662 'Missing required properties/entry args: test-str-arg, '
1663 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001664 str(e.exception))
1665
1666 def testEntryArgsInvalidFormat(self):
1667 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001668 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1669 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001670 with self.assertRaises(ValueError) as e:
1671 self._DoBinman(*args)
1672 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1673
1674 def testEntryArgsInvalidInteger(self):
1675 """Test that an invalid entry-argument integer is detected"""
1676 entry_args = {
1677 'test-int-arg': 'abc',
1678 }
1679 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001680 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001681 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1682 "'test-int-arg' (value 'abc') to integer",
1683 str(e.exception))
1684
1685 def testEntryArgsInvalidDatatype(self):
1686 """Test that an invalid entry-argument datatype is detected
1687
1688 This test could be written in entry_test.py except that it needs
1689 access to control.entry_args, which seems more than that module should
1690 be able to see.
1691 """
1692 entry_args = {
1693 'test-bad-datatype-arg': '12',
1694 }
1695 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001696 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001697 entry_args=entry_args)
1698 self.assertIn('GetArg() internal error: Unknown data type ',
1699 str(e.exception))
1700
Simon Glass2ca52032018-07-17 13:25:33 -06001701 def testText(self):
1702 """Test for a text entry type"""
1703 entry_args = {
1704 'test-id': TEXT_DATA,
1705 'test-id2': TEXT_DATA2,
1706 'test-id3': TEXT_DATA3,
1707 }
Simon Glass511f6582018-10-01 12:22:30 -06001708 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001709 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001710 expected = (tools.to_bytes(TEXT_DATA) +
1711 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1712 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001713 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001714 self.assertEqual(expected, data)
1715
Simon Glass969616c2018-07-17 13:25:36 -06001716 def testEntryDocs(self):
1717 """Test for creation of entry documentation"""
1718 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001719 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001720 self.assertTrue(len(stdout.getvalue()) > 0)
1721
1722 def testEntryDocsMissing(self):
1723 """Test handling of missing entry documentation"""
1724 with self.assertRaises(ValueError) as e:
1725 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001726 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001727 self.assertIn('Documentation is missing for modules: u_boot',
1728 str(e.exception))
1729
Simon Glass704784b2018-07-17 13:25:38 -06001730 def testFmap(self):
1731 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001732 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001733 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001734 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1735 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001736 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001737 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001738 self.assertEqual(1, fhdr.ver_major)
1739 self.assertEqual(0, fhdr.ver_minor)
1740 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001741 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001742 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001743 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001744 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001745 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001746
Simon Glass82059c22021-04-03 11:05:09 +13001747 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001748 self.assertEqual(b'SECTION0', fentry.name)
1749 self.assertEqual(0, fentry.offset)
1750 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001751 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001752
1753 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001754 self.assertEqual(b'RO_U_BOOT', fentry.name)
1755 self.assertEqual(0, fentry.offset)
1756 self.assertEqual(4, fentry.size)
1757 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001758
Simon Glass82059c22021-04-03 11:05:09 +13001759 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001760 self.assertEqual(b'SECTION1', fentry.name)
1761 self.assertEqual(16, fentry.offset)
1762 self.assertEqual(16, fentry.size)
1763 self.assertEqual(0, fentry.flags)
1764
1765 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001766 self.assertEqual(b'RW_U_BOOT', fentry.name)
1767 self.assertEqual(16, fentry.offset)
1768 self.assertEqual(4, fentry.size)
1769 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001770
Simon Glass82059c22021-04-03 11:05:09 +13001771 fentry = next(fiter)
1772 self.assertEqual(b'FMAP', fentry.name)
1773 self.assertEqual(32, fentry.offset)
1774 self.assertEqual(expect_size, fentry.size)
1775 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001776
Simon Glassdb168d42018-07-17 13:25:39 -06001777 def testBlobNamedByArg(self):
1778 """Test we can add a blob with the filename coming from an entry arg"""
1779 entry_args = {
1780 'cros-ec-rw-path': 'ecrw.bin',
1781 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001782 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001783
Simon Glass53f53992018-07-17 13:25:40 -06001784 def testFill(self):
1785 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001786 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001787 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001788 self.assertEqual(expected, data)
1789
1790 def testFillNoSize(self):
1791 """Test for an fill entry type with no size"""
1792 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001793 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001794 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001795 str(e.exception))
1796
Simon Glassc1ae83c2018-07-17 13:25:44 -06001797 def _HandleGbbCommand(self, pipe_list):
1798 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001799 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001800 fname = pipe_list[0][-1]
1801 # Append our GBB data to the file, which will happen every time the
1802 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001803 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001804 fd.write(GBB_DATA)
1805 return command.CommandResult()
1806
1807 def testGbb(self):
1808 """Test for the Chromium OS Google Binary Block"""
1809 command.test_result = self._HandleGbbCommand
1810 entry_args = {
1811 'keydir': 'devkeys',
1812 'bmpblk': 'bmpblk.bin',
1813 }
Simon Glass511f6582018-10-01 12:22:30 -06001814 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001815
1816 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001817 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1818 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001819 self.assertEqual(expected, data)
1820
1821 def testGbbTooSmall(self):
1822 """Test for the Chromium OS Google Binary Block being large enough"""
1823 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001824 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001825 self.assertIn("Node '/binman/gbb': GBB is too small",
1826 str(e.exception))
1827
1828 def testGbbNoSize(self):
1829 """Test for the Chromium OS Google Binary Block having a size"""
1830 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001831 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001832 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1833 str(e.exception))
1834
Simon Glass66152ce2022-01-09 20:14:09 -07001835 def testGbbMissing(self):
1836 """Test that binman still produces an image if futility is missing"""
1837 entry_args = {
1838 'keydir': 'devkeys',
1839 }
1840 with test_util.capture_sys_output() as (_, stderr):
1841 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1842 entry_args=entry_args)
1843 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001844 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001845
Simon Glass5c350162018-07-17 13:25:47 -06001846 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001847 """Fake calls to the futility utility
1848
1849 The expected pipe is:
1850
1851 [('futility', 'vbutil_firmware', '--vblock',
1852 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1853 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1854 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1855 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1856
1857 This writes to the output file (here, 'vblock.vblock'). If
1858 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1859 of the input data (here, 'input.vblock').
1860 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001861 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001862 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001863 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001864 if self._hash_data:
1865 infile = pipe_list[0][11]
1866 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001867 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001868 m.update(data)
1869 fd.write(m.digest())
1870 else:
1871 fd.write(VBLOCK_DATA)
1872
Simon Glass5c350162018-07-17 13:25:47 -06001873 return command.CommandResult()
1874
1875 def testVblock(self):
1876 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001877 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001878 command.test_result = self._HandleVblockCommand
1879 entry_args = {
1880 'keydir': 'devkeys',
1881 }
Simon Glass511f6582018-10-01 12:22:30 -06001882 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001883 entry_args=entry_args)
1884 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1885 self.assertEqual(expected, data)
1886
1887 def testVblockNoContent(self):
1888 """Test we detect a vblock which has no content to sign"""
1889 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001890 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001891 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001892 'property', str(e.exception))
1893
1894 def testVblockBadPhandle(self):
1895 """Test that we detect a vblock with an invalid phandle in contents"""
1896 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001897 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001898 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1899 '1000', str(e.exception))
1900
1901 def testVblockBadEntry(self):
1902 """Test that we detect an entry that points to a non-entry"""
1903 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001904 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001905 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1906 "'other'", str(e.exception))
1907
Simon Glass220c6222021-01-06 21:35:17 -07001908 def testVblockContent(self):
1909 """Test that the vblock signs the right data"""
1910 self._hash_data = True
1911 command.test_result = self._HandleVblockCommand
1912 entry_args = {
1913 'keydir': 'devkeys',
1914 }
1915 data = self._DoReadFileDtb(
1916 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1917 entry_args=entry_args)[0]
1918 hashlen = 32 # SHA256 hash is 32 bytes
1919 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1920 hashval = data[-hashlen:]
1921 dtb = data[len(U_BOOT_DATA):-hashlen]
1922
1923 expected_data = U_BOOT_DATA + dtb
1924
1925 # The hashval should be a hash of the dtb
1926 m = hashlib.sha256()
1927 m.update(expected_data)
1928 expected_hashval = m.digest()
1929 self.assertEqual(expected_hashval, hashval)
1930
Simon Glass66152ce2022-01-09 20:14:09 -07001931 def testVblockMissing(self):
1932 """Test that binman still produces an image if futility is missing"""
1933 entry_args = {
1934 'keydir': 'devkeys',
1935 }
1936 with test_util.capture_sys_output() as (_, stderr):
1937 self._DoTestFile('074_vblock.dts',
1938 force_missing_bintools='futility',
1939 entry_args=entry_args)
1940 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001941 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001942
Simon Glass8425a1f2018-07-17 13:25:48 -06001943 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001944 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001945 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001946 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001947 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001948 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1949
Simon Glass24b97442018-07-17 13:25:51 -06001950 def testUsesPos(self):
1951 """Test that the 'pos' property cannot be used anymore"""
1952 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001953 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001954 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1955 "'pos'", str(e.exception))
1956
Simon Glass274bf092018-09-14 04:57:08 -06001957 def testFillZero(self):
1958 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001959 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001960 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001961
Simon Glass267de432018-09-14 04:57:09 -06001962 def testTextMissing(self):
1963 """Test for a text entry type where there is no text"""
1964 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001965 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001966 self.assertIn("Node '/binman/text': No value provided for text label "
1967 "'test-id'", str(e.exception))
1968
Simon Glassed40e962018-09-14 04:57:10 -06001969 def testPackStart16Tpl(self):
1970 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001971 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001972 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1973
Simon Glass3b376c32018-09-14 04:57:12 -06001974 def testSelectImage(self):
1975 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001976 expected = 'Skipping images: image1'
1977
1978 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001979 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001980 with test_util.capture_sys_output() as (stdout, stderr):
1981 retcode = self._DoTestFile('006_dual_image.dts',
1982 verbosity=verbosity,
1983 images=['image2'])
1984 self.assertEqual(0, retcode)
1985 if verbosity:
1986 self.assertIn(expected, stdout.getvalue())
1987 else:
1988 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001989
Simon Glass80025522022-01-29 14:14:04 -07001990 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1991 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001992 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001993
Simon Glasse219aa42018-09-14 04:57:24 -06001994 def testUpdateFdtAll(self):
1995 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001996 self._SetupSplElf()
1997 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06001998 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001999
2000 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06002001 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002002 'image-pos': 0,
2003 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06002004 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002005 'section:image-pos': 0,
2006 'section:size': 565,
2007 'section/u-boot-dtb:offset': 0,
2008 'section/u-boot-dtb:image-pos': 0,
2009 'section/u-boot-dtb:size': 565,
2010 'u-boot-spl-dtb:offset': 565,
2011 'u-boot-spl-dtb:image-pos': 565,
2012 'u-boot-spl-dtb:size': 585,
2013 'u-boot-tpl-dtb:offset': 1150,
2014 'u-boot-tpl-dtb:image-pos': 1150,
2015 'u-boot-tpl-dtb:size': 585,
2016 'u-boot-vpl-dtb:image-pos': 1735,
2017 'u-boot-vpl-dtb:offset': 1735,
2018 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002019 }
2020
2021 # We expect three device-tree files in the output, one after the other.
2022 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2023 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2024 # main U-Boot tree. All three should have the same postions and offset.
2025 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002026 self.maxDiff = None
2027 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002028 dtb = fdt.Fdt.FromData(data[start:])
2029 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002030 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002031 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002032 expected = dict(base_expected)
2033 if item:
2034 expected[item] = 0
2035 self.assertEqual(expected, props)
2036 start += dtb._fdt_obj.totalsize()
2037
2038 def testUpdateFdtOutput(self):
2039 """Test that output DTB files are updated"""
2040 try:
Simon Glass511f6582018-10-01 12:22:30 -06002041 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002042 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2043
2044 # Unfortunately, compiling a source file always results in a file
2045 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002046 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002047 # binman as a file called u-boot.dtb. To fix this, copy the file
2048 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002049 start = 0
2050 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002051 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002052 dtb = fdt.Fdt.FromData(data[start:])
2053 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002054 pathname = tools.get_output_filename(os.path.split(fname)[1])
2055 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002056 name = os.path.split(fname)[0]
2057
2058 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002059 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002060 else:
2061 orig_indata = dtb_data
2062 self.assertNotEqual(outdata, orig_indata,
2063 "Expected output file '%s' be updated" % pathname)
2064 self.assertEqual(outdata, data[start:start + size],
2065 "Expected output file '%s' to match output image" %
2066 pathname)
2067 start += size
2068 finally:
2069 self._ResetDtbs()
2070
Simon Glass7ba33592018-09-14 04:57:26 -06002071 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002072 bintool = self.comp_bintools['lz4']
2073 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002074
2075 def testCompress(self):
2076 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002077 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002078 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002079 use_real_dtb=True, update_dtb=True)
2080 dtb = fdt.Fdt(out_dtb_fname)
2081 dtb.Scan()
2082 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2083 orig = self._decompress(data)
2084 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002085
2086 # Do a sanity check on various fields
2087 image = control.images['image']
2088 entries = image.GetEntries()
2089 self.assertEqual(1, len(entries))
2090
2091 entry = entries['blob']
2092 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2093 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2094 orig = self._decompress(entry.data)
2095 self.assertEqual(orig, entry.uncomp_data)
2096
Simon Glass72eeff12020-10-26 17:40:16 -06002097 self.assertEqual(image.data, entry.data)
2098
Simon Glass7ba33592018-09-14 04:57:26 -06002099 expected = {
2100 'blob:uncomp-size': len(COMPRESS_DATA),
2101 'blob:size': len(data),
2102 'size': len(data),
2103 }
2104 self.assertEqual(expected, props)
2105
Simon Glassac6328c2018-09-14 04:57:28 -06002106 def testFiles(self):
2107 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002108 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002109 self.assertEqual(FILES_DATA, data)
2110
2111 def testFilesCompress(self):
2112 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002113 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002114 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002115
2116 image = control.images['image']
2117 entries = image.GetEntries()
2118 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002119 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002120
Simon Glass303f62f2019-05-17 22:00:46 -06002121 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002122 for i in range(1, 3):
2123 key = '%d.dat' % i
2124 start = entries[key].image_pos
2125 len = entries[key].size
2126 chunk = data[start:start + len]
2127 orig += self._decompress(chunk)
2128
2129 self.assertEqual(FILES_DATA, orig)
2130
2131 def testFilesMissing(self):
2132 """Test missing files"""
2133 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002134 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002135 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2136 'no files', str(e.exception))
2137
2138 def testFilesNoPattern(self):
2139 """Test missing files"""
2140 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002141 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002142 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2143 str(e.exception))
2144
Simon Glassdd156a42022-03-05 20:18:59 -07002145 def testExtendSize(self):
2146 """Test an extending entry"""
2147 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002148 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002149 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2150 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2151 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2152 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002153 self.assertEqual(expect, data)
2154 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700215500000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600215600000000 00000000 00000008 fill
215700000008 00000008 00000004 u-boot
21580000000c 0000000c 00000004 section
21590000000c 00000000 00000003 intel-mrc
216000000010 00000010 00000004 u-boot2
216100000014 00000014 0000000c section2
216200000014 00000000 00000008 fill
21630000001c 00000008 00000004 u-boot
216400000020 00000020 00000008 fill2
2165''', map_data)
2166
Simon Glassdd156a42022-03-05 20:18:59 -07002167 def testExtendSizeBad(self):
2168 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002169 with test_util.capture_sys_output() as (stdout, stderr):
2170 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002171 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002172 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2173 'expanding entry', str(e.exception))
2174
Simon Glassae7cf032018-09-14 04:57:31 -06002175 def testHash(self):
2176 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002177 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002178 use_real_dtb=True, update_dtb=True)
2179 dtb = fdt.Fdt(out_dtb_fname)
2180 dtb.Scan()
2181 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2182 m = hashlib.sha256()
2183 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002184 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002185
2186 def testHashNoAlgo(self):
2187 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002188 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002189 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2190 'hash node', str(e.exception))
2191
2192 def testHashBadAlgo(self):
2193 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002194 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002195 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002196 str(e.exception))
2197
2198 def testHashSection(self):
2199 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002200 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002201 use_real_dtb=True, update_dtb=True)
2202 dtb = fdt.Fdt(out_dtb_fname)
2203 dtb.Scan()
2204 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2205 m = hashlib.sha256()
2206 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002207 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002208 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002209
Simon Glass3fb4f422018-09-14 04:57:32 -06002210 def testPackUBootTplMicrocode(self):
2211 """Test that x86 microcode can be handled correctly in TPL
2212
2213 We expect to see the following in the image, in order:
2214 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2215 place
2216 u-boot-tpl.dtb with the microcode removed
2217 the microcode
2218 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002219 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002220 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002221 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002222 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2223 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002224
Simon Glassc64aea52018-09-14 04:57:34 -06002225 def testFmapX86(self):
2226 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002227 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002228 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002229 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002230 self.assertEqual(expected, data[:32])
2231 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2232
2233 self.assertEqual(0x100, fhdr.image_size)
2234
2235 self.assertEqual(0, fentries[0].offset)
2236 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002237 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002238
2239 self.assertEqual(4, fentries[1].offset)
2240 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002241 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002242
2243 self.assertEqual(32, fentries[2].offset)
2244 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2245 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002246 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002247
2248 def testFmapX86Section(self):
2249 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002250 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002251 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002252 self.assertEqual(expected, data[:32])
2253 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2254
Simon Glassb1d414c2021-04-03 11:05:10 +13002255 self.assertEqual(0x180, fhdr.image_size)
2256 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002257 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002258
Simon Glass82059c22021-04-03 11:05:09 +13002259 fentry = next(fiter)
2260 self.assertEqual(b'U_BOOT', fentry.name)
2261 self.assertEqual(0, fentry.offset)
2262 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002263
Simon Glass82059c22021-04-03 11:05:09 +13002264 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002265 self.assertEqual(b'SECTION', fentry.name)
2266 self.assertEqual(4, fentry.offset)
2267 self.assertEqual(0x20 + expect_size, fentry.size)
2268
2269 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002270 self.assertEqual(b'INTEL_MRC', fentry.name)
2271 self.assertEqual(4, fentry.offset)
2272 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002273
Simon Glass82059c22021-04-03 11:05:09 +13002274 fentry = next(fiter)
2275 self.assertEqual(b'FMAP', fentry.name)
2276 self.assertEqual(36, fentry.offset)
2277 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002278
Simon Glassb1714232018-09-14 04:57:35 -06002279 def testElf(self):
2280 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002281 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002282 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002283 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002284 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002285 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002286
Simon Glass0d673792019-07-08 13:18:25 -06002287 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002288 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002289 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002290 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002291 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002292 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002293
Simon Glasscd817d52018-09-14 04:57:36 -06002294 def testPackOverlapMap(self):
2295 """Test that overlapping regions are detected"""
2296 with test_util.capture_sys_output() as (stdout, stderr):
2297 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002298 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002299 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002300 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2301 stdout.getvalue())
2302
2303 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002304 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002305 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002306 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002307 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002308<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002309<none> 00000000 00000004 u-boot
2310<none> 00000003 00000004 u-boot-align
2311''', map_data)
2312
Simon Glass0d673792019-07-08 13:18:25 -06002313 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002314 """Test that an image with an Intel Reference code binary works"""
2315 data = self._DoReadFile('100_intel_refcode.dts')
2316 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2317
Simon Glasseb023b32019-04-25 21:58:39 -06002318 def testSectionOffset(self):
2319 """Tests use of a section with an offset"""
2320 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2321 map=True)
2322 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700232300000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600232400000004 00000004 00000010 section@0
232500000004 00000000 00000004 u-boot
232600000018 00000018 00000010 section@1
232700000018 00000000 00000004 u-boot
23280000002c 0000002c 00000004 section@2
23290000002c 00000000 00000004 u-boot
2330''', map_data)
2331 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002332 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2333 tools.get_bytes(0x21, 12) +
2334 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2335 tools.get_bytes(0x61, 12) +
2336 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2337 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002338
Simon Glass1de34482019-07-08 13:18:53 -06002339 def testCbfsRaw(self):
2340 """Test base handling of a Coreboot Filesystem (CBFS)
2341
2342 The exact contents of the CBFS is verified by similar tests in
2343 cbfs_util_test.py. The tests here merely check that the files added to
2344 the CBFS can be found in the final image.
2345 """
2346 data = self._DoReadFile('102_cbfs_raw.dts')
2347 size = 0xb0
2348
2349 cbfs = cbfs_util.CbfsReader(data)
2350 self.assertEqual(size, cbfs.rom_size)
2351
2352 self.assertIn('u-boot-dtb', cbfs.files)
2353 cfile = cbfs.files['u-boot-dtb']
2354 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2355
2356 def testCbfsArch(self):
2357 """Test on non-x86 architecture"""
2358 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2359 size = 0x100
2360
2361 cbfs = cbfs_util.CbfsReader(data)
2362 self.assertEqual(size, cbfs.rom_size)
2363
2364 self.assertIn('u-boot-dtb', cbfs.files)
2365 cfile = cbfs.files['u-boot-dtb']
2366 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2367
2368 def testCbfsStage(self):
2369 """Tests handling of a Coreboot Filesystem (CBFS)"""
2370 if not elf.ELF_TOOLS:
2371 self.skipTest('Python elftools not available')
2372 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2373 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2374 size = 0xb0
2375
2376 data = self._DoReadFile('104_cbfs_stage.dts')
2377 cbfs = cbfs_util.CbfsReader(data)
2378 self.assertEqual(size, cbfs.rom_size)
2379
2380 self.assertIn('u-boot', cbfs.files)
2381 cfile = cbfs.files['u-boot']
2382 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2383
2384 def testCbfsRawCompress(self):
2385 """Test handling of compressing raw files"""
2386 self._CheckLz4()
2387 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2388 size = 0x140
2389
2390 cbfs = cbfs_util.CbfsReader(data)
2391 self.assertIn('u-boot', cbfs.files)
2392 cfile = cbfs.files['u-boot']
2393 self.assertEqual(COMPRESS_DATA, cfile.data)
2394
2395 def testCbfsBadArch(self):
2396 """Test handling of a bad architecture"""
2397 with self.assertRaises(ValueError) as e:
2398 self._DoReadFile('106_cbfs_bad_arch.dts')
2399 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2400
2401 def testCbfsNoSize(self):
2402 """Test handling of a missing size property"""
2403 with self.assertRaises(ValueError) as e:
2404 self._DoReadFile('107_cbfs_no_size.dts')
2405 self.assertIn('entry must have a size property', str(e.exception))
2406
Simon Glass3e28f4f2021-11-23 11:03:54 -07002407 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002408 """Test handling of a CBFS entry which does not provide contentsy"""
2409 with self.assertRaises(ValueError) as e:
2410 self._DoReadFile('108_cbfs_no_contents.dts')
2411 self.assertIn('Could not complete processing of contents',
2412 str(e.exception))
2413
2414 def testCbfsBadCompress(self):
2415 """Test handling of a bad architecture"""
2416 with self.assertRaises(ValueError) as e:
2417 self._DoReadFile('109_cbfs_bad_compress.dts')
2418 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2419 str(e.exception))
2420
2421 def testCbfsNamedEntries(self):
2422 """Test handling of named entries"""
2423 data = self._DoReadFile('110_cbfs_name.dts')
2424
2425 cbfs = cbfs_util.CbfsReader(data)
2426 self.assertIn('FRED', cbfs.files)
2427 cfile1 = cbfs.files['FRED']
2428 self.assertEqual(U_BOOT_DATA, cfile1.data)
2429
2430 self.assertIn('hello', cbfs.files)
2431 cfile2 = cbfs.files['hello']
2432 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2433
Simon Glass759af872019-07-08 13:18:54 -06002434 def _SetupIfwi(self, fname):
2435 """Set up to run an IFWI test
2436
2437 Args:
2438 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2439 """
2440 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002441 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002442
2443 # Intel Integrated Firmware Image (IFWI) file
2444 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2445 data = fd.read()
2446 TestFunctional._MakeInputFile(fname,data)
2447
2448 def _CheckIfwi(self, data):
2449 """Check that an image with an IFWI contains the correct output
2450
2451 Args:
2452 data: Conents of output file
2453 """
Simon Glass80025522022-01-29 14:14:04 -07002454 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002455 if data[:0x1000] != expected_desc:
2456 self.fail('Expected descriptor binary at start of image')
2457
2458 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002459 image_fname = tools.get_output_filename('image.bin')
2460 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002461 ifwitool = bintool.Bintool.create('ifwitool')
2462 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002463
Simon Glass80025522022-01-29 14:14:04 -07002464 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002465 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002466
2467 def testPackX86RomIfwi(self):
2468 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2469 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002470 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002471 self._CheckIfwi(data)
2472
2473 def testPackX86RomIfwiNoDesc(self):
2474 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2475 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002476 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002477 self._CheckIfwi(data)
2478
2479 def testPackX86RomIfwiNoData(self):
2480 """Test that an x86 ROM with IFWI handles missing data"""
2481 self._SetupIfwi('ifwi.bin')
2482 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002483 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002484 self.assertIn('Could not complete processing of contents',
2485 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002486
Simon Glass66152ce2022-01-09 20:14:09 -07002487 def testIfwiMissing(self):
2488 """Test that binman still produces an image if ifwitool is missing"""
2489 self._SetupIfwi('fitimage.bin')
2490 with test_util.capture_sys_output() as (_, stderr):
2491 self._DoTestFile('111_x86_rom_ifwi.dts',
2492 force_missing_bintools='ifwitool')
2493 err = stderr.getvalue()
2494 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002495 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002496
Simon Glassc2f1aed2019-07-08 13:18:56 -06002497 def testCbfsOffset(self):
2498 """Test a CBFS with files at particular offsets
2499
2500 Like all CFBS tests, this is just checking the logic that calls
2501 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2502 """
2503 data = self._DoReadFile('114_cbfs_offset.dts')
2504 size = 0x200
2505
2506 cbfs = cbfs_util.CbfsReader(data)
2507 self.assertEqual(size, cbfs.rom_size)
2508
2509 self.assertIn('u-boot', cbfs.files)
2510 cfile = cbfs.files['u-boot']
2511 self.assertEqual(U_BOOT_DATA, cfile.data)
2512 self.assertEqual(0x40, cfile.cbfs_offset)
2513
2514 self.assertIn('u-boot-dtb', cbfs.files)
2515 cfile2 = cbfs.files['u-boot-dtb']
2516 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2517 self.assertEqual(0x140, cfile2.cbfs_offset)
2518
Simon Glass0f621332019-07-08 14:25:27 -06002519 def testFdtmap(self):
2520 """Test an FDT map can be inserted in the image"""
2521 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2522 fdtmap_data = data[len(U_BOOT_DATA):]
2523 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002524 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002525 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002526
2527 fdt_data = fdtmap_data[16:]
2528 dtb = fdt.Fdt.FromData(fdt_data)
2529 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002530 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002531 self.assertEqual({
2532 'image-pos': 0,
2533 'offset': 0,
2534 'u-boot:offset': 0,
2535 'u-boot:size': len(U_BOOT_DATA),
2536 'u-boot:image-pos': 0,
2537 'fdtmap:image-pos': 4,
2538 'fdtmap:offset': 4,
2539 'fdtmap:size': len(fdtmap_data),
2540 'size': len(data),
2541 }, props)
2542
2543 def testFdtmapNoMatch(self):
2544 """Check handling of an FDT map when the section cannot be found"""
2545 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2546
2547 # Mangle the section name, which should cause a mismatch between the
2548 # correct FDT path and the one expected by the section
2549 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002550 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002551 entries = image.GetEntries()
2552 fdtmap = entries['fdtmap']
2553 with self.assertRaises(ValueError) as e:
2554 fdtmap._GetFdtmap()
2555 self.assertIn("Cannot locate node for path '/binman-suffix'",
2556 str(e.exception))
2557
Simon Glasscec34ba2019-07-08 14:25:28 -06002558 def testFdtmapHeader(self):
2559 """Test an FDT map and image header can be inserted in the image"""
2560 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2561 fdtmap_pos = len(U_BOOT_DATA)
2562 fdtmap_data = data[fdtmap_pos:]
2563 fdt_data = fdtmap_data[16:]
2564 dtb = fdt.Fdt.FromData(fdt_data)
2565 fdt_size = dtb.GetFdtObj().totalsize()
2566 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002567 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002568 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2569 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2570
2571 def testFdtmapHeaderStart(self):
2572 """Test an image header can be inserted at the image start"""
2573 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2574 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2575 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002576 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002577 offset = struct.unpack('<I', hdr_data[4:])[0]
2578 self.assertEqual(fdtmap_pos, offset)
2579
2580 def testFdtmapHeaderPos(self):
2581 """Test an image header can be inserted at a chosen position"""
2582 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2583 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2584 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002585 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002586 offset = struct.unpack('<I', hdr_data[4:])[0]
2587 self.assertEqual(fdtmap_pos, offset)
2588
2589 def testHeaderMissingFdtmap(self):
2590 """Test an image header requires an fdtmap"""
2591 with self.assertRaises(ValueError) as e:
2592 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2593 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2594 str(e.exception))
2595
2596 def testHeaderNoLocation(self):
2597 """Test an image header with a no specified location is detected"""
2598 with self.assertRaises(ValueError) as e:
2599 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2600 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2601 str(e.exception))
2602
Simon Glasse61b6f62019-07-08 14:25:37 -06002603 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002604 """Test extending an entry after it is packed"""
2605 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002606 self.assertEqual(b'aaa', data[:3])
2607 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2608 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002609
Simon Glassdd156a42022-03-05 20:18:59 -07002610 def testEntryExtendBad(self):
2611 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002612 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002613 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002614 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002615 str(e.exception))
2616
Simon Glassdd156a42022-03-05 20:18:59 -07002617 def testEntryExtendSection(self):
2618 """Test extending an entry within a section after it is packed"""
2619 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002620 self.assertEqual(b'aaa', data[:3])
2621 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2622 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002623
Simon Glass90d29682019-07-08 14:25:38 -06002624 def testCompressDtb(self):
2625 """Test that compress of device-tree files is supported"""
2626 self._CheckLz4()
2627 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2628 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2629 comp_data = data[len(U_BOOT_DATA):]
2630 orig = self._decompress(comp_data)
2631 dtb = fdt.Fdt.FromData(orig)
2632 dtb.Scan()
2633 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2634 expected = {
2635 'u-boot:size': len(U_BOOT_DATA),
2636 'u-boot-dtb:uncomp-size': len(orig),
2637 'u-boot-dtb:size': len(comp_data),
2638 'size': len(data),
2639 }
2640 self.assertEqual(expected, props)
2641
Simon Glass151bbbf2019-07-08 14:25:41 -06002642 def testCbfsUpdateFdt(self):
2643 """Test that we can update the device tree with CBFS offset/size info"""
2644 self._CheckLz4()
2645 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2646 update_dtb=True)
2647 dtb = fdt.Fdt(out_dtb_fname)
2648 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002649 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002650 del props['cbfs/u-boot:size']
2651 self.assertEqual({
2652 'offset': 0,
2653 'size': len(data),
2654 'image-pos': 0,
2655 'cbfs:offset': 0,
2656 'cbfs:size': len(data),
2657 'cbfs:image-pos': 0,
2658 'cbfs/u-boot:offset': 0x38,
2659 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2660 'cbfs/u-boot:image-pos': 0x38,
2661 'cbfs/u-boot-dtb:offset': 0xb8,
2662 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2663 'cbfs/u-boot-dtb:image-pos': 0xb8,
2664 }, props)
2665
Simon Glass3c9b4f22019-07-08 14:25:42 -06002666 def testCbfsBadType(self):
2667 """Test an image header with a no specified location is detected"""
2668 with self.assertRaises(ValueError) as e:
2669 self._DoReadFile('126_cbfs_bad_type.dts')
2670 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2671
Simon Glass6b156f82019-07-08 14:25:43 -06002672 def testList(self):
2673 """Test listing the files in an image"""
2674 self._CheckLz4()
2675 data = self._DoReadFile('127_list.dts')
2676 image = control.images['image']
2677 entries = image.BuildEntryList()
2678 self.assertEqual(7, len(entries))
2679
2680 ent = entries[0]
2681 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002682 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002683 self.assertEqual('section', ent.etype)
2684 self.assertEqual(len(data), ent.size)
2685 self.assertEqual(0, ent.image_pos)
2686 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002687 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002688
2689 ent = entries[1]
2690 self.assertEqual(1, ent.indent)
2691 self.assertEqual('u-boot', ent.name)
2692 self.assertEqual('u-boot', ent.etype)
2693 self.assertEqual(len(U_BOOT_DATA), ent.size)
2694 self.assertEqual(0, ent.image_pos)
2695 self.assertEqual(None, ent.uncomp_size)
2696 self.assertEqual(0, ent.offset)
2697
2698 ent = entries[2]
2699 self.assertEqual(1, ent.indent)
2700 self.assertEqual('section', ent.name)
2701 self.assertEqual('section', ent.etype)
2702 section_size = ent.size
2703 self.assertEqual(0x100, ent.image_pos)
2704 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002705 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002706
2707 ent = entries[3]
2708 self.assertEqual(2, ent.indent)
2709 self.assertEqual('cbfs', ent.name)
2710 self.assertEqual('cbfs', ent.etype)
2711 self.assertEqual(0x400, ent.size)
2712 self.assertEqual(0x100, ent.image_pos)
2713 self.assertEqual(None, ent.uncomp_size)
2714 self.assertEqual(0, ent.offset)
2715
2716 ent = entries[4]
2717 self.assertEqual(3, ent.indent)
2718 self.assertEqual('u-boot', ent.name)
2719 self.assertEqual('u-boot', ent.etype)
2720 self.assertEqual(len(U_BOOT_DATA), ent.size)
2721 self.assertEqual(0x138, ent.image_pos)
2722 self.assertEqual(None, ent.uncomp_size)
2723 self.assertEqual(0x38, ent.offset)
2724
2725 ent = entries[5]
2726 self.assertEqual(3, ent.indent)
2727 self.assertEqual('u-boot-dtb', ent.name)
2728 self.assertEqual('text', ent.etype)
2729 self.assertGreater(len(COMPRESS_DATA), ent.size)
2730 self.assertEqual(0x178, ent.image_pos)
2731 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2732 self.assertEqual(0x78, ent.offset)
2733
2734 ent = entries[6]
2735 self.assertEqual(2, ent.indent)
2736 self.assertEqual('u-boot-dtb', ent.name)
2737 self.assertEqual('u-boot-dtb', ent.etype)
2738 self.assertEqual(0x500, ent.image_pos)
2739 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2740 dtb_size = ent.size
2741 # Compressing this data expands it since headers are added
2742 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2743 self.assertEqual(0x400, ent.offset)
2744
2745 self.assertEqual(len(data), 0x100 + section_size)
2746 self.assertEqual(section_size, 0x400 + dtb_size)
2747
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002748 def testFindFdtmap(self):
2749 """Test locating an FDT map in an image"""
2750 self._CheckLz4()
2751 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2752 image = control.images['image']
2753 entries = image.GetEntries()
2754 entry = entries['fdtmap']
2755 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2756
2757 def testFindFdtmapMissing(self):
2758 """Test failing to locate an FDP map"""
2759 data = self._DoReadFile('005_simple.dts')
2760 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2761
Simon Glassed39a3c2019-07-08 14:25:45 -06002762 def testFindImageHeader(self):
2763 """Test locating a image header"""
2764 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002765 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002766 image = control.images['image']
2767 entries = image.GetEntries()
2768 entry = entries['fdtmap']
2769 # The header should point to the FDT map
2770 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2771
2772 def testFindImageHeaderStart(self):
2773 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002774 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002775 image = control.images['image']
2776 entries = image.GetEntries()
2777 entry = entries['fdtmap']
2778 # The header should point to the FDT map
2779 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2780
2781 def testFindImageHeaderMissing(self):
2782 """Test failing to locate an image header"""
2783 data = self._DoReadFile('005_simple.dts')
2784 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2785
Simon Glassb8424fa2019-07-08 14:25:46 -06002786 def testReadImage(self):
2787 """Test reading an image and accessing its FDT map"""
2788 self._CheckLz4()
2789 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002790 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002791 orig_image = control.images['image']
2792 image = Image.FromFile(image_fname)
2793 self.assertEqual(orig_image.GetEntries().keys(),
2794 image.GetEntries().keys())
2795
2796 orig_entry = orig_image.GetEntries()['fdtmap']
2797 entry = image.GetEntries()['fdtmap']
2798 self.assertEquals(orig_entry.offset, entry.offset)
2799 self.assertEquals(orig_entry.size, entry.size)
2800 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2801
2802 def testReadImageNoHeader(self):
2803 """Test accessing an image's FDT map without an image header"""
2804 self._CheckLz4()
2805 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002806 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002807 image = Image.FromFile(image_fname)
2808 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002809 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002810
2811 def testReadImageFail(self):
2812 """Test failing to read an image image's FDT map"""
2813 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002814 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002815 with self.assertRaises(ValueError) as e:
2816 image = Image.FromFile(image_fname)
2817 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002818
Simon Glassb2fd11d2019-07-08 14:25:48 -06002819 def testListCmd(self):
2820 """Test listing the files in an image using an Fdtmap"""
2821 self._CheckLz4()
2822 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2823
2824 # lz4 compression size differs depending on the version
2825 image = control.images['image']
2826 entries = image.GetEntries()
2827 section_size = entries['section'].size
2828 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2829 fdtmap_offset = entries['fdtmap'].offset
2830
Simon Glassb3d6fc72019-07-20 12:24:10 -06002831 try:
2832 tmpdir, updated_fname = self._SetupImageInTmpdir()
2833 with test_util.capture_sys_output() as (stdout, stderr):
2834 self._DoBinman('ls', '-i', updated_fname)
2835 finally:
2836 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002837 lines = stdout.getvalue().splitlines()
2838 expected = [
2839'Name Image-pos Size Entry-type Offset Uncomp-size',
2840'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002841'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002842' u-boot 0 4 u-boot 0',
2843' section 100 %x section 100' % section_size,
2844' cbfs 100 400 cbfs 0',
2845' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002846' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002847' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002848' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002849 (fdtmap_offset, fdtmap_offset),
2850' image-header bf8 8 image-header bf8',
2851 ]
2852 self.assertEqual(expected, lines)
2853
2854 def testListCmdFail(self):
2855 """Test failing to list an image"""
2856 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002857 try:
2858 tmpdir, updated_fname = self._SetupImageInTmpdir()
2859 with self.assertRaises(ValueError) as e:
2860 self._DoBinman('ls', '-i', updated_fname)
2861 finally:
2862 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002863 self.assertIn("Cannot find FDT map in image", str(e.exception))
2864
2865 def _RunListCmd(self, paths, expected):
2866 """List out entries and check the result
2867
2868 Args:
2869 paths: List of paths to pass to the list command
2870 expected: Expected list of filenames to be returned, in order
2871 """
2872 self._CheckLz4()
2873 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002874 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002875 image = Image.FromFile(image_fname)
2876 lines = image.GetListEntries(paths)[1]
2877 files = [line[0].strip() for line in lines[1:]]
2878 self.assertEqual(expected, files)
2879
2880 def testListCmdSection(self):
2881 """Test listing the files in a section"""
2882 self._RunListCmd(['section'],
2883 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2884
2885 def testListCmdFile(self):
2886 """Test listing a particular file"""
2887 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2888
2889 def testListCmdWildcard(self):
2890 """Test listing a wildcarded file"""
2891 self._RunListCmd(['*boot*'],
2892 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2893
2894 def testListCmdWildcardMulti(self):
2895 """Test listing a wildcarded file"""
2896 self._RunListCmd(['*cb*', '*head*'],
2897 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2898
2899 def testListCmdEmpty(self):
2900 """Test listing a wildcarded file"""
2901 self._RunListCmd(['nothing'], [])
2902
2903 def testListCmdPath(self):
2904 """Test listing the files in a sub-entry of a section"""
2905 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2906
Simon Glass4c613bf2019-07-08 14:25:50 -06002907 def _RunExtractCmd(self, entry_name, decomp=True):
2908 """Extract an entry from an image
2909
2910 Args:
2911 entry_name: Entry name to extract
2912 decomp: True to decompress the data if compressed, False to leave
2913 it in its raw uncompressed format
2914
2915 Returns:
2916 data from entry
2917 """
2918 self._CheckLz4()
2919 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002920 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002921 return control.ReadEntry(image_fname, entry_name, decomp)
2922
2923 def testExtractSimple(self):
2924 """Test extracting a single file"""
2925 data = self._RunExtractCmd('u-boot')
2926 self.assertEqual(U_BOOT_DATA, data)
2927
Simon Glass980a2842019-07-08 14:25:52 -06002928 def testExtractSection(self):
2929 """Test extracting the files in a section"""
2930 data = self._RunExtractCmd('section')
2931 cbfs_data = data[:0x400]
2932 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002933 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002934 dtb_data = data[0x400:]
2935 dtb = self._decompress(dtb_data)
2936 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2937
2938 def testExtractCompressed(self):
2939 """Test extracting compressed data"""
2940 data = self._RunExtractCmd('section/u-boot-dtb')
2941 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2942
2943 def testExtractRaw(self):
2944 """Test extracting compressed data without decompressing it"""
2945 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2946 dtb = self._decompress(data)
2947 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2948
2949 def testExtractCbfs(self):
2950 """Test extracting CBFS data"""
2951 data = self._RunExtractCmd('section/cbfs/u-boot')
2952 self.assertEqual(U_BOOT_DATA, data)
2953
2954 def testExtractCbfsCompressed(self):
2955 """Test extracting CBFS compressed data"""
2956 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2957 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2958
2959 def testExtractCbfsRaw(self):
2960 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002961 bintool = self.comp_bintools['lzma_alone']
2962 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06002963 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002964 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06002965 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2966
Simon Glass4c613bf2019-07-08 14:25:50 -06002967 def testExtractBadEntry(self):
2968 """Test extracting a bad section path"""
2969 with self.assertRaises(ValueError) as e:
2970 self._RunExtractCmd('section/does-not-exist')
2971 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2972 str(e.exception))
2973
2974 def testExtractMissingFile(self):
2975 """Test extracting file that does not exist"""
2976 with self.assertRaises(IOError) as e:
2977 control.ReadEntry('missing-file', 'name')
2978
2979 def testExtractBadFile(self):
2980 """Test extracting an invalid file"""
2981 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002982 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002983 with self.assertRaises(ValueError) as e:
2984 control.ReadEntry(fname, 'name')
2985
Simon Glass980a2842019-07-08 14:25:52 -06002986 def testExtractCmd(self):
2987 """Test extracting a file fron an image on the command line"""
2988 self._CheckLz4()
2989 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002990 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002991 try:
2992 tmpdir, updated_fname = self._SetupImageInTmpdir()
2993 with test_util.capture_sys_output() as (stdout, stderr):
2994 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2995 '-f', fname)
2996 finally:
2997 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07002998 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002999 self.assertEqual(U_BOOT_DATA, data)
3000
3001 def testExtractOneEntry(self):
3002 """Test extracting a single entry fron an image """
3003 self._CheckLz4()
3004 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003005 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003006 fname = os.path.join(self._indir, 'output.extact')
3007 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003008 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003009 self.assertEqual(U_BOOT_DATA, data)
3010
3011 def _CheckExtractOutput(self, decomp):
3012 """Helper to test file output with and without decompression
3013
3014 Args:
3015 decomp: True to decompress entry data, False to output it raw
3016 """
3017 def _CheckPresent(entry_path, expect_data, expect_size=None):
3018 """Check and remove expected file
3019
3020 This checks the data/size of a file and removes the file both from
3021 the outfiles set and from the output directory. Once all files are
3022 processed, both the set and directory should be empty.
3023
3024 Args:
3025 entry_path: Entry path
3026 expect_data: Data to expect in file, or None to skip check
3027 expect_size: Size of data to expect in file, or None to skip
3028 """
3029 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003030 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003031 os.remove(path)
3032 if expect_data:
3033 self.assertEqual(expect_data, data)
3034 elif expect_size:
3035 self.assertEqual(expect_size, len(data))
3036 outfiles.remove(path)
3037
3038 def _CheckDirPresent(name):
3039 """Remove expected directory
3040
3041 This gives an error if the directory does not exist as expected
3042
3043 Args:
3044 name: Name of directory to remove
3045 """
3046 path = os.path.join(outdir, name)
3047 os.rmdir(path)
3048
3049 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003050 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003051 outdir = os.path.join(self._indir, 'extract')
3052 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3053
3054 # Create a set of all file that were output (should be 9)
3055 outfiles = set()
3056 for root, dirs, files in os.walk(outdir):
3057 outfiles |= set([os.path.join(root, fname) for fname in files])
3058 self.assertEqual(9, len(outfiles))
3059 self.assertEqual(9, len(einfos))
3060
3061 image = control.images['image']
3062 entries = image.GetEntries()
3063
3064 # Check the 9 files in various ways
3065 section = entries['section']
3066 section_entries = section.GetEntries()
3067 cbfs_entries = section_entries['cbfs'].GetEntries()
3068 _CheckPresent('u-boot', U_BOOT_DATA)
3069 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3070 dtb_len = EXTRACT_DTB_SIZE
3071 if not decomp:
3072 dtb_len = cbfs_entries['u-boot-dtb'].size
3073 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3074 if not decomp:
3075 dtb_len = section_entries['u-boot-dtb'].size
3076 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3077
3078 fdtmap = entries['fdtmap']
3079 _CheckPresent('fdtmap', fdtmap.data)
3080 hdr = entries['image-header']
3081 _CheckPresent('image-header', hdr.data)
3082
3083 _CheckPresent('section/root', section.data)
3084 cbfs = section_entries['cbfs']
3085 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003086 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003087 _CheckPresent('root', data)
3088
3089 # There should be no files left. Remove all the directories to check.
3090 # If there are any files/dirs remaining, one of these checks will fail.
3091 self.assertEqual(0, len(outfiles))
3092 _CheckDirPresent('section/cbfs')
3093 _CheckDirPresent('section')
3094 _CheckDirPresent('')
3095 self.assertFalse(os.path.exists(outdir))
3096
3097 def testExtractAllEntries(self):
3098 """Test extracting all entries"""
3099 self._CheckLz4()
3100 self._CheckExtractOutput(decomp=True)
3101
3102 def testExtractAllEntriesRaw(self):
3103 """Test extracting all entries without decompressing them"""
3104 self._CheckLz4()
3105 self._CheckExtractOutput(decomp=False)
3106
3107 def testExtractSelectedEntries(self):
3108 """Test extracting some entries"""
3109 self._CheckLz4()
3110 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003111 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003112 outdir = os.path.join(self._indir, 'extract')
3113 einfos = control.ExtractEntries(image_fname, None, outdir,
3114 ['*cb*', '*head*'])
3115
3116 # File output is tested by testExtractAllEntries(), so just check that
3117 # the expected entries are selected
3118 names = [einfo.name for einfo in einfos]
3119 self.assertEqual(names,
3120 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3121
3122 def testExtractNoEntryPaths(self):
3123 """Test extracting some entries"""
3124 self._CheckLz4()
3125 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003126 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003127 with self.assertRaises(ValueError) as e:
3128 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003129 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003130 str(e.exception))
3131
3132 def testExtractTooManyEntryPaths(self):
3133 """Test extracting some entries"""
3134 self._CheckLz4()
3135 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003136 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003137 with self.assertRaises(ValueError) as e:
3138 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003139 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003140 str(e.exception))
3141
Simon Glass52d06212019-07-08 14:25:53 -06003142 def testPackAlignSection(self):
3143 """Test that sections can have alignment"""
3144 self._DoReadFile('131_pack_align_section.dts')
3145
3146 self.assertIn('image', control.images)
3147 image = control.images['image']
3148 entries = image.GetEntries()
3149 self.assertEqual(3, len(entries))
3150
3151 # First u-boot
3152 self.assertIn('u-boot', entries)
3153 entry = entries['u-boot']
3154 self.assertEqual(0, entry.offset)
3155 self.assertEqual(0, entry.image_pos)
3156 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3157 self.assertEqual(len(U_BOOT_DATA), entry.size)
3158
3159 # Section0
3160 self.assertIn('section0', entries)
3161 section0 = entries['section0']
3162 self.assertEqual(0x10, section0.offset)
3163 self.assertEqual(0x10, section0.image_pos)
3164 self.assertEqual(len(U_BOOT_DATA), section0.size)
3165
3166 # Second u-boot
3167 section_entries = section0.GetEntries()
3168 self.assertIn('u-boot', section_entries)
3169 entry = section_entries['u-boot']
3170 self.assertEqual(0, entry.offset)
3171 self.assertEqual(0x10, entry.image_pos)
3172 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3173 self.assertEqual(len(U_BOOT_DATA), entry.size)
3174
3175 # Section1
3176 self.assertIn('section1', entries)
3177 section1 = entries['section1']
3178 self.assertEqual(0x14, section1.offset)
3179 self.assertEqual(0x14, section1.image_pos)
3180 self.assertEqual(0x20, section1.size)
3181
3182 # Second u-boot
3183 section_entries = section1.GetEntries()
3184 self.assertIn('u-boot', section_entries)
3185 entry = section_entries['u-boot']
3186 self.assertEqual(0, entry.offset)
3187 self.assertEqual(0x14, entry.image_pos)
3188 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3189 self.assertEqual(len(U_BOOT_DATA), entry.size)
3190
3191 # Section2
3192 self.assertIn('section2', section_entries)
3193 section2 = section_entries['section2']
3194 self.assertEqual(0x4, section2.offset)
3195 self.assertEqual(0x18, section2.image_pos)
3196 self.assertEqual(4, section2.size)
3197
3198 # Third u-boot
3199 section_entries = section2.GetEntries()
3200 self.assertIn('u-boot', section_entries)
3201 entry = section_entries['u-boot']
3202 self.assertEqual(0, entry.offset)
3203 self.assertEqual(0x18, entry.image_pos)
3204 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3205 self.assertEqual(len(U_BOOT_DATA), entry.size)
3206
Simon Glassf8a54bc2019-07-20 12:23:56 -06003207 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3208 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003209 """Replace an entry in an image
3210
3211 This writes the entry data to update it, then opens the updated file and
3212 returns the value that it now finds there.
3213
3214 Args:
3215 entry_name: Entry name to replace
3216 data: Data to replace it with
3217 decomp: True to compress the data if needed, False if data is
3218 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003219 allow_resize: True to allow entries to change size, False to raise
3220 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003221
3222 Returns:
3223 Tuple:
3224 data from entry
3225 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003226 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003227 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003228 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003229 update_dtb=True)[1]
3230
3231 self.assertIn('image', control.images)
3232 image = control.images['image']
3233 entries = image.GetEntries()
3234 orig_dtb_data = entries['u-boot-dtb'].data
3235 orig_fdtmap_data = entries['fdtmap'].data
3236
Simon Glass80025522022-01-29 14:14:04 -07003237 image_fname = tools.get_output_filename('image.bin')
3238 updated_fname = tools.get_output_filename('image-updated.bin')
3239 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003240 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3241 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003242 data = control.ReadEntry(updated_fname, entry_name, decomp)
3243
Simon Glassf8a54bc2019-07-20 12:23:56 -06003244 # The DT data should not change unless resized:
3245 if not allow_resize:
3246 new_dtb_data = entries['u-boot-dtb'].data
3247 self.assertEqual(new_dtb_data, orig_dtb_data)
3248 new_fdtmap_data = entries['fdtmap'].data
3249 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003250
Simon Glassf8a54bc2019-07-20 12:23:56 -06003251 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003252
3253 def testReplaceSimple(self):
3254 """Test replacing a single file"""
3255 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003256 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3257 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003258 self.assertEqual(expected, data)
3259
3260 # Test that the state looks right. There should be an FDT for the fdtmap
3261 # that we jsut read back in, and it should match what we find in the
3262 # 'control' tables. Checking for an FDT that does not exist should
3263 # return None.
3264 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003265 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003266 self.assertEqual(expected_fdtmap, fdtmap)
3267
3268 dtb = state.GetFdtForEtype('fdtmap')
3269 self.assertEqual(dtb.GetContents(), fdtmap)
3270
3271 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3272 self.assertIsNone(missing_path)
3273 self.assertIsNone(missing_fdtmap)
3274
3275 missing_dtb = state.GetFdtForEtype('missing')
3276 self.assertIsNone(missing_dtb)
3277
3278 self.assertEqual('/binman', state.fdt_path_prefix)
3279
3280 def testReplaceResizeFail(self):
3281 """Test replacing a file by something larger"""
3282 expected = U_BOOT_DATA + b'x'
3283 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003284 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3285 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003286 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3287 str(e.exception))
3288
3289 def testReplaceMulti(self):
3290 """Test replacing entry data where multiple images are generated"""
3291 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3292 update_dtb=True)[0]
3293 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003294 updated_fname = tools.get_output_filename('image-updated.bin')
3295 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003296 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003297 control.WriteEntry(updated_fname, entry_name, expected,
3298 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003299 data = control.ReadEntry(updated_fname, entry_name)
3300 self.assertEqual(expected, data)
3301
3302 # Check the state looks right.
3303 self.assertEqual('/binman/image', state.fdt_path_prefix)
3304
3305 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003306 image_fname = tools.get_output_filename('first-image.bin')
3307 updated_fname = tools.get_output_filename('first-updated.bin')
3308 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003309 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003310 control.WriteEntry(updated_fname, entry_name, expected,
3311 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003312 data = control.ReadEntry(updated_fname, entry_name)
3313 self.assertEqual(expected, data)
3314
3315 # Check the state looks right.
3316 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003317
Simon Glassfb30e292019-07-20 12:23:51 -06003318 def testUpdateFdtAllRepack(self):
3319 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003320 self._SetupSplElf()
3321 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003322 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3323 SECTION_SIZE = 0x300
3324 DTB_SIZE = 602
3325 FDTMAP_SIZE = 608
3326 base_expected = {
3327 'offset': 0,
3328 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3329 'image-pos': 0,
3330 'section:offset': 0,
3331 'section:size': SECTION_SIZE,
3332 'section:image-pos': 0,
3333 'section/u-boot-dtb:offset': 4,
3334 'section/u-boot-dtb:size': 636,
3335 'section/u-boot-dtb:image-pos': 4,
3336 'u-boot-spl-dtb:offset': SECTION_SIZE,
3337 'u-boot-spl-dtb:size': DTB_SIZE,
3338 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3339 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3340 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3341 'u-boot-tpl-dtb:size': DTB_SIZE,
3342 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3343 'fdtmap:size': FDTMAP_SIZE,
3344 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3345 }
3346 main_expected = {
3347 'section:orig-size': SECTION_SIZE,
3348 'section/u-boot-dtb:orig-offset': 4,
3349 }
3350
3351 # We expect three device-tree files in the output, with the first one
3352 # within a fixed-size section.
3353 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3354 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3355 # main U-Boot tree. All three should have the same positions and offset
3356 # except that the main tree should include the main_expected properties
3357 start = 4
3358 for item in ['', 'spl', 'tpl', None]:
3359 if item is None:
3360 start += 16 # Move past fdtmap header
3361 dtb = fdt.Fdt.FromData(data[start:])
3362 dtb.Scan()
3363 props = self._GetPropTree(dtb,
3364 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3365 prefix='/' if item is None else '/binman/')
3366 expected = dict(base_expected)
3367 if item:
3368 expected[item] = 0
3369 else:
3370 # Main DTB and fdtdec should include the 'orig-' properties
3371 expected.update(main_expected)
3372 # Helpful for debugging:
3373 #for prop in sorted(props):
3374 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3375 self.assertEqual(expected, props)
3376 if item == '':
3377 start = SECTION_SIZE
3378 else:
3379 start += dtb._fdt_obj.totalsize()
3380
Simon Glass11453762019-07-20 12:23:55 -06003381 def testFdtmapHeaderMiddle(self):
3382 """Test an FDT map in the middle of an image when it should be at end"""
3383 with self.assertRaises(ValueError) as e:
3384 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3385 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3386 str(e.exception))
3387
3388 def testFdtmapHeaderStartBad(self):
3389 """Test an FDT map in middle of an image when it should be at start"""
3390 with self.assertRaises(ValueError) as e:
3391 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3392 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3393 str(e.exception))
3394
3395 def testFdtmapHeaderEndBad(self):
3396 """Test an FDT map at the start of an image when it should be at end"""
3397 with self.assertRaises(ValueError) as e:
3398 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3399 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3400 str(e.exception))
3401
3402 def testFdtmapHeaderNoSize(self):
3403 """Test an image header at the end of an image with undefined size"""
3404 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3405
Simon Glassf8a54bc2019-07-20 12:23:56 -06003406 def testReplaceResize(self):
3407 """Test replacing a single file in an entry with a larger file"""
3408 expected = U_BOOT_DATA + b'x'
3409 data, _, image = self._RunReplaceCmd('u-boot', expected,
3410 dts='139_replace_repack.dts')
3411 self.assertEqual(expected, data)
3412
3413 entries = image.GetEntries()
3414 dtb_data = entries['u-boot-dtb'].data
3415 dtb = fdt.Fdt.FromData(dtb_data)
3416 dtb.Scan()
3417
3418 # The u-boot section should now be larger in the dtb
3419 node = dtb.GetNode('/binman/u-boot')
3420 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3421
3422 # Same for the fdtmap
3423 fdata = entries['fdtmap'].data
3424 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3425 fdtb.Scan()
3426 fnode = fdtb.GetNode('/u-boot')
3427 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3428
3429 def testReplaceResizeNoRepack(self):
3430 """Test replacing an entry with a larger file when not allowed"""
3431 expected = U_BOOT_DATA + b'x'
3432 with self.assertRaises(ValueError) as e:
3433 self._RunReplaceCmd('u-boot', expected)
3434 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3435 str(e.exception))
3436
Simon Glass9d8ee322019-07-20 12:23:58 -06003437 def testEntryShrink(self):
3438 """Test contracting an entry after it is packed"""
3439 try:
3440 state.SetAllowEntryContraction(True)
3441 data = self._DoReadFileDtb('140_entry_shrink.dts',
3442 update_dtb=True)[0]
3443 finally:
3444 state.SetAllowEntryContraction(False)
3445 self.assertEqual(b'a', data[:1])
3446 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3447 self.assertEqual(b'a', data[-1:])
3448
3449 def testEntryShrinkFail(self):
3450 """Test not being allowed to contract an entry after it is packed"""
3451 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3452
3453 # In this case there is a spare byte at the end of the data. The size of
3454 # the contents is only 1 byte but we still have the size before it
3455 # shrunk.
3456 self.assertEqual(b'a\0', data[:2])
3457 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3458 self.assertEqual(b'a\0', data[-2:])
3459
Simon Glass70e32982019-07-20 12:24:01 -06003460 def testDescriptorOffset(self):
3461 """Test that the Intel descriptor is always placed at at the start"""
3462 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3463 image = control.images['image']
3464 entries = image.GetEntries()
3465 desc = entries['intel-descriptor']
3466 self.assertEqual(0xff800000, desc.offset);
3467 self.assertEqual(0xff800000, desc.image_pos);
3468
Simon Glass37fdd142019-07-20 12:24:06 -06003469 def testReplaceCbfs(self):
3470 """Test replacing a single file in CBFS without changing the size"""
3471 self._CheckLz4()
3472 expected = b'x' * len(U_BOOT_DATA)
3473 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003474 updated_fname = tools.get_output_filename('image-updated.bin')
3475 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003476 entry_name = 'section/cbfs/u-boot'
3477 control.WriteEntry(updated_fname, entry_name, expected,
3478 allow_resize=True)
3479 data = control.ReadEntry(updated_fname, entry_name)
3480 self.assertEqual(expected, data)
3481
3482 def testReplaceResizeCbfs(self):
3483 """Test replacing a single file in CBFS with one of a different size"""
3484 self._CheckLz4()
3485 expected = U_BOOT_DATA + b'x'
3486 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003487 updated_fname = tools.get_output_filename('image-updated.bin')
3488 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003489 entry_name = 'section/cbfs/u-boot'
3490 control.WriteEntry(updated_fname, entry_name, expected,
3491 allow_resize=True)
3492 data = control.ReadEntry(updated_fname, entry_name)
3493 self.assertEqual(expected, data)
3494
Simon Glass30033c22019-07-20 12:24:15 -06003495 def _SetupForReplace(self):
3496 """Set up some files to use to replace entries
3497
3498 This generates an image, copies it to a new file, extracts all the files
3499 in it and updates some of them
3500
3501 Returns:
3502 List
3503 Image filename
3504 Output directory
3505 Expected values for updated entries, each a string
3506 """
3507 data = self._DoReadFileRealDtb('143_replace_all.dts')
3508
Simon Glass80025522022-01-29 14:14:04 -07003509 updated_fname = tools.get_output_filename('image-updated.bin')
3510 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003511
3512 outdir = os.path.join(self._indir, 'extract')
3513 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3514
3515 expected1 = b'x' + U_BOOT_DATA + b'y'
3516 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003517 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003518
3519 expected2 = b'a' + U_BOOT_DATA + b'b'
3520 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003521 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003522
3523 expected_text = b'not the same text'
3524 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003525 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003526
3527 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3528 dtb = fdt.FdtScan(dtb_fname)
3529 node = dtb.GetNode('/binman/text')
3530 node.AddString('my-property', 'the value')
3531 dtb.Sync(auto_resize=True)
3532 dtb.Flush()
3533
3534 return updated_fname, outdir, expected1, expected2, expected_text
3535
3536 def _CheckReplaceMultiple(self, entry_paths):
3537 """Handle replacing the contents of multiple entries
3538
3539 Args:
3540 entry_paths: List of entry paths to replace
3541
3542 Returns:
3543 List
3544 Dict of entries in the image:
3545 key: Entry name
3546 Value: Entry object
3547 Expected values for updated entries, each a string
3548 """
3549 updated_fname, outdir, expected1, expected2, expected_text = (
3550 self._SetupForReplace())
3551 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3552
3553 image = Image.FromFile(updated_fname)
3554 image.LoadData()
3555 return image.GetEntries(), expected1, expected2, expected_text
3556
3557 def testReplaceAll(self):
3558 """Test replacing the contents of all entries"""
3559 entries, expected1, expected2, expected_text = (
3560 self._CheckReplaceMultiple([]))
3561 data = entries['u-boot'].data
3562 self.assertEqual(expected1, data)
3563
3564 data = entries['u-boot2'].data
3565 self.assertEqual(expected2, data)
3566
3567 data = entries['text'].data
3568 self.assertEqual(expected_text, data)
3569
3570 # Check that the device tree is updated
3571 data = entries['u-boot-dtb'].data
3572 dtb = fdt.Fdt.FromData(data)
3573 dtb.Scan()
3574 node = dtb.GetNode('/binman/text')
3575 self.assertEqual('the value', node.props['my-property'].value)
3576
3577 def testReplaceSome(self):
3578 """Test replacing the contents of a few entries"""
3579 entries, expected1, expected2, expected_text = (
3580 self._CheckReplaceMultiple(['u-boot2', 'text']))
3581
3582 # This one should not change
3583 data = entries['u-boot'].data
3584 self.assertEqual(U_BOOT_DATA, data)
3585
3586 data = entries['u-boot2'].data
3587 self.assertEqual(expected2, data)
3588
3589 data = entries['text'].data
3590 self.assertEqual(expected_text, data)
3591
3592 def testReplaceCmd(self):
3593 """Test replacing a file fron an image on the command line"""
3594 self._DoReadFileRealDtb('143_replace_all.dts')
3595
3596 try:
3597 tmpdir, updated_fname = self._SetupImageInTmpdir()
3598
3599 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3600 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003601 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003602
3603 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003604 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003605 self.assertEqual(expected, data[:len(expected)])
3606 map_fname = os.path.join(tmpdir, 'image-updated.map')
3607 self.assertFalse(os.path.exists(map_fname))
3608 finally:
3609 shutil.rmtree(tmpdir)
3610
3611 def testReplaceCmdSome(self):
3612 """Test replacing some files fron an image on the command line"""
3613 updated_fname, outdir, expected1, expected2, expected_text = (
3614 self._SetupForReplace())
3615
3616 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3617 'u-boot2', 'text')
3618
Simon Glass80025522022-01-29 14:14:04 -07003619 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003620 image = Image.FromFile(updated_fname)
3621 image.LoadData()
3622 entries = image.GetEntries()
3623
3624 # This one should not change
3625 data = entries['u-boot'].data
3626 self.assertEqual(U_BOOT_DATA, data)
3627
3628 data = entries['u-boot2'].data
3629 self.assertEqual(expected2, data)
3630
3631 data = entries['text'].data
3632 self.assertEqual(expected_text, data)
3633
3634 def testReplaceMissing(self):
3635 """Test replacing entries where the file is missing"""
3636 updated_fname, outdir, expected1, expected2, expected_text = (
3637 self._SetupForReplace())
3638
3639 # Remove one of the files, to generate a warning
3640 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3641 os.remove(u_boot_fname1)
3642
3643 with test_util.capture_sys_output() as (stdout, stderr):
3644 control.ReplaceEntries(updated_fname, None, outdir, [])
3645 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003646 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003647
3648 def testReplaceCmdMap(self):
3649 """Test replacing a file fron an image on the command line"""
3650 self._DoReadFileRealDtb('143_replace_all.dts')
3651
3652 try:
3653 tmpdir, updated_fname = self._SetupImageInTmpdir()
3654
3655 fname = os.path.join(self._indir, 'update-u-boot.bin')
3656 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003657 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003658
3659 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3660 '-f', fname, '-m')
3661 map_fname = os.path.join(tmpdir, 'image-updated.map')
3662 self.assertTrue(os.path.exists(map_fname))
3663 finally:
3664 shutil.rmtree(tmpdir)
3665
3666 def testReplaceNoEntryPaths(self):
3667 """Test replacing an entry without an entry path"""
3668 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003669 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003670 with self.assertRaises(ValueError) as e:
3671 control.ReplaceEntries(image_fname, 'fname', None, [])
3672 self.assertIn('Must specify an entry path to read with -f',
3673 str(e.exception))
3674
3675 def testReplaceTooManyEntryPaths(self):
3676 """Test extracting some entries"""
3677 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003678 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003679 with self.assertRaises(ValueError) as e:
3680 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3681 self.assertIn('Must specify exactly one entry path to write with -f',
3682 str(e.exception))
3683
Simon Glass0b074d62019-08-24 07:22:48 -06003684 def testPackReset16(self):
3685 """Test that an image with an x86 reset16 region can be created"""
3686 data = self._DoReadFile('144_x86_reset16.dts')
3687 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3688
3689 def testPackReset16Spl(self):
3690 """Test that an image with an x86 reset16-spl region can be created"""
3691 data = self._DoReadFile('145_x86_reset16_spl.dts')
3692 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3693
3694 def testPackReset16Tpl(self):
3695 """Test that an image with an x86 reset16-tpl region can be created"""
3696 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3697 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3698
Simon Glass232f90c2019-08-24 07:22:50 -06003699 def testPackIntelFit(self):
3700 """Test that an image with an Intel FIT and pointer can be created"""
3701 data = self._DoReadFile('147_intel_fit.dts')
3702 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3703 fit = data[16:32];
3704 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3705 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3706
3707 image = control.images['image']
3708 entries = image.GetEntries()
3709 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3710 self.assertEqual(expected_ptr, ptr)
3711
3712 def testPackIntelFitMissing(self):
3713 """Test detection of a FIT pointer with not FIT region"""
3714 with self.assertRaises(ValueError) as e:
3715 self._DoReadFile('148_intel_fit_missing.dts')
3716 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3717 str(e.exception))
3718
Simon Glass72555fa2019-11-06 17:22:44 -07003719 def _CheckSymbolsTplSection(self, dts, expected_vals):
3720 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003721 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003722 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003723 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003724 self.assertEqual(expected1, data[:upto1])
3725
3726 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003727 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003728 self.assertEqual(expected2, data[upto1:upto2])
3729
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003730 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003731 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003732 self.assertEqual(expected3, data[upto2:upto3])
3733
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003734 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003735 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3736
3737 def testSymbolsTplSection(self):
3738 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3739 self._SetupSplElf('u_boot_binman_syms')
3740 self._SetupTplElf('u_boot_binman_syms')
3741 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003742 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003743
3744 def testSymbolsTplSectionX86(self):
3745 """Test binman can assign symbols in a section with end-at-4gb"""
3746 self._SetupSplElf('u_boot_binman_syms_x86')
3747 self._SetupTplElf('u_boot_binman_syms_x86')
3748 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003749 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003750 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003751
Simon Glass98c59572019-08-24 07:23:03 -06003752 def testPackX86RomIfwiSectiom(self):
3753 """Test that a section can be placed in an IFWI region"""
3754 self._SetupIfwi('fitimage.bin')
3755 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3756 self._CheckIfwi(data)
3757
Simon Glassba7985d2019-08-24 07:23:07 -06003758 def testPackFspM(self):
3759 """Test that an image with a FSP memory-init binary can be created"""
3760 data = self._DoReadFile('152_intel_fsp_m.dts')
3761 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3762
Simon Glass4d9086d2019-10-20 21:31:35 -06003763 def testPackFspS(self):
3764 """Test that an image with a FSP silicon-init binary can be created"""
3765 data = self._DoReadFile('153_intel_fsp_s.dts')
3766 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003767
Simon Glass9ea87b22019-10-20 21:31:36 -06003768 def testPackFspT(self):
3769 """Test that an image with a FSP temp-ram-init binary can be created"""
3770 data = self._DoReadFile('154_intel_fsp_t.dts')
3771 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3772
Simon Glass48f3aad2020-07-09 18:39:31 -06003773 def testMkimage(self):
3774 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003775 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003776 data = self._DoReadFile('156_mkimage.dts')
3777
3778 # Just check that the data appears in the file somewhere
3779 self.assertIn(U_BOOT_SPL_DATA, data)
3780
Simon Glass66152ce2022-01-09 20:14:09 -07003781 def testMkimageMissing(self):
3782 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003783 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003784 with test_util.capture_sys_output() as (_, stderr):
3785 self._DoTestFile('156_mkimage.dts',
3786 force_missing_bintools='mkimage')
3787 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003788 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003789
Simon Glass5e560182020-07-09 18:39:36 -06003790 def testExtblob(self):
3791 """Test an image with an external blob"""
3792 data = self._DoReadFile('157_blob_ext.dts')
3793 self.assertEqual(REFCODE_DATA, data)
3794
3795 def testExtblobMissing(self):
3796 """Test an image with a missing external blob"""
3797 with self.assertRaises(ValueError) as e:
3798 self._DoReadFile('158_blob_ext_missing.dts')
3799 self.assertIn("Filename 'missing-file' not found in input path",
3800 str(e.exception))
3801
Simon Glass5d94cc62020-07-09 18:39:38 -06003802 def testExtblobMissingOk(self):
3803 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003804 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003805 ret = self._DoTestFile('158_blob_ext_missing.dts',
3806 allow_missing=True)
3807 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003808 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003809 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003810 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003811 self.assertIn('Some images are invalid', err)
3812
3813 def testExtblobMissingOkFlag(self):
3814 """Test an image with an missing external blob allowed with -W"""
3815 with test_util.capture_sys_output() as (stdout, stderr):
3816 ret = self._DoTestFile('158_blob_ext_missing.dts',
3817 allow_missing=True, ignore_missing=True)
3818 self.assertEqual(0, ret)
3819 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003820 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003821 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003822 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003823
3824 def testExtblobMissingOkSect(self):
3825 """Test an image with an missing external blob that is allowed"""
3826 with test_util.capture_sys_output() as (stdout, stderr):
3827 self._DoTestFile('159_blob_ext_missing_sect.dts',
3828 allow_missing=True)
3829 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003830 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003831
Simon Glasse88cef92020-07-09 18:39:41 -06003832 def testPackX86RomMeMissingDesc(self):
3833 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003834 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003835 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003836 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003837 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003838
3839 def testPackX86RomMissingIfwi(self):
3840 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3841 self._SetupIfwi('fitimage.bin')
3842 pathname = os.path.join(self._indir, 'fitimage.bin')
3843 os.remove(pathname)
3844 with test_util.capture_sys_output() as (stdout, stderr):
3845 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3846 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003847 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003848
Simon Glass2a0fa982022-02-11 13:23:21 -07003849 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003850 """Test that zero-size overlapping regions are ignored"""
3851 self._DoTestFile('160_pack_overlap_zero.dts')
3852
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003853 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003854 # The data should be inside the FIT
3855 dtb = fdt.Fdt.FromData(fit_data)
3856 dtb.Scan()
3857 fnode = dtb.GetNode('/images/kernel')
3858 self.assertIn('data', fnode.props)
3859
3860 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003861 tools.write_file(fname, fit_data)
3862 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003863
3864 # Check a few features to make sure the plumbing works. We don't need
3865 # to test the operation of mkimage or dumpimage here. First convert the
3866 # output into a dict where the keys are the fields printed by dumpimage
3867 # and the values are a list of values for each field
3868 lines = out.splitlines()
3869
3870 # Converts "Compression: gzip compressed" into two groups:
3871 # 'Compression' and 'gzip compressed'
3872 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3873 vals = collections.defaultdict(list)
3874 for line in lines:
3875 mat = re_line.match(line)
3876 vals[mat.group(1)].append(mat.group(2))
3877
3878 self.assertEquals('FIT description: test-desc', lines[0])
3879 self.assertIn('Created:', lines[1])
3880 self.assertIn('Image 0 (kernel)', vals)
3881 self.assertIn('Hash value', vals)
3882 data_sizes = vals.get('Data Size')
3883 self.assertIsNotNone(data_sizes)
3884 self.assertEqual(2, len(data_sizes))
3885 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003886 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3887 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3888
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003889 # Check if entry listing correctly omits /images/
3890 image = control.images['image']
3891 fit_entry = image.GetEntries()['fit']
3892 subentries = list(fit_entry.GetEntries().keys())
3893 expected = ['kernel', 'fdt-1']
3894 self.assertEqual(expected, subentries)
3895
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003896 def testSimpleFit(self):
3897 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003898 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003899 data = self._DoReadFile('161_fit.dts')
3900 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3901 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3902 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3903
3904 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3905
3906 def testSimpleFitExpandsSubentries(self):
3907 """Test that FIT images expand their subentries"""
3908 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3909 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3910 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3911 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3912
3913 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003914
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003915 def testSimpleFitImagePos(self):
3916 """Test that we have correct image-pos for FIT subentries"""
3917 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3918 update_dtb=True)
3919 dtb = fdt.Fdt(out_dtb_fname)
3920 dtb.Scan()
3921 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3922
Simon Glassb7bad182022-03-05 20:19:01 -07003923 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003924 self.assertEqual({
3925 'image-pos': 0,
3926 'offset': 0,
3927 'size': 1890,
3928
3929 'u-boot:image-pos': 0,
3930 'u-boot:offset': 0,
3931 'u-boot:size': 4,
3932
3933 'fit:image-pos': 4,
3934 'fit:offset': 4,
3935 'fit:size': 1840,
3936
Simon Glassb7bad182022-03-05 20:19:01 -07003937 'fit/images/kernel:image-pos': 304,
3938 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003939 'fit/images/kernel:size': 4,
3940
Simon Glassb7bad182022-03-05 20:19:01 -07003941 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003942 'fit/images/kernel/u-boot:offset': 0,
3943 'fit/images/kernel/u-boot:size': 4,
3944
Simon Glassb7bad182022-03-05 20:19:01 -07003945 'fit/images/fdt-1:image-pos': 552,
3946 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003947 'fit/images/fdt-1:size': 6,
3948
Simon Glassb7bad182022-03-05 20:19:01 -07003949 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003950 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3951 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3952
3953 'u-boot-nodtb:image-pos': 1844,
3954 'u-boot-nodtb:offset': 1844,
3955 'u-boot-nodtb:size': 46,
3956 }, props)
3957
3958 # Actually check the data is where we think it is
3959 for node, expected in [
3960 ("u-boot", U_BOOT_DATA),
3961 ("fit/images/kernel", U_BOOT_DATA),
3962 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3963 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3964 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3965 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3966 ]:
3967 image_pos = props[f"{node}:image-pos"]
3968 size = props[f"{node}:size"]
3969 self.assertEqual(len(expected), size)
3970 self.assertEqual(expected, data[image_pos:image_pos+size])
3971
Simon Glass45d556d2020-07-09 18:39:45 -06003972 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003973 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003974 data = self._DoReadFile('162_fit_external.dts')
3975 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3976
Simon Glass7932c882022-01-09 20:13:39 -07003977 # Size of the external-data region as set up by mkimage
3978 external_data_size = len(U_BOOT_DATA) + 2
3979 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003980 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003981 len(U_BOOT_NODTB_DATA))
3982
Simon Glass45d556d2020-07-09 18:39:45 -06003983 # The data should be outside the FIT
3984 dtb = fdt.Fdt.FromData(fit_data)
3985 dtb.Scan()
3986 fnode = dtb.GetNode('/images/kernel')
3987 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003988 self.assertEqual(len(U_BOOT_DATA),
3989 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3990 fit_pos = 0x400;
3991 self.assertEqual(
3992 fit_pos,
3993 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3994
3995 self.assertEquals(expected_size, len(data))
3996 actual_pos = len(U_BOOT_DATA) + fit_pos
3997 self.assertEqual(U_BOOT_DATA + b'aa',
3998 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003999
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004000 def testFitExternalImagePos(self):
4001 """Test that we have correct image-pos for external FIT subentries"""
4002 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4003 update_dtb=True)
4004 dtb = fdt.Fdt(out_dtb_fname)
4005 dtb.Scan()
4006 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4007
4008 self.assertEqual({
4009 'image-pos': 0,
4010 'offset': 0,
4011 'size': 1082,
4012
4013 'u-boot:image-pos': 0,
4014 'u-boot:offset': 0,
4015 'u-boot:size': 4,
4016
4017 'fit:size': 1032,
4018 'fit:offset': 4,
4019 'fit:image-pos': 4,
4020
4021 'fit/images/kernel:size': 4,
4022 'fit/images/kernel:offset': 1024,
4023 'fit/images/kernel:image-pos': 1028,
4024
4025 'fit/images/kernel/u-boot:size': 4,
4026 'fit/images/kernel/u-boot:offset': 0,
4027 'fit/images/kernel/u-boot:image-pos': 1028,
4028
4029 'fit/images/fdt-1:size': 2,
4030 'fit/images/fdt-1:offset': 1028,
4031 'fit/images/fdt-1:image-pos': 1032,
4032
4033 'fit/images/fdt-1/_testing:size': 2,
4034 'fit/images/fdt-1/_testing:offset': 0,
4035 'fit/images/fdt-1/_testing:image-pos': 1032,
4036
4037 'u-boot-nodtb:image-pos': 1036,
4038 'u-boot-nodtb:offset': 1036,
4039 'u-boot-nodtb:size': 46,
4040 }, props)
4041
4042 # Actually check the data is where we think it is
4043 for node, expected in [
4044 ("u-boot", U_BOOT_DATA),
4045 ("fit/images/kernel", U_BOOT_DATA),
4046 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4047 ("fit/images/fdt-1", b'aa'),
4048 ("fit/images/fdt-1/_testing", b'aa'),
4049 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4050 ]:
4051 image_pos = props[f"{node}:image-pos"]
4052 size = props[f"{node}:size"]
4053 self.assertEqual(len(expected), size)
4054 self.assertEqual(expected, data[image_pos:image_pos+size])
4055
Simon Glass66152ce2022-01-09 20:14:09 -07004056 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004057 """Test that binman complains if mkimage is missing"""
4058 with self.assertRaises(ValueError) as e:
4059 self._DoTestFile('162_fit_external.dts',
4060 force_missing_bintools='mkimage')
4061 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4062 str(e.exception))
4063
4064 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004065 """Test that binman still produces a FIT image if mkimage is missing"""
4066 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004067 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004068 force_missing_bintools='mkimage')
4069 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004070 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004071
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004072 def testSectionIgnoreHashSignature(self):
4073 """Test that sections ignore hash, signature nodes for its data"""
4074 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4075 expected = (U_BOOT_DATA + U_BOOT_DATA)
4076 self.assertEqual(expected, data)
4077
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004078 def testPadInSections(self):
4079 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004080 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4081 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004082 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4083 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004084 U_BOOT_DATA)
4085 self.assertEqual(expected, data)
4086
Simon Glassd12599d2020-10-26 17:40:09 -06004087 dtb = fdt.Fdt(out_dtb_fname)
4088 dtb.Scan()
4089 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4090 expected = {
4091 'image-pos': 0,
4092 'offset': 0,
4093 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4094
4095 'section:image-pos': 0,
4096 'section:offset': 0,
4097 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4098
4099 'section/before:image-pos': 0,
4100 'section/before:offset': 0,
4101 'section/before:size': len(U_BOOT_DATA),
4102
4103 'section/u-boot:image-pos': 4,
4104 'section/u-boot:offset': 4,
4105 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4106
4107 'section/after:image-pos': 26,
4108 'section/after:offset': 26,
4109 'section/after:size': len(U_BOOT_DATA),
4110 }
4111 self.assertEqual(expected, props)
4112
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004113 def testFitImageSubentryAlignment(self):
4114 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004115 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004116 entry_args = {
4117 'test-id': TEXT_DATA,
4118 }
4119 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4120 entry_args=entry_args)
4121 dtb = fdt.Fdt.FromData(data)
4122 dtb.Scan()
4123
4124 node = dtb.GetNode('/images/kernel')
4125 data = dtb.GetProps(node)["data"].bytes
4126 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004127 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4128 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004129 self.assertEqual(expected, data)
4130
4131 node = dtb.GetNode('/images/fdt-1')
4132 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004133 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4134 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004135 U_BOOT_DTB_DATA)
4136 self.assertEqual(expected, data)
4137
4138 def testFitExtblobMissingOk(self):
4139 """Test a FIT with a missing external blob that is allowed"""
4140 with test_util.capture_sys_output() as (stdout, stderr):
4141 self._DoTestFile('168_fit_missing_blob.dts',
4142 allow_missing=True)
4143 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004144 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004145
Simon Glass21db0ff2020-09-01 05:13:54 -06004146 def testBlobNamedByArgMissing(self):
4147 """Test handling of a missing entry arg"""
4148 with self.assertRaises(ValueError) as e:
4149 self._DoReadFile('068_blob_named_by_arg.dts')
4150 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4151 str(e.exception))
4152
Simon Glass559c4de2020-09-01 05:13:58 -06004153 def testPackBl31(self):
4154 """Test that an image with an ATF BL31 binary can be created"""
4155 data = self._DoReadFile('169_atf_bl31.dts')
4156 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4157
Samuel Holland9d8cc632020-10-21 21:12:15 -05004158 def testPackScp(self):
4159 """Test that an image with an SCP binary can be created"""
4160 data = self._DoReadFile('172_scp.dts')
4161 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4162
Simon Glassa435cd12020-09-01 05:13:59 -06004163 def testFitFdt(self):
4164 """Test an image with an FIT with multiple FDT images"""
4165 def _CheckFdt(seq, expected_data):
4166 """Check the FDT nodes
4167
4168 Args:
4169 seq: Sequence number to check (0 or 1)
4170 expected_data: Expected contents of 'data' property
4171 """
4172 name = 'fdt-%d' % seq
4173 fnode = dtb.GetNode('/images/%s' % name)
4174 self.assertIsNotNone(fnode)
4175 self.assertEqual({'description','type', 'compression', 'data'},
4176 set(fnode.props.keys()))
4177 self.assertEqual(expected_data, fnode.props['data'].bytes)
4178 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4179 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004180 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004181
4182 def _CheckConfig(seq, expected_data):
4183 """Check the configuration nodes
4184
4185 Args:
4186 seq: Sequence number to check (0 or 1)
4187 expected_data: Expected contents of 'data' property
4188 """
4189 cnode = dtb.GetNode('/configurations')
4190 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004191 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004192
4193 name = 'config-%d' % seq
4194 fnode = dtb.GetNode('/configurations/%s' % name)
4195 self.assertIsNotNone(fnode)
4196 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4197 set(fnode.props.keys()))
4198 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4199 fnode.props['description'].value)
4200 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4201
4202 entry_args = {
4203 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004204 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004205 }
4206 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004207 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004208 entry_args=entry_args,
4209 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4210 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4211 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4212
4213 dtb = fdt.Fdt.FromData(fit_data)
4214 dtb.Scan()
4215 fnode = dtb.GetNode('/images/kernel')
4216 self.assertIn('data', fnode.props)
4217
4218 # Check all the properties in fdt-1 and fdt-2
4219 _CheckFdt(1, TEST_FDT1_DATA)
4220 _CheckFdt(2, TEST_FDT2_DATA)
4221
4222 # Check configurations
4223 _CheckConfig(1, TEST_FDT1_DATA)
4224 _CheckConfig(2, TEST_FDT2_DATA)
4225
4226 def testFitFdtMissingList(self):
4227 """Test handling of a missing 'of-list' entry arg"""
4228 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004229 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004230 self.assertIn("Generator node requires 'of-list' entry argument",
4231 str(e.exception))
4232
4233 def testFitFdtEmptyList(self):
4234 """Test handling of an empty 'of-list' entry arg"""
4235 entry_args = {
4236 'of-list': '',
4237 }
4238 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4239
4240 def testFitFdtMissingProp(self):
4241 """Test handling of a missing 'fit,fdt-list' property"""
4242 with self.assertRaises(ValueError) as e:
4243 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4244 self.assertIn("Generator node requires 'fit,fdt-list' property",
4245 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004246
Simon Glass1032acc2020-09-06 10:39:08 -06004247 def testFitFdtMissing(self):
4248 """Test handling of a missing 'default-dt' entry arg"""
4249 entry_args = {
4250 'of-list': 'test-fdt1 test-fdt2',
4251 }
4252 with self.assertRaises(ValueError) as e:
4253 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004254 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004255 entry_args=entry_args,
4256 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4257 self.assertIn("Generated 'default' node requires default-dt entry argument",
4258 str(e.exception))
4259
4260 def testFitFdtNotInList(self):
4261 """Test handling of a default-dt that is not in the of-list"""
4262 entry_args = {
4263 'of-list': 'test-fdt1 test-fdt2',
4264 'default-dt': 'test-fdt3',
4265 }
4266 with self.assertRaises(ValueError) as e:
4267 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004268 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004269 entry_args=entry_args,
4270 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4271 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4272 str(e.exception))
4273
Simon Glassa820af72020-09-06 10:39:09 -06004274 def testFitExtblobMissingHelp(self):
4275 """Test display of help messages when an external blob is missing"""
4276 control.missing_blob_help = control._ReadMissingBlobHelp()
4277 control.missing_blob_help['wibble'] = 'Wibble test'
4278 control.missing_blob_help['another'] = 'Another test'
4279 with test_util.capture_sys_output() as (stdout, stderr):
4280 self._DoTestFile('168_fit_missing_blob.dts',
4281 allow_missing=True)
4282 err = stderr.getvalue()
4283
4284 # We can get the tag from the name, the type or the missing-msg
4285 # property. Check all three.
4286 self.assertIn('You may need to build ARM Trusted', err)
4287 self.assertIn('Wibble test', err)
4288 self.assertIn('Another test', err)
4289
Simon Glass6f1f4d42020-09-06 10:35:32 -06004290 def testMissingBlob(self):
4291 """Test handling of a blob containing a missing file"""
4292 with self.assertRaises(ValueError) as e:
4293 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4294 self.assertIn("Filename 'missing' not found in input path",
4295 str(e.exception))
4296
Simon Glassa0729502020-09-06 10:35:33 -06004297 def testEnvironment(self):
4298 """Test adding a U-Boot environment"""
4299 data = self._DoReadFile('174_env.dts')
4300 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4301 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4302 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4303 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4304 env)
4305
4306 def testEnvironmentNoSize(self):
4307 """Test that a missing 'size' property is detected"""
4308 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004309 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004310 self.assertIn("'u-boot-env' entry must have a size property",
4311 str(e.exception))
4312
4313 def testEnvironmentTooSmall(self):
4314 """Test handling of an environment that does not fit"""
4315 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004316 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004317
4318 # checksum, start byte, environment with \0 terminator, final \0
4319 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4320 short = need - 0x8
4321 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4322 str(e.exception))
4323
Simon Glassd1fdf752020-10-26 17:40:01 -06004324 def testSkipAtStart(self):
4325 """Test handling of skip-at-start section"""
4326 data = self._DoReadFile('177_skip_at_start.dts')
4327 self.assertEqual(U_BOOT_DATA, data)
4328
4329 image = control.images['image']
4330 entries = image.GetEntries()
4331 section = entries['section']
4332 self.assertEqual(0, section.offset)
4333 self.assertEqual(len(U_BOOT_DATA), section.size)
4334 self.assertEqual(U_BOOT_DATA, section.GetData())
4335
4336 entry = section.GetEntries()['u-boot']
4337 self.assertEqual(16, entry.offset)
4338 self.assertEqual(len(U_BOOT_DATA), entry.size)
4339 self.assertEqual(U_BOOT_DATA, entry.data)
4340
4341 def testSkipAtStartPad(self):
4342 """Test handling of skip-at-start section with padded entry"""
4343 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004344 before = tools.get_bytes(0, 8)
4345 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004346 all = before + U_BOOT_DATA + after
4347 self.assertEqual(all, data)
4348
4349 image = control.images['image']
4350 entries = image.GetEntries()
4351 section = entries['section']
4352 self.assertEqual(0, section.offset)
4353 self.assertEqual(len(all), section.size)
4354 self.assertEqual(all, section.GetData())
4355
4356 entry = section.GetEntries()['u-boot']
4357 self.assertEqual(16, entry.offset)
4358 self.assertEqual(len(all), entry.size)
4359 self.assertEqual(U_BOOT_DATA, entry.data)
4360
4361 def testSkipAtStartSectionPad(self):
4362 """Test handling of skip-at-start section with padding"""
4363 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004364 before = tools.get_bytes(0, 8)
4365 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004366 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004367 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004368
4369 image = control.images['image']
4370 entries = image.GetEntries()
4371 section = entries['section']
4372 self.assertEqual(0, section.offset)
4373 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004374 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004375 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004376
4377 entry = section.GetEntries()['u-boot']
4378 self.assertEqual(16, entry.offset)
4379 self.assertEqual(len(U_BOOT_DATA), entry.size)
4380 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004381
Simon Glassbb395742020-10-26 17:40:14 -06004382 def testSectionPad(self):
4383 """Testing padding with sections"""
4384 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004385 expected = (tools.get_bytes(ord('&'), 3) +
4386 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004387 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004388 tools.get_bytes(ord('!'), 1) +
4389 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004390 self.assertEqual(expected, data)
4391
4392 def testSectionAlign(self):
4393 """Testing alignment with sections"""
4394 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4395 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004396 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004397 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004398 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004399 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004400 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4401 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004402 self.assertEqual(expected, data)
4403
Simon Glassd92c8362020-10-26 17:40:25 -06004404 def testCompressImage(self):
4405 """Test compression of the entire image"""
4406 self._CheckLz4()
4407 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4408 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4409 dtb = fdt.Fdt(out_dtb_fname)
4410 dtb.Scan()
4411 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4412 'uncomp-size'])
4413 orig = self._decompress(data)
4414 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4415
4416 # Do a sanity check on various fields
4417 image = control.images['image']
4418 entries = image.GetEntries()
4419 self.assertEqual(2, len(entries))
4420
4421 entry = entries['blob']
4422 self.assertEqual(COMPRESS_DATA, entry.data)
4423 self.assertEqual(len(COMPRESS_DATA), entry.size)
4424
4425 entry = entries['u-boot']
4426 self.assertEqual(U_BOOT_DATA, entry.data)
4427 self.assertEqual(len(U_BOOT_DATA), entry.size)
4428
4429 self.assertEqual(len(data), image.size)
4430 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4431 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4432 orig = self._decompress(image.data)
4433 self.assertEqual(orig, image.uncomp_data)
4434
4435 expected = {
4436 'blob:offset': 0,
4437 'blob:size': len(COMPRESS_DATA),
4438 'u-boot:offset': len(COMPRESS_DATA),
4439 'u-boot:size': len(U_BOOT_DATA),
4440 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4441 'offset': 0,
4442 'image-pos': 0,
4443 'size': len(data),
4444 }
4445 self.assertEqual(expected, props)
4446
4447 def testCompressImageLess(self):
4448 """Test compression where compression reduces the image size"""
4449 self._CheckLz4()
4450 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4451 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4452 dtb = fdt.Fdt(out_dtb_fname)
4453 dtb.Scan()
4454 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4455 'uncomp-size'])
4456 orig = self._decompress(data)
4457
4458 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4459
4460 # Do a sanity check on various fields
4461 image = control.images['image']
4462 entries = image.GetEntries()
4463 self.assertEqual(2, len(entries))
4464
4465 entry = entries['blob']
4466 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4467 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4468
4469 entry = entries['u-boot']
4470 self.assertEqual(U_BOOT_DATA, entry.data)
4471 self.assertEqual(len(U_BOOT_DATA), entry.size)
4472
4473 self.assertEqual(len(data), image.size)
4474 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4475 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4476 image.uncomp_size)
4477 orig = self._decompress(image.data)
4478 self.assertEqual(orig, image.uncomp_data)
4479
4480 expected = {
4481 'blob:offset': 0,
4482 'blob:size': len(COMPRESS_DATA_BIG),
4483 'u-boot:offset': len(COMPRESS_DATA_BIG),
4484 'u-boot:size': len(U_BOOT_DATA),
4485 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4486 'offset': 0,
4487 'image-pos': 0,
4488 'size': len(data),
4489 }
4490 self.assertEqual(expected, props)
4491
4492 def testCompressSectionSize(self):
4493 """Test compression of a section with a fixed size"""
4494 self._CheckLz4()
4495 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4496 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4497 dtb = fdt.Fdt(out_dtb_fname)
4498 dtb.Scan()
4499 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4500 'uncomp-size'])
4501 orig = self._decompress(data)
4502 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4503 expected = {
4504 'section/blob:offset': 0,
4505 'section/blob:size': len(COMPRESS_DATA),
4506 'section/u-boot:offset': len(COMPRESS_DATA),
4507 'section/u-boot:size': len(U_BOOT_DATA),
4508 'section:offset': 0,
4509 'section:image-pos': 0,
4510 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4511 'section:size': 0x30,
4512 'offset': 0,
4513 'image-pos': 0,
4514 'size': 0x30,
4515 }
4516 self.assertEqual(expected, props)
4517
4518 def testCompressSection(self):
4519 """Test compression of a section with no fixed size"""
4520 self._CheckLz4()
4521 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4522 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4523 dtb = fdt.Fdt(out_dtb_fname)
4524 dtb.Scan()
4525 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4526 'uncomp-size'])
4527 orig = self._decompress(data)
4528 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4529 expected = {
4530 'section/blob:offset': 0,
4531 'section/blob:size': len(COMPRESS_DATA),
4532 'section/u-boot:offset': len(COMPRESS_DATA),
4533 'section/u-boot:size': len(U_BOOT_DATA),
4534 'section:offset': 0,
4535 'section:image-pos': 0,
4536 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4537 'section:size': len(data),
4538 'offset': 0,
4539 'image-pos': 0,
4540 'size': len(data),
4541 }
4542 self.assertEqual(expected, props)
4543
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004544 def testLz4Missing(self):
4545 """Test that binman still produces an image if lz4 is missing"""
4546 with test_util.capture_sys_output() as (_, stderr):
4547 self._DoTestFile('185_compress_section.dts',
4548 force_missing_bintools='lz4')
4549 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004550 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004551
Simon Glassd92c8362020-10-26 17:40:25 -06004552 def testCompressExtra(self):
4553 """Test compression of a section with no fixed size"""
4554 self._CheckLz4()
4555 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4556 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4557 dtb = fdt.Fdt(out_dtb_fname)
4558 dtb.Scan()
4559 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4560 'uncomp-size'])
4561
4562 base = data[len(U_BOOT_DATA):]
4563 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4564 rest = base[len(U_BOOT_DATA):]
4565
4566 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004567 bintool = self.comp_bintools['lz4']
4568 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004569 data1 = rest[:len(expect1)]
4570 section1 = self._decompress(data1)
4571 self.assertEquals(expect1, data1)
Simon Glassd92c8362020-10-26 17:40:25 -06004572 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4573 rest1 = rest[len(expect1):]
4574
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004575 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004576 data2 = rest1[:len(expect2)]
4577 section2 = self._decompress(data2)
4578 self.assertEquals(expect2, data2)
Simon Glassd92c8362020-10-26 17:40:25 -06004579 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4580 rest2 = rest1[len(expect2):]
4581
4582 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4583 len(expect2) + len(U_BOOT_DATA))
4584 #self.assertEquals(expect_size, len(data))
4585
4586 #self.assertEquals(U_BOOT_DATA, rest2)
4587
4588 self.maxDiff = None
4589 expected = {
4590 'u-boot:offset': 0,
4591 'u-boot:image-pos': 0,
4592 'u-boot:size': len(U_BOOT_DATA),
4593
4594 'base:offset': len(U_BOOT_DATA),
4595 'base:image-pos': len(U_BOOT_DATA),
4596 'base:size': len(data) - len(U_BOOT_DATA),
4597 'base/u-boot:offset': 0,
4598 'base/u-boot:image-pos': len(U_BOOT_DATA),
4599 'base/u-boot:size': len(U_BOOT_DATA),
4600 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4601 len(expect2),
4602 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4603 len(expect2),
4604 'base/u-boot2:size': len(U_BOOT_DATA),
4605
4606 'base/section:offset': len(U_BOOT_DATA),
4607 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4608 'base/section:size': len(expect1),
4609 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4610 'base/section/blob:offset': 0,
4611 'base/section/blob:size': len(COMPRESS_DATA),
4612 'base/section/u-boot:offset': len(COMPRESS_DATA),
4613 'base/section/u-boot:size': len(U_BOOT_DATA),
4614
4615 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4616 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4617 'base/section2:size': len(expect2),
4618 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4619 'base/section2/blob:offset': 0,
4620 'base/section2/blob:size': len(COMPRESS_DATA),
4621 'base/section2/blob2:offset': len(COMPRESS_DATA),
4622 'base/section2/blob2:size': len(COMPRESS_DATA),
4623
4624 'offset': 0,
4625 'image-pos': 0,
4626 'size': len(data),
4627 }
4628 self.assertEqual(expected, props)
4629
Simon Glassecbe4732021-01-06 21:35:15 -07004630 def testSymbolsSubsection(self):
4631 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004632 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004633
Simon Glass3fb25402021-01-06 21:35:16 -07004634 def testReadImageEntryArg(self):
4635 """Test reading an image that would need an entry arg to generate"""
4636 entry_args = {
4637 'cros-ec-rw-path': 'ecrw.bin',
4638 }
4639 data = self.data = self._DoReadFileDtb(
4640 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4641 entry_args=entry_args)
4642
Simon Glass80025522022-01-29 14:14:04 -07004643 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004644 orig_image = control.images['image']
4645
4646 # This should not generate an error about the missing 'cros-ec-rw-path'
4647 # since we are reading the image from a file. Compare with
4648 # testEntryArgsRequired()
4649 image = Image.FromFile(image_fname)
4650 self.assertEqual(orig_image.GetEntries().keys(),
4651 image.GetEntries().keys())
4652
Simon Glassa2af7302021-01-06 21:35:18 -07004653 def testFilesAlign(self):
4654 """Test alignment with files"""
4655 data = self._DoReadFile('190_files_align.dts')
4656
4657 # The first string is 15 bytes so will align to 16
4658 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4659 self.assertEqual(expect, data)
4660
Simon Glassdb84b562021-01-06 21:35:19 -07004661 def testReadImageSkip(self):
4662 """Test reading an image and accessing its FDT map"""
4663 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004664 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004665 orig_image = control.images['image']
4666 image = Image.FromFile(image_fname)
4667 self.assertEqual(orig_image.GetEntries().keys(),
4668 image.GetEntries().keys())
4669
4670 orig_entry = orig_image.GetEntries()['fdtmap']
4671 entry = image.GetEntries()['fdtmap']
4672 self.assertEqual(orig_entry.offset, entry.offset)
4673 self.assertEqual(orig_entry.size, entry.size)
4674 self.assertEqual(16, entry.image_pos)
4675
4676 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4677
4678 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4679
Simon Glassc98de972021-03-18 20:24:57 +13004680 def testTplNoDtb(self):
4681 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004682 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004683 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4684 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4685 data[:len(U_BOOT_TPL_NODTB_DATA)])
4686
Simon Glass63f41d42021-03-18 20:24:58 +13004687 def testTplBssPad(self):
4688 """Test that we can pad TPL's BSS with zeros"""
4689 # ELF file with a '__bss_size' symbol
4690 self._SetupTplElf()
4691 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004692 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004693 data)
4694
4695 def testTplBssPadMissing(self):
4696 """Test that a missing symbol is detected"""
4697 self._SetupTplElf('u_boot_ucode_ptr')
4698 with self.assertRaises(ValueError) as e:
4699 self._DoReadFile('193_tpl_bss_pad.dts')
4700 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4701 str(e.exception))
4702
Simon Glass718b5292021-03-18 20:25:07 +13004703 def checkDtbSizes(self, data, pad_len, start):
4704 """Check the size arguments in a dtb embedded in an image
4705
4706 Args:
4707 data: The image data
4708 pad_len: Length of the pad section in the image, in bytes
4709 start: Start offset of the devicetree to examine, within the image
4710
4711 Returns:
4712 Size of the devicetree in bytes
4713 """
4714 dtb_data = data[start:]
4715 dtb = fdt.Fdt.FromData(dtb_data)
4716 fdt_size = dtb.GetFdtObj().totalsize()
4717 dtb.Scan()
4718 props = self._GetPropTree(dtb, 'size')
4719 self.assertEqual({
4720 'size': len(data),
4721 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4722 'u-boot-spl/u-boot-spl-dtb:size': 801,
4723 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4724 'u-boot-spl:size': 860,
4725 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4726 'u-boot/u-boot-dtb:size': 781,
4727 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4728 'u-boot:size': 827,
4729 }, props)
4730 return fdt_size
4731
4732 def testExpanded(self):
4733 """Test that an expanded entry type is selected when needed"""
4734 self._SetupSplElf()
4735 self._SetupTplElf()
4736
4737 # SPL has a devicetree, TPL does not
4738 entry_args = {
4739 'spl-dtb': '1',
4740 'spl-bss-pad': 'y',
4741 'tpl-dtb': '',
4742 }
4743 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4744 entry_args=entry_args)
4745 image = control.images['image']
4746 entries = image.GetEntries()
4747 self.assertEqual(3, len(entries))
4748
4749 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4750 self.assertIn('u-boot', entries)
4751 entry = entries['u-boot']
4752 self.assertEqual('u-boot-expanded', entry.etype)
4753 subent = entry.GetEntries()
4754 self.assertEqual(2, len(subent))
4755 self.assertIn('u-boot-nodtb', subent)
4756 self.assertIn('u-boot-dtb', subent)
4757
4758 # Second, u-boot-spl, which should be expanded into three parts
4759 self.assertIn('u-boot-spl', entries)
4760 entry = entries['u-boot-spl']
4761 self.assertEqual('u-boot-spl-expanded', entry.etype)
4762 subent = entry.GetEntries()
4763 self.assertEqual(3, len(subent))
4764 self.assertIn('u-boot-spl-nodtb', subent)
4765 self.assertIn('u-boot-spl-bss-pad', subent)
4766 self.assertIn('u-boot-spl-dtb', subent)
4767
4768 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4769 # devicetree
4770 self.assertIn('u-boot-tpl', entries)
4771 entry = entries['u-boot-tpl']
4772 self.assertEqual('u-boot-tpl', entry.etype)
4773 self.assertEqual(None, entry.GetEntries())
4774
4775 def testExpandedTpl(self):
4776 """Test that an expanded entry type is selected for TPL when needed"""
4777 self._SetupTplElf()
4778
4779 entry_args = {
4780 'tpl-bss-pad': 'y',
4781 'tpl-dtb': 'y',
4782 }
4783 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4784 entry_args=entry_args)
4785 image = control.images['image']
4786 entries = image.GetEntries()
4787 self.assertEqual(1, len(entries))
4788
4789 # We only have u-boot-tpl, which be expanded
4790 self.assertIn('u-boot-tpl', entries)
4791 entry = entries['u-boot-tpl']
4792 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4793 subent = entry.GetEntries()
4794 self.assertEqual(3, len(subent))
4795 self.assertIn('u-boot-tpl-nodtb', subent)
4796 self.assertIn('u-boot-tpl-bss-pad', subent)
4797 self.assertIn('u-boot-tpl-dtb', subent)
4798
4799 def testExpandedNoPad(self):
4800 """Test an expanded entry without BSS pad enabled"""
4801 self._SetupSplElf()
4802 self._SetupTplElf()
4803
4804 # SPL has a devicetree, TPL does not
4805 entry_args = {
4806 'spl-dtb': 'something',
4807 'spl-bss-pad': 'n',
4808 'tpl-dtb': '',
4809 }
4810 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4811 entry_args=entry_args)
4812 image = control.images['image']
4813 entries = image.GetEntries()
4814
4815 # Just check u-boot-spl, which should be expanded into two parts
4816 self.assertIn('u-boot-spl', entries)
4817 entry = entries['u-boot-spl']
4818 self.assertEqual('u-boot-spl-expanded', entry.etype)
4819 subent = entry.GetEntries()
4820 self.assertEqual(2, len(subent))
4821 self.assertIn('u-boot-spl-nodtb', subent)
4822 self.assertIn('u-boot-spl-dtb', subent)
4823
4824 def testExpandedTplNoPad(self):
4825 """Test that an expanded entry type with padding disabled in TPL"""
4826 self._SetupTplElf()
4827
4828 entry_args = {
4829 'tpl-bss-pad': '',
4830 'tpl-dtb': 'y',
4831 }
4832 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4833 entry_args=entry_args)
4834 image = control.images['image']
4835 entries = image.GetEntries()
4836 self.assertEqual(1, len(entries))
4837
4838 # We only have u-boot-tpl, which be expanded
4839 self.assertIn('u-boot-tpl', entries)
4840 entry = entries['u-boot-tpl']
4841 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4842 subent = entry.GetEntries()
4843 self.assertEqual(2, len(subent))
4844 self.assertIn('u-boot-tpl-nodtb', subent)
4845 self.assertIn('u-boot-tpl-dtb', subent)
4846
4847 def testFdtInclude(self):
4848 """Test that an Fdt is update within all binaries"""
4849 self._SetupSplElf()
4850 self._SetupTplElf()
4851
4852 # SPL has a devicetree, TPL does not
4853 self.maxDiff = None
4854 entry_args = {
4855 'spl-dtb': '1',
4856 'spl-bss-pad': 'y',
4857 'tpl-dtb': '',
4858 }
4859 # Build the image. It includes two separate devicetree binaries, each
4860 # with their own contents, but all contain the binman definition.
4861 data = self._DoReadFileDtb(
4862 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4863 update_dtb=True, entry_args=entry_args)[0]
4864 pad_len = 10
4865
4866 # Check the U-Boot dtb
4867 start = len(U_BOOT_NODTB_DATA)
4868 fdt_size = self.checkDtbSizes(data, pad_len, start)
4869
4870 # Now check SPL
4871 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4872 fdt_size = self.checkDtbSizes(data, pad_len, start)
4873
4874 # TPL has no devicetree
4875 start += fdt_size + len(U_BOOT_TPL_DATA)
4876 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004877
Simon Glass7098b7f2021-03-21 18:24:30 +13004878 def testSymbolsExpanded(self):
4879 """Test binman can assign symbols in expanded entries"""
4880 entry_args = {
4881 'spl-dtb': '1',
4882 }
4883 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4884 U_BOOT_SPL_DTB_DATA, 0x38,
4885 entry_args=entry_args, use_expanded=True)
4886
Simon Glasse1915782021-03-21 18:24:31 +13004887 def testCollection(self):
4888 """Test a collection"""
4889 data = self._DoReadFile('198_collection.dts')
4890 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004891 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4892 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004893 data)
4894
Simon Glass27a7f772021-03-21 18:24:32 +13004895 def testCollectionSection(self):
4896 """Test a collection where a section must be built first"""
4897 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004898 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004899 # building the contents, producing an error is anything is still
4900 # missing.
4901 data = self._DoReadFile('199_collection_section.dts')
4902 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004903 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4904 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004905 data)
4906
Simon Glassf427c5f2021-03-21 18:24:33 +13004907 def testAlignDefault(self):
4908 """Test that default alignment works on sections"""
4909 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004910 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004911 U_BOOT_DATA)
4912 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004913 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004914 # No alignment within the nested section
4915 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4916 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004917 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004918 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004919
Bin Mengc0b15742021-05-10 20:23:33 +08004920 def testPackOpenSBI(self):
4921 """Test that an image with an OpenSBI binary can be created"""
4922 data = self._DoReadFile('201_opensbi.dts')
4923 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4924
Simon Glass76f496d2021-07-06 10:36:37 -06004925 def testSectionsSingleThread(self):
4926 """Test sections without multithreading"""
4927 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004928 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4929 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4930 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004931 self.assertEqual(expected, data)
4932
4933 def testThreadTimeout(self):
4934 """Test handling a thread that takes too long"""
4935 with self.assertRaises(ValueError) as e:
4936 self._DoTestFile('202_section_timeout.dts',
4937 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004938 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004939
Simon Glass748a1d42021-07-06 10:36:41 -06004940 def testTiming(self):
4941 """Test output of timing information"""
4942 data = self._DoReadFile('055_sections.dts')
4943 with test_util.capture_sys_output() as (stdout, stderr):
4944 state.TimingShow()
4945 self.assertIn('read:', stdout.getvalue())
4946 self.assertIn('compress:', stdout.getvalue())
4947
Simon Glassadfb8492021-11-03 21:09:18 -06004948 def testUpdateFdtInElf(self):
4949 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004950 if not elf.ELF_TOOLS:
4951 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004952 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4953 outfile = os.path.join(self._indir, 'u-boot.out')
4954 begin_sym = 'dtb_embed_begin'
4955 end_sym = 'dtb_embed_end'
4956 retcode = self._DoTestFile(
4957 '060_fdt_update.dts', update_dtb=True,
4958 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4959 self.assertEqual(0, retcode)
4960
4961 # Check that the output file does in fact contact a dtb with the binman
4962 # definition in the correct place
4963 syms = elf.GetSymbolFileOffset(infile,
4964 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004965 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004966 dtb_data = data[syms['dtb_embed_begin'].offset:
4967 syms['dtb_embed_end'].offset]
4968
4969 dtb = fdt.Fdt.FromData(dtb_data)
4970 dtb.Scan()
4971 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4972 self.assertEqual({
4973 'image-pos': 0,
4974 'offset': 0,
4975 '_testing:offset': 32,
4976 '_testing:size': 2,
4977 '_testing:image-pos': 32,
4978 'section@0/u-boot:offset': 0,
4979 'section@0/u-boot:size': len(U_BOOT_DATA),
4980 'section@0/u-boot:image-pos': 0,
4981 'section@0:offset': 0,
4982 'section@0:size': 16,
4983 'section@0:image-pos': 0,
4984
4985 'section@1/u-boot:offset': 0,
4986 'section@1/u-boot:size': len(U_BOOT_DATA),
4987 'section@1/u-boot:image-pos': 16,
4988 'section@1:offset': 16,
4989 'section@1:size': 16,
4990 'section@1:image-pos': 16,
4991 'size': 40
4992 }, props)
4993
4994 def testUpdateFdtInElfInvalid(self):
4995 """Test that invalid args are detected with --update-fdt-in-elf"""
4996 with self.assertRaises(ValueError) as e:
4997 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4998 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4999 str(e.exception))
5000
5001 def testUpdateFdtInElfNoSyms(self):
5002 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005003 if not elf.ELF_TOOLS:
5004 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005005 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5006 outfile = ''
5007 begin_sym = 'wrong_begin'
5008 end_sym = 'wrong_end'
5009 with self.assertRaises(ValueError) as e:
5010 self._DoTestFile(
5011 '060_fdt_update.dts',
5012 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5013 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5014 str(e.exception))
5015
5016 def testUpdateFdtInElfTooSmall(self):
5017 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005018 if not elf.ELF_TOOLS:
5019 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005020 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5021 outfile = os.path.join(self._indir, 'u-boot.out')
5022 begin_sym = 'dtb_embed_begin'
5023 end_sym = 'dtb_embed_end'
5024 with self.assertRaises(ValueError) as e:
5025 self._DoTestFile(
5026 '060_fdt_update.dts', update_dtb=True,
5027 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5028 self.assertRegex(
5029 str(e.exception),
5030 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5031
Simon Glass88e04da2021-11-23 11:03:42 -07005032 def testVersion(self):
5033 """Test we can get the binman version"""
5034 version = '(unreleased)'
5035 self.assertEqual(version, state.GetVersion(self._indir))
5036
5037 with self.assertRaises(SystemExit):
5038 with test_util.capture_sys_output() as (_, stderr):
5039 self._DoBinman('-V')
5040 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5041
5042 # Try running the tool too, just to be safe
5043 result = self._RunBinman('-V')
5044 self.assertEqual('Binman %s\n' % version, result.stderr)
5045
5046 # Set up a version file to make sure that works
5047 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005048 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005049 binary=False)
5050 self.assertEqual(version, state.GetVersion(self._indir))
5051
Simon Glass637958f2021-11-23 21:09:50 -07005052 def testAltFormat(self):
5053 """Test that alternative formats can be used to extract"""
5054 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5055
5056 try:
5057 tmpdir, updated_fname = self._SetupImageInTmpdir()
5058 with test_util.capture_sys_output() as (stdout, _):
5059 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5060 self.assertEqual(
5061 '''Flag (-F) Entry type Description
5062fdt fdtmap Extract the devicetree blob from the fdtmap
5063''',
5064 stdout.getvalue())
5065
5066 dtb = os.path.join(tmpdir, 'fdt.dtb')
5067 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5068 dtb, 'fdtmap')
5069
5070 # Check that we can read it and it can be scanning, meaning it does
5071 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005072 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005073 dtb = fdt.Fdt.FromData(data)
5074 dtb.Scan()
5075
5076 # Now check u-boot which has no alt_format
5077 fname = os.path.join(tmpdir, 'fdt.dtb')
5078 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5079 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005080 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005081 self.assertEqual(U_BOOT_DATA, data)
5082
5083 finally:
5084 shutil.rmtree(tmpdir)
5085
Simon Glass0b00ae62021-11-23 21:09:52 -07005086 def testExtblobList(self):
5087 """Test an image with an external blob list"""
5088 data = self._DoReadFile('215_blob_ext_list.dts')
5089 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5090
5091 def testExtblobListMissing(self):
5092 """Test an image with a missing external blob"""
5093 with self.assertRaises(ValueError) as e:
5094 self._DoReadFile('216_blob_ext_list_missing.dts')
5095 self.assertIn("Filename 'missing-file' not found in input path",
5096 str(e.exception))
5097
5098 def testExtblobListMissingOk(self):
5099 """Test an image with an missing external blob that is allowed"""
5100 with test_util.capture_sys_output() as (stdout, stderr):
5101 self._DoTestFile('216_blob_ext_list_missing.dts',
5102 allow_missing=True)
5103 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005104 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005105
Simon Glass3efb2972021-11-23 21:08:59 -07005106 def testFip(self):
5107 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5108 data = self._DoReadFile('203_fip.dts')
5109 hdr, fents = fip_util.decode_fip(data)
5110 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5111 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5112 self.assertEqual(0x123, hdr.flags)
5113
5114 self.assertEqual(2, len(fents))
5115
5116 fent = fents[0]
5117 self.assertEqual(
5118 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5119 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5120 self.assertEqual('soc-fw', fent.fip_type)
5121 self.assertEqual(0x88, fent.offset)
5122 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5123 self.assertEqual(0x123456789abcdef, fent.flags)
5124 self.assertEqual(ATF_BL31_DATA, fent.data)
5125 self.assertEqual(True, fent.valid)
5126
5127 fent = fents[1]
5128 self.assertEqual(
5129 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5130 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5131 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5132 self.assertEqual(0x8c, fent.offset)
5133 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5134 self.assertEqual(0, fent.flags)
5135 self.assertEqual(ATF_BL2U_DATA, fent.data)
5136 self.assertEqual(True, fent.valid)
5137
5138 def testFipOther(self):
5139 """Basic FIP with something that isn't a external blob"""
5140 data = self._DoReadFile('204_fip_other.dts')
5141 hdr, fents = fip_util.decode_fip(data)
5142
5143 self.assertEqual(2, len(fents))
5144 fent = fents[1]
5145 self.assertEqual('rot-cert', fent.fip_type)
5146 self.assertEqual(b'aa', fent.data)
5147
Simon Glass3efb2972021-11-23 21:08:59 -07005148 def testFipNoType(self):
5149 """FIP with an entry of an unknown type"""
5150 with self.assertRaises(ValueError) as e:
5151 self._DoReadFile('205_fip_no_type.dts')
5152 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5153 str(e.exception))
5154
5155 def testFipUuid(self):
5156 """Basic FIP with a manual uuid"""
5157 data = self._DoReadFile('206_fip_uuid.dts')
5158 hdr, fents = fip_util.decode_fip(data)
5159
5160 self.assertEqual(2, len(fents))
5161 fent = fents[1]
5162 self.assertEqual(None, fent.fip_type)
5163 self.assertEqual(
5164 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5165 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5166 fent.uuid)
5167 self.assertEqual(U_BOOT_DATA, fent.data)
5168
5169 def testFipLs(self):
5170 """Test listing a FIP"""
5171 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5172 hdr, fents = fip_util.decode_fip(data)
5173
5174 try:
5175 tmpdir, updated_fname = self._SetupImageInTmpdir()
5176 with test_util.capture_sys_output() as (stdout, stderr):
5177 self._DoBinman('ls', '-i', updated_fname)
5178 finally:
5179 shutil.rmtree(tmpdir)
5180 lines = stdout.getvalue().splitlines()
5181 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005182'Name Image-pos Size Entry-type Offset Uncomp-size',
5183'--------------------------------------------------------------',
5184'image 0 2d3 section 0',
5185' atf-fip 0 90 atf-fip 0',
5186' soc-fw 88 4 blob-ext 88',
5187' u-boot 8c 4 u-boot 8c',
5188' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005189]
5190 self.assertEqual(expected, lines)
5191
5192 image = control.images['image']
5193 entries = image.GetEntries()
5194 fdtmap = entries['fdtmap']
5195
5196 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5197 magic = fdtmap_data[:8]
5198 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005199 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005200
5201 fdt_data = fdtmap_data[16:]
5202 dtb = fdt.Fdt.FromData(fdt_data)
5203 dtb.Scan()
5204 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5205 self.assertEqual({
5206 'atf-fip/soc-fw:image-pos': 136,
5207 'atf-fip/soc-fw:offset': 136,
5208 'atf-fip/soc-fw:size': 4,
5209 'atf-fip/u-boot:image-pos': 140,
5210 'atf-fip/u-boot:offset': 140,
5211 'atf-fip/u-boot:size': 4,
5212 'atf-fip:image-pos': 0,
5213 'atf-fip:offset': 0,
5214 'atf-fip:size': 144,
5215 'image-pos': 0,
5216 'offset': 0,
5217 'fdtmap:image-pos': fdtmap.image_pos,
5218 'fdtmap:offset': fdtmap.offset,
5219 'fdtmap:size': len(fdtmap_data),
5220 'size': len(data),
5221 }, props)
5222
5223 def testFipExtractOneEntry(self):
5224 """Test extracting a single entry fron an FIP"""
5225 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005226 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005227 fname = os.path.join(self._indir, 'output.extact')
5228 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005229 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005230 self.assertEqual(U_BOOT_DATA, data)
5231
5232 def testFipReplace(self):
5233 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005234 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005235 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005236 updated_fname = tools.get_output_filename('image-updated.bin')
5237 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005238 entry_name = 'atf-fip/u-boot'
5239 control.WriteEntry(updated_fname, entry_name, expected,
5240 allow_resize=True)
5241 actual = control.ReadEntry(updated_fname, entry_name)
5242 self.assertEqual(expected, actual)
5243
Simon Glass80025522022-01-29 14:14:04 -07005244 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005245 hdr, fents = fip_util.decode_fip(new_data)
5246
5247 self.assertEqual(2, len(fents))
5248
5249 # Check that the FIP entry is updated
5250 fent = fents[1]
5251 self.assertEqual(0x8c, fent.offset)
5252 self.assertEqual(len(expected), fent.size)
5253 self.assertEqual(0, fent.flags)
5254 self.assertEqual(expected, fent.data)
5255 self.assertEqual(True, fent.valid)
5256
5257 def testFipMissing(self):
5258 with test_util.capture_sys_output() as (stdout, stderr):
5259 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5260 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005261 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005262
5263 def testFipSize(self):
5264 """Test a FIP with a size property"""
5265 data = self._DoReadFile('210_fip_size.dts')
5266 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5267 hdr, fents = fip_util.decode_fip(data)
5268 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5269 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5270
5271 self.assertEqual(1, len(fents))
5272
5273 fent = fents[0]
5274 self.assertEqual('soc-fw', fent.fip_type)
5275 self.assertEqual(0x60, fent.offset)
5276 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5277 self.assertEqual(ATF_BL31_DATA, fent.data)
5278 self.assertEqual(True, fent.valid)
5279
5280 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005281 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005282
5283 def testFipBadAlign(self):
5284 """Test that an invalid alignment value in a FIP is detected"""
5285 with self.assertRaises(ValueError) as e:
5286 self._DoTestFile('211_fip_bad_align.dts')
5287 self.assertIn(
5288 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5289 str(e.exception))
5290
5291 def testFipCollection(self):
5292 """Test using a FIP in a collection"""
5293 data = self._DoReadFile('212_fip_collection.dts')
5294 entry1 = control.images['image'].GetEntries()['collection']
5295 data1 = data[:entry1.size]
5296 hdr1, fents2 = fip_util.decode_fip(data1)
5297
5298 entry2 = control.images['image'].GetEntries()['atf-fip']
5299 data2 = data[entry2.offset:entry2.offset + entry2.size]
5300 hdr1, fents2 = fip_util.decode_fip(data2)
5301
5302 # The 'collection' entry should have U-Boot included at the end
5303 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5304 self.assertEqual(data1, data2 + U_BOOT_DATA)
5305 self.assertEqual(U_BOOT_DATA, data1[-4:])
5306
5307 # There should be a U-Boot after the final FIP
5308 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005309
Simon Glassccae6862022-01-12 13:10:35 -07005310 def testFakeBlob(self):
5311 """Test handling of faking an external blob"""
5312 with test_util.capture_sys_output() as (stdout, stderr):
5313 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5314 allow_fake_blobs=True)
5315 err = stderr.getvalue()
5316 self.assertRegex(
5317 err,
5318 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005319
Simon Glassceb5f912022-01-09 20:13:46 -07005320 def testExtblobListFaked(self):
5321 """Test an extblob with missing external blob that are faked"""
5322 with test_util.capture_sys_output() as (stdout, stderr):
5323 self._DoTestFile('216_blob_ext_list_missing.dts',
5324 allow_fake_blobs=True)
5325 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005326 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005327
Simon Glass162017b2022-01-09 20:13:57 -07005328 def testListBintools(self):
5329 args = ['tool', '--list']
5330 with test_util.capture_sys_output() as (stdout, _):
5331 self._DoBinman(*args)
5332 out = stdout.getvalue().splitlines()
5333 self.assertTrue(len(out) >= 2)
5334
5335 def testFetchBintools(self):
5336 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005337 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005338 raise urllib.error.URLError('my error')
5339
5340 args = ['tool']
5341 with self.assertRaises(ValueError) as e:
5342 self._DoBinman(*args)
5343 self.assertIn("Invalid arguments to 'tool' subcommand",
5344 str(e.exception))
5345
5346 args = ['tool', '--fetch']
5347 with self.assertRaises(ValueError) as e:
5348 self._DoBinman(*args)
5349 self.assertIn('Please specify bintools to fetch', str(e.exception))
5350
5351 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005352 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005353 side_effect=fail_download):
5354 with test_util.capture_sys_output() as (stdout, _):
5355 self._DoBinman(*args)
5356 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5357
Simon Glass620c4462022-01-09 20:14:11 -07005358 def testBintoolDocs(self):
5359 """Test for creation of bintool documentation"""
5360 with test_util.capture_sys_output() as (stdout, stderr):
5361 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5362 self.assertTrue(len(stdout.getvalue()) > 0)
5363
5364 def testBintoolDocsMissing(self):
5365 """Test handling of missing bintool documentation"""
5366 with self.assertRaises(ValueError) as e:
5367 with test_util.capture_sys_output() as (stdout, stderr):
5368 control.write_bintool_docs(
5369 control.bintool.Bintool.get_tool_list(), 'mkimage')
5370 self.assertIn('Documentation is missing for modules: mkimage',
5371 str(e.exception))
5372
Jan Kiszka58c407f2022-01-28 20:37:53 +01005373 def testListWithGenNode(self):
5374 """Check handling of an FDT map when the section cannot be found"""
5375 entry_args = {
5376 'of-list': 'test-fdt1 test-fdt2',
5377 }
5378 data = self._DoReadFileDtb(
5379 '219_fit_gennode.dts',
5380 entry_args=entry_args,
5381 use_real_dtb=True,
5382 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5383
5384 try:
5385 tmpdir, updated_fname = self._SetupImageInTmpdir()
5386 with test_util.capture_sys_output() as (stdout, stderr):
5387 self._RunBinman('ls', '-i', updated_fname)
5388 finally:
5389 shutil.rmtree(tmpdir)
5390
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005391 def testFitSubentryUsesBintool(self):
5392 """Test that binman FIT subentries can use bintools"""
5393 command.test_result = self._HandleGbbCommand
5394 entry_args = {
5395 'keydir': 'devkeys',
5396 'bmpblk': 'bmpblk.bin',
5397 }
5398 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5399 entry_args=entry_args)
5400
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005401 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5402 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005403 self.assertIn(expected, data)
5404
5405 def testFitSubentryMissingBintool(self):
5406 """Test that binman reports missing bintools for FIT subentries"""
5407 entry_args = {
5408 'keydir': 'devkeys',
5409 }
5410 with test_util.capture_sys_output() as (_, stderr):
5411 self._DoTestFile('220_fit_subentry_bintool.dts',
5412 force_missing_bintools='futility', entry_args=entry_args)
5413 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005414 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005415
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005416 def testFitSubentryHashSubnode(self):
5417 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005418 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005419 data, _, _, out_dtb_name = self._DoReadFileDtb(
5420 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5421
5422 mkimage_dtb = fdt.Fdt.FromData(data)
5423 mkimage_dtb.Scan()
5424 binman_dtb = fdt.Fdt(out_dtb_name)
5425 binman_dtb.Scan()
5426
5427 # Check that binman didn't add hash values
5428 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5429 self.assertNotIn('value', fnode.props)
5430
5431 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5432 self.assertNotIn('value', fnode.props)
5433
5434 # Check that mkimage added hash values
5435 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5436 self.assertIn('value', fnode.props)
5437
5438 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5439 self.assertIn('value', fnode.props)
5440
Roger Quadros5cdcea02022-02-19 20:50:04 +02005441 def testPackTeeOs(self):
5442 """Test that an image with an TEE binary can be created"""
5443 data = self._DoReadFile('222_tee_os.dts')
5444 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5445
Simon Glass912339f2022-02-08 11:50:03 -07005446 def testFitFdtOper(self):
5447 """Check handling of a specified FIT operation"""
5448 entry_args = {
5449 'of-list': 'test-fdt1 test-fdt2',
5450 'default-dt': 'test-fdt2',
5451 }
5452 self._DoReadFileDtb(
5453 '223_fit_fdt_oper.dts',
5454 entry_args=entry_args,
5455 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5456
5457 def testFitFdtBadOper(self):
5458 """Check handling of an FDT map when the section cannot be found"""
5459 with self.assertRaises(ValueError) as exc:
5460 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005461 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005462 str(exc.exception))
5463
Simon Glassdd156a42022-03-05 20:18:59 -07005464 def test_uses_expand_size(self):
5465 """Test that the 'expand-size' property cannot be used anymore"""
5466 with self.assertRaises(ValueError) as e:
5467 data = self._DoReadFile('225_expand_size_bad.dts')
5468 self.assertIn(
5469 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5470 str(e.exception))
5471
Simon Glass5f423422022-03-05 20:19:12 -07005472 def testFitSplitElf(self):
5473 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005474 if not elf.ELF_TOOLS:
5475 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005476 entry_args = {
5477 'of-list': 'test-fdt1 test-fdt2',
5478 'default-dt': 'test-fdt2',
5479 'atf-bl31-path': 'bl31.elf',
5480 'tee-os-path': 'tee.elf',
5481 }
5482 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5483 data = self._DoReadFileDtb(
5484 '226_fit_split_elf.dts',
5485 entry_args=entry_args,
5486 extra_indirs=[test_subdir])[0]
5487
5488 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5489 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5490
5491 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5492 'data', 'load'}
5493 dtb = fdt.Fdt.FromData(fit_data)
5494 dtb.Scan()
5495
5496 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5497 segments, entry = elf.read_loadable_segments(elf_data)
5498
5499 # We assume there are two segments
5500 self.assertEquals(2, len(segments))
5501
5502 atf1 = dtb.GetNode('/images/atf-1')
5503 _, start, data = segments[0]
5504 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5505 self.assertEqual(entry,
5506 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5507 self.assertEqual(start,
5508 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5509 self.assertEqual(data, atf1.props['data'].bytes)
5510
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005511 hash_node = atf1.FindNode('hash')
5512 self.assertIsNotNone(hash_node)
5513 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5514
Simon Glass5f423422022-03-05 20:19:12 -07005515 atf2 = dtb.GetNode('/images/atf-2')
5516 self.assertEqual(base_keys, atf2.props.keys())
5517 _, start, data = segments[1]
5518 self.assertEqual(start,
5519 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5520 self.assertEqual(data, atf2.props['data'].bytes)
5521
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005522 hash_node = atf2.FindNode('hash')
5523 self.assertIsNotNone(hash_node)
5524 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5525
5526 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5527 self.assertIsNotNone(hash_node)
5528 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5529
Simon Glass5f423422022-03-05 20:19:12 -07005530 conf = dtb.GetNode('/configurations')
5531 self.assertEqual({'default'}, conf.props.keys())
5532
5533 for subnode in conf.subnodes:
5534 self.assertEqual({'description', 'fdt', 'loadables'},
5535 subnode.props.keys())
5536 self.assertEqual(
5537 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5538 fdt_util.GetStringList(subnode, 'loadables'))
5539
5540 def _check_bad_fit(self, dts):
5541 """Check a bad FIT
5542
5543 This runs with the given dts and returns the assertion raised
5544
5545 Args:
5546 dts (str): dts filename to use
5547
5548 Returns:
5549 str: Assertion string raised
5550 """
5551 entry_args = {
5552 'of-list': 'test-fdt1 test-fdt2',
5553 'default-dt': 'test-fdt2',
5554 'atf-bl31-path': 'bl31.elf',
5555 'tee-os-path': 'tee.elf',
5556 }
5557 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5558 with self.assertRaises(ValueError) as exc:
5559 self._DoReadFileDtb(dts, entry_args=entry_args,
5560 extra_indirs=[test_subdir])[0]
5561 return str(exc.exception)
5562
5563 def testFitSplitElfBadElf(self):
5564 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005565 if not elf.ELF_TOOLS:
5566 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005567 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5568 entry_args = {
5569 'of-list': 'test-fdt1 test-fdt2',
5570 'default-dt': 'test-fdt2',
5571 'atf-bl31-path': 'bad.elf',
5572 'tee-os-path': 'tee.elf',
5573 }
5574 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5575 with self.assertRaises(ValueError) as exc:
5576 self._DoReadFileDtb(
5577 '226_fit_split_elf.dts',
5578 entry_args=entry_args,
5579 extra_indirs=[test_subdir])[0]
5580 self.assertIn(
5581 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5582 str(exc.exception))
5583
Simon Glass5f423422022-03-05 20:19:12 -07005584 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005585 """Test an split-elf FIT with a missing ELF file
5586
5587 Args:
5588 kwargs (dict of str): Arguments to pass to _DoTestFile()
5589
5590 Returns:
5591 tuple:
5592 str: stdout result
5593 str: stderr result
5594 """
Simon Glass5f423422022-03-05 20:19:12 -07005595 entry_args = {
5596 'of-list': 'test-fdt1 test-fdt2',
5597 'default-dt': 'test-fdt2',
5598 'atf-bl31-path': 'bl31.elf',
5599 'tee-os-path': 'missing.elf',
5600 }
5601 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5602 with test_util.capture_sys_output() as (stdout, stderr):
5603 self._DoTestFile(
5604 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005605 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5606 out = stdout.getvalue()
5607 err = stderr.getvalue()
5608 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005609
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005610 def testFitSplitElfBadDirective(self):
5611 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5612 if not elf.ELF_TOOLS:
5613 self.skipTest('Python elftools not available')
5614 err = self._check_bad_fit('227_fit_bad_dir.dts')
5615 self.assertIn(
5616 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5617 err)
5618
5619 def testFitSplitElfBadDirectiveConfig(self):
5620 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5621 if not elf.ELF_TOOLS:
5622 self.skipTest('Python elftools not available')
5623 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5624 self.assertEqual(
5625 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5626 err)
5627
5628
Simon Glass5f423422022-03-05 20:19:12 -07005629 def testFitSplitElfMissing(self):
5630 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005631 if not elf.ELF_TOOLS:
5632 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005633 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005634 self.assertRegex(
5635 err,
5636 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005637 self.assertNotRegex(out, '.*Faked blob.*')
5638 fname = tools.get_output_filename('binman-fake/missing.elf')
5639 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005640
5641 def testFitSplitElfFaked(self):
5642 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005643 if not elf.ELF_TOOLS:
5644 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005645 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005646 self.assertRegex(
5647 err,
5648 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005649 self.assertRegex(
5650 out,
5651 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5652 fname = tools.get_output_filename('binman-fake/missing.elf')
5653 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005654
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005655 def testMkimageMissingBlob(self):
5656 """Test using mkimage to build an image"""
5657 with test_util.capture_sys_output() as (stdout, stderr):
5658 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5659 allow_fake_blobs=True)
5660 err = stderr.getvalue()
5661 self.assertRegex(
5662 err,
5663 "Image '.*' has faked external blobs and is non-functional: .*")
5664
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005665 def testPreLoad(self):
5666 """Test an image with a pre-load header"""
5667 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005668 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005669 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005670 data = self._DoReadFileDtb(
5671 '230_pre_load.dts', entry_args=entry_args,
5672 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005673 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5674 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5675 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Simon Glasse2dfb962023-07-24 09:19:57 -06005676
5677 def testPreLoadNoKey(self):
5678 """Test an image with a pre-load heade0r with missing key"""
5679 with self.assertRaises(FileNotFoundError) as exc:
5680 self._DoReadFile('230_pre_load.dts')
5681 self.assertIn("No such file or directory: 'dev.key'",
5682 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005683
5684 def testPreLoadPkcs(self):
5685 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005686 entry_args = {
5687 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5688 }
5689 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5690 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005691 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5692 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5693 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5694
5695 def testPreLoadPss(self):
5696 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005697 entry_args = {
5698 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5699 }
5700 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5701 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005702 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5703 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5704 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5705
5706 def testPreLoadInvalidPadding(self):
5707 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005708 entry_args = {
5709 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5710 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005711 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005712 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5713 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005714
5715 def testPreLoadInvalidSha(self):
5716 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005717 entry_args = {
5718 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5719 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005720 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005721 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5722 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005723
5724 def testPreLoadInvalidAlgo(self):
5725 """Test an image with a pre-load header with an invalid algo"""
5726 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005727 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005728
5729 def testPreLoadInvalidKey(self):
5730 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005731 entry_args = {
5732 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5733 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005734 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005735 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5736 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005737
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005738 def _CheckSafeUniqueNames(self, *images):
5739 """Check all entries of given images for unsafe unique names"""
5740 for image in images:
5741 entries = {}
5742 image._CollectEntries(entries, {}, image)
5743 for entry in entries.values():
5744 uniq = entry.GetUniqueName()
5745
5746 # Used as part of a filename, so must not be absolute paths.
5747 self.assertFalse(os.path.isabs(uniq))
5748
5749 def testSafeUniqueNames(self):
5750 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005751 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005752
5753 orig_image = control.images['image']
5754 image_fname = tools.get_output_filename('image.bin')
5755 image = Image.FromFile(image_fname)
5756
5757 self._CheckSafeUniqueNames(orig_image, image)
5758
5759 def testSafeUniqueNamesMulti(self):
5760 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005761 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005762
5763 orig_image = control.images['image']
5764 image_fname = tools.get_output_filename('image.bin')
5765 image = Image.FromFile(image_fname)
5766
5767 self._CheckSafeUniqueNames(orig_image, image)
5768
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005769 def testReplaceCmdWithBintool(self):
5770 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005771 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005772 expected = U_BOOT_DATA + b'aa'
5773 self.assertEqual(expected, data[:len(expected)])
5774
5775 try:
5776 tmpdir, updated_fname = self._SetupImageInTmpdir()
5777 fname = os.path.join(tmpdir, 'update-testing.bin')
5778 tools.write_file(fname, b'zz')
5779 self._DoBinman('replace', '-i', updated_fname,
5780 '_testing', '-f', fname)
5781
5782 data = tools.read_file(updated_fname)
5783 expected = U_BOOT_DATA + b'zz'
5784 self.assertEqual(expected, data[:len(expected)])
5785 finally:
5786 shutil.rmtree(tmpdir)
5787
5788 def testReplaceCmdOtherWithBintool(self):
5789 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005790 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005791 expected = U_BOOT_DATA + b'aa'
5792 self.assertEqual(expected, data[:len(expected)])
5793
5794 try:
5795 tmpdir, updated_fname = self._SetupImageInTmpdir()
5796 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5797 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5798 self._DoBinman('replace', '-i', updated_fname,
5799 'u-boot', '-f', fname)
5800
5801 data = tools.read_file(updated_fname)
5802 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5803 self.assertEqual(expected, data[:len(expected)])
5804 finally:
5805 shutil.rmtree(tmpdir)
5806
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005807 def testReplaceResizeNoRepackSameSize(self):
5808 """Test replacing entries with same-size data without repacking"""
5809 expected = b'x' * len(U_BOOT_DATA)
5810 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5811 self.assertEqual(expected, data)
5812
5813 path, fdtmap = state.GetFdtContents('fdtmap')
5814 self.assertIsNotNone(path)
5815 self.assertEqual(expected_fdtmap, fdtmap)
5816
5817 def testReplaceResizeNoRepackSmallerSize(self):
5818 """Test replacing entries with smaller-size data without repacking"""
5819 new_data = b'x'
5820 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5821 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5822 self.assertEqual(expected, data)
5823
5824 path, fdtmap = state.GetFdtContents('fdtmap')
5825 self.assertIsNotNone(path)
5826 self.assertEqual(expected_fdtmap, fdtmap)
5827
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005828 def testExtractFit(self):
5829 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005830 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005831 image_fname = tools.get_output_filename('image.bin')
5832
5833 fit_data = control.ReadEntry(image_fname, 'fit')
5834 fit = fdt.Fdt.FromData(fit_data)
5835 fit.Scan()
5836
5837 # Check subentry data inside the extracted fit
5838 for node_path, expected in [
5839 ('/images/kernel', U_BOOT_DATA),
5840 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5841 ('/images/scr-1', COMPRESS_DATA),
5842 ]:
5843 node = fit.GetNode(node_path)
5844 data = fit.GetProps(node)['data'].bytes
5845 self.assertEqual(expected, data)
5846
5847 def testExtractFitSubentries(self):
5848 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005849 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005850 image_fname = tools.get_output_filename('image.bin')
5851
5852 for entry_path, expected in [
5853 ('fit/kernel', U_BOOT_DATA),
5854 ('fit/kernel/u-boot', U_BOOT_DATA),
5855 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5856 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5857 ('fit/scr-1', COMPRESS_DATA),
5858 ('fit/scr-1/blob', COMPRESS_DATA),
5859 ]:
5860 data = control.ReadEntry(image_fname, entry_path)
5861 self.assertEqual(expected, data)
5862
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005863 def testReplaceFitSubentryLeafSameSize(self):
5864 """Test replacing a FIT leaf subentry with same-size data"""
5865 new_data = b'x' * len(U_BOOT_DATA)
5866 data, expected_fdtmap, _ = self._RunReplaceCmd(
5867 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005868 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005869 self.assertEqual(new_data, data)
5870
5871 path, fdtmap = state.GetFdtContents('fdtmap')
5872 self.assertIsNotNone(path)
5873 self.assertEqual(expected_fdtmap, fdtmap)
5874
5875 def testReplaceFitSubentryLeafBiggerSize(self):
5876 """Test replacing a FIT leaf subentry with bigger-size data"""
5877 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5878 data, expected_fdtmap, _ = self._RunReplaceCmd(
5879 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005880 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005881 self.assertEqual(new_data, data)
5882
5883 # Will be repacked, so fdtmap must change
5884 path, fdtmap = state.GetFdtContents('fdtmap')
5885 self.assertIsNotNone(path)
5886 self.assertNotEqual(expected_fdtmap, fdtmap)
5887
5888 def testReplaceFitSubentryLeafSmallerSize(self):
5889 """Test replacing a FIT leaf subentry with smaller-size data"""
5890 new_data = b'x'
5891 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5892 data, expected_fdtmap, _ = self._RunReplaceCmd(
5893 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005894 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005895 self.assertEqual(expected, data)
5896
5897 path, fdtmap = state.GetFdtContents('fdtmap')
5898 self.assertIsNotNone(path)
5899 self.assertEqual(expected_fdtmap, fdtmap)
5900
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005901 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005902 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005903 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005904 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5905 new_data, dts='241_replace_section_simple.dts')
5906 self.assertEqual(new_data, data)
5907
5908 entries = image.GetEntries()
5909 self.assertIn('section', entries)
5910 entry = entries['section']
5911 self.assertEqual(len(new_data), entry.size)
5912
5913 def testReplaceSectionLarger(self):
5914 """Test replacing a simple section with larger data"""
5915 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5916 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5917 new_data, dts='241_replace_section_simple.dts')
5918 self.assertEqual(new_data, data)
5919
5920 entries = image.GetEntries()
5921 self.assertIn('section', entries)
5922 entry = entries['section']
5923 self.assertEqual(len(new_data), entry.size)
5924 fentry = entries['fdtmap']
5925 self.assertEqual(entry.offset + entry.size, fentry.offset)
5926
5927 def testReplaceSectionSmaller(self):
5928 """Test replacing a simple section with smaller data"""
5929 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5930 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5931 new_data, dts='241_replace_section_simple.dts')
5932 self.assertEqual(new_data, data)
5933
5934 # The new size is the same as the old, just with a pad byte at the end
5935 entries = image.GetEntries()
5936 self.assertIn('section', entries)
5937 entry = entries['section']
5938 self.assertEqual(len(new_data), entry.size)
5939
5940 def testReplaceSectionSmallerAllow(self):
5941 """Test failing to replace a simple section with smaller data"""
5942 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5943 try:
5944 state.SetAllowEntryContraction(True)
5945 with self.assertRaises(ValueError) as exc:
5946 self._RunReplaceCmd('section', new_data,
5947 dts='241_replace_section_simple.dts')
5948 finally:
5949 state.SetAllowEntryContraction(False)
5950
5951 # Since we have no information about the position of things within the
5952 # section, we cannot adjust the position of /section-u-boot so it ends
5953 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06005954 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07005955 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5956 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06005957 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005958
Simon Glass8fbca772022-08-13 11:40:48 -06005959 def testMkimageImagename(self):
5960 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005961 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005962 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005963
5964 # Check that the data appears in the file somewhere
5965 self.assertIn(U_BOOT_SPL_DATA, data)
5966
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005967 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005968 name = data[0x20:0x40]
5969
5970 # Build the filename that we expect to be placed in there, by virtue of
5971 # the -n paraameter
5972 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5973
5974 # Check that the image name is set to the temporary filename used
5975 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5976
Simon Glassb1669752022-08-13 11:40:49 -06005977 def testMkimageImage(self):
5978 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005979 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005980 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005981
5982 # Check that the data appears in the file somewhere
5983 self.assertIn(U_BOOT_SPL_DATA, data)
5984
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005985 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06005986 name = data[0x20:0x40]
5987
5988 # Build the filename that we expect to be placed in there, by virtue of
5989 # the -n paraameter
5990 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5991
5992 # Check that the image name is set to the temporary filename used
5993 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5994
5995 # Check the corect data is in the imagename file
5996 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5997
5998 def testMkimageImageNoContent(self):
5999 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006000 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006001 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006002 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006003 self.assertIn('Could not complete processing of contents',
6004 str(exc.exception))
6005
6006 def testMkimageImageBad(self):
6007 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006008 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006009 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006010 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006011 self.assertIn('Cannot use both imagename node and data-to-imagename',
6012 str(exc.exception))
6013
Simon Glassbd5cd882022-08-13 11:40:50 -06006014 def testCollectionOther(self):
6015 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006016 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006017 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6018 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6019 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6020 data)
6021
6022 def testMkimageCollection(self):
6023 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006024 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006025 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006026 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6027 self.assertEqual(expect, data[:len(expect)])
6028
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006029 def testCompressDtbPrependInvalid(self):
6030 """Test that invalid header is detected"""
6031 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006032 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006033 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6034 "'u-boot-dtb': 'invalid'", str(e.exception))
6035
6036 def testCompressDtbPrependLength(self):
6037 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006038 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006039 image = control.images['image']
6040 entries = image.GetEntries()
6041 self.assertIn('u-boot-dtb', entries)
6042 u_boot_dtb = entries['u-boot-dtb']
6043 self.assertIn('fdtmap', entries)
6044 fdtmap = entries['fdtmap']
6045
6046 image_fname = tools.get_output_filename('image.bin')
6047 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6048 dtb = fdt.Fdt.FromData(orig)
6049 dtb.Scan()
6050 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6051 expected = {
6052 'u-boot:size': len(U_BOOT_DATA),
6053 'u-boot-dtb:uncomp-size': len(orig),
6054 'u-boot-dtb:size': u_boot_dtb.size,
6055 'fdtmap:size': fdtmap.size,
6056 'size': len(data),
6057 }
6058 self.assertEqual(expected, props)
6059
6060 # Check implementation
6061 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6062 rest = data[len(U_BOOT_DATA):]
6063 comp_data_len = struct.unpack('<I', rest[:4])[0]
6064 comp_data = rest[4:4 + comp_data_len]
6065 orig2 = self._decompress(comp_data)
6066 self.assertEqual(orig, orig2)
6067
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006068 def testInvalidCompress(self):
6069 """Test that invalid compress algorithm is detected"""
6070 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006071 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006072 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6073
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006074 def testCompUtilCompressions(self):
6075 """Test compression algorithms"""
6076 for bintool in self.comp_bintools.values():
6077 self._CheckBintool(bintool)
6078 data = bintool.compress(COMPRESS_DATA)
6079 self.assertNotEqual(COMPRESS_DATA, data)
6080 orig = bintool.decompress(data)
6081 self.assertEquals(COMPRESS_DATA, orig)
6082
6083 def testCompUtilVersions(self):
6084 """Test tool version of compression algorithms"""
6085 for bintool in self.comp_bintools.values():
6086 self._CheckBintool(bintool)
6087 version = bintool.version()
6088 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6089
6090 def testCompUtilPadding(self):
6091 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006092 # Skip zstd because it doesn't support padding
6093 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006094 self._CheckBintool(bintool)
6095 data = bintool.compress(COMPRESS_DATA)
6096 self.assertNotEqual(COMPRESS_DATA, data)
6097 data += tools.get_bytes(0, 64)
6098 orig = bintool.decompress(data)
6099 self.assertEquals(COMPRESS_DATA, orig)
6100
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006101 def testCompressDtbZstd(self):
6102 """Test that zstd compress of device-tree files failed"""
6103 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006104 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006105 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6106 "requires a length header", str(e.exception))
6107
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006108 def testMkimageMultipleDataFiles(self):
6109 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006110 self._SetupSplElf()
6111 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006112 data = self._DoReadFile('252_mkimage_mult_data.dts')
6113 # Size of files are packed in their 4B big-endian format
6114 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6115 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6116 # Size info is always followed by a 4B zero value.
6117 expect += tools.get_bytes(0, 4)
6118 expect += U_BOOT_TPL_DATA
6119 # All but last files are 4B-aligned
6120 align_pad = len(U_BOOT_TPL_DATA) % 4
6121 if align_pad:
6122 expect += tools.get_bytes(0, align_pad)
6123 expect += U_BOOT_SPL_DATA
6124 self.assertEqual(expect, data[-len(expect):])
6125
Marek Vasutf7413f02023-07-18 07:23:58 -06006126 def testMkimageMultipleExpanded(self):
6127 """Test passing multiple files to mkimage in a mkimage entry"""
6128 self._SetupSplElf()
6129 self._SetupTplElf()
6130 entry_args = {
6131 'spl-bss-pad': 'y',
6132 'spl-dtb': 'y',
6133 }
6134 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6135 use_expanded=True, entry_args=entry_args)[0]
6136 pad_len = 10
6137 tpl_expect = U_BOOT_TPL_DATA
6138 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6139 spl_expect += U_BOOT_SPL_DTB_DATA
6140
6141 content = data[0x40:]
6142 lens = struct.unpack('>III', content[:12])
6143
6144 # Size of files are packed in their 4B big-endian format
6145 # Size info is always followed by a 4B zero value.
6146 self.assertEqual(len(tpl_expect), lens[0])
6147 self.assertEqual(len(spl_expect), lens[1])
6148 self.assertEqual(0, lens[2])
6149
6150 rest = content[12:]
6151 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6152
6153 rest = rest[len(tpl_expect):]
6154 align_pad = len(tpl_expect) % 4
6155 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6156 rest = rest[align_pad:]
6157 self.assertEqual(spl_expect, rest)
6158
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006159 def testMkimageMultipleNoContent(self):
6160 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006161 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006162 with self.assertRaises(ValueError) as exc:
6163 self._DoReadFile('253_mkimage_mult_no_content.dts')
6164 self.assertIn('Could not complete processing of contents',
6165 str(exc.exception))
6166
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006167 def testMkimageFilename(self):
6168 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006169 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006170 retcode = self._DoTestFile('254_mkimage_filename.dts')
6171 self.assertEqual(0, retcode)
6172 fname = tools.get_output_filename('mkimage-test.bin')
6173 self.assertTrue(os.path.exists(fname))
6174
Simon Glass56d05412022-02-28 07:16:54 -07006175 def testVpl(self):
6176 """Test that an image with VPL and its device tree can be created"""
6177 # ELF file with a '__bss_size' symbol
6178 self._SetupVplElf()
6179 data = self._DoReadFile('255_u_boot_vpl.dts')
6180 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6181
6182 def testVplNoDtb(self):
6183 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6184 self._SetupVplElf()
6185 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6186 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6187 data[:len(U_BOOT_VPL_NODTB_DATA)])
6188
6189 def testExpandedVpl(self):
6190 """Test that an expanded entry type is selected for TPL when needed"""
6191 self._SetupVplElf()
6192
6193 entry_args = {
6194 'vpl-bss-pad': 'y',
6195 'vpl-dtb': 'y',
6196 }
6197 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6198 entry_args=entry_args)
6199 image = control.images['image']
6200 entries = image.GetEntries()
6201 self.assertEqual(1, len(entries))
6202
6203 # We only have u-boot-vpl, which be expanded
6204 self.assertIn('u-boot-vpl', entries)
6205 entry = entries['u-boot-vpl']
6206 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6207 subent = entry.GetEntries()
6208 self.assertEqual(3, len(subent))
6209 self.assertIn('u-boot-vpl-nodtb', subent)
6210 self.assertIn('u-boot-vpl-bss-pad', subent)
6211 self.assertIn('u-boot-vpl-dtb', subent)
6212
6213 def testVplBssPadMissing(self):
6214 """Test that a missing symbol is detected"""
6215 self._SetupVplElf('u_boot_ucode_ptr')
6216 with self.assertRaises(ValueError) as e:
6217 self._DoReadFile('258_vpl_bss_pad.dts')
6218 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6219 str(e.exception))
6220
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306221 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306222 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306223 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6224 self.assertEqual(0, retcode)
6225 image = control.images['test_image']
6226 fname = tools.get_output_filename('test_image.bin')
6227 sname = tools.get_output_filename('symlink_to_test.bin')
6228 self.assertTrue(os.path.islink(sname))
6229 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006230
Andrew Davis6b463da2023-07-22 00:14:44 +05306231 def testSymlinkOverwrite(self):
6232 """Test that symlinked images can be overwritten"""
6233 testdir = TestFunctional._MakeInputDir('symlinktest')
6234 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6235 # build the same image again in the same directory so that existing symlink is present
6236 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6237 fname = tools.get_output_filename('test_image.bin')
6238 sname = tools.get_output_filename('symlink_to_test.bin')
6239 self.assertTrue(os.path.islink(sname))
6240 self.assertEqual(os.readlink(sname), fname)
6241
Simon Glass37f85de2022-10-20 18:22:47 -06006242 def testSymbolsElf(self):
6243 """Test binman can assign symbols embedded in an ELF file"""
6244 if not elf.ELF_TOOLS:
6245 self.skipTest('Python elftools not available')
6246 self._SetupTplElf('u_boot_binman_syms')
6247 self._SetupVplElf('u_boot_binman_syms')
6248 self._SetupSplElf('u_boot_binman_syms')
6249 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6250 image_fname = tools.get_output_filename('image.bin')
6251
6252 image = control.images['image']
6253 entries = image.GetEntries()
6254
6255 for entry in entries.values():
6256 # No symbols in u-boot and it has faked contents anyway
6257 if entry.name == 'u-boot':
6258 continue
6259 edata = data[entry.image_pos:entry.image_pos + entry.size]
6260 efname = tools.get_output_filename(f'edata-{entry.name}')
6261 tools.write_file(efname, edata)
6262
6263 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6264 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6265 for name, sym in syms.items():
6266 msg = 'test'
6267 val = elf.GetSymbolValue(sym, edata, msg)
6268 entry_m = re_name.match(name)
6269 if entry_m:
6270 ename, prop = entry_m.group(1), entry_m.group(3)
6271 entry, entry_name, prop_name = image.LookupEntry(entries,
6272 name, msg)
6273 if prop_name == 'offset':
6274 expect_val = entry.offset
6275 elif prop_name == 'image_pos':
6276 expect_val = entry.image_pos
6277 elif prop_name == 'size':
6278 expect_val = entry.size
6279 self.assertEqual(expect_val, val)
6280
6281 def testSymbolsElfBad(self):
6282 """Check error when trying to write symbols without the elftools lib"""
6283 if not elf.ELF_TOOLS:
6284 self.skipTest('Python elftools not available')
6285 self._SetupTplElf('u_boot_binman_syms')
6286 self._SetupVplElf('u_boot_binman_syms')
6287 self._SetupSplElf('u_boot_binman_syms')
6288 try:
6289 elf.ELF_TOOLS = False
6290 with self.assertRaises(ValueError) as exc:
6291 self._DoReadFileDtb('260_symbols_elf.dts')
6292 finally:
6293 elf.ELF_TOOLS = True
6294 self.assertIn(
6295 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6296 'Cannot write symbols to an ELF file without Python elftools',
6297 str(exc.exception))
6298
Simon Glassde244162023-01-07 14:07:08 -07006299 def testSectionFilename(self):
6300 """Check writing of section contents to a file"""
6301 data = self._DoReadFile('261_section_fname.dts')
6302 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6303 tools.get_bytes(ord('!'), 7) +
6304 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6305 self.assertEqual(expected, data)
6306
6307 sect_fname = tools.get_output_filename('outfile.bin')
6308 self.assertTrue(os.path.exists(sect_fname))
6309 sect_data = tools.read_file(sect_fname)
6310 self.assertEqual(U_BOOT_DATA, sect_data)
6311
Simon Glass1e9e61c2023-01-07 14:07:12 -07006312 def testAbsent(self):
6313 """Check handling of absent entries"""
6314 data = self._DoReadFile('262_absent.dts')
6315 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6316
Simon Glassad5cfe12023-01-07 14:07:14 -07006317 def testPackTeeOsOptional(self):
6318 """Test that an image with an optional TEE binary can be created"""
6319 entry_args = {
6320 'tee-os-path': 'tee.elf',
6321 }
6322 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6323 entry_args=entry_args)[0]
6324 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6325
6326 def checkFitTee(self, dts, tee_fname):
6327 """Check that a tee-os entry works and returns data
6328
6329 Args:
6330 dts (str): Device tree filename to use
6331 tee_fname (str): filename containing tee-os
6332
6333 Returns:
6334 bytes: Image contents
6335 """
6336 if not elf.ELF_TOOLS:
6337 self.skipTest('Python elftools not available')
6338 entry_args = {
6339 'of-list': 'test-fdt1 test-fdt2',
6340 'default-dt': 'test-fdt2',
6341 'tee-os-path': tee_fname,
6342 }
6343 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6344 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6345 extra_indirs=[test_subdir])[0]
6346 return data
6347
6348 def testFitTeeOsOptionalFit(self):
6349 """Test an image with a FIT with an optional OP-TEE binary"""
6350 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6351
6352 # There should be only one node, holding the data set up in SetUpClass()
6353 # for tee.bin
6354 dtb = fdt.Fdt.FromData(data)
6355 dtb.Scan()
6356 node = dtb.GetNode('/images/tee-1')
6357 self.assertEqual(TEE_ADDR,
6358 fdt_util.fdt32_to_cpu(node.props['load'].value))
6359 self.assertEqual(TEE_ADDR,
6360 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6361 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6362
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006363 with test_util.capture_sys_output() as (stdout, stderr):
6364 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6365 err = stderr.getvalue()
6366 self.assertRegex(
6367 err,
6368 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6369
Simon Glassad5cfe12023-01-07 14:07:14 -07006370 def testFitTeeOsOptionalFitBad(self):
6371 """Test an image with a FIT with an optional OP-TEE binary"""
6372 with self.assertRaises(ValueError) as exc:
6373 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6374 self.assertIn(
6375 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6376 str(exc.exception))
6377
6378 def testFitTeeOsBad(self):
6379 """Test an OP-TEE binary with wrong formats"""
6380 self.make_tee_bin('tee.bad1', 123)
6381 with self.assertRaises(ValueError) as exc:
6382 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6383 self.assertIn(
6384 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6385 str(exc.exception))
6386
6387 self.make_tee_bin('tee.bad2', 0, b'extra data')
6388 with self.assertRaises(ValueError) as exc:
6389 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6390 self.assertIn(
6391 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6392 str(exc.exception))
6393
Simon Glass63328f12023-01-07 14:07:15 -07006394 def testExtblobOptional(self):
6395 """Test an image with an external blob that is optional"""
6396 with test_util.capture_sys_output() as (stdout, stderr):
6397 data = self._DoReadFile('266_blob_ext_opt.dts')
6398 self.assertEqual(REFCODE_DATA, data)
6399 err = stderr.getvalue()
6400 self.assertRegex(
6401 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006402 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006403
Simon Glass7447a9d2023-01-11 16:10:12 -07006404 def testSectionInner(self):
6405 """Test an inner section with a size"""
6406 data = self._DoReadFile('267_section_inner.dts')
6407 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6408 self.assertEqual(expected, data)
6409
Simon Glassa4948b22023-01-11 16:10:14 -07006410 def testNull(self):
6411 """Test an image with a null entry"""
6412 data = self._DoReadFile('268_null.dts')
6413 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6414
Simon Glassf1ee03b2023-01-11 16:10:16 -07006415 def testOverlap(self):
6416 """Test an image with a overlapping entry"""
6417 data = self._DoReadFile('269_overlap.dts')
6418 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6419
6420 image = control.images['image']
6421 entries = image.GetEntries()
6422
6423 self.assertIn('inset', entries)
6424 inset = entries['inset']
6425 self.assertEqual(1, inset.offset);
6426 self.assertEqual(1, inset.image_pos);
6427 self.assertEqual(2, inset.size);
6428
6429 def testOverlapNull(self):
6430 """Test an image with a null overlap"""
6431 data = self._DoReadFile('270_overlap_null.dts')
6432 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6433
6434 # Check the FMAP
6435 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6436 self.assertEqual(4, fhdr.nareas)
6437 fiter = iter(fentries)
6438
6439 fentry = next(fiter)
6440 self.assertEqual(b'SECTION', fentry.name)
6441 self.assertEqual(0, fentry.offset)
6442 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6443 self.assertEqual(0, fentry.flags)
6444
6445 fentry = next(fiter)
6446 self.assertEqual(b'U_BOOT', fentry.name)
6447 self.assertEqual(0, fentry.offset)
6448 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6449 self.assertEqual(0, fentry.flags)
6450
6451 # Make sure that the NULL entry appears in the FMAP
6452 fentry = next(fiter)
6453 self.assertEqual(b'NULL', fentry.name)
6454 self.assertEqual(1, fentry.offset)
6455 self.assertEqual(2, fentry.size)
6456 self.assertEqual(0, fentry.flags)
6457
6458 fentry = next(fiter)
6459 self.assertEqual(b'FMAP', fentry.name)
6460 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6461
6462 def testOverlapBad(self):
6463 """Test an image with a bad overlapping entry"""
6464 with self.assertRaises(ValueError) as exc:
6465 self._DoReadFile('271_overlap_bad.dts')
6466 self.assertIn(
6467 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6468 str(exc.exception))
6469
6470 def testOverlapNoOffset(self):
6471 """Test an image with a bad overlapping entry"""
6472 with self.assertRaises(ValueError) as exc:
6473 self._DoReadFile('272_overlap_no_size.dts')
6474 self.assertIn(
6475 "Node '/binman/inset': 'fill' entry is missing properties: size",
6476 str(exc.exception))
6477
Simon Glasse0035c92023-01-11 16:10:17 -07006478 def testBlobSymbol(self):
6479 """Test a blob with symbols read from an ELF file"""
6480 elf_fname = self.ElfTestFile('blob_syms')
6481 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6482 TestFunctional._MakeInputFile('blob_syms.bin',
6483 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6484
6485 data = self._DoReadFile('273_blob_symbol.dts')
6486
6487 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6488 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6489 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6490 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6491 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6492
6493 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6494 expected = sym_values
6495 self.assertEqual(expected, data[:len(expected)])
6496
Simon Glass49e9c002023-01-11 16:10:19 -07006497 def testOffsetFromElf(self):
6498 """Test a blob with symbols read from an ELF file"""
6499 elf_fname = self.ElfTestFile('blob_syms')
6500 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6501 TestFunctional._MakeInputFile('blob_syms.bin',
6502 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6503
6504 data = self._DoReadFile('274_offset_from_elf.dts')
6505
6506 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6507 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6508
6509 image = control.images['image']
6510 entries = image.GetEntries()
6511
6512 self.assertIn('inset', entries)
6513 inset = entries['inset']
6514
6515 self.assertEqual(base + 4, inset.offset);
6516 self.assertEqual(base + 4, inset.image_pos);
6517 self.assertEqual(4, inset.size);
6518
6519 self.assertIn('inset2', entries)
6520 inset = entries['inset2']
6521 self.assertEqual(base + 8, inset.offset);
6522 self.assertEqual(base + 8, inset.image_pos);
6523 self.assertEqual(4, inset.size);
6524
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006525 def testFitAlign(self):
6526 """Test an image with an FIT with aligned external data"""
6527 data = self._DoReadFile('275_fit_align.dts')
6528 self.assertEqual(4096, len(data))
6529
6530 dtb = fdt.Fdt.FromData(data)
6531 dtb.Scan()
6532
6533 props = self._GetPropTree(dtb, ['data-position'])
6534 expected = {
6535 'u-boot:data-position': 1024,
6536 'fdt-1:data-position': 2048,
6537 'fdt-2:data-position': 3072,
6538 }
6539 self.assertEqual(expected, props)
6540
Jonas Karlman490f73c2023-01-21 19:02:12 +00006541 def testFitFirmwareLoadables(self):
6542 """Test an image with an FIT that use fit,firmware"""
6543 if not elf.ELF_TOOLS:
6544 self.skipTest('Python elftools not available')
6545 entry_args = {
6546 'of-list': 'test-fdt1',
6547 'default-dt': 'test-fdt1',
6548 'atf-bl31-path': 'bl31.elf',
6549 'tee-os-path': 'missing.bin',
6550 }
6551 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006552 with test_util.capture_sys_output() as (stdout, stderr):
6553 data = self._DoReadFileDtb(
6554 '276_fit_firmware_loadables.dts',
6555 entry_args=entry_args,
6556 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006557
6558 dtb = fdt.Fdt.FromData(data)
6559 dtb.Scan()
6560
6561 node = dtb.GetNode('/configurations/conf-uboot-1')
6562 self.assertEqual('u-boot', node.props['firmware'].value)
6563 self.assertEqual(['atf-1', 'atf-2'],
6564 fdt_util.GetStringList(node, 'loadables'))
6565
6566 node = dtb.GetNode('/configurations/conf-atf-1')
6567 self.assertEqual('atf-1', node.props['firmware'].value)
6568 self.assertEqual(['u-boot', 'atf-2'],
6569 fdt_util.GetStringList(node, 'loadables'))
6570
6571 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6572 self.assertEqual('u-boot', node.props['firmware'].value)
6573 self.assertEqual(['atf-1', 'atf-2'],
6574 fdt_util.GetStringList(node, 'loadables'))
6575
6576 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6577 self.assertEqual('atf-1', node.props['firmware'].value)
6578 self.assertEqual(['u-boot', 'atf-2'],
6579 fdt_util.GetStringList(node, 'loadables'))
6580
6581 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6582 self.assertEqual('atf-1', node.props['firmware'].value)
6583 self.assertEqual(['u-boot', 'atf-2'],
6584 fdt_util.GetStringList(node, 'loadables'))
6585
Simon Glass9a1c7262023-02-22 12:14:49 -07006586 def testTooldir(self):
6587 """Test that we can specify the tooldir"""
6588 with test_util.capture_sys_output() as (stdout, stderr):
6589 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6590 'tool', '-l'))
6591 self.assertEqual('fred', bintool.Bintool.tooldir)
6592
6593 # Check that the toolpath is updated correctly
6594 self.assertEqual(['fred'], tools.tool_search_paths)
6595
6596 # Try with a few toolpaths; the tooldir should be at the end
6597 with test_util.capture_sys_output() as (stdout, stderr):
6598 self.assertEqual(0, self._DoBinman(
6599 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6600 'tool', '-l'))
6601 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6602
Simon Glass49b77e82023-03-02 17:02:44 -07006603 def testReplaceSectionEntry(self):
6604 """Test replacing an entry in a section"""
6605 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6606 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6607 expect_data, dts='241_replace_section_simple.dts')
6608 self.assertEqual(expect_data, entry_data)
6609
6610 entries = image.GetEntries()
6611 self.assertIn('section', entries)
6612 section = entries['section']
6613
6614 sect_entries = section.GetEntries()
6615 self.assertIn('blob', sect_entries)
6616 entry = sect_entries['blob']
6617 self.assertEqual(len(expect_data), entry.size)
6618
6619 fname = tools.get_output_filename('image-updated.bin')
6620 data = tools.read_file(fname)
6621
6622 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6623 self.assertEqual(expect_data, new_blob_data)
6624
6625 self.assertEqual(U_BOOT_DATA,
6626 data[entry.image_pos + len(expect_data):]
6627 [:len(U_BOOT_DATA)])
6628
6629 def testReplaceSectionDeep(self):
6630 """Test replacing an entry in two levels of sections"""
6631 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6632 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6633 'section/section/blob', expect_data,
6634 dts='278_replace_section_deep.dts')
6635 self.assertEqual(expect_data, entry_data)
6636
6637 entries = image.GetEntries()
6638 self.assertIn('section', entries)
6639 section = entries['section']
6640
6641 subentries = section.GetEntries()
6642 self.assertIn('section', subentries)
6643 section = subentries['section']
6644
6645 sect_entries = section.GetEntries()
6646 self.assertIn('blob', sect_entries)
6647 entry = sect_entries['blob']
6648 self.assertEqual(len(expect_data), entry.size)
6649
6650 fname = tools.get_output_filename('image-updated.bin')
6651 data = tools.read_file(fname)
6652
6653 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6654 self.assertEqual(expect_data, new_blob_data)
6655
6656 self.assertEqual(U_BOOT_DATA,
6657 data[entry.image_pos + len(expect_data):]
6658 [:len(U_BOOT_DATA)])
6659
6660 def testReplaceFitSibling(self):
6661 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006662 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006663 fname = TestFunctional._MakeInputFile('once', b'available once')
6664 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6665 os.remove(fname)
6666
6667 try:
6668 tmpdir, updated_fname = self._SetupImageInTmpdir()
6669
6670 fname = os.path.join(tmpdir, 'update-blob')
6671 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6672 tools.write_file(fname, expected)
6673
6674 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6675 data = tools.read_file(updated_fname)
6676 start = len(U_BOOT_DTB_DATA)
6677 self.assertEqual(expected, data[start:start + len(expected)])
6678 map_fname = os.path.join(tmpdir, 'image-updated.map')
6679 self.assertFalse(os.path.exists(map_fname))
6680 finally:
6681 shutil.rmtree(tmpdir)
6682
Simon Glassc3fe97f2023-03-02 17:02:45 -07006683 def testX509Cert(self):
6684 """Test creating an X509 certificate"""
6685 keyfile = self.TestFile('key.key')
6686 entry_args = {
6687 'keyfile': keyfile,
6688 }
6689 data = self._DoReadFileDtb('279_x509_cert.dts',
6690 entry_args=entry_args)[0]
6691 cert = data[:-4]
6692 self.assertEqual(U_BOOT_DATA, data[-4:])
6693
6694 # TODO: verify the signature
6695
6696 def testX509CertMissing(self):
6697 """Test that binman still produces an image if openssl is missing"""
6698 keyfile = self.TestFile('key.key')
6699 entry_args = {
6700 'keyfile': 'keyfile',
6701 }
6702 with test_util.capture_sys_output() as (_, stderr):
6703 self._DoTestFile('279_x509_cert.dts',
6704 force_missing_bintools='openssl',
6705 entry_args=entry_args)
6706 err = stderr.getvalue()
6707 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6708
Jonas Karlman35305492023-02-25 19:01:33 +00006709 def testPackRockchipTpl(self):
6710 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006711 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006712 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6713
Jonas Karlman1016ec72023-02-25 19:01:35 +00006714 def testMkimageMissingBlobMultiple(self):
6715 """Test missing blob with mkimage entry and multiple-data-files"""
6716 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006717 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006718 err = stderr.getvalue()
6719 self.assertIn("is missing external blobs and is non-functional", err)
6720
6721 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006722 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006723 self.assertIn("not found in input path", str(e.exception))
6724
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006725 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6726 """Prepare sign environment
6727
6728 Create private and public keys, add pubkey into dtb.
6729
6730 Returns:
6731 Tuple:
6732 FIT container
6733 Image name
6734 Private key
6735 DTB
6736 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006737 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006738 data = self._DoReadFileRealDtb(dts)
6739 updated_fname = tools.get_output_filename('image-updated.bin')
6740 tools.write_file(updated_fname, data)
6741 dtb = tools.get_output_filename('source.dtb')
6742 private_key = tools.get_output_filename('test_key.key')
6743 public_key = tools.get_output_filename('test_key.crt')
6744 fit = tools.get_output_filename('fit.fit')
6745 key_dir = tools.get_output_dir()
6746
6747 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6748 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6749 private_key, '-out', public_key)
6750 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6751 '-n', 'test_key', '-r', 'conf', dtb)
6752
6753 return fit, updated_fname, private_key, dtb
6754
6755 def testSignSimple(self):
6756 """Test that a FIT container can be signed in image"""
6757 is_signed = False
6758 fit, fname, private_key, dtb = self._PrepareSignEnv()
6759
6760 # do sign with private key
6761 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6762 ['fit'])
6763 is_signed = self._CheckSign(fit, dtb)
6764
6765 self.assertEqual(is_signed, True)
6766
6767 def testSignExactFIT(self):
6768 """Test that a FIT container can be signed and replaced in image"""
6769 is_signed = False
6770 fit, fname, private_key, dtb = self._PrepareSignEnv()
6771
6772 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6773 args = []
6774 if self.toolpath:
6775 for path in self.toolpath:
6776 args += ['--toolpath', path]
6777
6778 # do sign with private key
6779 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6780 'sha256,rsa4096', '-f', fit, 'fit')
6781 is_signed = self._CheckSign(fit, dtb)
6782
6783 self.assertEqual(is_signed, True)
6784
6785 def testSignNonFit(self):
6786 """Test a non-FIT entry cannot be signed"""
6787 is_signed = False
6788 fit, fname, private_key, _ = self._PrepareSignEnv(
6789 '281_sign_non_fit.dts')
6790
6791 # do sign with private key
6792 with self.assertRaises(ValueError) as e:
6793 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6794 'sha256,rsa4096', '-f', fit, 'u-boot')
6795 self.assertIn(
6796 "Node '/u-boot': Updating signatures is not supported with this entry type",
6797 str(e.exception))
6798
6799 def testSignMissingMkimage(self):
6800 """Test that FIT signing handles a missing mkimage tool"""
6801 fit, fname, private_key, _ = self._PrepareSignEnv()
6802
6803 # try to sign with a missing mkimage tool
6804 bintool.Bintool.set_missing_list(['mkimage'])
6805 with self.assertRaises(ValueError) as e:
6806 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6807 ['fit'])
6808 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6809
Simon Glass4abf7842023-07-18 07:23:54 -06006810 def testSymbolNoWrite(self):
6811 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006812 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006813 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6814 no_write_symbols=True)
6815
6816 def testSymbolNoWriteExpanded(self):
6817 """Test disabling of symbol writing in expanded entries"""
6818 entry_args = {
6819 'spl-dtb': '1',
6820 }
6821 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6822 U_BOOT_SPL_DTB_DATA, 0x38,
6823 entry_args=entry_args, use_expanded=True,
6824 no_write_symbols=True)
6825
Marek Vasutf7413f02023-07-18 07:23:58 -06006826 def testMkimageSpecial(self):
6827 """Test mkimage ignores special hash-1 node"""
6828 data = self._DoReadFile('283_mkimage_special.dts')
6829
6830 # Just check that the data appears in the file somewhere
6831 self.assertIn(U_BOOT_DATA, data)
6832
Simon Glass2d94c422023-07-18 07:23:59 -06006833 def testFitFdtList(self):
6834 """Test an image with an FIT with the fit,fdt-list-val option"""
6835 entry_args = {
6836 'default-dt': 'test-fdt2',
6837 }
6838 data = self._DoReadFileDtb(
6839 '284_fit_fdt_list.dts',
6840 entry_args=entry_args,
6841 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6842 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6843 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6844
Simon Glass83b8bfe2023-07-18 07:24:01 -06006845 def testSplEmptyBss(self):
6846 """Test an expanded SPL with a zero-size BSS"""
6847 # ELF file with a '__bss_size' symbol
6848 self._SetupSplElf(src_fname='bss_data_zero')
6849
6850 entry_args = {
6851 'spl-bss-pad': 'y',
6852 'spl-dtb': 'y',
6853 }
6854 data = self._DoReadFileDtb('285_spl_expand.dts',
6855 use_expanded=True, entry_args=entry_args)[0]
6856
Simon Glassfc792842023-07-18 07:24:04 -06006857 def testTemplate(self):
6858 """Test using a template"""
6859 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6860 data = self._DoReadFile('286_template.dts')
6861 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6862 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6863 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6864
Simon Glass09490b02023-07-22 21:43:52 -06006865 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6866 self.assertTrue(os.path.exists(dtb_fname1))
6867 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6868 dtb.Scan()
6869 node1 = dtb.GetNode('/binman/template')
6870 self.assertTrue(node1)
6871 vga = dtb.GetNode('/binman/first/intel-vga')
6872 self.assertTrue(vga)
6873
Simon Glass54825e12023-07-22 21:43:56 -06006874 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6875 self.assertTrue(os.path.exists(dtb_fname2))
6876 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6877 dtb2.Scan()
6878 node2 = dtb2.GetNode('/binman/template')
6879 self.assertFalse(node2)
6880
Simon Glass9909c112023-07-18 07:24:05 -06006881 def testTemplateBlobMulti(self):
6882 """Test using a template with 'multiple-images' enabled"""
6883 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6884 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6885 retcode = self._DoTestFile('287_template_multi.dts')
6886
6887 self.assertEqual(0, retcode)
6888 image = control.images['image']
6889 image_fname = tools.get_output_filename('my-image.bin')
6890 data = tools.read_file(image_fname)
6891 self.assertEqual(b'blob@@@@other', data)
6892
Simon Glass5dc511b2023-07-18 07:24:06 -06006893 def testTemplateFit(self):
6894 """Test using a template in a FIT"""
6895 fit_data = self._DoReadFile('288_template_fit.dts')
6896 fname = os.path.join(self._indir, 'fit_data.fit')
6897 tools.write_file(fname, fit_data)
6898 out = tools.run('dumpimage', '-l', fname)
6899
Simon Glassaa6e0552023-07-18 07:24:07 -06006900 def testTemplateSection(self):
6901 """Test using a template in a section (not at top level)"""
6902 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6903 data = self._DoReadFile('289_template_section.dts')
6904 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6905 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6906 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6907
Simon Glassf53a7bc2023-07-18 07:24:08 -06006908 def testMkimageSymbols(self):
6909 """Test using mkimage to build an image with symbols in it"""
6910 self._SetupSplElf('u_boot_binman_syms')
6911 data = self._DoReadFile('290_mkimage_sym.dts')
6912
6913 image = control.images['image']
6914 entries = image.GetEntries()
6915 self.assertIn('u-boot', entries)
6916 u_boot = entries['u-boot']
6917
6918 mkim = entries['mkimage']
6919 mkim_entries = mkim.GetEntries()
6920 self.assertIn('u-boot-spl', mkim_entries)
6921 spl = mkim_entries['u-boot-spl']
6922 self.assertIn('u-boot-spl2', mkim_entries)
6923 spl2 = mkim_entries['u-boot-spl2']
6924
6925 # skip the mkimage header and the area sizes
6926 mk_data = data[mkim.offset + 0x40:]
6927 size, term = struct.unpack('>LL', mk_data[:8])
6928
6929 # There should be only one image, so check that the zero terminator is
6930 # present
6931 self.assertEqual(0, term)
6932
6933 content = mk_data[8:8 + size]
6934
6935 # The image should contain the symbols from u_boot_binman_syms.c
6936 # Note that image_pos is adjusted by the base address of the image,
6937 # which is 0x10 in our test image
6938 spl_data = content[:0x18]
6939 content = content[0x1b:]
6940
6941 # After the header is a table of offsets for each image. There should
6942 # only be one image, then a 0 terminator, so figure out the real start
6943 # of the image data
6944 base = 0x40 + 8
6945
6946 # Check symbols in both u-boot-spl and u-boot-spl2
6947 for i in range(2):
6948 vals = struct.unpack('<LLQLL', spl_data)
6949
6950 # The image should contain the symbols from u_boot_binman_syms.c
6951 # Note that image_pos is adjusted by the base address of the image,
6952 # which is 0x10 in our 'u_boot_binman_syms' test image
6953 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6954 self.assertEqual(base, vals[1])
6955 self.assertEqual(spl2.offset, vals[2])
6956 # figure out the internal positions of its components
6957 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6958
6959 # Check that spl and spl2 are actually at the indicated positions
6960 self.assertEqual(
6961 elf.BINMAN_SYM_MAGIC_VALUE,
6962 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6963 self.assertEqual(
6964 elf.BINMAN_SYM_MAGIC_VALUE,
6965 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6966
6967 self.assertEqual(len(U_BOOT_DATA), vals[4])
6968
6969 # Move to next
6970 spl_data = content[:0x18]
6971
Neha Malcom Francis3b788942023-07-22 00:14:24 +05306972 def testTIBoardConfig(self):
6973 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06006974 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05306975 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
6976
6977 def testTIBoardConfigCombined(self):
6978 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06006979 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05306980 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
6981 self.assertGreater(data, configlen_noheader)
6982
6983 def testTIBoardConfigNoDataType(self):
6984 """Test that error is thrown when data type is not supported"""
6985 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06006986 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05306987 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07006988
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05306989 def testPackTiSecure(self):
6990 """Test that an image with a TI secured binary can be created"""
6991 keyfile = self.TestFile('key.key')
6992 entry_args = {
6993 'keyfile': keyfile,
6994 }
Simon Glassf1264ba2023-07-24 09:19:59 -06006995 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05306996 entry_args=entry_args)[0]
6997 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
6998
6999 def testPackTiSecureMissingTool(self):
7000 """Test that an image with a TI secured binary (non-functional) can be created
7001 when openssl is missing"""
7002 keyfile = self.TestFile('key.key')
7003 entry_args = {
7004 'keyfile': keyfile,
7005 }
7006 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007007 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307008 force_missing_bintools='openssl',
7009 entry_args=entry_args)
7010 err = stderr.getvalue()
7011 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7012
7013 def testPackTiSecureROM(self):
7014 """Test that a ROM image with a TI secured binary can be created"""
7015 keyfile = self.TestFile('key.key')
7016 entry_args = {
7017 'keyfile': keyfile,
7018 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007019 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307020 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007021 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307022 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007023 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307024 entry_args=entry_args)[0]
7025 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7026 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7027 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7028
7029 def testPackTiSecureROMCombined(self):
7030 """Test that a ROM image with a TI secured binary can be created"""
7031 keyfile = self.TestFile('key.key')
7032 entry_args = {
7033 'keyfile': keyfile,
7034 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007035 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307036 entry_args=entry_args)[0]
7037 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7038
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007039 def testEncryptedNoAlgo(self):
7040 """Test encrypted node with missing required properties"""
7041 with self.assertRaises(ValueError) as e:
7042 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7043 self.assertIn(
7044 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7045 str(e.exception))
7046
7047 def testEncryptedInvalidIvfile(self):
7048 """Test encrypted node with invalid iv file"""
7049 with self.assertRaises(ValueError) as e:
7050 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7051 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7052 str(e.exception))
7053
7054 def testEncryptedMissingKey(self):
7055 """Test encrypted node with missing key properties"""
7056 with self.assertRaises(ValueError) as e:
7057 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7058 self.assertIn(
7059 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7060 str(e.exception))
7061
7062 def testEncryptedKeySource(self):
7063 """Test encrypted node with key-source property"""
7064 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7065
7066 dtb = fdt.Fdt.FromData(data)
7067 dtb.Scan()
7068
7069 node = dtb.GetNode('/images/u-boot/cipher')
7070 self.assertEqual('algo-name', node.props['algo'].value)
7071 self.assertEqual('key-source-value', node.props['key-source'].value)
7072 self.assertEqual(ENCRYPTED_IV_DATA,
7073 tools.to_bytes(''.join(node.props['iv'].value)))
7074 self.assertNotIn('key', node.props)
7075
7076 def testEncryptedKeyFile(self):
7077 """Test encrypted node with key-filename property"""
7078 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7079
7080 dtb = fdt.Fdt.FromData(data)
7081 dtb.Scan()
7082
7083 node = dtb.GetNode('/images/u-boot/cipher')
7084 self.assertEqual('algo-name', node.props['algo'].value)
7085 self.assertEqual(ENCRYPTED_IV_DATA,
7086 tools.to_bytes(''.join(node.props['iv'].value)))
7087 self.assertEqual(ENCRYPTED_KEY_DATA,
7088 tools.to_bytes(''.join(node.props['key'].value)))
7089 self.assertNotIn('key-source', node.props)
7090
Lukas Funkee901faf2023-07-18 13:53:13 +02007091
7092 def testSplPubkeyDtb(self):
7093 """Test u_boot_spl_pubkey_dtb etype"""
7094 data = tools.read_file(self.TestFile("key.pem"))
7095 self._MakeInputFile("key.crt", data)
7096 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7097 image = control.images['image']
7098 entries = image.GetEntries()
7099 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7100 dtb_data = dtb_entry.GetData()
7101 dtb = fdt.Fdt.FromData(dtb_data)
7102 dtb.Scan()
7103
7104 signature_node = dtb.GetNode('/signature')
7105 self.assertIsNotNone(signature_node)
7106 key_node = signature_node.FindNode("key-key")
7107 self.assertIsNotNone(key_node)
7108 self.assertEqual(fdt_util.GetString(key_node, "required"),
7109 "conf")
7110 self.assertEqual(fdt_util.GetString(key_node, "algo"),
7111 "sha384,rsa4096")
7112 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"),
7113 "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007114
Simon Glassac599912017-11-12 21:52:22 -07007115if __name__ == "__main__":
7116 unittest.main()