blob: a5ce44bbb2d4d09ffa136cc3044e79749949060a [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()
Simon Glass49cd2b32023-02-07 14:34:18 -07003809 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003810 self.assertIn('Some images are invalid', err)
3811
3812 def testExtblobMissingOkFlag(self):
3813 """Test an image with an missing external blob allowed with -W"""
3814 with test_util.capture_sys_output() as (stdout, stderr):
3815 ret = self._DoTestFile('158_blob_ext_missing.dts',
3816 allow_missing=True, ignore_missing=True)
3817 self.assertEqual(0, ret)
3818 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003819 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003820 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003821
3822 def testExtblobMissingOkSect(self):
3823 """Test an image with an missing external blob that is allowed"""
3824 with test_util.capture_sys_output() as (stdout, stderr):
3825 self._DoTestFile('159_blob_ext_missing_sect.dts',
3826 allow_missing=True)
3827 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003828 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003829
Simon Glasse88cef92020-07-09 18:39:41 -06003830 def testPackX86RomMeMissingDesc(self):
3831 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003832 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003833 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003834 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003835 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003836
3837 def testPackX86RomMissingIfwi(self):
3838 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3839 self._SetupIfwi('fitimage.bin')
3840 pathname = os.path.join(self._indir, 'fitimage.bin')
3841 os.remove(pathname)
3842 with test_util.capture_sys_output() as (stdout, stderr):
3843 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3844 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003845 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003846
Simon Glass2a0fa982022-02-11 13:23:21 -07003847 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003848 """Test that zero-size overlapping regions are ignored"""
3849 self._DoTestFile('160_pack_overlap_zero.dts')
3850
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003851 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003852 # The data should be inside the FIT
3853 dtb = fdt.Fdt.FromData(fit_data)
3854 dtb.Scan()
3855 fnode = dtb.GetNode('/images/kernel')
3856 self.assertIn('data', fnode.props)
3857
3858 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003859 tools.write_file(fname, fit_data)
3860 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003861
3862 # Check a few features to make sure the plumbing works. We don't need
3863 # to test the operation of mkimage or dumpimage here. First convert the
3864 # output into a dict where the keys are the fields printed by dumpimage
3865 # and the values are a list of values for each field
3866 lines = out.splitlines()
3867
3868 # Converts "Compression: gzip compressed" into two groups:
3869 # 'Compression' and 'gzip compressed'
3870 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3871 vals = collections.defaultdict(list)
3872 for line in lines:
3873 mat = re_line.match(line)
3874 vals[mat.group(1)].append(mat.group(2))
3875
3876 self.assertEquals('FIT description: test-desc', lines[0])
3877 self.assertIn('Created:', lines[1])
3878 self.assertIn('Image 0 (kernel)', vals)
3879 self.assertIn('Hash value', vals)
3880 data_sizes = vals.get('Data Size')
3881 self.assertIsNotNone(data_sizes)
3882 self.assertEqual(2, len(data_sizes))
3883 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003884 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3885 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3886
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003887 # Check if entry listing correctly omits /images/
3888 image = control.images['image']
3889 fit_entry = image.GetEntries()['fit']
3890 subentries = list(fit_entry.GetEntries().keys())
3891 expected = ['kernel', 'fdt-1']
3892 self.assertEqual(expected, subentries)
3893
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003894 def testSimpleFit(self):
3895 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003896 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003897 data = self._DoReadFile('161_fit.dts')
3898 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3899 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3900 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3901
3902 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3903
3904 def testSimpleFitExpandsSubentries(self):
3905 """Test that FIT images expand their subentries"""
3906 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3907 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3908 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3909 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3910
3911 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003912
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003913 def testSimpleFitImagePos(self):
3914 """Test that we have correct image-pos for FIT subentries"""
3915 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3916 update_dtb=True)
3917 dtb = fdt.Fdt(out_dtb_fname)
3918 dtb.Scan()
3919 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3920
Simon Glassb7bad182022-03-05 20:19:01 -07003921 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003922 self.assertEqual({
3923 'image-pos': 0,
3924 'offset': 0,
3925 'size': 1890,
3926
3927 'u-boot:image-pos': 0,
3928 'u-boot:offset': 0,
3929 'u-boot:size': 4,
3930
3931 'fit:image-pos': 4,
3932 'fit:offset': 4,
3933 'fit:size': 1840,
3934
Simon Glassb7bad182022-03-05 20:19:01 -07003935 'fit/images/kernel:image-pos': 304,
3936 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003937 'fit/images/kernel:size': 4,
3938
Simon Glassb7bad182022-03-05 20:19:01 -07003939 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003940 'fit/images/kernel/u-boot:offset': 0,
3941 'fit/images/kernel/u-boot:size': 4,
3942
Simon Glassb7bad182022-03-05 20:19:01 -07003943 'fit/images/fdt-1:image-pos': 552,
3944 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003945 'fit/images/fdt-1:size': 6,
3946
Simon Glassb7bad182022-03-05 20:19:01 -07003947 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003948 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3949 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3950
3951 'u-boot-nodtb:image-pos': 1844,
3952 'u-boot-nodtb:offset': 1844,
3953 'u-boot-nodtb:size': 46,
3954 }, props)
3955
3956 # Actually check the data is where we think it is
3957 for node, expected in [
3958 ("u-boot", U_BOOT_DATA),
3959 ("fit/images/kernel", U_BOOT_DATA),
3960 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3961 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3962 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3963 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3964 ]:
3965 image_pos = props[f"{node}:image-pos"]
3966 size = props[f"{node}:size"]
3967 self.assertEqual(len(expected), size)
3968 self.assertEqual(expected, data[image_pos:image_pos+size])
3969
Simon Glass45d556d2020-07-09 18:39:45 -06003970 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003971 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003972 data = self._DoReadFile('162_fit_external.dts')
3973 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3974
Simon Glass7932c882022-01-09 20:13:39 -07003975 # Size of the external-data region as set up by mkimage
3976 external_data_size = len(U_BOOT_DATA) + 2
3977 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003978 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003979 len(U_BOOT_NODTB_DATA))
3980
Simon Glass45d556d2020-07-09 18:39:45 -06003981 # The data should be outside the FIT
3982 dtb = fdt.Fdt.FromData(fit_data)
3983 dtb.Scan()
3984 fnode = dtb.GetNode('/images/kernel')
3985 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003986 self.assertEqual(len(U_BOOT_DATA),
3987 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3988 fit_pos = 0x400;
3989 self.assertEqual(
3990 fit_pos,
3991 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3992
3993 self.assertEquals(expected_size, len(data))
3994 actual_pos = len(U_BOOT_DATA) + fit_pos
3995 self.assertEqual(U_BOOT_DATA + b'aa',
3996 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003997
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003998 def testFitExternalImagePos(self):
3999 """Test that we have correct image-pos for external FIT subentries"""
4000 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4001 update_dtb=True)
4002 dtb = fdt.Fdt(out_dtb_fname)
4003 dtb.Scan()
4004 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4005
4006 self.assertEqual({
4007 'image-pos': 0,
4008 'offset': 0,
4009 'size': 1082,
4010
4011 'u-boot:image-pos': 0,
4012 'u-boot:offset': 0,
4013 'u-boot:size': 4,
4014
4015 'fit:size': 1032,
4016 'fit:offset': 4,
4017 'fit:image-pos': 4,
4018
4019 'fit/images/kernel:size': 4,
4020 'fit/images/kernel:offset': 1024,
4021 'fit/images/kernel:image-pos': 1028,
4022
4023 'fit/images/kernel/u-boot:size': 4,
4024 'fit/images/kernel/u-boot:offset': 0,
4025 'fit/images/kernel/u-boot:image-pos': 1028,
4026
4027 'fit/images/fdt-1:size': 2,
4028 'fit/images/fdt-1:offset': 1028,
4029 'fit/images/fdt-1:image-pos': 1032,
4030
4031 'fit/images/fdt-1/_testing:size': 2,
4032 'fit/images/fdt-1/_testing:offset': 0,
4033 'fit/images/fdt-1/_testing:image-pos': 1032,
4034
4035 'u-boot-nodtb:image-pos': 1036,
4036 'u-boot-nodtb:offset': 1036,
4037 'u-boot-nodtb:size': 46,
4038 }, props)
4039
4040 # Actually check the data is where we think it is
4041 for node, expected in [
4042 ("u-boot", U_BOOT_DATA),
4043 ("fit/images/kernel", U_BOOT_DATA),
4044 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4045 ("fit/images/fdt-1", b'aa'),
4046 ("fit/images/fdt-1/_testing", b'aa'),
4047 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4048 ]:
4049 image_pos = props[f"{node}:image-pos"]
4050 size = props[f"{node}:size"]
4051 self.assertEqual(len(expected), size)
4052 self.assertEqual(expected, data[image_pos:image_pos+size])
4053
Simon Glass66152ce2022-01-09 20:14:09 -07004054 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004055 """Test that binman complains if mkimage is missing"""
4056 with self.assertRaises(ValueError) as e:
4057 self._DoTestFile('162_fit_external.dts',
4058 force_missing_bintools='mkimage')
4059 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4060 str(e.exception))
4061
4062 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004063 """Test that binman still produces a FIT image if mkimage is missing"""
4064 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004065 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004066 force_missing_bintools='mkimage')
4067 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004068 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004069
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004070 def testSectionIgnoreHashSignature(self):
4071 """Test that sections ignore hash, signature nodes for its data"""
4072 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4073 expected = (U_BOOT_DATA + U_BOOT_DATA)
4074 self.assertEqual(expected, data)
4075
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004076 def testPadInSections(self):
4077 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004078 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4079 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004080 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4081 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004082 U_BOOT_DATA)
4083 self.assertEqual(expected, data)
4084
Simon Glassd12599d2020-10-26 17:40:09 -06004085 dtb = fdt.Fdt(out_dtb_fname)
4086 dtb.Scan()
4087 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4088 expected = {
4089 'image-pos': 0,
4090 'offset': 0,
4091 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4092
4093 'section:image-pos': 0,
4094 'section:offset': 0,
4095 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4096
4097 'section/before:image-pos': 0,
4098 'section/before:offset': 0,
4099 'section/before:size': len(U_BOOT_DATA),
4100
4101 'section/u-boot:image-pos': 4,
4102 'section/u-boot:offset': 4,
4103 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4104
4105 'section/after:image-pos': 26,
4106 'section/after:offset': 26,
4107 'section/after:size': len(U_BOOT_DATA),
4108 }
4109 self.assertEqual(expected, props)
4110
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004111 def testFitImageSubentryAlignment(self):
4112 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004113 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004114 entry_args = {
4115 'test-id': TEXT_DATA,
4116 }
4117 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4118 entry_args=entry_args)
4119 dtb = fdt.Fdt.FromData(data)
4120 dtb.Scan()
4121
4122 node = dtb.GetNode('/images/kernel')
4123 data = dtb.GetProps(node)["data"].bytes
4124 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004125 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4126 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004127 self.assertEqual(expected, data)
4128
4129 node = dtb.GetNode('/images/fdt-1')
4130 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004131 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4132 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004133 U_BOOT_DTB_DATA)
4134 self.assertEqual(expected, data)
4135
4136 def testFitExtblobMissingOk(self):
4137 """Test a FIT with a missing external blob that is allowed"""
4138 with test_util.capture_sys_output() as (stdout, stderr):
4139 self._DoTestFile('168_fit_missing_blob.dts',
4140 allow_missing=True)
4141 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004142 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004143
Simon Glass21db0ff2020-09-01 05:13:54 -06004144 def testBlobNamedByArgMissing(self):
4145 """Test handling of a missing entry arg"""
4146 with self.assertRaises(ValueError) as e:
4147 self._DoReadFile('068_blob_named_by_arg.dts')
4148 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4149 str(e.exception))
4150
Simon Glass559c4de2020-09-01 05:13:58 -06004151 def testPackBl31(self):
4152 """Test that an image with an ATF BL31 binary can be created"""
4153 data = self._DoReadFile('169_atf_bl31.dts')
4154 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4155
Samuel Holland9d8cc632020-10-21 21:12:15 -05004156 def testPackScp(self):
4157 """Test that an image with an SCP binary can be created"""
4158 data = self._DoReadFile('172_scp.dts')
4159 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4160
Simon Glassa435cd12020-09-01 05:13:59 -06004161 def testFitFdt(self):
4162 """Test an image with an FIT with multiple FDT images"""
4163 def _CheckFdt(seq, expected_data):
4164 """Check the FDT nodes
4165
4166 Args:
4167 seq: Sequence number to check (0 or 1)
4168 expected_data: Expected contents of 'data' property
4169 """
4170 name = 'fdt-%d' % seq
4171 fnode = dtb.GetNode('/images/%s' % name)
4172 self.assertIsNotNone(fnode)
4173 self.assertEqual({'description','type', 'compression', 'data'},
4174 set(fnode.props.keys()))
4175 self.assertEqual(expected_data, fnode.props['data'].bytes)
4176 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4177 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004178 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004179
4180 def _CheckConfig(seq, expected_data):
4181 """Check the configuration nodes
4182
4183 Args:
4184 seq: Sequence number to check (0 or 1)
4185 expected_data: Expected contents of 'data' property
4186 """
4187 cnode = dtb.GetNode('/configurations')
4188 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004189 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004190
4191 name = 'config-%d' % seq
4192 fnode = dtb.GetNode('/configurations/%s' % name)
4193 self.assertIsNotNone(fnode)
4194 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4195 set(fnode.props.keys()))
4196 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4197 fnode.props['description'].value)
4198 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4199
4200 entry_args = {
4201 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004202 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004203 }
4204 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004205 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004206 entry_args=entry_args,
4207 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4208 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4209 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4210
4211 dtb = fdt.Fdt.FromData(fit_data)
4212 dtb.Scan()
4213 fnode = dtb.GetNode('/images/kernel')
4214 self.assertIn('data', fnode.props)
4215
4216 # Check all the properties in fdt-1 and fdt-2
4217 _CheckFdt(1, TEST_FDT1_DATA)
4218 _CheckFdt(2, TEST_FDT2_DATA)
4219
4220 # Check configurations
4221 _CheckConfig(1, TEST_FDT1_DATA)
4222 _CheckConfig(2, TEST_FDT2_DATA)
4223
4224 def testFitFdtMissingList(self):
4225 """Test handling of a missing 'of-list' entry arg"""
4226 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004227 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004228 self.assertIn("Generator node requires 'of-list' entry argument",
4229 str(e.exception))
4230
4231 def testFitFdtEmptyList(self):
4232 """Test handling of an empty 'of-list' entry arg"""
4233 entry_args = {
4234 'of-list': '',
4235 }
4236 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4237
4238 def testFitFdtMissingProp(self):
4239 """Test handling of a missing 'fit,fdt-list' property"""
4240 with self.assertRaises(ValueError) as e:
4241 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4242 self.assertIn("Generator node requires 'fit,fdt-list' property",
4243 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004244
Simon Glass1032acc2020-09-06 10:39:08 -06004245 def testFitFdtMissing(self):
4246 """Test handling of a missing 'default-dt' entry arg"""
4247 entry_args = {
4248 'of-list': 'test-fdt1 test-fdt2',
4249 }
4250 with self.assertRaises(ValueError) as e:
4251 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004252 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004253 entry_args=entry_args,
4254 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4255 self.assertIn("Generated 'default' node requires default-dt entry argument",
4256 str(e.exception))
4257
4258 def testFitFdtNotInList(self):
4259 """Test handling of a default-dt that is not in the of-list"""
4260 entry_args = {
4261 'of-list': 'test-fdt1 test-fdt2',
4262 'default-dt': 'test-fdt3',
4263 }
4264 with self.assertRaises(ValueError) as e:
4265 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004266 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004267 entry_args=entry_args,
4268 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4269 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4270 str(e.exception))
4271
Simon Glassa820af72020-09-06 10:39:09 -06004272 def testFitExtblobMissingHelp(self):
4273 """Test display of help messages when an external blob is missing"""
4274 control.missing_blob_help = control._ReadMissingBlobHelp()
4275 control.missing_blob_help['wibble'] = 'Wibble test'
4276 control.missing_blob_help['another'] = 'Another test'
4277 with test_util.capture_sys_output() as (stdout, stderr):
4278 self._DoTestFile('168_fit_missing_blob.dts',
4279 allow_missing=True)
4280 err = stderr.getvalue()
4281
4282 # We can get the tag from the name, the type or the missing-msg
4283 # property. Check all three.
4284 self.assertIn('You may need to build ARM Trusted', err)
4285 self.assertIn('Wibble test', err)
4286 self.assertIn('Another test', err)
4287
Simon Glass6f1f4d42020-09-06 10:35:32 -06004288 def testMissingBlob(self):
4289 """Test handling of a blob containing a missing file"""
4290 with self.assertRaises(ValueError) as e:
4291 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4292 self.assertIn("Filename 'missing' not found in input path",
4293 str(e.exception))
4294
Simon Glassa0729502020-09-06 10:35:33 -06004295 def testEnvironment(self):
4296 """Test adding a U-Boot environment"""
4297 data = self._DoReadFile('174_env.dts')
4298 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4299 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4300 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4301 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4302 env)
4303
4304 def testEnvironmentNoSize(self):
4305 """Test that a missing 'size' property is detected"""
4306 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004307 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004308 self.assertIn("'u-boot-env' entry must have a size property",
4309 str(e.exception))
4310
4311 def testEnvironmentTooSmall(self):
4312 """Test handling of an environment that does not fit"""
4313 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004314 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004315
4316 # checksum, start byte, environment with \0 terminator, final \0
4317 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4318 short = need - 0x8
4319 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4320 str(e.exception))
4321
Simon Glassd1fdf752020-10-26 17:40:01 -06004322 def testSkipAtStart(self):
4323 """Test handling of skip-at-start section"""
4324 data = self._DoReadFile('177_skip_at_start.dts')
4325 self.assertEqual(U_BOOT_DATA, data)
4326
4327 image = control.images['image']
4328 entries = image.GetEntries()
4329 section = entries['section']
4330 self.assertEqual(0, section.offset)
4331 self.assertEqual(len(U_BOOT_DATA), section.size)
4332 self.assertEqual(U_BOOT_DATA, section.GetData())
4333
4334 entry = section.GetEntries()['u-boot']
4335 self.assertEqual(16, entry.offset)
4336 self.assertEqual(len(U_BOOT_DATA), entry.size)
4337 self.assertEqual(U_BOOT_DATA, entry.data)
4338
4339 def testSkipAtStartPad(self):
4340 """Test handling of skip-at-start section with padded entry"""
4341 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004342 before = tools.get_bytes(0, 8)
4343 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004344 all = before + U_BOOT_DATA + after
4345 self.assertEqual(all, data)
4346
4347 image = control.images['image']
4348 entries = image.GetEntries()
4349 section = entries['section']
4350 self.assertEqual(0, section.offset)
4351 self.assertEqual(len(all), section.size)
4352 self.assertEqual(all, section.GetData())
4353
4354 entry = section.GetEntries()['u-boot']
4355 self.assertEqual(16, entry.offset)
4356 self.assertEqual(len(all), entry.size)
4357 self.assertEqual(U_BOOT_DATA, entry.data)
4358
4359 def testSkipAtStartSectionPad(self):
4360 """Test handling of skip-at-start section with padding"""
4361 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004362 before = tools.get_bytes(0, 8)
4363 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004364 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004365 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004366
4367 image = control.images['image']
4368 entries = image.GetEntries()
4369 section = entries['section']
4370 self.assertEqual(0, section.offset)
4371 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004372 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004373 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004374
4375 entry = section.GetEntries()['u-boot']
4376 self.assertEqual(16, entry.offset)
4377 self.assertEqual(len(U_BOOT_DATA), entry.size)
4378 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004379
Simon Glassbb395742020-10-26 17:40:14 -06004380 def testSectionPad(self):
4381 """Testing padding with sections"""
4382 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004383 expected = (tools.get_bytes(ord('&'), 3) +
4384 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004385 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004386 tools.get_bytes(ord('!'), 1) +
4387 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004388 self.assertEqual(expected, data)
4389
4390 def testSectionAlign(self):
4391 """Testing alignment with sections"""
4392 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4393 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004394 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004395 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004396 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004397 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004398 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4399 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004400 self.assertEqual(expected, data)
4401
Simon Glassd92c8362020-10-26 17:40:25 -06004402 def testCompressImage(self):
4403 """Test compression of the entire image"""
4404 self._CheckLz4()
4405 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4406 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4407 dtb = fdt.Fdt(out_dtb_fname)
4408 dtb.Scan()
4409 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4410 'uncomp-size'])
4411 orig = self._decompress(data)
4412 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4413
4414 # Do a sanity check on various fields
4415 image = control.images['image']
4416 entries = image.GetEntries()
4417 self.assertEqual(2, len(entries))
4418
4419 entry = entries['blob']
4420 self.assertEqual(COMPRESS_DATA, entry.data)
4421 self.assertEqual(len(COMPRESS_DATA), entry.size)
4422
4423 entry = entries['u-boot']
4424 self.assertEqual(U_BOOT_DATA, entry.data)
4425 self.assertEqual(len(U_BOOT_DATA), entry.size)
4426
4427 self.assertEqual(len(data), image.size)
4428 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4429 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4430 orig = self._decompress(image.data)
4431 self.assertEqual(orig, image.uncomp_data)
4432
4433 expected = {
4434 'blob:offset': 0,
4435 'blob:size': len(COMPRESS_DATA),
4436 'u-boot:offset': len(COMPRESS_DATA),
4437 'u-boot:size': len(U_BOOT_DATA),
4438 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4439 'offset': 0,
4440 'image-pos': 0,
4441 'size': len(data),
4442 }
4443 self.assertEqual(expected, props)
4444
4445 def testCompressImageLess(self):
4446 """Test compression where compression reduces the image size"""
4447 self._CheckLz4()
4448 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4449 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4450 dtb = fdt.Fdt(out_dtb_fname)
4451 dtb.Scan()
4452 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4453 'uncomp-size'])
4454 orig = self._decompress(data)
4455
4456 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4457
4458 # Do a sanity check on various fields
4459 image = control.images['image']
4460 entries = image.GetEntries()
4461 self.assertEqual(2, len(entries))
4462
4463 entry = entries['blob']
4464 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4465 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4466
4467 entry = entries['u-boot']
4468 self.assertEqual(U_BOOT_DATA, entry.data)
4469 self.assertEqual(len(U_BOOT_DATA), entry.size)
4470
4471 self.assertEqual(len(data), image.size)
4472 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4473 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4474 image.uncomp_size)
4475 orig = self._decompress(image.data)
4476 self.assertEqual(orig, image.uncomp_data)
4477
4478 expected = {
4479 'blob:offset': 0,
4480 'blob:size': len(COMPRESS_DATA_BIG),
4481 'u-boot:offset': len(COMPRESS_DATA_BIG),
4482 'u-boot:size': len(U_BOOT_DATA),
4483 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4484 'offset': 0,
4485 'image-pos': 0,
4486 'size': len(data),
4487 }
4488 self.assertEqual(expected, props)
4489
4490 def testCompressSectionSize(self):
4491 """Test compression of a section with a fixed size"""
4492 self._CheckLz4()
4493 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4494 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4495 dtb = fdt.Fdt(out_dtb_fname)
4496 dtb.Scan()
4497 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4498 'uncomp-size'])
4499 orig = self._decompress(data)
4500 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4501 expected = {
4502 'section/blob:offset': 0,
4503 'section/blob:size': len(COMPRESS_DATA),
4504 'section/u-boot:offset': len(COMPRESS_DATA),
4505 'section/u-boot:size': len(U_BOOT_DATA),
4506 'section:offset': 0,
4507 'section:image-pos': 0,
4508 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4509 'section:size': 0x30,
4510 'offset': 0,
4511 'image-pos': 0,
4512 'size': 0x30,
4513 }
4514 self.assertEqual(expected, props)
4515
4516 def testCompressSection(self):
4517 """Test compression of a section with no fixed size"""
4518 self._CheckLz4()
4519 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4520 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4521 dtb = fdt.Fdt(out_dtb_fname)
4522 dtb.Scan()
4523 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4524 'uncomp-size'])
4525 orig = self._decompress(data)
4526 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4527 expected = {
4528 'section/blob:offset': 0,
4529 'section/blob:size': len(COMPRESS_DATA),
4530 'section/u-boot:offset': len(COMPRESS_DATA),
4531 'section/u-boot:size': len(U_BOOT_DATA),
4532 'section:offset': 0,
4533 'section:image-pos': 0,
4534 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4535 'section:size': len(data),
4536 'offset': 0,
4537 'image-pos': 0,
4538 'size': len(data),
4539 }
4540 self.assertEqual(expected, props)
4541
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004542 def testLz4Missing(self):
4543 """Test that binman still produces an image if lz4 is missing"""
4544 with test_util.capture_sys_output() as (_, stderr):
4545 self._DoTestFile('185_compress_section.dts',
4546 force_missing_bintools='lz4')
4547 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004548 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004549
Simon Glassd92c8362020-10-26 17:40:25 -06004550 def testCompressExtra(self):
4551 """Test compression of a section with no fixed size"""
4552 self._CheckLz4()
4553 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4554 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4555 dtb = fdt.Fdt(out_dtb_fname)
4556 dtb.Scan()
4557 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4558 'uncomp-size'])
4559
4560 base = data[len(U_BOOT_DATA):]
4561 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4562 rest = base[len(U_BOOT_DATA):]
4563
4564 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004565 bintool = self.comp_bintools['lz4']
4566 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004567 data1 = rest[:len(expect1)]
4568 section1 = self._decompress(data1)
4569 self.assertEquals(expect1, data1)
Simon Glassd92c8362020-10-26 17:40:25 -06004570 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4571 rest1 = rest[len(expect1):]
4572
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004573 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004574 data2 = rest1[:len(expect2)]
4575 section2 = self._decompress(data2)
4576 self.assertEquals(expect2, data2)
Simon Glassd92c8362020-10-26 17:40:25 -06004577 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4578 rest2 = rest1[len(expect2):]
4579
4580 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4581 len(expect2) + len(U_BOOT_DATA))
4582 #self.assertEquals(expect_size, len(data))
4583
4584 #self.assertEquals(U_BOOT_DATA, rest2)
4585
4586 self.maxDiff = None
4587 expected = {
4588 'u-boot:offset': 0,
4589 'u-boot:image-pos': 0,
4590 'u-boot:size': len(U_BOOT_DATA),
4591
4592 'base:offset': len(U_BOOT_DATA),
4593 'base:image-pos': len(U_BOOT_DATA),
4594 'base:size': len(data) - len(U_BOOT_DATA),
4595 'base/u-boot:offset': 0,
4596 'base/u-boot:image-pos': len(U_BOOT_DATA),
4597 'base/u-boot:size': len(U_BOOT_DATA),
4598 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4599 len(expect2),
4600 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4601 len(expect2),
4602 'base/u-boot2:size': len(U_BOOT_DATA),
4603
4604 'base/section:offset': len(U_BOOT_DATA),
4605 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4606 'base/section:size': len(expect1),
4607 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4608 'base/section/blob:offset': 0,
4609 'base/section/blob:size': len(COMPRESS_DATA),
4610 'base/section/u-boot:offset': len(COMPRESS_DATA),
4611 'base/section/u-boot:size': len(U_BOOT_DATA),
4612
4613 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4614 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4615 'base/section2:size': len(expect2),
4616 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4617 'base/section2/blob:offset': 0,
4618 'base/section2/blob:size': len(COMPRESS_DATA),
4619 'base/section2/blob2:offset': len(COMPRESS_DATA),
4620 'base/section2/blob2:size': len(COMPRESS_DATA),
4621
4622 'offset': 0,
4623 'image-pos': 0,
4624 'size': len(data),
4625 }
4626 self.assertEqual(expected, props)
4627
Simon Glassecbe4732021-01-06 21:35:15 -07004628 def testSymbolsSubsection(self):
4629 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004630 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004631
Simon Glass3fb25402021-01-06 21:35:16 -07004632 def testReadImageEntryArg(self):
4633 """Test reading an image that would need an entry arg to generate"""
4634 entry_args = {
4635 'cros-ec-rw-path': 'ecrw.bin',
4636 }
4637 data = self.data = self._DoReadFileDtb(
4638 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4639 entry_args=entry_args)
4640
Simon Glass80025522022-01-29 14:14:04 -07004641 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004642 orig_image = control.images['image']
4643
4644 # This should not generate an error about the missing 'cros-ec-rw-path'
4645 # since we are reading the image from a file. Compare with
4646 # testEntryArgsRequired()
4647 image = Image.FromFile(image_fname)
4648 self.assertEqual(orig_image.GetEntries().keys(),
4649 image.GetEntries().keys())
4650
Simon Glassa2af7302021-01-06 21:35:18 -07004651 def testFilesAlign(self):
4652 """Test alignment with files"""
4653 data = self._DoReadFile('190_files_align.dts')
4654
4655 # The first string is 15 bytes so will align to 16
4656 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4657 self.assertEqual(expect, data)
4658
Simon Glassdb84b562021-01-06 21:35:19 -07004659 def testReadImageSkip(self):
4660 """Test reading an image and accessing its FDT map"""
4661 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004662 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004663 orig_image = control.images['image']
4664 image = Image.FromFile(image_fname)
4665 self.assertEqual(orig_image.GetEntries().keys(),
4666 image.GetEntries().keys())
4667
4668 orig_entry = orig_image.GetEntries()['fdtmap']
4669 entry = image.GetEntries()['fdtmap']
4670 self.assertEqual(orig_entry.offset, entry.offset)
4671 self.assertEqual(orig_entry.size, entry.size)
4672 self.assertEqual(16, entry.image_pos)
4673
4674 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4675
4676 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4677
Simon Glassc98de972021-03-18 20:24:57 +13004678 def testTplNoDtb(self):
4679 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004680 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004681 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4682 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4683 data[:len(U_BOOT_TPL_NODTB_DATA)])
4684
Simon Glass63f41d42021-03-18 20:24:58 +13004685 def testTplBssPad(self):
4686 """Test that we can pad TPL's BSS with zeros"""
4687 # ELF file with a '__bss_size' symbol
4688 self._SetupTplElf()
4689 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004690 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004691 data)
4692
4693 def testTplBssPadMissing(self):
4694 """Test that a missing symbol is detected"""
4695 self._SetupTplElf('u_boot_ucode_ptr')
4696 with self.assertRaises(ValueError) as e:
4697 self._DoReadFile('193_tpl_bss_pad.dts')
4698 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4699 str(e.exception))
4700
Simon Glass718b5292021-03-18 20:25:07 +13004701 def checkDtbSizes(self, data, pad_len, start):
4702 """Check the size arguments in a dtb embedded in an image
4703
4704 Args:
4705 data: The image data
4706 pad_len: Length of the pad section in the image, in bytes
4707 start: Start offset of the devicetree to examine, within the image
4708
4709 Returns:
4710 Size of the devicetree in bytes
4711 """
4712 dtb_data = data[start:]
4713 dtb = fdt.Fdt.FromData(dtb_data)
4714 fdt_size = dtb.GetFdtObj().totalsize()
4715 dtb.Scan()
4716 props = self._GetPropTree(dtb, 'size')
4717 self.assertEqual({
4718 'size': len(data),
4719 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4720 'u-boot-spl/u-boot-spl-dtb:size': 801,
4721 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4722 'u-boot-spl:size': 860,
4723 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4724 'u-boot/u-boot-dtb:size': 781,
4725 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4726 'u-boot:size': 827,
4727 }, props)
4728 return fdt_size
4729
4730 def testExpanded(self):
4731 """Test that an expanded entry type is selected when needed"""
4732 self._SetupSplElf()
4733 self._SetupTplElf()
4734
4735 # SPL has a devicetree, TPL does not
4736 entry_args = {
4737 'spl-dtb': '1',
4738 'spl-bss-pad': 'y',
4739 'tpl-dtb': '',
4740 }
4741 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4742 entry_args=entry_args)
4743 image = control.images['image']
4744 entries = image.GetEntries()
4745 self.assertEqual(3, len(entries))
4746
4747 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4748 self.assertIn('u-boot', entries)
4749 entry = entries['u-boot']
4750 self.assertEqual('u-boot-expanded', entry.etype)
4751 subent = entry.GetEntries()
4752 self.assertEqual(2, len(subent))
4753 self.assertIn('u-boot-nodtb', subent)
4754 self.assertIn('u-boot-dtb', subent)
4755
4756 # Second, u-boot-spl, which should be expanded into three parts
4757 self.assertIn('u-boot-spl', entries)
4758 entry = entries['u-boot-spl']
4759 self.assertEqual('u-boot-spl-expanded', entry.etype)
4760 subent = entry.GetEntries()
4761 self.assertEqual(3, len(subent))
4762 self.assertIn('u-boot-spl-nodtb', subent)
4763 self.assertIn('u-boot-spl-bss-pad', subent)
4764 self.assertIn('u-boot-spl-dtb', subent)
4765
4766 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4767 # devicetree
4768 self.assertIn('u-boot-tpl', entries)
4769 entry = entries['u-boot-tpl']
4770 self.assertEqual('u-boot-tpl', entry.etype)
4771 self.assertEqual(None, entry.GetEntries())
4772
4773 def testExpandedTpl(self):
4774 """Test that an expanded entry type is selected for TPL when needed"""
4775 self._SetupTplElf()
4776
4777 entry_args = {
4778 'tpl-bss-pad': 'y',
4779 'tpl-dtb': 'y',
4780 }
4781 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4782 entry_args=entry_args)
4783 image = control.images['image']
4784 entries = image.GetEntries()
4785 self.assertEqual(1, len(entries))
4786
4787 # We only have u-boot-tpl, which be expanded
4788 self.assertIn('u-boot-tpl', entries)
4789 entry = entries['u-boot-tpl']
4790 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4791 subent = entry.GetEntries()
4792 self.assertEqual(3, len(subent))
4793 self.assertIn('u-boot-tpl-nodtb', subent)
4794 self.assertIn('u-boot-tpl-bss-pad', subent)
4795 self.assertIn('u-boot-tpl-dtb', subent)
4796
4797 def testExpandedNoPad(self):
4798 """Test an expanded entry without BSS pad enabled"""
4799 self._SetupSplElf()
4800 self._SetupTplElf()
4801
4802 # SPL has a devicetree, TPL does not
4803 entry_args = {
4804 'spl-dtb': 'something',
4805 'spl-bss-pad': 'n',
4806 'tpl-dtb': '',
4807 }
4808 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4809 entry_args=entry_args)
4810 image = control.images['image']
4811 entries = image.GetEntries()
4812
4813 # Just check u-boot-spl, which should be expanded into two parts
4814 self.assertIn('u-boot-spl', entries)
4815 entry = entries['u-boot-spl']
4816 self.assertEqual('u-boot-spl-expanded', entry.etype)
4817 subent = entry.GetEntries()
4818 self.assertEqual(2, len(subent))
4819 self.assertIn('u-boot-spl-nodtb', subent)
4820 self.assertIn('u-boot-spl-dtb', subent)
4821
4822 def testExpandedTplNoPad(self):
4823 """Test that an expanded entry type with padding disabled in TPL"""
4824 self._SetupTplElf()
4825
4826 entry_args = {
4827 'tpl-bss-pad': '',
4828 'tpl-dtb': 'y',
4829 }
4830 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4831 entry_args=entry_args)
4832 image = control.images['image']
4833 entries = image.GetEntries()
4834 self.assertEqual(1, len(entries))
4835
4836 # We only have u-boot-tpl, which be expanded
4837 self.assertIn('u-boot-tpl', entries)
4838 entry = entries['u-boot-tpl']
4839 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4840 subent = entry.GetEntries()
4841 self.assertEqual(2, len(subent))
4842 self.assertIn('u-boot-tpl-nodtb', subent)
4843 self.assertIn('u-boot-tpl-dtb', subent)
4844
4845 def testFdtInclude(self):
4846 """Test that an Fdt is update within all binaries"""
4847 self._SetupSplElf()
4848 self._SetupTplElf()
4849
4850 # SPL has a devicetree, TPL does not
4851 self.maxDiff = None
4852 entry_args = {
4853 'spl-dtb': '1',
4854 'spl-bss-pad': 'y',
4855 'tpl-dtb': '',
4856 }
4857 # Build the image. It includes two separate devicetree binaries, each
4858 # with their own contents, but all contain the binman definition.
4859 data = self._DoReadFileDtb(
4860 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4861 update_dtb=True, entry_args=entry_args)[0]
4862 pad_len = 10
4863
4864 # Check the U-Boot dtb
4865 start = len(U_BOOT_NODTB_DATA)
4866 fdt_size = self.checkDtbSizes(data, pad_len, start)
4867
4868 # Now check SPL
4869 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4870 fdt_size = self.checkDtbSizes(data, pad_len, start)
4871
4872 # TPL has no devicetree
4873 start += fdt_size + len(U_BOOT_TPL_DATA)
4874 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004875
Simon Glass7098b7f2021-03-21 18:24:30 +13004876 def testSymbolsExpanded(self):
4877 """Test binman can assign symbols in expanded entries"""
4878 entry_args = {
4879 'spl-dtb': '1',
4880 }
4881 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4882 U_BOOT_SPL_DTB_DATA, 0x38,
4883 entry_args=entry_args, use_expanded=True)
4884
Simon Glasse1915782021-03-21 18:24:31 +13004885 def testCollection(self):
4886 """Test a collection"""
4887 data = self._DoReadFile('198_collection.dts')
4888 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004889 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4890 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004891 data)
4892
Simon Glass27a7f772021-03-21 18:24:32 +13004893 def testCollectionSection(self):
4894 """Test a collection where a section must be built first"""
4895 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004896 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004897 # building the contents, producing an error is anything is still
4898 # missing.
4899 data = self._DoReadFile('199_collection_section.dts')
4900 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004901 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4902 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004903 data)
4904
Simon Glassf427c5f2021-03-21 18:24:33 +13004905 def testAlignDefault(self):
4906 """Test that default alignment works on sections"""
4907 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004908 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004909 U_BOOT_DATA)
4910 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004911 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004912 # No alignment within the nested section
4913 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4914 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004915 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004916 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004917
Bin Mengc0b15742021-05-10 20:23:33 +08004918 def testPackOpenSBI(self):
4919 """Test that an image with an OpenSBI binary can be created"""
4920 data = self._DoReadFile('201_opensbi.dts')
4921 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4922
Simon Glass76f496d2021-07-06 10:36:37 -06004923 def testSectionsSingleThread(self):
4924 """Test sections without multithreading"""
4925 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004926 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4927 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4928 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004929 self.assertEqual(expected, data)
4930
4931 def testThreadTimeout(self):
4932 """Test handling a thread that takes too long"""
4933 with self.assertRaises(ValueError) as e:
4934 self._DoTestFile('202_section_timeout.dts',
4935 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004936 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004937
Simon Glass748a1d42021-07-06 10:36:41 -06004938 def testTiming(self):
4939 """Test output of timing information"""
4940 data = self._DoReadFile('055_sections.dts')
4941 with test_util.capture_sys_output() as (stdout, stderr):
4942 state.TimingShow()
4943 self.assertIn('read:', stdout.getvalue())
4944 self.assertIn('compress:', stdout.getvalue())
4945
Simon Glassadfb8492021-11-03 21:09:18 -06004946 def testUpdateFdtInElf(self):
4947 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004948 if not elf.ELF_TOOLS:
4949 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004950 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4951 outfile = os.path.join(self._indir, 'u-boot.out')
4952 begin_sym = 'dtb_embed_begin'
4953 end_sym = 'dtb_embed_end'
4954 retcode = self._DoTestFile(
4955 '060_fdt_update.dts', update_dtb=True,
4956 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4957 self.assertEqual(0, retcode)
4958
4959 # Check that the output file does in fact contact a dtb with the binman
4960 # definition in the correct place
4961 syms = elf.GetSymbolFileOffset(infile,
4962 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004963 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004964 dtb_data = data[syms['dtb_embed_begin'].offset:
4965 syms['dtb_embed_end'].offset]
4966
4967 dtb = fdt.Fdt.FromData(dtb_data)
4968 dtb.Scan()
4969 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4970 self.assertEqual({
4971 'image-pos': 0,
4972 'offset': 0,
4973 '_testing:offset': 32,
4974 '_testing:size': 2,
4975 '_testing:image-pos': 32,
4976 'section@0/u-boot:offset': 0,
4977 'section@0/u-boot:size': len(U_BOOT_DATA),
4978 'section@0/u-boot:image-pos': 0,
4979 'section@0:offset': 0,
4980 'section@0:size': 16,
4981 'section@0:image-pos': 0,
4982
4983 'section@1/u-boot:offset': 0,
4984 'section@1/u-boot:size': len(U_BOOT_DATA),
4985 'section@1/u-boot:image-pos': 16,
4986 'section@1:offset': 16,
4987 'section@1:size': 16,
4988 'section@1:image-pos': 16,
4989 'size': 40
4990 }, props)
4991
4992 def testUpdateFdtInElfInvalid(self):
4993 """Test that invalid args are detected with --update-fdt-in-elf"""
4994 with self.assertRaises(ValueError) as e:
4995 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4996 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4997 str(e.exception))
4998
4999 def testUpdateFdtInElfNoSyms(self):
5000 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005001 if not elf.ELF_TOOLS:
5002 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005003 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5004 outfile = ''
5005 begin_sym = 'wrong_begin'
5006 end_sym = 'wrong_end'
5007 with self.assertRaises(ValueError) as e:
5008 self._DoTestFile(
5009 '060_fdt_update.dts',
5010 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5011 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5012 str(e.exception))
5013
5014 def testUpdateFdtInElfTooSmall(self):
5015 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005016 if not elf.ELF_TOOLS:
5017 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005018 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5019 outfile = os.path.join(self._indir, 'u-boot.out')
5020 begin_sym = 'dtb_embed_begin'
5021 end_sym = 'dtb_embed_end'
5022 with self.assertRaises(ValueError) as e:
5023 self._DoTestFile(
5024 '060_fdt_update.dts', update_dtb=True,
5025 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5026 self.assertRegex(
5027 str(e.exception),
5028 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5029
Simon Glass88e04da2021-11-23 11:03:42 -07005030 def testVersion(self):
5031 """Test we can get the binman version"""
5032 version = '(unreleased)'
5033 self.assertEqual(version, state.GetVersion(self._indir))
5034
5035 with self.assertRaises(SystemExit):
5036 with test_util.capture_sys_output() as (_, stderr):
5037 self._DoBinman('-V')
5038 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5039
5040 # Try running the tool too, just to be safe
5041 result = self._RunBinman('-V')
5042 self.assertEqual('Binman %s\n' % version, result.stderr)
5043
5044 # Set up a version file to make sure that works
5045 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005046 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005047 binary=False)
5048 self.assertEqual(version, state.GetVersion(self._indir))
5049
Simon Glass637958f2021-11-23 21:09:50 -07005050 def testAltFormat(self):
5051 """Test that alternative formats can be used to extract"""
5052 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5053
5054 try:
5055 tmpdir, updated_fname = self._SetupImageInTmpdir()
5056 with test_util.capture_sys_output() as (stdout, _):
5057 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5058 self.assertEqual(
5059 '''Flag (-F) Entry type Description
5060fdt fdtmap Extract the devicetree blob from the fdtmap
5061''',
5062 stdout.getvalue())
5063
5064 dtb = os.path.join(tmpdir, 'fdt.dtb')
5065 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5066 dtb, 'fdtmap')
5067
5068 # Check that we can read it and it can be scanning, meaning it does
5069 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005070 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005071 dtb = fdt.Fdt.FromData(data)
5072 dtb.Scan()
5073
5074 # Now check u-boot which has no alt_format
5075 fname = os.path.join(tmpdir, 'fdt.dtb')
5076 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5077 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005078 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005079 self.assertEqual(U_BOOT_DATA, data)
5080
5081 finally:
5082 shutil.rmtree(tmpdir)
5083
Simon Glass0b00ae62021-11-23 21:09:52 -07005084 def testExtblobList(self):
5085 """Test an image with an external blob list"""
5086 data = self._DoReadFile('215_blob_ext_list.dts')
5087 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5088
5089 def testExtblobListMissing(self):
5090 """Test an image with a missing external blob"""
5091 with self.assertRaises(ValueError) as e:
5092 self._DoReadFile('216_blob_ext_list_missing.dts')
5093 self.assertIn("Filename 'missing-file' not found in input path",
5094 str(e.exception))
5095
5096 def testExtblobListMissingOk(self):
5097 """Test an image with an missing external blob that is allowed"""
5098 with test_util.capture_sys_output() as (stdout, stderr):
5099 self._DoTestFile('216_blob_ext_list_missing.dts',
5100 allow_missing=True)
5101 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005102 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005103
Simon Glass3efb2972021-11-23 21:08:59 -07005104 def testFip(self):
5105 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5106 data = self._DoReadFile('203_fip.dts')
5107 hdr, fents = fip_util.decode_fip(data)
5108 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5109 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5110 self.assertEqual(0x123, hdr.flags)
5111
5112 self.assertEqual(2, len(fents))
5113
5114 fent = fents[0]
5115 self.assertEqual(
5116 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5117 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5118 self.assertEqual('soc-fw', fent.fip_type)
5119 self.assertEqual(0x88, fent.offset)
5120 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5121 self.assertEqual(0x123456789abcdef, fent.flags)
5122 self.assertEqual(ATF_BL31_DATA, fent.data)
5123 self.assertEqual(True, fent.valid)
5124
5125 fent = fents[1]
5126 self.assertEqual(
5127 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5128 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5129 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5130 self.assertEqual(0x8c, fent.offset)
5131 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5132 self.assertEqual(0, fent.flags)
5133 self.assertEqual(ATF_BL2U_DATA, fent.data)
5134 self.assertEqual(True, fent.valid)
5135
5136 def testFipOther(self):
5137 """Basic FIP with something that isn't a external blob"""
5138 data = self._DoReadFile('204_fip_other.dts')
5139 hdr, fents = fip_util.decode_fip(data)
5140
5141 self.assertEqual(2, len(fents))
5142 fent = fents[1]
5143 self.assertEqual('rot-cert', fent.fip_type)
5144 self.assertEqual(b'aa', fent.data)
5145
Simon Glass3efb2972021-11-23 21:08:59 -07005146 def testFipNoType(self):
5147 """FIP with an entry of an unknown type"""
5148 with self.assertRaises(ValueError) as e:
5149 self._DoReadFile('205_fip_no_type.dts')
5150 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5151 str(e.exception))
5152
5153 def testFipUuid(self):
5154 """Basic FIP with a manual uuid"""
5155 data = self._DoReadFile('206_fip_uuid.dts')
5156 hdr, fents = fip_util.decode_fip(data)
5157
5158 self.assertEqual(2, len(fents))
5159 fent = fents[1]
5160 self.assertEqual(None, fent.fip_type)
5161 self.assertEqual(
5162 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5163 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5164 fent.uuid)
5165 self.assertEqual(U_BOOT_DATA, fent.data)
5166
5167 def testFipLs(self):
5168 """Test listing a FIP"""
5169 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5170 hdr, fents = fip_util.decode_fip(data)
5171
5172 try:
5173 tmpdir, updated_fname = self._SetupImageInTmpdir()
5174 with test_util.capture_sys_output() as (stdout, stderr):
5175 self._DoBinman('ls', '-i', updated_fname)
5176 finally:
5177 shutil.rmtree(tmpdir)
5178 lines = stdout.getvalue().splitlines()
5179 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005180'Name Image-pos Size Entry-type Offset Uncomp-size',
5181'--------------------------------------------------------------',
5182'image 0 2d3 section 0',
5183' atf-fip 0 90 atf-fip 0',
5184' soc-fw 88 4 blob-ext 88',
5185' u-boot 8c 4 u-boot 8c',
5186' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005187]
5188 self.assertEqual(expected, lines)
5189
5190 image = control.images['image']
5191 entries = image.GetEntries()
5192 fdtmap = entries['fdtmap']
5193
5194 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5195 magic = fdtmap_data[:8]
5196 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005197 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005198
5199 fdt_data = fdtmap_data[16:]
5200 dtb = fdt.Fdt.FromData(fdt_data)
5201 dtb.Scan()
5202 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5203 self.assertEqual({
5204 'atf-fip/soc-fw:image-pos': 136,
5205 'atf-fip/soc-fw:offset': 136,
5206 'atf-fip/soc-fw:size': 4,
5207 'atf-fip/u-boot:image-pos': 140,
5208 'atf-fip/u-boot:offset': 140,
5209 'atf-fip/u-boot:size': 4,
5210 'atf-fip:image-pos': 0,
5211 'atf-fip:offset': 0,
5212 'atf-fip:size': 144,
5213 'image-pos': 0,
5214 'offset': 0,
5215 'fdtmap:image-pos': fdtmap.image_pos,
5216 'fdtmap:offset': fdtmap.offset,
5217 'fdtmap:size': len(fdtmap_data),
5218 'size': len(data),
5219 }, props)
5220
5221 def testFipExtractOneEntry(self):
5222 """Test extracting a single entry fron an FIP"""
5223 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005224 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005225 fname = os.path.join(self._indir, 'output.extact')
5226 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005227 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005228 self.assertEqual(U_BOOT_DATA, data)
5229
5230 def testFipReplace(self):
5231 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005232 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005233 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005234 updated_fname = tools.get_output_filename('image-updated.bin')
5235 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005236 entry_name = 'atf-fip/u-boot'
5237 control.WriteEntry(updated_fname, entry_name, expected,
5238 allow_resize=True)
5239 actual = control.ReadEntry(updated_fname, entry_name)
5240 self.assertEqual(expected, actual)
5241
Simon Glass80025522022-01-29 14:14:04 -07005242 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005243 hdr, fents = fip_util.decode_fip(new_data)
5244
5245 self.assertEqual(2, len(fents))
5246
5247 # Check that the FIP entry is updated
5248 fent = fents[1]
5249 self.assertEqual(0x8c, fent.offset)
5250 self.assertEqual(len(expected), fent.size)
5251 self.assertEqual(0, fent.flags)
5252 self.assertEqual(expected, fent.data)
5253 self.assertEqual(True, fent.valid)
5254
5255 def testFipMissing(self):
5256 with test_util.capture_sys_output() as (stdout, stderr):
5257 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5258 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005259 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005260
5261 def testFipSize(self):
5262 """Test a FIP with a size property"""
5263 data = self._DoReadFile('210_fip_size.dts')
5264 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5265 hdr, fents = fip_util.decode_fip(data)
5266 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5267 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5268
5269 self.assertEqual(1, len(fents))
5270
5271 fent = fents[0]
5272 self.assertEqual('soc-fw', fent.fip_type)
5273 self.assertEqual(0x60, fent.offset)
5274 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5275 self.assertEqual(ATF_BL31_DATA, fent.data)
5276 self.assertEqual(True, fent.valid)
5277
5278 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005279 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005280
5281 def testFipBadAlign(self):
5282 """Test that an invalid alignment value in a FIP is detected"""
5283 with self.assertRaises(ValueError) as e:
5284 self._DoTestFile('211_fip_bad_align.dts')
5285 self.assertIn(
5286 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5287 str(e.exception))
5288
5289 def testFipCollection(self):
5290 """Test using a FIP in a collection"""
5291 data = self._DoReadFile('212_fip_collection.dts')
5292 entry1 = control.images['image'].GetEntries()['collection']
5293 data1 = data[:entry1.size]
5294 hdr1, fents2 = fip_util.decode_fip(data1)
5295
5296 entry2 = control.images['image'].GetEntries()['atf-fip']
5297 data2 = data[entry2.offset:entry2.offset + entry2.size]
5298 hdr1, fents2 = fip_util.decode_fip(data2)
5299
5300 # The 'collection' entry should have U-Boot included at the end
5301 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5302 self.assertEqual(data1, data2 + U_BOOT_DATA)
5303 self.assertEqual(U_BOOT_DATA, data1[-4:])
5304
5305 # There should be a U-Boot after the final FIP
5306 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005307
Simon Glassccae6862022-01-12 13:10:35 -07005308 def testFakeBlob(self):
5309 """Test handling of faking an external blob"""
5310 with test_util.capture_sys_output() as (stdout, stderr):
5311 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5312 allow_fake_blobs=True)
5313 err = stderr.getvalue()
5314 self.assertRegex(
5315 err,
5316 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005317
Simon Glassceb5f912022-01-09 20:13:46 -07005318 def testExtblobListFaked(self):
5319 """Test an extblob with missing external blob that are faked"""
5320 with test_util.capture_sys_output() as (stdout, stderr):
5321 self._DoTestFile('216_blob_ext_list_missing.dts',
5322 allow_fake_blobs=True)
5323 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005324 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005325
Simon Glass162017b2022-01-09 20:13:57 -07005326 def testListBintools(self):
5327 args = ['tool', '--list']
5328 with test_util.capture_sys_output() as (stdout, _):
5329 self._DoBinman(*args)
5330 out = stdout.getvalue().splitlines()
5331 self.assertTrue(len(out) >= 2)
5332
5333 def testFetchBintools(self):
5334 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005335 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005336 raise urllib.error.URLError('my error')
5337
5338 args = ['tool']
5339 with self.assertRaises(ValueError) as e:
5340 self._DoBinman(*args)
5341 self.assertIn("Invalid arguments to 'tool' subcommand",
5342 str(e.exception))
5343
5344 args = ['tool', '--fetch']
5345 with self.assertRaises(ValueError) as e:
5346 self._DoBinman(*args)
5347 self.assertIn('Please specify bintools to fetch', str(e.exception))
5348
5349 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005350 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005351 side_effect=fail_download):
5352 with test_util.capture_sys_output() as (stdout, _):
5353 self._DoBinman(*args)
5354 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5355
Simon Glass620c4462022-01-09 20:14:11 -07005356 def testBintoolDocs(self):
5357 """Test for creation of bintool documentation"""
5358 with test_util.capture_sys_output() as (stdout, stderr):
5359 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5360 self.assertTrue(len(stdout.getvalue()) > 0)
5361
5362 def testBintoolDocsMissing(self):
5363 """Test handling of missing bintool documentation"""
5364 with self.assertRaises(ValueError) as e:
5365 with test_util.capture_sys_output() as (stdout, stderr):
5366 control.write_bintool_docs(
5367 control.bintool.Bintool.get_tool_list(), 'mkimage')
5368 self.assertIn('Documentation is missing for modules: mkimage',
5369 str(e.exception))
5370
Jan Kiszka58c407f2022-01-28 20:37:53 +01005371 def testListWithGenNode(self):
5372 """Check handling of an FDT map when the section cannot be found"""
5373 entry_args = {
5374 'of-list': 'test-fdt1 test-fdt2',
5375 }
5376 data = self._DoReadFileDtb(
5377 '219_fit_gennode.dts',
5378 entry_args=entry_args,
5379 use_real_dtb=True,
5380 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5381
5382 try:
5383 tmpdir, updated_fname = self._SetupImageInTmpdir()
5384 with test_util.capture_sys_output() as (stdout, stderr):
5385 self._RunBinman('ls', '-i', updated_fname)
5386 finally:
5387 shutil.rmtree(tmpdir)
5388
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005389 def testFitSubentryUsesBintool(self):
5390 """Test that binman FIT subentries can use bintools"""
5391 command.test_result = self._HandleGbbCommand
5392 entry_args = {
5393 'keydir': 'devkeys',
5394 'bmpblk': 'bmpblk.bin',
5395 }
5396 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5397 entry_args=entry_args)
5398
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005399 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5400 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005401 self.assertIn(expected, data)
5402
5403 def testFitSubentryMissingBintool(self):
5404 """Test that binman reports missing bintools for FIT subentries"""
5405 entry_args = {
5406 'keydir': 'devkeys',
5407 }
5408 with test_util.capture_sys_output() as (_, stderr):
5409 self._DoTestFile('220_fit_subentry_bintool.dts',
5410 force_missing_bintools='futility', entry_args=entry_args)
5411 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005412 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005413
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005414 def testFitSubentryHashSubnode(self):
5415 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005416 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005417 data, _, _, out_dtb_name = self._DoReadFileDtb(
5418 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5419
5420 mkimage_dtb = fdt.Fdt.FromData(data)
5421 mkimage_dtb.Scan()
5422 binman_dtb = fdt.Fdt(out_dtb_name)
5423 binman_dtb.Scan()
5424
5425 # Check that binman didn't add hash values
5426 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5427 self.assertNotIn('value', fnode.props)
5428
5429 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5430 self.assertNotIn('value', fnode.props)
5431
5432 # Check that mkimage added hash values
5433 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5434 self.assertIn('value', fnode.props)
5435
5436 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5437 self.assertIn('value', fnode.props)
5438
Roger Quadros5cdcea02022-02-19 20:50:04 +02005439 def testPackTeeOs(self):
5440 """Test that an image with an TEE binary can be created"""
5441 data = self._DoReadFile('222_tee_os.dts')
5442 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5443
Simon Glass912339f2022-02-08 11:50:03 -07005444 def testFitFdtOper(self):
5445 """Check handling of a specified FIT operation"""
5446 entry_args = {
5447 'of-list': 'test-fdt1 test-fdt2',
5448 'default-dt': 'test-fdt2',
5449 }
5450 self._DoReadFileDtb(
5451 '223_fit_fdt_oper.dts',
5452 entry_args=entry_args,
5453 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5454
5455 def testFitFdtBadOper(self):
5456 """Check handling of an FDT map when the section cannot be found"""
5457 with self.assertRaises(ValueError) as exc:
5458 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005459 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005460 str(exc.exception))
5461
Simon Glassdd156a42022-03-05 20:18:59 -07005462 def test_uses_expand_size(self):
5463 """Test that the 'expand-size' property cannot be used anymore"""
5464 with self.assertRaises(ValueError) as e:
5465 data = self._DoReadFile('225_expand_size_bad.dts')
5466 self.assertIn(
5467 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5468 str(e.exception))
5469
Simon Glass5f423422022-03-05 20:19:12 -07005470 def testFitSplitElf(self):
5471 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005472 if not elf.ELF_TOOLS:
5473 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005474 entry_args = {
5475 'of-list': 'test-fdt1 test-fdt2',
5476 'default-dt': 'test-fdt2',
5477 'atf-bl31-path': 'bl31.elf',
5478 'tee-os-path': 'tee.elf',
5479 }
5480 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5481 data = self._DoReadFileDtb(
5482 '226_fit_split_elf.dts',
5483 entry_args=entry_args,
5484 extra_indirs=[test_subdir])[0]
5485
5486 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5487 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5488
5489 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5490 'data', 'load'}
5491 dtb = fdt.Fdt.FromData(fit_data)
5492 dtb.Scan()
5493
5494 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5495 segments, entry = elf.read_loadable_segments(elf_data)
5496
5497 # We assume there are two segments
5498 self.assertEquals(2, len(segments))
5499
5500 atf1 = dtb.GetNode('/images/atf-1')
5501 _, start, data = segments[0]
5502 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5503 self.assertEqual(entry,
5504 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5505 self.assertEqual(start,
5506 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5507 self.assertEqual(data, atf1.props['data'].bytes)
5508
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005509 hash_node = atf1.FindNode('hash')
5510 self.assertIsNotNone(hash_node)
5511 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5512
Simon Glass5f423422022-03-05 20:19:12 -07005513 atf2 = dtb.GetNode('/images/atf-2')
5514 self.assertEqual(base_keys, atf2.props.keys())
5515 _, start, data = segments[1]
5516 self.assertEqual(start,
5517 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5518 self.assertEqual(data, atf2.props['data'].bytes)
5519
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005520 hash_node = atf2.FindNode('hash')
5521 self.assertIsNotNone(hash_node)
5522 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5523
5524 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5525 self.assertIsNotNone(hash_node)
5526 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5527
Simon Glass5f423422022-03-05 20:19:12 -07005528 conf = dtb.GetNode('/configurations')
5529 self.assertEqual({'default'}, conf.props.keys())
5530
5531 for subnode in conf.subnodes:
5532 self.assertEqual({'description', 'fdt', 'loadables'},
5533 subnode.props.keys())
5534 self.assertEqual(
5535 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5536 fdt_util.GetStringList(subnode, 'loadables'))
5537
5538 def _check_bad_fit(self, dts):
5539 """Check a bad FIT
5540
5541 This runs with the given dts and returns the assertion raised
5542
5543 Args:
5544 dts (str): dts filename to use
5545
5546 Returns:
5547 str: Assertion string raised
5548 """
5549 entry_args = {
5550 'of-list': 'test-fdt1 test-fdt2',
5551 'default-dt': 'test-fdt2',
5552 'atf-bl31-path': 'bl31.elf',
5553 'tee-os-path': 'tee.elf',
5554 }
5555 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5556 with self.assertRaises(ValueError) as exc:
5557 self._DoReadFileDtb(dts, entry_args=entry_args,
5558 extra_indirs=[test_subdir])[0]
5559 return str(exc.exception)
5560
5561 def testFitSplitElfBadElf(self):
5562 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005563 if not elf.ELF_TOOLS:
5564 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005565 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5566 entry_args = {
5567 'of-list': 'test-fdt1 test-fdt2',
5568 'default-dt': 'test-fdt2',
5569 'atf-bl31-path': 'bad.elf',
5570 'tee-os-path': 'tee.elf',
5571 }
5572 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5573 with self.assertRaises(ValueError) as exc:
5574 self._DoReadFileDtb(
5575 '226_fit_split_elf.dts',
5576 entry_args=entry_args,
5577 extra_indirs=[test_subdir])[0]
5578 self.assertIn(
5579 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5580 str(exc.exception))
5581
Simon Glass5f423422022-03-05 20:19:12 -07005582 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005583 """Test an split-elf FIT with a missing ELF file
5584
5585 Args:
5586 kwargs (dict of str): Arguments to pass to _DoTestFile()
5587
5588 Returns:
5589 tuple:
5590 str: stdout result
5591 str: stderr result
5592 """
Simon Glass5f423422022-03-05 20:19:12 -07005593 entry_args = {
5594 'of-list': 'test-fdt1 test-fdt2',
5595 'default-dt': 'test-fdt2',
5596 'atf-bl31-path': 'bl31.elf',
5597 'tee-os-path': 'missing.elf',
5598 }
5599 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5600 with test_util.capture_sys_output() as (stdout, stderr):
5601 self._DoTestFile(
5602 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005603 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5604 out = stdout.getvalue()
5605 err = stderr.getvalue()
5606 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005607
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005608 def testFitSplitElfBadDirective(self):
5609 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5610 if not elf.ELF_TOOLS:
5611 self.skipTest('Python elftools not available')
5612 err = self._check_bad_fit('227_fit_bad_dir.dts')
5613 self.assertIn(
5614 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5615 err)
5616
5617 def testFitSplitElfBadDirectiveConfig(self):
5618 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5619 if not elf.ELF_TOOLS:
5620 self.skipTest('Python elftools not available')
5621 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5622 self.assertEqual(
5623 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5624 err)
5625
5626
Simon Glass5f423422022-03-05 20:19:12 -07005627 def testFitSplitElfMissing(self):
5628 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005629 if not elf.ELF_TOOLS:
5630 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005631 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005632 self.assertRegex(
5633 err,
5634 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005635 self.assertNotRegex(out, '.*Faked blob.*')
5636 fname = tools.get_output_filename('binman-fake/missing.elf')
5637 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005638
5639 def testFitSplitElfFaked(self):
5640 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005641 if not elf.ELF_TOOLS:
5642 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005643 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005644 self.assertRegex(
5645 err,
5646 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005647 self.assertRegex(
5648 out,
5649 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5650 fname = tools.get_output_filename('binman-fake/missing.elf')
5651 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005652
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005653 def testMkimageMissingBlob(self):
5654 """Test using mkimage to build an image"""
5655 with test_util.capture_sys_output() as (stdout, stderr):
5656 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5657 allow_fake_blobs=True)
5658 err = stderr.getvalue()
5659 self.assertRegex(
5660 err,
5661 "Image '.*' has faked external blobs and is non-functional: .*")
5662
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005663 def testPreLoad(self):
5664 """Test an image with a pre-load header"""
5665 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005666 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005667 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005668 data = self._DoReadFileDtb(
5669 '230_pre_load.dts', entry_args=entry_args,
5670 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005671 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5672 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5673 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Simon Glasse2dfb962023-07-24 09:19:57 -06005674
5675 def testPreLoadNoKey(self):
5676 """Test an image with a pre-load heade0r with missing key"""
5677 with self.assertRaises(FileNotFoundError) as exc:
5678 self._DoReadFile('230_pre_load.dts')
5679 self.assertIn("No such file or directory: 'dev.key'",
5680 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005681
5682 def testPreLoadPkcs(self):
5683 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005684 entry_args = {
5685 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5686 }
5687 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5688 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005689 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5690 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5691 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5692
5693 def testPreLoadPss(self):
5694 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005695 entry_args = {
5696 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5697 }
5698 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5699 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005700 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5701 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5702 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5703
5704 def testPreLoadInvalidPadding(self):
5705 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005706 entry_args = {
5707 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5708 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005709 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005710 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5711 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005712
5713 def testPreLoadInvalidSha(self):
5714 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005715 entry_args = {
5716 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5717 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005718 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005719 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5720 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005721
5722 def testPreLoadInvalidAlgo(self):
5723 """Test an image with a pre-load header with an invalid algo"""
5724 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005725 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005726
5727 def testPreLoadInvalidKey(self):
5728 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005729 entry_args = {
5730 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5731 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005732 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005733 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5734 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005735
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005736 def _CheckSafeUniqueNames(self, *images):
5737 """Check all entries of given images for unsafe unique names"""
5738 for image in images:
5739 entries = {}
5740 image._CollectEntries(entries, {}, image)
5741 for entry in entries.values():
5742 uniq = entry.GetUniqueName()
5743
5744 # Used as part of a filename, so must not be absolute paths.
5745 self.assertFalse(os.path.isabs(uniq))
5746
5747 def testSafeUniqueNames(self):
5748 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005749 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005750
5751 orig_image = control.images['image']
5752 image_fname = tools.get_output_filename('image.bin')
5753 image = Image.FromFile(image_fname)
5754
5755 self._CheckSafeUniqueNames(orig_image, image)
5756
5757 def testSafeUniqueNamesMulti(self):
5758 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005759 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005760
5761 orig_image = control.images['image']
5762 image_fname = tools.get_output_filename('image.bin')
5763 image = Image.FromFile(image_fname)
5764
5765 self._CheckSafeUniqueNames(orig_image, image)
5766
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005767 def testReplaceCmdWithBintool(self):
5768 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005769 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005770 expected = U_BOOT_DATA + b'aa'
5771 self.assertEqual(expected, data[:len(expected)])
5772
5773 try:
5774 tmpdir, updated_fname = self._SetupImageInTmpdir()
5775 fname = os.path.join(tmpdir, 'update-testing.bin')
5776 tools.write_file(fname, b'zz')
5777 self._DoBinman('replace', '-i', updated_fname,
5778 '_testing', '-f', fname)
5779
5780 data = tools.read_file(updated_fname)
5781 expected = U_BOOT_DATA + b'zz'
5782 self.assertEqual(expected, data[:len(expected)])
5783 finally:
5784 shutil.rmtree(tmpdir)
5785
5786 def testReplaceCmdOtherWithBintool(self):
5787 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005788 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005789 expected = U_BOOT_DATA + b'aa'
5790 self.assertEqual(expected, data[:len(expected)])
5791
5792 try:
5793 tmpdir, updated_fname = self._SetupImageInTmpdir()
5794 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5795 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5796 self._DoBinman('replace', '-i', updated_fname,
5797 'u-boot', '-f', fname)
5798
5799 data = tools.read_file(updated_fname)
5800 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5801 self.assertEqual(expected, data[:len(expected)])
5802 finally:
5803 shutil.rmtree(tmpdir)
5804
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005805 def testReplaceResizeNoRepackSameSize(self):
5806 """Test replacing entries with same-size data without repacking"""
5807 expected = b'x' * len(U_BOOT_DATA)
5808 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5809 self.assertEqual(expected, data)
5810
5811 path, fdtmap = state.GetFdtContents('fdtmap')
5812 self.assertIsNotNone(path)
5813 self.assertEqual(expected_fdtmap, fdtmap)
5814
5815 def testReplaceResizeNoRepackSmallerSize(self):
5816 """Test replacing entries with smaller-size data without repacking"""
5817 new_data = b'x'
5818 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5819 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5820 self.assertEqual(expected, data)
5821
5822 path, fdtmap = state.GetFdtContents('fdtmap')
5823 self.assertIsNotNone(path)
5824 self.assertEqual(expected_fdtmap, fdtmap)
5825
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005826 def testExtractFit(self):
5827 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005828 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005829 image_fname = tools.get_output_filename('image.bin')
5830
5831 fit_data = control.ReadEntry(image_fname, 'fit')
5832 fit = fdt.Fdt.FromData(fit_data)
5833 fit.Scan()
5834
5835 # Check subentry data inside the extracted fit
5836 for node_path, expected in [
5837 ('/images/kernel', U_BOOT_DATA),
5838 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5839 ('/images/scr-1', COMPRESS_DATA),
5840 ]:
5841 node = fit.GetNode(node_path)
5842 data = fit.GetProps(node)['data'].bytes
5843 self.assertEqual(expected, data)
5844
5845 def testExtractFitSubentries(self):
5846 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005847 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005848 image_fname = tools.get_output_filename('image.bin')
5849
5850 for entry_path, expected in [
5851 ('fit/kernel', U_BOOT_DATA),
5852 ('fit/kernel/u-boot', U_BOOT_DATA),
5853 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5854 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5855 ('fit/scr-1', COMPRESS_DATA),
5856 ('fit/scr-1/blob', COMPRESS_DATA),
5857 ]:
5858 data = control.ReadEntry(image_fname, entry_path)
5859 self.assertEqual(expected, data)
5860
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005861 def testReplaceFitSubentryLeafSameSize(self):
5862 """Test replacing a FIT leaf subentry with same-size data"""
5863 new_data = b'x' * len(U_BOOT_DATA)
5864 data, expected_fdtmap, _ = self._RunReplaceCmd(
5865 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005866 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005867 self.assertEqual(new_data, data)
5868
5869 path, fdtmap = state.GetFdtContents('fdtmap')
5870 self.assertIsNotNone(path)
5871 self.assertEqual(expected_fdtmap, fdtmap)
5872
5873 def testReplaceFitSubentryLeafBiggerSize(self):
5874 """Test replacing a FIT leaf subentry with bigger-size data"""
5875 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5876 data, expected_fdtmap, _ = self._RunReplaceCmd(
5877 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005878 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005879 self.assertEqual(new_data, data)
5880
5881 # Will be repacked, so fdtmap must change
5882 path, fdtmap = state.GetFdtContents('fdtmap')
5883 self.assertIsNotNone(path)
5884 self.assertNotEqual(expected_fdtmap, fdtmap)
5885
5886 def testReplaceFitSubentryLeafSmallerSize(self):
5887 """Test replacing a FIT leaf subentry with smaller-size data"""
5888 new_data = b'x'
5889 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5890 data, expected_fdtmap, _ = self._RunReplaceCmd(
5891 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005892 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005893 self.assertEqual(expected, data)
5894
5895 path, fdtmap = state.GetFdtContents('fdtmap')
5896 self.assertIsNotNone(path)
5897 self.assertEqual(expected_fdtmap, fdtmap)
5898
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005899 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005900 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005901 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005902 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5903 new_data, dts='241_replace_section_simple.dts')
5904 self.assertEqual(new_data, data)
5905
5906 entries = image.GetEntries()
5907 self.assertIn('section', entries)
5908 entry = entries['section']
5909 self.assertEqual(len(new_data), entry.size)
5910
5911 def testReplaceSectionLarger(self):
5912 """Test replacing a simple section with larger data"""
5913 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5914 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5915 new_data, dts='241_replace_section_simple.dts')
5916 self.assertEqual(new_data, data)
5917
5918 entries = image.GetEntries()
5919 self.assertIn('section', entries)
5920 entry = entries['section']
5921 self.assertEqual(len(new_data), entry.size)
5922 fentry = entries['fdtmap']
5923 self.assertEqual(entry.offset + entry.size, fentry.offset)
5924
5925 def testReplaceSectionSmaller(self):
5926 """Test replacing a simple section with smaller data"""
5927 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5928 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5929 new_data, dts='241_replace_section_simple.dts')
5930 self.assertEqual(new_data, data)
5931
5932 # The new size is the same as the old, just with a pad byte at the end
5933 entries = image.GetEntries()
5934 self.assertIn('section', entries)
5935 entry = entries['section']
5936 self.assertEqual(len(new_data), entry.size)
5937
5938 def testReplaceSectionSmallerAllow(self):
5939 """Test failing to replace a simple section with smaller data"""
5940 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5941 try:
5942 state.SetAllowEntryContraction(True)
5943 with self.assertRaises(ValueError) as exc:
5944 self._RunReplaceCmd('section', new_data,
5945 dts='241_replace_section_simple.dts')
5946 finally:
5947 state.SetAllowEntryContraction(False)
5948
5949 # Since we have no information about the position of things within the
5950 # section, we cannot adjust the position of /section-u-boot so it ends
5951 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06005952 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07005953 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5954 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06005955 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005956
Simon Glass8fbca772022-08-13 11:40:48 -06005957 def testMkimageImagename(self):
5958 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005959 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005960 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005961
5962 # Check that the data appears in the file somewhere
5963 self.assertIn(U_BOOT_SPL_DATA, data)
5964
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005965 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005966 name = data[0x20:0x40]
5967
5968 # Build the filename that we expect to be placed in there, by virtue of
5969 # the -n paraameter
5970 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5971
5972 # Check that the image name is set to the temporary filename used
5973 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5974
Simon Glassb1669752022-08-13 11:40:49 -06005975 def testMkimageImage(self):
5976 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005977 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005978 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005979
5980 # Check that the data appears in the file somewhere
5981 self.assertIn(U_BOOT_SPL_DATA, data)
5982
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005983 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06005984 name = data[0x20:0x40]
5985
5986 # Build the filename that we expect to be placed in there, by virtue of
5987 # the -n paraameter
5988 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5989
5990 # Check that the image name is set to the temporary filename used
5991 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5992
5993 # Check the corect data is in the imagename file
5994 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5995
5996 def testMkimageImageNoContent(self):
5997 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005998 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06005999 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006000 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006001 self.assertIn('Could not complete processing of contents',
6002 str(exc.exception))
6003
6004 def testMkimageImageBad(self):
6005 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006006 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006007 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006008 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006009 self.assertIn('Cannot use both imagename node and data-to-imagename',
6010 str(exc.exception))
6011
Simon Glassbd5cd882022-08-13 11:40:50 -06006012 def testCollectionOther(self):
6013 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006014 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006015 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6016 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6017 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6018 data)
6019
6020 def testMkimageCollection(self):
6021 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006022 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006023 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006024 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6025 self.assertEqual(expect, data[:len(expect)])
6026
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006027 def testCompressDtbPrependInvalid(self):
6028 """Test that invalid header is detected"""
6029 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006030 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006031 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6032 "'u-boot-dtb': 'invalid'", str(e.exception))
6033
6034 def testCompressDtbPrependLength(self):
6035 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006036 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006037 image = control.images['image']
6038 entries = image.GetEntries()
6039 self.assertIn('u-boot-dtb', entries)
6040 u_boot_dtb = entries['u-boot-dtb']
6041 self.assertIn('fdtmap', entries)
6042 fdtmap = entries['fdtmap']
6043
6044 image_fname = tools.get_output_filename('image.bin')
6045 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6046 dtb = fdt.Fdt.FromData(orig)
6047 dtb.Scan()
6048 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6049 expected = {
6050 'u-boot:size': len(U_BOOT_DATA),
6051 'u-boot-dtb:uncomp-size': len(orig),
6052 'u-boot-dtb:size': u_boot_dtb.size,
6053 'fdtmap:size': fdtmap.size,
6054 'size': len(data),
6055 }
6056 self.assertEqual(expected, props)
6057
6058 # Check implementation
6059 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6060 rest = data[len(U_BOOT_DATA):]
6061 comp_data_len = struct.unpack('<I', rest[:4])[0]
6062 comp_data = rest[4:4 + comp_data_len]
6063 orig2 = self._decompress(comp_data)
6064 self.assertEqual(orig, orig2)
6065
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006066 def testInvalidCompress(self):
6067 """Test that invalid compress algorithm is detected"""
6068 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006069 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006070 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6071
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006072 def testCompUtilCompressions(self):
6073 """Test compression algorithms"""
6074 for bintool in self.comp_bintools.values():
6075 self._CheckBintool(bintool)
6076 data = bintool.compress(COMPRESS_DATA)
6077 self.assertNotEqual(COMPRESS_DATA, data)
6078 orig = bintool.decompress(data)
6079 self.assertEquals(COMPRESS_DATA, orig)
6080
6081 def testCompUtilVersions(self):
6082 """Test tool version of compression algorithms"""
6083 for bintool in self.comp_bintools.values():
6084 self._CheckBintool(bintool)
6085 version = bintool.version()
6086 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6087
6088 def testCompUtilPadding(self):
6089 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006090 # Skip zstd because it doesn't support padding
6091 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006092 self._CheckBintool(bintool)
6093 data = bintool.compress(COMPRESS_DATA)
6094 self.assertNotEqual(COMPRESS_DATA, data)
6095 data += tools.get_bytes(0, 64)
6096 orig = bintool.decompress(data)
6097 self.assertEquals(COMPRESS_DATA, orig)
6098
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006099 def testCompressDtbZstd(self):
6100 """Test that zstd compress of device-tree files failed"""
6101 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006102 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006103 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6104 "requires a length header", str(e.exception))
6105
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006106 def testMkimageMultipleDataFiles(self):
6107 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006108 self._SetupSplElf()
6109 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006110 data = self._DoReadFile('252_mkimage_mult_data.dts')
6111 # Size of files are packed in their 4B big-endian format
6112 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6113 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6114 # Size info is always followed by a 4B zero value.
6115 expect += tools.get_bytes(0, 4)
6116 expect += U_BOOT_TPL_DATA
6117 # All but last files are 4B-aligned
6118 align_pad = len(U_BOOT_TPL_DATA) % 4
6119 if align_pad:
6120 expect += tools.get_bytes(0, align_pad)
6121 expect += U_BOOT_SPL_DATA
6122 self.assertEqual(expect, data[-len(expect):])
6123
Marek Vasutf7413f02023-07-18 07:23:58 -06006124 def testMkimageMultipleExpanded(self):
6125 """Test passing multiple files to mkimage in a mkimage entry"""
6126 self._SetupSplElf()
6127 self._SetupTplElf()
6128 entry_args = {
6129 'spl-bss-pad': 'y',
6130 'spl-dtb': 'y',
6131 }
6132 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6133 use_expanded=True, entry_args=entry_args)[0]
6134 pad_len = 10
6135 tpl_expect = U_BOOT_TPL_DATA
6136 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6137 spl_expect += U_BOOT_SPL_DTB_DATA
6138
6139 content = data[0x40:]
6140 lens = struct.unpack('>III', content[:12])
6141
6142 # Size of files are packed in their 4B big-endian format
6143 # Size info is always followed by a 4B zero value.
6144 self.assertEqual(len(tpl_expect), lens[0])
6145 self.assertEqual(len(spl_expect), lens[1])
6146 self.assertEqual(0, lens[2])
6147
6148 rest = content[12:]
6149 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6150
6151 rest = rest[len(tpl_expect):]
6152 align_pad = len(tpl_expect) % 4
6153 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6154 rest = rest[align_pad:]
6155 self.assertEqual(spl_expect, rest)
6156
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006157 def testMkimageMultipleNoContent(self):
6158 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006159 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006160 with self.assertRaises(ValueError) as exc:
6161 self._DoReadFile('253_mkimage_mult_no_content.dts')
6162 self.assertIn('Could not complete processing of contents',
6163 str(exc.exception))
6164
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006165 def testMkimageFilename(self):
6166 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006167 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006168 retcode = self._DoTestFile('254_mkimage_filename.dts')
6169 self.assertEqual(0, retcode)
6170 fname = tools.get_output_filename('mkimage-test.bin')
6171 self.assertTrue(os.path.exists(fname))
6172
Simon Glass56d05412022-02-28 07:16:54 -07006173 def testVpl(self):
6174 """Test that an image with VPL and its device tree can be created"""
6175 # ELF file with a '__bss_size' symbol
6176 self._SetupVplElf()
6177 data = self._DoReadFile('255_u_boot_vpl.dts')
6178 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6179
6180 def testVplNoDtb(self):
6181 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6182 self._SetupVplElf()
6183 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6184 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6185 data[:len(U_BOOT_VPL_NODTB_DATA)])
6186
6187 def testExpandedVpl(self):
6188 """Test that an expanded entry type is selected for TPL when needed"""
6189 self._SetupVplElf()
6190
6191 entry_args = {
6192 'vpl-bss-pad': 'y',
6193 'vpl-dtb': 'y',
6194 }
6195 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6196 entry_args=entry_args)
6197 image = control.images['image']
6198 entries = image.GetEntries()
6199 self.assertEqual(1, len(entries))
6200
6201 # We only have u-boot-vpl, which be expanded
6202 self.assertIn('u-boot-vpl', entries)
6203 entry = entries['u-boot-vpl']
6204 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6205 subent = entry.GetEntries()
6206 self.assertEqual(3, len(subent))
6207 self.assertIn('u-boot-vpl-nodtb', subent)
6208 self.assertIn('u-boot-vpl-bss-pad', subent)
6209 self.assertIn('u-boot-vpl-dtb', subent)
6210
6211 def testVplBssPadMissing(self):
6212 """Test that a missing symbol is detected"""
6213 self._SetupVplElf('u_boot_ucode_ptr')
6214 with self.assertRaises(ValueError) as e:
6215 self._DoReadFile('258_vpl_bss_pad.dts')
6216 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6217 str(e.exception))
6218
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306219 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306220 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306221 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6222 self.assertEqual(0, retcode)
6223 image = control.images['test_image']
6224 fname = tools.get_output_filename('test_image.bin')
6225 sname = tools.get_output_filename('symlink_to_test.bin')
6226 self.assertTrue(os.path.islink(sname))
6227 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006228
Andrew Davis6b463da2023-07-22 00:14:44 +05306229 def testSymlinkOverwrite(self):
6230 """Test that symlinked images can be overwritten"""
6231 testdir = TestFunctional._MakeInputDir('symlinktest')
6232 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6233 # build the same image again in the same directory so that existing symlink is present
6234 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6235 fname = tools.get_output_filename('test_image.bin')
6236 sname = tools.get_output_filename('symlink_to_test.bin')
6237 self.assertTrue(os.path.islink(sname))
6238 self.assertEqual(os.readlink(sname), fname)
6239
Simon Glass37f85de2022-10-20 18:22:47 -06006240 def testSymbolsElf(self):
6241 """Test binman can assign symbols embedded in an ELF file"""
6242 if not elf.ELF_TOOLS:
6243 self.skipTest('Python elftools not available')
6244 self._SetupTplElf('u_boot_binman_syms')
6245 self._SetupVplElf('u_boot_binman_syms')
6246 self._SetupSplElf('u_boot_binman_syms')
6247 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6248 image_fname = tools.get_output_filename('image.bin')
6249
6250 image = control.images['image']
6251 entries = image.GetEntries()
6252
6253 for entry in entries.values():
6254 # No symbols in u-boot and it has faked contents anyway
6255 if entry.name == 'u-boot':
6256 continue
6257 edata = data[entry.image_pos:entry.image_pos + entry.size]
6258 efname = tools.get_output_filename(f'edata-{entry.name}')
6259 tools.write_file(efname, edata)
6260
6261 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6262 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6263 for name, sym in syms.items():
6264 msg = 'test'
6265 val = elf.GetSymbolValue(sym, edata, msg)
6266 entry_m = re_name.match(name)
6267 if entry_m:
6268 ename, prop = entry_m.group(1), entry_m.group(3)
6269 entry, entry_name, prop_name = image.LookupEntry(entries,
6270 name, msg)
6271 if prop_name == 'offset':
6272 expect_val = entry.offset
6273 elif prop_name == 'image_pos':
6274 expect_val = entry.image_pos
6275 elif prop_name == 'size':
6276 expect_val = entry.size
6277 self.assertEqual(expect_val, val)
6278
6279 def testSymbolsElfBad(self):
6280 """Check error when trying to write symbols without the elftools lib"""
6281 if not elf.ELF_TOOLS:
6282 self.skipTest('Python elftools not available')
6283 self._SetupTplElf('u_boot_binman_syms')
6284 self._SetupVplElf('u_boot_binman_syms')
6285 self._SetupSplElf('u_boot_binman_syms')
6286 try:
6287 elf.ELF_TOOLS = False
6288 with self.assertRaises(ValueError) as exc:
6289 self._DoReadFileDtb('260_symbols_elf.dts')
6290 finally:
6291 elf.ELF_TOOLS = True
6292 self.assertIn(
6293 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6294 'Cannot write symbols to an ELF file without Python elftools',
6295 str(exc.exception))
6296
Simon Glassde244162023-01-07 14:07:08 -07006297 def testSectionFilename(self):
6298 """Check writing of section contents to a file"""
6299 data = self._DoReadFile('261_section_fname.dts')
6300 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6301 tools.get_bytes(ord('!'), 7) +
6302 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6303 self.assertEqual(expected, data)
6304
6305 sect_fname = tools.get_output_filename('outfile.bin')
6306 self.assertTrue(os.path.exists(sect_fname))
6307 sect_data = tools.read_file(sect_fname)
6308 self.assertEqual(U_BOOT_DATA, sect_data)
6309
Simon Glass1e9e61c2023-01-07 14:07:12 -07006310 def testAbsent(self):
6311 """Check handling of absent entries"""
6312 data = self._DoReadFile('262_absent.dts')
6313 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6314
Simon Glassad5cfe12023-01-07 14:07:14 -07006315 def testPackTeeOsOptional(self):
6316 """Test that an image with an optional TEE binary can be created"""
6317 entry_args = {
6318 'tee-os-path': 'tee.elf',
6319 }
6320 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6321 entry_args=entry_args)[0]
6322 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6323
6324 def checkFitTee(self, dts, tee_fname):
6325 """Check that a tee-os entry works and returns data
6326
6327 Args:
6328 dts (str): Device tree filename to use
6329 tee_fname (str): filename containing tee-os
6330
6331 Returns:
6332 bytes: Image contents
6333 """
6334 if not elf.ELF_TOOLS:
6335 self.skipTest('Python elftools not available')
6336 entry_args = {
6337 'of-list': 'test-fdt1 test-fdt2',
6338 'default-dt': 'test-fdt2',
6339 'tee-os-path': tee_fname,
6340 }
6341 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6342 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6343 extra_indirs=[test_subdir])[0]
6344 return data
6345
6346 def testFitTeeOsOptionalFit(self):
6347 """Test an image with a FIT with an optional OP-TEE binary"""
6348 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6349
6350 # There should be only one node, holding the data set up in SetUpClass()
6351 # for tee.bin
6352 dtb = fdt.Fdt.FromData(data)
6353 dtb.Scan()
6354 node = dtb.GetNode('/images/tee-1')
6355 self.assertEqual(TEE_ADDR,
6356 fdt_util.fdt32_to_cpu(node.props['load'].value))
6357 self.assertEqual(TEE_ADDR,
6358 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6359 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6360
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006361 with test_util.capture_sys_output() as (stdout, stderr):
6362 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6363 err = stderr.getvalue()
6364 self.assertRegex(
6365 err,
6366 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6367
Simon Glassad5cfe12023-01-07 14:07:14 -07006368 def testFitTeeOsOptionalFitBad(self):
6369 """Test an image with a FIT with an optional OP-TEE binary"""
6370 with self.assertRaises(ValueError) as exc:
6371 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6372 self.assertIn(
6373 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6374 str(exc.exception))
6375
6376 def testFitTeeOsBad(self):
6377 """Test an OP-TEE binary with wrong formats"""
6378 self.make_tee_bin('tee.bad1', 123)
6379 with self.assertRaises(ValueError) as exc:
6380 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6381 self.assertIn(
6382 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6383 str(exc.exception))
6384
6385 self.make_tee_bin('tee.bad2', 0, b'extra data')
6386 with self.assertRaises(ValueError) as exc:
6387 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6388 self.assertIn(
6389 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6390 str(exc.exception))
6391
Simon Glass63328f12023-01-07 14:07:15 -07006392 def testExtblobOptional(self):
6393 """Test an image with an external blob that is optional"""
6394 with test_util.capture_sys_output() as (stdout, stderr):
6395 data = self._DoReadFile('266_blob_ext_opt.dts')
6396 self.assertEqual(REFCODE_DATA, data)
6397 err = stderr.getvalue()
6398 self.assertRegex(
6399 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006400 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006401
Simon Glass7447a9d2023-01-11 16:10:12 -07006402 def testSectionInner(self):
6403 """Test an inner section with a size"""
6404 data = self._DoReadFile('267_section_inner.dts')
6405 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6406 self.assertEqual(expected, data)
6407
Simon Glassa4948b22023-01-11 16:10:14 -07006408 def testNull(self):
6409 """Test an image with a null entry"""
6410 data = self._DoReadFile('268_null.dts')
6411 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6412
Simon Glassf1ee03b2023-01-11 16:10:16 -07006413 def testOverlap(self):
6414 """Test an image with a overlapping entry"""
6415 data = self._DoReadFile('269_overlap.dts')
6416 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6417
6418 image = control.images['image']
6419 entries = image.GetEntries()
6420
6421 self.assertIn('inset', entries)
6422 inset = entries['inset']
6423 self.assertEqual(1, inset.offset);
6424 self.assertEqual(1, inset.image_pos);
6425 self.assertEqual(2, inset.size);
6426
6427 def testOverlapNull(self):
6428 """Test an image with a null overlap"""
6429 data = self._DoReadFile('270_overlap_null.dts')
6430 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6431
6432 # Check the FMAP
6433 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6434 self.assertEqual(4, fhdr.nareas)
6435 fiter = iter(fentries)
6436
6437 fentry = next(fiter)
6438 self.assertEqual(b'SECTION', fentry.name)
6439 self.assertEqual(0, fentry.offset)
6440 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6441 self.assertEqual(0, fentry.flags)
6442
6443 fentry = next(fiter)
6444 self.assertEqual(b'U_BOOT', fentry.name)
6445 self.assertEqual(0, fentry.offset)
6446 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6447 self.assertEqual(0, fentry.flags)
6448
6449 # Make sure that the NULL entry appears in the FMAP
6450 fentry = next(fiter)
6451 self.assertEqual(b'NULL', fentry.name)
6452 self.assertEqual(1, fentry.offset)
6453 self.assertEqual(2, fentry.size)
6454 self.assertEqual(0, fentry.flags)
6455
6456 fentry = next(fiter)
6457 self.assertEqual(b'FMAP', fentry.name)
6458 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6459
6460 def testOverlapBad(self):
6461 """Test an image with a bad overlapping entry"""
6462 with self.assertRaises(ValueError) as exc:
6463 self._DoReadFile('271_overlap_bad.dts')
6464 self.assertIn(
6465 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6466 str(exc.exception))
6467
6468 def testOverlapNoOffset(self):
6469 """Test an image with a bad overlapping entry"""
6470 with self.assertRaises(ValueError) as exc:
6471 self._DoReadFile('272_overlap_no_size.dts')
6472 self.assertIn(
6473 "Node '/binman/inset': 'fill' entry is missing properties: size",
6474 str(exc.exception))
6475
Simon Glasse0035c92023-01-11 16:10:17 -07006476 def testBlobSymbol(self):
6477 """Test a blob with symbols read from an ELF file"""
6478 elf_fname = self.ElfTestFile('blob_syms')
6479 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6480 TestFunctional._MakeInputFile('blob_syms.bin',
6481 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6482
6483 data = self._DoReadFile('273_blob_symbol.dts')
6484
6485 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6486 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6487 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6488 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6489 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6490
6491 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6492 expected = sym_values
6493 self.assertEqual(expected, data[:len(expected)])
6494
Simon Glass49e9c002023-01-11 16:10:19 -07006495 def testOffsetFromElf(self):
6496 """Test a blob with symbols read from an ELF file"""
6497 elf_fname = self.ElfTestFile('blob_syms')
6498 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6499 TestFunctional._MakeInputFile('blob_syms.bin',
6500 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6501
6502 data = self._DoReadFile('274_offset_from_elf.dts')
6503
6504 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6505 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6506
6507 image = control.images['image']
6508 entries = image.GetEntries()
6509
6510 self.assertIn('inset', entries)
6511 inset = entries['inset']
6512
6513 self.assertEqual(base + 4, inset.offset);
6514 self.assertEqual(base + 4, inset.image_pos);
6515 self.assertEqual(4, inset.size);
6516
6517 self.assertIn('inset2', entries)
6518 inset = entries['inset2']
6519 self.assertEqual(base + 8, inset.offset);
6520 self.assertEqual(base + 8, inset.image_pos);
6521 self.assertEqual(4, inset.size);
6522
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006523 def testFitAlign(self):
6524 """Test an image with an FIT with aligned external data"""
6525 data = self._DoReadFile('275_fit_align.dts')
6526 self.assertEqual(4096, len(data))
6527
6528 dtb = fdt.Fdt.FromData(data)
6529 dtb.Scan()
6530
6531 props = self._GetPropTree(dtb, ['data-position'])
6532 expected = {
6533 'u-boot:data-position': 1024,
6534 'fdt-1:data-position': 2048,
6535 'fdt-2:data-position': 3072,
6536 }
6537 self.assertEqual(expected, props)
6538
Jonas Karlman490f73c2023-01-21 19:02:12 +00006539 def testFitFirmwareLoadables(self):
6540 """Test an image with an FIT that use fit,firmware"""
6541 if not elf.ELF_TOOLS:
6542 self.skipTest('Python elftools not available')
6543 entry_args = {
6544 'of-list': 'test-fdt1',
6545 'default-dt': 'test-fdt1',
6546 'atf-bl31-path': 'bl31.elf',
6547 'tee-os-path': 'missing.bin',
6548 }
6549 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006550 with test_util.capture_sys_output() as (stdout, stderr):
6551 data = self._DoReadFileDtb(
6552 '276_fit_firmware_loadables.dts',
6553 entry_args=entry_args,
6554 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006555
6556 dtb = fdt.Fdt.FromData(data)
6557 dtb.Scan()
6558
6559 node = dtb.GetNode('/configurations/conf-uboot-1')
6560 self.assertEqual('u-boot', node.props['firmware'].value)
6561 self.assertEqual(['atf-1', 'atf-2'],
6562 fdt_util.GetStringList(node, 'loadables'))
6563
6564 node = dtb.GetNode('/configurations/conf-atf-1')
6565 self.assertEqual('atf-1', node.props['firmware'].value)
6566 self.assertEqual(['u-boot', 'atf-2'],
6567 fdt_util.GetStringList(node, 'loadables'))
6568
6569 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6570 self.assertEqual('u-boot', node.props['firmware'].value)
6571 self.assertEqual(['atf-1', 'atf-2'],
6572 fdt_util.GetStringList(node, 'loadables'))
6573
6574 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6575 self.assertEqual('atf-1', node.props['firmware'].value)
6576 self.assertEqual(['u-boot', 'atf-2'],
6577 fdt_util.GetStringList(node, 'loadables'))
6578
6579 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6580 self.assertEqual('atf-1', node.props['firmware'].value)
6581 self.assertEqual(['u-boot', 'atf-2'],
6582 fdt_util.GetStringList(node, 'loadables'))
6583
Simon Glass9a1c7262023-02-22 12:14:49 -07006584 def testTooldir(self):
6585 """Test that we can specify the tooldir"""
6586 with test_util.capture_sys_output() as (stdout, stderr):
6587 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6588 'tool', '-l'))
6589 self.assertEqual('fred', bintool.Bintool.tooldir)
6590
6591 # Check that the toolpath is updated correctly
6592 self.assertEqual(['fred'], tools.tool_search_paths)
6593
6594 # Try with a few toolpaths; the tooldir should be at the end
6595 with test_util.capture_sys_output() as (stdout, stderr):
6596 self.assertEqual(0, self._DoBinman(
6597 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6598 'tool', '-l'))
6599 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6600
Simon Glass49b77e82023-03-02 17:02:44 -07006601 def testReplaceSectionEntry(self):
6602 """Test replacing an entry in a section"""
6603 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6604 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6605 expect_data, dts='241_replace_section_simple.dts')
6606 self.assertEqual(expect_data, entry_data)
6607
6608 entries = image.GetEntries()
6609 self.assertIn('section', entries)
6610 section = entries['section']
6611
6612 sect_entries = section.GetEntries()
6613 self.assertIn('blob', sect_entries)
6614 entry = sect_entries['blob']
6615 self.assertEqual(len(expect_data), entry.size)
6616
6617 fname = tools.get_output_filename('image-updated.bin')
6618 data = tools.read_file(fname)
6619
6620 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6621 self.assertEqual(expect_data, new_blob_data)
6622
6623 self.assertEqual(U_BOOT_DATA,
6624 data[entry.image_pos + len(expect_data):]
6625 [:len(U_BOOT_DATA)])
6626
6627 def testReplaceSectionDeep(self):
6628 """Test replacing an entry in two levels of sections"""
6629 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6630 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6631 'section/section/blob', expect_data,
6632 dts='278_replace_section_deep.dts')
6633 self.assertEqual(expect_data, entry_data)
6634
6635 entries = image.GetEntries()
6636 self.assertIn('section', entries)
6637 section = entries['section']
6638
6639 subentries = section.GetEntries()
6640 self.assertIn('section', subentries)
6641 section = subentries['section']
6642
6643 sect_entries = section.GetEntries()
6644 self.assertIn('blob', sect_entries)
6645 entry = sect_entries['blob']
6646 self.assertEqual(len(expect_data), entry.size)
6647
6648 fname = tools.get_output_filename('image-updated.bin')
6649 data = tools.read_file(fname)
6650
6651 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6652 self.assertEqual(expect_data, new_blob_data)
6653
6654 self.assertEqual(U_BOOT_DATA,
6655 data[entry.image_pos + len(expect_data):]
6656 [:len(U_BOOT_DATA)])
6657
6658 def testReplaceFitSibling(self):
6659 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006660 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006661 fname = TestFunctional._MakeInputFile('once', b'available once')
6662 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6663 os.remove(fname)
6664
6665 try:
6666 tmpdir, updated_fname = self._SetupImageInTmpdir()
6667
6668 fname = os.path.join(tmpdir, 'update-blob')
6669 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6670 tools.write_file(fname, expected)
6671
6672 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6673 data = tools.read_file(updated_fname)
6674 start = len(U_BOOT_DTB_DATA)
6675 self.assertEqual(expected, data[start:start + len(expected)])
6676 map_fname = os.path.join(tmpdir, 'image-updated.map')
6677 self.assertFalse(os.path.exists(map_fname))
6678 finally:
6679 shutil.rmtree(tmpdir)
6680
Simon Glassc3fe97f2023-03-02 17:02:45 -07006681 def testX509Cert(self):
6682 """Test creating an X509 certificate"""
6683 keyfile = self.TestFile('key.key')
6684 entry_args = {
6685 'keyfile': keyfile,
6686 }
6687 data = self._DoReadFileDtb('279_x509_cert.dts',
6688 entry_args=entry_args)[0]
6689 cert = data[:-4]
6690 self.assertEqual(U_BOOT_DATA, data[-4:])
6691
6692 # TODO: verify the signature
6693
6694 def testX509CertMissing(self):
6695 """Test that binman still produces an image if openssl is missing"""
6696 keyfile = self.TestFile('key.key')
6697 entry_args = {
6698 'keyfile': 'keyfile',
6699 }
6700 with test_util.capture_sys_output() as (_, stderr):
6701 self._DoTestFile('279_x509_cert.dts',
6702 force_missing_bintools='openssl',
6703 entry_args=entry_args)
6704 err = stderr.getvalue()
6705 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6706
Jonas Karlman35305492023-02-25 19:01:33 +00006707 def testPackRockchipTpl(self):
6708 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006709 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006710 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6711
Jonas Karlman1016ec72023-02-25 19:01:35 +00006712 def testMkimageMissingBlobMultiple(self):
6713 """Test missing blob with mkimage entry and multiple-data-files"""
6714 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006715 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006716 err = stderr.getvalue()
6717 self.assertIn("is missing external blobs and is non-functional", err)
6718
6719 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006720 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006721 self.assertIn("not found in input path", str(e.exception))
6722
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006723 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6724 """Prepare sign environment
6725
6726 Create private and public keys, add pubkey into dtb.
6727
6728 Returns:
6729 Tuple:
6730 FIT container
6731 Image name
6732 Private key
6733 DTB
6734 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006735 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006736 data = self._DoReadFileRealDtb(dts)
6737 updated_fname = tools.get_output_filename('image-updated.bin')
6738 tools.write_file(updated_fname, data)
6739 dtb = tools.get_output_filename('source.dtb')
6740 private_key = tools.get_output_filename('test_key.key')
6741 public_key = tools.get_output_filename('test_key.crt')
6742 fit = tools.get_output_filename('fit.fit')
6743 key_dir = tools.get_output_dir()
6744
6745 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6746 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6747 private_key, '-out', public_key)
6748 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6749 '-n', 'test_key', '-r', 'conf', dtb)
6750
6751 return fit, updated_fname, private_key, dtb
6752
6753 def testSignSimple(self):
6754 """Test that a FIT container can be signed in image"""
6755 is_signed = False
6756 fit, fname, private_key, dtb = self._PrepareSignEnv()
6757
6758 # do sign with private key
6759 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6760 ['fit'])
6761 is_signed = self._CheckSign(fit, dtb)
6762
6763 self.assertEqual(is_signed, True)
6764
6765 def testSignExactFIT(self):
6766 """Test that a FIT container can be signed and replaced in image"""
6767 is_signed = False
6768 fit, fname, private_key, dtb = self._PrepareSignEnv()
6769
6770 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6771 args = []
6772 if self.toolpath:
6773 for path in self.toolpath:
6774 args += ['--toolpath', path]
6775
6776 # do sign with private key
6777 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6778 'sha256,rsa4096', '-f', fit, 'fit')
6779 is_signed = self._CheckSign(fit, dtb)
6780
6781 self.assertEqual(is_signed, True)
6782
6783 def testSignNonFit(self):
6784 """Test a non-FIT entry cannot be signed"""
6785 is_signed = False
6786 fit, fname, private_key, _ = self._PrepareSignEnv(
6787 '281_sign_non_fit.dts')
6788
6789 # do sign with private key
6790 with self.assertRaises(ValueError) as e:
6791 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6792 'sha256,rsa4096', '-f', fit, 'u-boot')
6793 self.assertIn(
6794 "Node '/u-boot': Updating signatures is not supported with this entry type",
6795 str(e.exception))
6796
6797 def testSignMissingMkimage(self):
6798 """Test that FIT signing handles a missing mkimage tool"""
6799 fit, fname, private_key, _ = self._PrepareSignEnv()
6800
6801 # try to sign with a missing mkimage tool
6802 bintool.Bintool.set_missing_list(['mkimage'])
6803 with self.assertRaises(ValueError) as e:
6804 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6805 ['fit'])
6806 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6807
Simon Glass4abf7842023-07-18 07:23:54 -06006808 def testSymbolNoWrite(self):
6809 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006810 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006811 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6812 no_write_symbols=True)
6813
6814 def testSymbolNoWriteExpanded(self):
6815 """Test disabling of symbol writing in expanded entries"""
6816 entry_args = {
6817 'spl-dtb': '1',
6818 }
6819 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6820 U_BOOT_SPL_DTB_DATA, 0x38,
6821 entry_args=entry_args, use_expanded=True,
6822 no_write_symbols=True)
6823
Marek Vasutf7413f02023-07-18 07:23:58 -06006824 def testMkimageSpecial(self):
6825 """Test mkimage ignores special hash-1 node"""
6826 data = self._DoReadFile('283_mkimage_special.dts')
6827
6828 # Just check that the data appears in the file somewhere
6829 self.assertIn(U_BOOT_DATA, data)
6830
Simon Glass2d94c422023-07-18 07:23:59 -06006831 def testFitFdtList(self):
6832 """Test an image with an FIT with the fit,fdt-list-val option"""
6833 entry_args = {
6834 'default-dt': 'test-fdt2',
6835 }
6836 data = self._DoReadFileDtb(
6837 '284_fit_fdt_list.dts',
6838 entry_args=entry_args,
6839 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6840 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6841 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6842
Simon Glass83b8bfe2023-07-18 07:24:01 -06006843 def testSplEmptyBss(self):
6844 """Test an expanded SPL with a zero-size BSS"""
6845 # ELF file with a '__bss_size' symbol
6846 self._SetupSplElf(src_fname='bss_data_zero')
6847
6848 entry_args = {
6849 'spl-bss-pad': 'y',
6850 'spl-dtb': 'y',
6851 }
6852 data = self._DoReadFileDtb('285_spl_expand.dts',
6853 use_expanded=True, entry_args=entry_args)[0]
6854
Simon Glassfc792842023-07-18 07:24:04 -06006855 def testTemplate(self):
6856 """Test using a template"""
6857 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6858 data = self._DoReadFile('286_template.dts')
6859 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6860 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6861 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6862
Simon Glass9909c112023-07-18 07:24:05 -06006863 def testTemplateBlobMulti(self):
6864 """Test using a template with 'multiple-images' enabled"""
6865 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6866 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6867 retcode = self._DoTestFile('287_template_multi.dts')
6868
6869 self.assertEqual(0, retcode)
6870 image = control.images['image']
6871 image_fname = tools.get_output_filename('my-image.bin')
6872 data = tools.read_file(image_fname)
6873 self.assertEqual(b'blob@@@@other', data)
6874
Simon Glass5dc511b2023-07-18 07:24:06 -06006875 def testTemplateFit(self):
6876 """Test using a template in a FIT"""
6877 fit_data = self._DoReadFile('288_template_fit.dts')
6878 fname = os.path.join(self._indir, 'fit_data.fit')
6879 tools.write_file(fname, fit_data)
6880 out = tools.run('dumpimage', '-l', fname)
6881
Simon Glassaa6e0552023-07-18 07:24:07 -06006882 def testTemplateSection(self):
6883 """Test using a template in a section (not at top level)"""
6884 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6885 data = self._DoReadFile('289_template_section.dts')
6886 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6887 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6888 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6889
Simon Glassf53a7bc2023-07-18 07:24:08 -06006890 def testMkimageSymbols(self):
6891 """Test using mkimage to build an image with symbols in it"""
6892 self._SetupSplElf('u_boot_binman_syms')
6893 data = self._DoReadFile('290_mkimage_sym.dts')
6894
6895 image = control.images['image']
6896 entries = image.GetEntries()
6897 self.assertIn('u-boot', entries)
6898 u_boot = entries['u-boot']
6899
6900 mkim = entries['mkimage']
6901 mkim_entries = mkim.GetEntries()
6902 self.assertIn('u-boot-spl', mkim_entries)
6903 spl = mkim_entries['u-boot-spl']
6904 self.assertIn('u-boot-spl2', mkim_entries)
6905 spl2 = mkim_entries['u-boot-spl2']
6906
6907 # skip the mkimage header and the area sizes
6908 mk_data = data[mkim.offset + 0x40:]
6909 size, term = struct.unpack('>LL', mk_data[:8])
6910
6911 # There should be only one image, so check that the zero terminator is
6912 # present
6913 self.assertEqual(0, term)
6914
6915 content = mk_data[8:8 + size]
6916
6917 # The image should contain the symbols from u_boot_binman_syms.c
6918 # Note that image_pos is adjusted by the base address of the image,
6919 # which is 0x10 in our test image
6920 spl_data = content[:0x18]
6921 content = content[0x1b:]
6922
6923 # After the header is a table of offsets for each image. There should
6924 # only be one image, then a 0 terminator, so figure out the real start
6925 # of the image data
6926 base = 0x40 + 8
6927
6928 # Check symbols in both u-boot-spl and u-boot-spl2
6929 for i in range(2):
6930 vals = struct.unpack('<LLQLL', spl_data)
6931
6932 # The image should contain the symbols from u_boot_binman_syms.c
6933 # Note that image_pos is adjusted by the base address of the image,
6934 # which is 0x10 in our 'u_boot_binman_syms' test image
6935 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6936 self.assertEqual(base, vals[1])
6937 self.assertEqual(spl2.offset, vals[2])
6938 # figure out the internal positions of its components
6939 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6940
6941 # Check that spl and spl2 are actually at the indicated positions
6942 self.assertEqual(
6943 elf.BINMAN_SYM_MAGIC_VALUE,
6944 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6945 self.assertEqual(
6946 elf.BINMAN_SYM_MAGIC_VALUE,
6947 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6948
6949 self.assertEqual(len(U_BOOT_DATA), vals[4])
6950
6951 # Move to next
6952 spl_data = content[:0x18]
6953
Neha Malcom Francis3b788942023-07-22 00:14:24 +05306954 def testTIBoardConfig(self):
6955 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06006956 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05306957 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
6958
6959 def testTIBoardConfigCombined(self):
6960 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06006961 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05306962 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
6963 self.assertGreater(data, configlen_noheader)
6964
6965 def testTIBoardConfigNoDataType(self):
6966 """Test that error is thrown when data type is not supported"""
6967 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06006968 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05306969 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07006970
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05306971 def testPackTiSecure(self):
6972 """Test that an image with a TI secured binary can be created"""
6973 keyfile = self.TestFile('key.key')
6974 entry_args = {
6975 'keyfile': keyfile,
6976 }
Simon Glassf1264ba2023-07-24 09:19:59 -06006977 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05306978 entry_args=entry_args)[0]
6979 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
6980
6981 def testPackTiSecureMissingTool(self):
6982 """Test that an image with a TI secured binary (non-functional) can be created
6983 when openssl is missing"""
6984 keyfile = self.TestFile('key.key')
6985 entry_args = {
6986 'keyfile': keyfile,
6987 }
6988 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06006989 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05306990 force_missing_bintools='openssl',
6991 entry_args=entry_args)
6992 err = stderr.getvalue()
6993 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6994
6995 def testPackTiSecureROM(self):
6996 """Test that a ROM image with a TI secured binary can be created"""
6997 keyfile = self.TestFile('key.key')
6998 entry_args = {
6999 'keyfile': keyfile,
7000 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007001 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307002 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007003 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307004 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007005 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307006 entry_args=entry_args)[0]
7007 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7008 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7009 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7010
7011 def testPackTiSecureROMCombined(self):
7012 """Test that a ROM image with a TI secured binary can be created"""
7013 keyfile = self.TestFile('key.key')
7014 entry_args = {
7015 'keyfile': keyfile,
7016 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007017 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307018 entry_args=entry_args)[0]
7019 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7020
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007021 def testEncryptedNoAlgo(self):
7022 """Test encrypted node with missing required properties"""
7023 with self.assertRaises(ValueError) as e:
7024 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7025 self.assertIn(
7026 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7027 str(e.exception))
7028
7029 def testEncryptedInvalidIvfile(self):
7030 """Test encrypted node with invalid iv file"""
7031 with self.assertRaises(ValueError) as e:
7032 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7033 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7034 str(e.exception))
7035
7036 def testEncryptedMissingKey(self):
7037 """Test encrypted node with missing key properties"""
7038 with self.assertRaises(ValueError) as e:
7039 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7040 self.assertIn(
7041 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7042 str(e.exception))
7043
7044 def testEncryptedKeySource(self):
7045 """Test encrypted node with key-source property"""
7046 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7047
7048 dtb = fdt.Fdt.FromData(data)
7049 dtb.Scan()
7050
7051 node = dtb.GetNode('/images/u-boot/cipher')
7052 self.assertEqual('algo-name', node.props['algo'].value)
7053 self.assertEqual('key-source-value', node.props['key-source'].value)
7054 self.assertEqual(ENCRYPTED_IV_DATA,
7055 tools.to_bytes(''.join(node.props['iv'].value)))
7056 self.assertNotIn('key', node.props)
7057
7058 def testEncryptedKeyFile(self):
7059 """Test encrypted node with key-filename property"""
7060 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7061
7062 dtb = fdt.Fdt.FromData(data)
7063 dtb.Scan()
7064
7065 node = dtb.GetNode('/images/u-boot/cipher')
7066 self.assertEqual('algo-name', node.props['algo'].value)
7067 self.assertEqual(ENCRYPTED_IV_DATA,
7068 tools.to_bytes(''.join(node.props['iv'].value)))
7069 self.assertEqual(ENCRYPTED_KEY_DATA,
7070 tools.to_bytes(''.join(node.props['key'].value)))
7071 self.assertNotIn('key-source', node.props)
7072
Lukas Funkee901faf2023-07-18 13:53:13 +02007073
7074 def testSplPubkeyDtb(self):
7075 """Test u_boot_spl_pubkey_dtb etype"""
7076 data = tools.read_file(self.TestFile("key.pem"))
7077 self._MakeInputFile("key.crt", data)
7078 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7079 image = control.images['image']
7080 entries = image.GetEntries()
7081 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7082 dtb_data = dtb_entry.GetData()
7083 dtb = fdt.Fdt.FromData(dtb_data)
7084 dtb.Scan()
7085
7086 signature_node = dtb.GetNode('/signature')
7087 self.assertIsNotNone(signature_node)
7088 key_node = signature_node.FindNode("key-key")
7089 self.assertIsNotNone(key_node)
7090 self.assertEqual(fdt_util.GetString(key_node, "required"),
7091 "conf")
7092 self.assertEqual(fdt_util.GetString(key_node, "algo"),
7093 "sha384,rsa4096")
7094 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"),
7095 "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007096
Simon Glassac599912017-11-12 21:52:22 -07007097if __name__ == "__main__":
7098 unittest.main()