blob: 2ea18d2d089f7216d6efa1519630e590388ab05f [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'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +053051EFI_CAPSULE_DATA = b'efi'
Simon Glass303f62f2019-05-17 22:00:46 -060052U_BOOT_DTB_DATA = b'udtb'
53U_BOOT_SPL_DTB_DATA = b'spldtb'
54U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass56d05412022-02-28 07:16:54 -070055U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glass303f62f2019-05-17 22:00:46 -060056X86_START16_DATA = b'start16'
57X86_START16_SPL_DATA = b'start16spl'
58X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060059X86_RESET16_DATA = b'reset16'
60X86_RESET16_SPL_DATA = b'reset16spl'
61X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060062PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
63U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
64U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
65U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass56d05412022-02-28 07:16:54 -070066U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +030067U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
68U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
69U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glass303f62f2019-05-17 22:00:46 -060070FSP_DATA = b'fsp'
71CMC_DATA = b'cmc'
72VBT_DATA = b'vbt'
73MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060074TEXT_DATA = 'text'
75TEXT_DATA2 = 'text2'
76TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060077CROS_EC_RW_DATA = b'ecrw'
78GBB_DATA = b'gbbd'
79BMPBLK_DATA = b'bmp'
80VBLOCK_DATA = b'vblk'
81FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
82 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060083COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060084COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060085REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060086FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060087FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060088FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060089ATF_BL31_DATA = b'bl31'
Roger Quadros5cdcea02022-02-19 20:50:04 +020090TEE_OS_DATA = b'this is some tee OS data'
Simon Glass3efb2972021-11-23 21:08:59 -070091ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080092OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050093SCP_DATA = b'scp'
Jonas Karlman35305492023-02-25 19:01:33 +000094ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glassa435cd12020-09-01 05:13:59 -060095TEST_FDT1_DATA = b'fdt1'
96TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060097ENV_DATA = b'var1=1\nvar2="2"'
Christian Taedcke62ac29a2023-07-17 09:05:54 +020098ENCRYPTED_IV_DATA = b'123456'
99ENCRYPTED_KEY_DATA = b'abcde'
Philippe Reynesebe96cb2022-03-28 22:57:04 +0200100PRE_LOAD_MAGIC = b'UBSH'
101PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
102PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530103TI_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 +0530104TI_UNSECURE_DATA = b'unsecuredata'
Simon Glassa435cd12020-09-01 05:13:59 -0600105
106# Subdirectory of the input dir to use to put test FDTs
107TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600108
Simon Glass2c6adba2019-07-20 12:23:47 -0600109# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600110EXTRACT_DTB_SIZE = 0x3c9
111
Simon Glass2c6adba2019-07-20 12:23:47 -0600112# Properties expected to be in the device tree when update_dtb is used
113BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
114
Simon Glassfb30e292019-07-20 12:23:51 -0600115# Extra properties expected to be in the device tree when allow-repack is used
116REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
117
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200118# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200119COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700120
Simon Glassad5cfe12023-01-07 14:07:14 -0700121TEE_ADDR = 0x5678
122
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530123# Firmware Management Protocol(FMP) GUID
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530124FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530125# Image GUID specified in the DTS
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530126CAPSULE_IMAGE_GUID = '09d7cf52-0720-4710-91d1-08469b7fe9c8'
127# Windows cert GUID
128WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530129
Simon Glass57454f42016-11-25 20:15:52 -0700130class TestFunctional(unittest.TestCase):
131 """Functional tests for binman
132
133 Most of these use a sample .dts file to build an image and then check
134 that it looks correct. The sample files are in the test/ subdirectory
135 and are numbered.
136
137 For each entry type a very small test file is created using fixed
138 string contents. This makes it easy to test that things look right, and
139 debug problems.
140
141 In some cases a 'real' file must be used - these are also supplied in
142 the test/ diurectory.
143 """
144 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600145 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700146 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600147 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700148
Simon Glass57454f42016-11-25 20:15:52 -0700149 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600150 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
151 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700152
153 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600154 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700155
156 # Create some test files
157 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
158 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
159 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600160 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700161 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700162 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700163 TestFunctional._MakeInputFile('me.bin', ME_DATA)
164 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600165 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600166
Jagdish Gediya311d4842018-09-03 21:35:08 +0530167 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600168
Simon Glassabab18c2019-08-24 07:22:49 -0600169 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
170 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700171 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600172 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600173 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600174
175 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
176 X86_RESET16_DATA)
177 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
178 X86_RESET16_SPL_DATA)
179 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
180 X86_RESET16_TPL_DATA)
181
Simon Glass57454f42016-11-25 20:15:52 -0700182 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700183 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
184 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600185 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
186 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700187 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
188 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700189 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
190 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700191 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700192 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600193 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600194 TestFunctional._MakeInputDir('devkeys')
195 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600196 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600197 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600198 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600199 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700200
Simon Glassf6290892019-08-24 07:22:53 -0600201 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
202 elf_test.BuildElfTestFiles(cls._elf_testdir)
203
Simon Glass72232452016-11-25 20:15:53 -0700204 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600205 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700206 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700207
208 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600209 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700210
Simon Glass862f8e22019-08-24 07:22:43 -0600211 shutil.copytree(cls.TestFile('files'),
212 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600213
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530214 shutil.copytree(cls.TestFile('yaml'),
215 os.path.join(cls._indir, 'yaml'))
216
Simon Glass7ba33592018-09-14 04:57:26 -0600217 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600218 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600219 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200220 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700221 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800222 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500223 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman35305492023-02-25 19:01:33 +0000224 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530225 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530226 TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600227
Simon Glassa435cd12020-09-01 05:13:59 -0600228 # Add a few .dtb files for testing
229 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
230 TEST_FDT1_DATA)
231 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
232 TEST_FDT2_DATA)
233
Simon Glassa0729502020-09-06 10:35:33 -0600234 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
235
Simon Glass5f423422022-03-05 20:19:12 -0700236 # ELF file with two sections in different parts of memory, used for both
237 # ATF and OP_TEE
238 TestFunctional._MakeInputFile('bl31.elf',
239 tools.read_file(cls.ElfTestFile('elf_sections')))
240 TestFunctional._MakeInputFile('tee.elf',
241 tools.read_file(cls.ElfTestFile('elf_sections')))
242
Simon Glassad5cfe12023-01-07 14:07:14 -0700243 # Newer OP_TEE file in v1 binary format
244 cls.make_tee_bin('tee.bin')
245
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200246 # test files for encrypted tests
247 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
248 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
249
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200250 cls.comp_bintools = {}
251 for name in COMP_BINTOOLS:
252 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600253
Simon Glass57454f42016-11-25 20:15:52 -0700254 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600255 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700256 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600257 if cls.preserve_indir:
258 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600259 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600260 if cls._indir:
261 shutil.rmtree(cls._indir)
262 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700263
Simon Glass1c420c92019-07-08 13:18:49 -0600264 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600265 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600266 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600267 """Accept arguments controlling test execution
268
269 Args:
270 preserve_indir: Preserve the shared input directory used by all
271 tests in this class.
272 preserve_outdir: Preserve the output directories used by tests. Each
273 test has its own, so this is normally only useful when running a
274 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600275 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600276 """
277 cls.preserve_indir = preserve_indir
278 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600279 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600280 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600281
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200282 def _CheckBintool(self, bintool):
283 if not bintool.is_present():
284 self.skipTest('%s not available' % bintool.name)
285
Simon Glass1de34482019-07-08 13:18:53 -0600286 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200287 bintool = self.comp_bintools['lz4']
288 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600289
Simon Glassee9d10d2019-07-20 12:24:09 -0600290 def _CleanupOutputDir(self):
291 """Remove the temporary output directory"""
292 if self.preserve_outdirs:
293 print('Preserving output dir: %s' % tools.outdir)
294 else:
Simon Glass80025522022-01-29 14:14:04 -0700295 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600296
Simon Glass57454f42016-11-25 20:15:52 -0700297 def setUp(self):
298 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700299 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700300 command.test_result = None
301
302 def tearDown(self):
303 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600304 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700305
Simon Glassb3d6fc72019-07-20 12:24:10 -0600306 def _SetupImageInTmpdir(self):
307 """Set up the output image in a new temporary directory
308
309 This is used when an image has been generated in the output directory,
310 but we want to run binman again. This will create a new output
311 directory and fail to delete the original one.
312
313 This creates a new temporary directory, copies the image to it (with a
314 new name) and removes the old output directory.
315
316 Returns:
317 Tuple:
318 Temporary directory to use
319 New image filename
320 """
Simon Glass80025522022-01-29 14:14:04 -0700321 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600322 tmpdir = tempfile.mkdtemp(prefix='binman.')
323 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700324 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600325 self._CleanupOutputDir()
326 return tmpdir, updated_fname
327
Simon Glass8425a1f2018-07-17 13:25:48 -0600328 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600329 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600330 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
331 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
332 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700333 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600334
Simon Glass57454f42016-11-25 20:15:52 -0700335 def _RunBinman(self, *args, **kwargs):
336 """Run binman using the command line
337
338 Args:
339 Arguments to pass, as a list of strings
340 kwargs: Arguments to pass to Command.RunPipe()
341 """
Simon Glass840be732022-01-29 14:14:05 -0700342 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700343 capture=True, capture_stderr=True, raise_on_error=False)
344 if result.return_code and kwargs.get('raise_on_error', True):
345 raise Exception("Error running '%s': %s" % (' '.join(args),
346 result.stdout + result.stderr))
347 return result
348
Simon Glassf46732a2019-07-08 14:25:29 -0600349 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700350 """Run binman using directly (in the same process)
351
352 Args:
353 Arguments to pass, as a list of strings
354 Returns:
355 Return value (0 for success)
356 """
Simon Glassf46732a2019-07-08 14:25:29 -0600357 argv = list(argv)
358 args = cmdline.ParseArgs(argv)
359 args.pager = 'binman-invalid-pager'
360 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700361
362 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600363 # args.verbosity = tout.DEBUG
364 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700365
Simon Glass91710b32018-07-17 13:25:32 -0600366 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600367 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300368 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100369 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700370 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis6b463da2023-07-22 00:14:44 +0530371 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass57454f42016-11-25 20:15:52 -0700372 """Run binman with a given test file
373
374 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600375 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600376 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600377 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600378 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600379 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600380 entry_args: Dict of entry args to supply to binman
381 key: arg name
382 value: value of that arg
383 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600384 use_real_dtb: True to use the test file as the contents of
385 the u-boot-dtb entry. Normally this is not needed and the
386 test contents (the U_BOOT_DTB_DATA string) can be used.
387 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300388 use_expanded: True to use expanded entries where available, e.g.
389 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600390 verbosity: Verbosity level to use (0-3, None=don't set it)
391 allow_missing: Set the '--allow-missing' flag so that missing
392 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100393 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600394 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600395 threads: Number of threads to use (None for default, 0 for
396 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600397 test_section_timeout: True to force the first time to timeout, as
398 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600399 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass66152ce2022-01-09 20:14:09 -0700400 force_missing_tools (str): comma-separated list of bintools to
401 regard as missing
Andrew Davis6b463da2023-07-22 00:14:44 +0530402 output_dir: Specific output directory to use for image using -O
Simon Glass9a798402021-11-03 21:09:17 -0600403
404 Returns:
405 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700406 """
Simon Glassf46732a2019-07-08 14:25:29 -0600407 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700408 if debug:
409 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600410 if verbosity is not None:
411 args.append('-v%d' % verbosity)
412 elif self.verbosity:
413 args.append('-v%d' % self.verbosity)
414 if self.toolpath:
415 for path in self.toolpath:
416 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600417 if threads is not None:
418 args.append('-T%d' % threads)
419 if test_section_timeout:
420 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600421 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600422 if map:
423 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600424 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600425 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600426 if not use_real_dtb:
427 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300428 if not use_expanded:
429 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600430 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600431 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600432 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600433 if allow_missing:
434 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700435 if ignore_missing:
436 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100437 if allow_fake_blobs:
438 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700439 if force_missing_bintools:
440 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600441 if update_fdt_in_elf:
442 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600443 if images:
444 for image in images:
445 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600446 if extra_indirs:
447 for indir in extra_indirs:
448 args += ['-I', indir]
Andrew Davis6b463da2023-07-22 00:14:44 +0530449 if output_dir:
450 args += ['-O', output_dir]
Simon Glass075a45c2017-11-13 18:55:00 -0700451 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700452
453 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700454 """Set up a new test device-tree file
455
456 The given file is compiled and set up as the device tree to be used
457 for ths test.
458
459 Args:
460 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600461 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700462
463 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600464 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700465 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600466 tmpdir = tempfile.mkdtemp(prefix='binmant.')
467 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600468 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700469 data = fd.read()
470 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600471 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600472 return data
Simon Glass57454f42016-11-25 20:15:52 -0700473
Simon Glass56d05412022-02-28 07:16:54 -0700474 def _GetDtbContentsForSpls(self, dtb_data, name):
475 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600476
477 For testing we don't actually have different versions of the DTB. With
478 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
479 we don't normally have any unwanted nodes.
480
481 We still want the DTBs for SPL and TPL to be different though, since
482 otherwise it is confusing to know which one we are looking at. So add
483 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600484
485 Args:
486 dtb_data: dtb data to modify (this should be a value devicetree)
487 name: Name of a new property to add
488
489 Returns:
490 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600491 """
492 dtb = fdt.Fdt.FromData(dtb_data)
493 dtb.Scan()
494 dtb.GetNode('/binman').AddZeroProp(name)
495 dtb.Sync(auto_resize=True)
496 dtb.Pack()
497 return dtb.GetContents()
498
Simon Glassed930672021-03-18 20:25:05 +1300499 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
500 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600501 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700502 """Run binman and return the resulting image
503
504 This runs binman with a given test file and then reads the resulting
505 output file. It is a shortcut function since most tests need to do
506 these steps.
507
508 Raises an assertion failure if binman returns a non-zero exit code.
509
510 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600511 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700512 use_real_dtb: True to use the test file as the contents of
513 the u-boot-dtb entry. Normally this is not needed and the
514 test contents (the U_BOOT_DTB_DATA string) can be used.
515 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300516 use_expanded: True to use expanded entries where available, e.g.
517 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600518 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600519 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600520 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600521 entry_args: Dict of entry args to supply to binman
522 key: arg name
523 value: value of that arg
524 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
525 function. If reset_dtbs is True, then the original test dtb
526 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600527 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600528 threads: Number of threads to use (None for default, 0 for
529 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700530
531 Returns:
532 Tuple:
533 Resulting image contents
534 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600535 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600536 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700537 """
Simon Glass72232452016-11-25 20:15:53 -0700538 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700539 # Use the compiled test file as the u-boot-dtb input
540 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700541 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600542
543 # For testing purposes, make a copy of the DT for SPL and TPL. Add
544 # a node indicating which it is, so aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700545 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600546 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
547 outfile = os.path.join(self._indir, dtb_fname)
548 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700549 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700550
551 try:
Simon Glass91710b32018-07-17 13:25:32 -0600552 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600553 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600554 use_expanded=use_expanded, extra_indirs=extra_indirs,
555 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700556 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700557 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700558
559 # Find the (only) image, read it and return its contents
560 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700561 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600562 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600563 if map:
Simon Glass80025522022-01-29 14:14:04 -0700564 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600565 with open(map_fname) as fd:
566 map_data = fd.read()
567 else:
568 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600569 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600570 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700571 finally:
572 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600573 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600574 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700575
Simon Glass5b4bce32019-07-08 14:25:26 -0600576 def _DoReadFileRealDtb(self, fname):
577 """Run binman with a real .dtb file and return the resulting data
578
579 Args:
580 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
581
582 Returns:
583 Resulting image contents
584 """
585 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
586
Simon Glass72232452016-11-25 20:15:53 -0700587 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600588 """Helper function which discards the device-tree binary
589
590 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600591 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600592 use_real_dtb: True to use the test file as the contents of
593 the u-boot-dtb entry. Normally this is not needed and the
594 test contents (the U_BOOT_DTB_DATA string) can be used.
595 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600596
597 Returns:
598 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600599 """
Simon Glass72232452016-11-25 20:15:53 -0700600 return self._DoReadFileDtb(fname, use_real_dtb)[0]
601
Simon Glass57454f42016-11-25 20:15:52 -0700602 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600603 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700604 """Create a new test input file, creating directories as needed
605
606 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600607 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700608 contents: File contents to write in to the file
609 Returns:
610 Full pathname of file created
611 """
Simon Glass862f8e22019-08-24 07:22:43 -0600612 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700613 dirname = os.path.dirname(pathname)
614 if dirname and not os.path.exists(dirname):
615 os.makedirs(dirname)
616 with open(pathname, 'wb') as fd:
617 fd.write(contents)
618 return pathname
619
620 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600621 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600622 """Create a new test input directory, creating directories as needed
623
624 Args:
625 dirname: Directory name to create
626
627 Returns:
628 Full pathname of directory created
629 """
Simon Glass862f8e22019-08-24 07:22:43 -0600630 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600631 if not os.path.exists(pathname):
632 os.makedirs(pathname)
633 return pathname
634
635 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600636 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600637 """Set up an ELF file with a '_dt_ucode_base_size' symbol
638
639 Args:
640 Filename of ELF file to use as SPL
641 """
Simon Glass93a806f2019-08-24 07:22:59 -0600642 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700643 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600644
645 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600646 def _SetupTplElf(cls, src_fname='bss_data'):
647 """Set up an ELF file with a '_dt_ucode_base_size' symbol
648
649 Args:
650 Filename of ELF file to use as TPL
651 """
652 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700653 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600654
655 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700656 def _SetupVplElf(cls, src_fname='bss_data'):
657 """Set up an ELF file with a '_dt_ucode_base_size' symbol
658
659 Args:
660 Filename of ELF file to use as VPL
661 """
662 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
663 tools.read_file(cls.ElfTestFile(src_fname)))
664
665 @classmethod
Lukas Funkee901faf2023-07-18 13:53:13 +0200666 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
667 """Set up an ELF file with a '_dt_ucode_base_size' symbol
668
669 Args:
670 Filename of ELF file to use as VPL
671 """
672 TestFunctional._MakeInputFile('pmu-firmware.elf',
673 tools.read_file(cls.ElfTestFile(src_fname)))
674
675 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600676 def _SetupDescriptor(cls):
677 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
678 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
679
680 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600681 def TestFile(cls, fname):
682 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700683
Simon Glassf6290892019-08-24 07:22:53 -0600684 @classmethod
685 def ElfTestFile(cls, fname):
686 return os.path.join(cls._elf_testdir, fname)
687
Simon Glassad5cfe12023-01-07 14:07:14 -0700688 @classmethod
689 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
690 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
691 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
692 dummy, paged_sz) + U_BOOT_DATA
693 data += extra_data
694 TestFunctional._MakeInputFile(fname, data)
695
Simon Glass57454f42016-11-25 20:15:52 -0700696 def AssertInList(self, grep_list, target):
697 """Assert that at least one of a list of things is in a target
698
699 Args:
700 grep_list: List of strings to check
701 target: Target string
702 """
703 for grep in grep_list:
704 if grep in target:
705 return
Simon Glass848cdb52019-05-17 22:00:50 -0600706 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700707
708 def CheckNoGaps(self, entries):
709 """Check that all entries fit together without gaps
710
711 Args:
712 entries: List of entries to check
713 """
Simon Glasse8561af2018-08-01 15:22:37 -0600714 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700715 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600716 self.assertEqual(offset, entry.offset)
717 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700718
Simon Glass72232452016-11-25 20:15:53 -0700719 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600720 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700721
722 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600723 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700724
725 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600726 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700727 """
728 return struct.unpack('>L', dtb[4:8])[0]
729
Simon Glass0f621332019-07-08 14:25:27 -0600730 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600731 def AddNode(node, path):
732 if node.name != '/':
733 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600734 for prop in node.props.values():
735 if prop.name in prop_names:
736 prop_path = path + ':' + prop.name
737 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
738 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600739 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600740 AddNode(subnode, path)
741
742 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600743 AddNode(dtb.GetRoot(), '')
744 return tree
745
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000746 def _CheckSign(self, fit, key):
747 try:
748 tools.run('fit_check_sign', '-k', key, '-f', fit)
749 except:
750 self.fail('Expected signed FIT container')
751 return False
752 return True
753
Simon Glass57454f42016-11-25 20:15:52 -0700754 def testRun(self):
755 """Test a basic run with valid args"""
756 result = self._RunBinman('-h')
757
758 def testFullHelp(self):
759 """Test that the full help is displayed with -H"""
760 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300761 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500762 # Remove possible extraneous strings
763 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
764 gothelp = result.stdout.replace(extra, '')
765 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700766 self.assertEqual(0, len(result.stderr))
767 self.assertEqual(0, result.return_code)
768
769 def testFullHelpInternal(self):
770 """Test that the full help is displayed with -H"""
771 try:
772 command.test_result = command.CommandResult()
773 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300774 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700775 finally:
776 command.test_result = None
777
778 def testHelp(self):
779 """Test that the basic help is displayed with -h"""
780 result = self._RunBinman('-h')
781 self.assertTrue(len(result.stdout) > 200)
782 self.assertEqual(0, len(result.stderr))
783 self.assertEqual(0, result.return_code)
784
Simon Glass57454f42016-11-25 20:15:52 -0700785 def testBoard(self):
786 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600787 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700788 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300789 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700790 self.assertEqual(0, result)
791
792 def testNeedBoard(self):
793 """Test that we get an error when no board ius supplied"""
794 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600795 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700796 self.assertIn("Must provide a board to process (use -b <board>)",
797 str(e.exception))
798
799 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600800 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700801 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600802 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700803 # We get one error from libfdt, and a different one from fdtget.
804 self.AssertInList(["Couldn't open blob from 'missing_file'",
805 'No such file or directory'], str(e.exception))
806
807 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600808 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700809
810 Since this is a source file it should be compiled and the error
811 will come from the device-tree compiler (dtc).
812 """
813 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600814 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700815 self.assertIn("FATAL ERROR: Unable to parse input tree",
816 str(e.exception))
817
818 def testMissingNode(self):
819 """Test that a device tree without a 'binman' node generates an error"""
820 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600821 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700822 self.assertIn("does not have a 'binman' node", str(e.exception))
823
824 def testEmpty(self):
825 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600826 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700827 self.assertEqual(0, len(result.stderr))
828 self.assertEqual(0, result.return_code)
829
830 def testInvalidEntry(self):
831 """Test that an invalid entry is flagged"""
832 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600833 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600834 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700835 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
836 "'/binman/not-a-valid-type'", str(e.exception))
837
838 def testSimple(self):
839 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600840 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700841 self.assertEqual(U_BOOT_DATA, data)
842
Simon Glass075a45c2017-11-13 18:55:00 -0700843 def testSimpleDebug(self):
844 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600845 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700846
Simon Glass57454f42016-11-25 20:15:52 -0700847 def testDual(self):
848 """Test that we can handle creating two images
849
850 This also tests image padding.
851 """
Simon Glass511f6582018-10-01 12:22:30 -0600852 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700853 self.assertEqual(0, retcode)
854
855 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600856 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700857 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700858 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600859 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700860 data = fd.read()
861 self.assertEqual(U_BOOT_DATA, data)
862
863 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600864 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700865 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700866 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600867 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700868 data = fd.read()
869 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700870 self.assertEqual(tools.get_bytes(0, 3), data[:3])
871 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700872
873 def testBadAlign(self):
874 """Test that an invalid alignment value is detected"""
875 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600876 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700877 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
878 "of two", str(e.exception))
879
880 def testPackSimple(self):
881 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600882 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700883 self.assertEqual(0, retcode)
884 self.assertIn('image', control.images)
885 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600886 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700887 self.assertEqual(5, len(entries))
888
889 # First u-boot
890 self.assertIn('u-boot', entries)
891 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600892 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700893 self.assertEqual(len(U_BOOT_DATA), entry.size)
894
895 # Second u-boot, aligned to 16-byte boundary
896 self.assertIn('u-boot-align', entries)
897 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600898 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700899 self.assertEqual(len(U_BOOT_DATA), entry.size)
900
901 # Third u-boot, size 23 bytes
902 self.assertIn('u-boot-size', entries)
903 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600904 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700905 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
906 self.assertEqual(23, entry.size)
907
908 # Fourth u-boot, placed immediate after the above
909 self.assertIn('u-boot-next', entries)
910 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600911 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700912 self.assertEqual(len(U_BOOT_DATA), entry.size)
913
Simon Glasse8561af2018-08-01 15:22:37 -0600914 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700915 self.assertIn('u-boot-fixed', entries)
916 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600917 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700918 self.assertEqual(len(U_BOOT_DATA), entry.size)
919
Simon Glass39dd2152019-07-08 14:25:47 -0600920 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700921
922 def testPackExtra(self):
923 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600924 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
925 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700926
Simon Glass57454f42016-11-25 20:15:52 -0700927 self.assertIn('image', control.images)
928 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600929 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600930 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700931
Samuel Hollande2574022023-01-21 17:25:16 -0600932 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700933 self.assertIn('u-boot', entries)
934 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600935 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700936 self.assertEqual(3, entry.pad_before)
937 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600938 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700939 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
940 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600941 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700942
943 # Second u-boot has an aligned size, but it has no effect
944 self.assertIn('u-boot-align-size-nop', entries)
945 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600946 self.assertEqual(pos, entry.offset)
947 self.assertEqual(len(U_BOOT_DATA), entry.size)
948 self.assertEqual(U_BOOT_DATA, entry.data)
949 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
950 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700951
952 # Third u-boot has an aligned size too
953 self.assertIn('u-boot-align-size', entries)
954 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600955 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700956 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600957 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700958 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600959 data[pos:pos + entry.size])
960 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700961
962 # Fourth u-boot has an aligned end
963 self.assertIn('u-boot-align-end', entries)
964 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600965 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700966 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600967 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700968 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600969 data[pos:pos + entry.size])
970 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700971
972 # Fifth u-boot immediately afterwards
973 self.assertIn('u-boot-align-both', entries)
974 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600975 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700976 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600977 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700978 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600979 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700980
Samuel Hollande2574022023-01-21 17:25:16 -0600981 # Sixth u-boot with both minimum size and aligned size
982 self.assertIn('u-boot-min-size', entries)
983 entry = entries['u-boot-min-size']
984 self.assertEqual(128, entry.offset)
985 self.assertEqual(32, entry.size)
986 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
987 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
988 data[pos:pos + entry.size])
989
Simon Glass57454f42016-11-25 20:15:52 -0700990 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -0600991 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700992
Simon Glassafb9caa2020-10-26 17:40:10 -0600993 dtb = fdt.Fdt(out_dtb_fname)
994 dtb.Scan()
995 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
996 expected = {
997 'image-pos': 0,
998 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -0600999 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -06001000
1001 'u-boot:image-pos': 0,
1002 'u-boot:offset': 0,
1003 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1004
1005 'u-boot-align-size-nop:image-pos': 12,
1006 'u-boot-align-size-nop:offset': 12,
1007 'u-boot-align-size-nop:size': 4,
1008
1009 'u-boot-align-size:image-pos': 16,
1010 'u-boot-align-size:offset': 16,
1011 'u-boot-align-size:size': 32,
1012
1013 'u-boot-align-end:image-pos': 48,
1014 'u-boot-align-end:offset': 48,
1015 'u-boot-align-end:size': 16,
1016
1017 'u-boot-align-both:image-pos': 64,
1018 'u-boot-align-both:offset': 64,
1019 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -06001020
1021 'u-boot-min-size:image-pos': 128,
1022 'u-boot-min-size:offset': 128,
1023 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -06001024 }
1025 self.assertEqual(expected, props)
1026
Simon Glass57454f42016-11-25 20:15:52 -07001027 def testPackAlignPowerOf2(self):
1028 """Test that invalid entry alignment is detected"""
1029 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001030 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001031 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1032 "of two", str(e.exception))
1033
1034 def testPackAlignSizePowerOf2(self):
1035 """Test that invalid entry size alignment is detected"""
1036 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001037 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001038 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1039 "power of two", str(e.exception))
1040
1041 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001042 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001043 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001044 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001045 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001046 "align 0x4 (4)", str(e.exception))
1047
1048 def testPackInvalidSizeAlign(self):
1049 """Test that invalid entry size alignment is detected"""
1050 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001051 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001052 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1053 "align-size 0x4 (4)", str(e.exception))
1054
1055 def testPackOverlap(self):
1056 """Test that overlapping regions are detected"""
1057 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001058 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001059 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001060 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1061 str(e.exception))
1062
1063 def testPackEntryOverflow(self):
1064 """Test that entries that overflow their size are detected"""
1065 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001066 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001067 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1068 "but entry size is 0x3 (3)", str(e.exception))
1069
1070 def testPackImageOverflow(self):
1071 """Test that entries which overflow the image size are detected"""
1072 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001073 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001074 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001075 "size 0x3 (3)", str(e.exception))
1076
1077 def testPackImageSize(self):
1078 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001079 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001080 self.assertEqual(0, retcode)
1081 self.assertIn('image', control.images)
1082 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001083 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001084
1085 def testPackImageSizeAlign(self):
1086 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001087 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001088 self.assertEqual(0, retcode)
1089 self.assertIn('image', control.images)
1090 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001091 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001092
1093 def testPackInvalidImageAlign(self):
1094 """Test that invalid image alignment is detected"""
1095 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001096 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001097 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001098 "align-size 0x8 (8)", str(e.exception))
1099
Simon Glass2a0fa982022-02-11 13:23:21 -07001100 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001101 """Test that invalid image alignment is detected"""
1102 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001103 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001104 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001105 "two", str(e.exception))
1106
1107 def testImagePadByte(self):
1108 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001109 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001110 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001111 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001112 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001113
1114 def testImageName(self):
1115 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001116 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001117 self.assertEqual(0, retcode)
1118 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001119 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001120 self.assertTrue(os.path.exists(fname))
1121
1122 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001123 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001124 self.assertTrue(os.path.exists(fname))
1125
1126 def testBlobFilename(self):
1127 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001128 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001129 self.assertEqual(BLOB_DATA, data)
1130
1131 def testPackSorted(self):
1132 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001133 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001134 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001135 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1136 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001137
Simon Glasse8561af2018-08-01 15:22:37 -06001138 def testPackZeroOffset(self):
1139 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001140 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001141 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001142 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001143 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001144 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1145 str(e.exception))
1146
1147 def testPackUbootDtb(self):
1148 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001149 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001150 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001151
1152 def testPackX86RomNoSize(self):
1153 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001154 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001155 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001156 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001157 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001158 "using end-at-4gb", str(e.exception))
1159
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301160 def test4gbAndSkipAtStartTogether(self):
1161 """Test that the end-at-4gb and skip-at-size property can't be used
1162 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001163 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301164 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001165 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001166 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301167 "'skip-at-start'", str(e.exception))
1168
Simon Glass72232452016-11-25 20:15:53 -07001169 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001170 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001171 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001172 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001173 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001174 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1175 "is outside the section '/binman' starting at "
1176 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001177 str(e.exception))
1178
1179 def testPackX86Rom(self):
1180 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001181 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001182 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001183 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1184 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001185
1186 def testPackX86RomMeNoDesc(self):
1187 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001188 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001189 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001190 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001191 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001192 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1193 str(e.exception))
1194 finally:
1195 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001196
1197 def testPackX86RomBadDesc(self):
1198 """Test that the Intel requires a descriptor entry"""
1199 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001200 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001201 self.assertIn("Node '/binman/intel-me': No offset set with "
1202 "offset-unset: should another entry provide this correct "
1203 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001204
1205 def testPackX86RomMe(self):
1206 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001207 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001208 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001209 if data[:0x1000] != expected_desc:
1210 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001211 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1212
1213 def testPackVga(self):
1214 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001215 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001216 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1217
1218 def testPackStart16(self):
1219 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001220 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001221 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1222
Jagdish Gediya311d4842018-09-03 21:35:08 +05301223 def testPackPowerpcMpc85xxBootpgResetvec(self):
1224 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1225 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001226 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301227 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1228
Simon Glass6ba679c2018-07-06 10:27:17 -06001229 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001230 """Handle running a test for insertion of microcode
1231
1232 Args:
1233 dts_fname: Name of test .dts file
1234 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001235 ucode_second: True if the microsecond entry is second instead of
1236 third
Simon Glass820af1d2018-07-06 10:27:16 -06001237
1238 Returns:
1239 Tuple:
1240 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001241 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001242 in the above (two 4-byte words)
1243 """
Simon Glass3d274232017-11-12 21:52:27 -07001244 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001245
1246 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001247 if ucode_second:
1248 ucode_content = data[len(nodtb_data):]
1249 ucode_pos = len(nodtb_data)
1250 dtb_with_ucode = ucode_content[16:]
1251 fdt_len = self.GetFdtLen(dtb_with_ucode)
1252 else:
1253 dtb_with_ucode = data[len(nodtb_data):]
1254 fdt_len = self.GetFdtLen(dtb_with_ucode)
1255 ucode_content = dtb_with_ucode[fdt_len:]
1256 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001257 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001258 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001259 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001260 dtb = fdt.FdtScan(fname)
1261 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001262 self.assertTrue(ucode)
1263 for node in ucode.subnodes:
1264 self.assertFalse(node.props.get('data'))
1265
Simon Glass72232452016-11-25 20:15:53 -07001266 # Check that the microcode appears immediately after the Fdt
1267 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001268 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001269 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1270 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001271 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001272
1273 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001274 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001275 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1276 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001277 u_boot = data[:len(nodtb_data)]
1278 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001279
1280 def testPackUbootMicrocode(self):
1281 """Test that x86 microcode can be handled correctly
1282
1283 We expect to see the following in the image, in order:
1284 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1285 place
1286 u-boot.dtb with the microcode removed
1287 the microcode
1288 """
Simon Glass511f6582018-10-01 12:22:30 -06001289 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001290 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001291 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1292 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001293
Simon Glassbac25c82017-05-27 07:38:26 -06001294 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001295 """Test that x86 microcode can be handled correctly
1296
1297 We expect to see the following in the image, in order:
1298 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1299 place
1300 u-boot.dtb with the microcode
1301 an empty microcode region
1302 """
1303 # We need the libfdt library to run this test since only that allows
1304 # finding the offset of a property. This is required by
1305 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001306 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001307
1308 second = data[len(U_BOOT_NODTB_DATA):]
1309
1310 fdt_len = self.GetFdtLen(second)
1311 third = second[fdt_len:]
1312 second = second[:fdt_len]
1313
Simon Glassbac25c82017-05-27 07:38:26 -06001314 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1315 self.assertIn(ucode_data, second)
1316 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001317
Simon Glassbac25c82017-05-27 07:38:26 -06001318 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001319 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001320 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1321 len(ucode_data))
1322 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001323 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1324 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001325
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001326 def testPackUbootSingleMicrocode(self):
1327 """Test that x86 microcode can be handled correctly with fdt_normal.
1328 """
Simon Glassbac25c82017-05-27 07:38:26 -06001329 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001330
Simon Glass996021e2016-11-25 20:15:54 -07001331 def testUBootImg(self):
1332 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001333 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001334 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001335
1336 def testNoMicrocode(self):
1337 """Test that a missing microcode region is detected"""
1338 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001339 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001340 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1341 "node found in ", str(e.exception))
1342
1343 def testMicrocodeWithoutNode(self):
1344 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1345 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001346 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001347 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1348 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1349
1350 def testMicrocodeWithoutNode2(self):
1351 """Test that a missing u-boot-ucode node is detected"""
1352 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001353 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001354 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1355 "microcode region u-boot-ucode", str(e.exception))
1356
1357 def testMicrocodeWithoutPtrInElf(self):
1358 """Test that a U-Boot binary without the microcode symbol is detected"""
1359 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001360 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001361 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001362 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001363
1364 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001365 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001366 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1367 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1368
1369 finally:
1370 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001371 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001372 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001373
1374 def testMicrocodeNotInImage(self):
1375 """Test that microcode must be placed within the image"""
1376 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001377 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001378 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1379 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001380 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001381
1382 def testWithoutMicrocode(self):
1383 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001384 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001385 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001386 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001387
1388 # Now check the device tree has no microcode
1389 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1390 second = data[len(U_BOOT_NODTB_DATA):]
1391
1392 fdt_len = self.GetFdtLen(second)
1393 self.assertEqual(dtb, second[:fdt_len])
1394
1395 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1396 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001397 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001398
1399 def testUnknownPosSize(self):
1400 """Test that microcode must be placed within the image"""
1401 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001402 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001403 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001404 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001405
1406 def testPackFsp(self):
1407 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001408 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001409 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1410
1411 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001412 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001413 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001414 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001415
1416 def testPackVbt(self):
1417 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001418 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001419 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001420
Simon Glass7f94e832017-11-12 21:52:25 -07001421 def testSplBssPad(self):
1422 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001423 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001424 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001425 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001426 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001427 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001428
Simon Glass04cda032018-10-01 21:12:42 -06001429 def testSplBssPadMissing(self):
1430 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001431 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001432 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001433 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001434 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1435 str(e.exception))
1436
Simon Glasse83679d2017-11-12 21:52:26 -07001437 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001438 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001439 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001440 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1441
Simon Glass6ba679c2018-07-06 10:27:17 -06001442 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1443 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001444
1445 We expect to see the following in the image, in order:
1446 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1447 correct place
1448 u-boot.dtb with the microcode removed
1449 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001450
1451 Args:
1452 dts: Device tree file to use for test
1453 ucode_second: True if the microsecond entry is second instead of
1454 third
Simon Glass3d274232017-11-12 21:52:27 -07001455 """
Simon Glass7057d022018-10-01 21:12:47 -06001456 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001457 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1458 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001459 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1460 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001461
Simon Glass6ba679c2018-07-06 10:27:17 -06001462 def testPackUbootSplMicrocode(self):
1463 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001464 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001465 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001466
1467 def testPackUbootSplMicrocodeReorder(self):
1468 """Test that order doesn't matter for microcode entries
1469
1470 This is the same as testPackUbootSplMicrocode but when we process the
1471 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1472 entry, so we reply on binman to try later.
1473 """
Simon Glass511f6582018-10-01 12:22:30 -06001474 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001475 ucode_second=True)
1476
Simon Glassa409c932017-11-12 21:52:28 -07001477 def testPackMrc(self):
1478 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001479 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001480 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1481
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001482 def testSplDtb(self):
1483 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001484 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001485 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001486 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1487
Simon Glass0a6da312017-11-13 18:54:56 -07001488 def testSplNoDtb(self):
1489 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001490 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001491 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001492 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1493
Simon Glass7098b7f2021-03-21 18:24:30 +13001494 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4abf7842023-07-18 07:23:54 -06001495 use_expanded=False, no_write_symbols=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001496 """Check the image contains the expected symbol values
1497
1498 Args:
1499 dts: Device tree file to use for test
1500 base_data: Data before and after 'u-boot' section
1501 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001502 entry_args: Dict of entry args to supply to binman
1503 key: arg name
1504 value: value of that arg
1505 use_expanded: True to use expanded entries where available, e.g.
1506 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001507 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001508 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001509 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1510 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001511 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001512 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001513 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001514
Simon Glass7057d022018-10-01 21:12:47 -06001515 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001516 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1517 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001518 # The image should contain the symbols from u_boot_binman_syms.c
1519 # Note that image_pos is adjusted by the base address of the image,
1520 # which is 0x10 in our test image
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001521 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1522 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glass31e04cb2021-03-18 20:24:56 +13001523 0x10 + u_boot_offset, 0x04)
Simon Glass4abf7842023-07-18 07:23:54 -06001524 if no_write_symbols:
1525 expected = (base_data +
1526 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1527 U_BOOT_DATA + base_data)
1528 else:
1529 expected = (sym_values + base_data[24:] +
1530 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1531 base_data[24:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001532 self.assertEqual(expected, data)
1533
Simon Glass31e04cb2021-03-18 20:24:56 +13001534 def testSymbols(self):
1535 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001536 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001537
1538 def testSymbolsNoDtb(self):
1539 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001540 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001541 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1542 0x38)
1543
Simon Glasse76a3e62018-06-01 09:38:11 -06001544 def testPackUnitAddress(self):
1545 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001546 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001547 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1548
Simon Glassa91e1152018-06-01 09:38:16 -06001549 def testSections(self):
1550 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001551 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001552 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1553 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1554 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001555 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001556
Simon Glass30732662018-06-01 09:38:20 -06001557 def testMap(self):
1558 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001559 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001560 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700156100000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600156200000000 00000000 00000010 section@0
156300000000 00000000 00000004 u-boot
156400000010 00000010 00000010 section@1
156500000010 00000000 00000004 u-boot
156600000020 00000020 00000004 section@2
156700000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001568''', map_data)
1569
Simon Glass3b78d532018-06-01 09:38:21 -06001570 def testNamePrefix(self):
1571 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001572 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001573 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700157400000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600157500000000 00000000 00000010 section@0
157600000000 00000000 00000004 ro-u-boot
157700000010 00000010 00000010 section@1
157800000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001579''', map_data)
1580
Simon Glass6ba679c2018-07-06 10:27:17 -06001581 def testUnknownContents(self):
1582 """Test that obtaining the contents works as expected"""
1583 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001584 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001585 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001586 "processing of contents: remaining ["
1587 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001588
Simon Glass2e1169f2018-07-06 10:27:19 -06001589 def testBadChangeSize(self):
1590 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001591 try:
1592 state.SetAllowEntryExpansion(False)
1593 with self.assertRaises(ValueError) as e:
1594 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001595 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001596 str(e.exception))
1597 finally:
1598 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001599
Simon Glassa87014e2018-07-06 10:27:42 -06001600 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001601 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001602 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001603 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001604 dtb = fdt.Fdt(out_dtb_fname)
1605 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001606 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001607 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001608 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001609 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001610 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001611 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001612 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001613 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001614 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001615 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001616 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001617 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001618 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001619
Simon Glasse8561af2018-08-01 15:22:37 -06001620 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001621 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001622 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001623 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001624 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001625 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001626 'size': 40
1627 }, props)
1628
1629 def testUpdateFdtBad(self):
1630 """Test that we detect when ProcessFdt never completes"""
1631 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001632 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001633 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001634 '[<binman.etype._testing.Entry__testing',
1635 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001636
Simon Glass91710b32018-07-17 13:25:32 -06001637 def testEntryArgs(self):
1638 """Test passing arguments to entries from the command line"""
1639 entry_args = {
1640 'test-str-arg': 'test1',
1641 'test-int-arg': '456',
1642 }
Simon Glass511f6582018-10-01 12:22:30 -06001643 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001644 self.assertIn('image', control.images)
1645 entry = control.images['image'].GetEntries()['_testing']
1646 self.assertEqual('test0', entry.test_str_fdt)
1647 self.assertEqual('test1', entry.test_str_arg)
1648 self.assertEqual(123, entry.test_int_fdt)
1649 self.assertEqual(456, entry.test_int_arg)
1650
1651 def testEntryArgsMissing(self):
1652 """Test missing arguments and properties"""
1653 entry_args = {
1654 'test-int-arg': '456',
1655 }
Simon Glass511f6582018-10-01 12:22:30 -06001656 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001657 entry = control.images['image'].GetEntries()['_testing']
1658 self.assertEqual('test0', entry.test_str_fdt)
1659 self.assertEqual(None, entry.test_str_arg)
1660 self.assertEqual(None, entry.test_int_fdt)
1661 self.assertEqual(456, entry.test_int_arg)
1662
1663 def testEntryArgsRequired(self):
1664 """Test missing arguments and properties"""
1665 entry_args = {
1666 'test-int-arg': '456',
1667 }
1668 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001669 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001670 self.assertIn("Node '/binman/_testing': "
1671 'Missing required properties/entry args: test-str-arg, '
1672 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001673 str(e.exception))
1674
1675 def testEntryArgsInvalidFormat(self):
1676 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001677 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1678 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001679 with self.assertRaises(ValueError) as e:
1680 self._DoBinman(*args)
1681 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1682
1683 def testEntryArgsInvalidInteger(self):
1684 """Test that an invalid entry-argument integer is detected"""
1685 entry_args = {
1686 'test-int-arg': 'abc',
1687 }
1688 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001689 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001690 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1691 "'test-int-arg' (value 'abc') to integer",
1692 str(e.exception))
1693
1694 def testEntryArgsInvalidDatatype(self):
1695 """Test that an invalid entry-argument datatype is detected
1696
1697 This test could be written in entry_test.py except that it needs
1698 access to control.entry_args, which seems more than that module should
1699 be able to see.
1700 """
1701 entry_args = {
1702 'test-bad-datatype-arg': '12',
1703 }
1704 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001705 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001706 entry_args=entry_args)
1707 self.assertIn('GetArg() internal error: Unknown data type ',
1708 str(e.exception))
1709
Simon Glass2ca52032018-07-17 13:25:33 -06001710 def testText(self):
1711 """Test for a text entry type"""
1712 entry_args = {
1713 'test-id': TEXT_DATA,
1714 'test-id2': TEXT_DATA2,
1715 'test-id3': TEXT_DATA3,
1716 }
Simon Glass511f6582018-10-01 12:22:30 -06001717 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001718 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001719 expected = (tools.to_bytes(TEXT_DATA) +
1720 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1721 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001722 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001723 self.assertEqual(expected, data)
1724
Simon Glass969616c2018-07-17 13:25:36 -06001725 def testEntryDocs(self):
1726 """Test for creation of entry documentation"""
1727 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001728 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001729 self.assertTrue(len(stdout.getvalue()) > 0)
1730
1731 def testEntryDocsMissing(self):
1732 """Test handling of missing entry documentation"""
1733 with self.assertRaises(ValueError) as e:
1734 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001735 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001736 self.assertIn('Documentation is missing for modules: u_boot',
1737 str(e.exception))
1738
Simon Glass704784b2018-07-17 13:25:38 -06001739 def testFmap(self):
1740 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001741 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001742 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001743 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1744 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001745 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001746 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001747 self.assertEqual(1, fhdr.ver_major)
1748 self.assertEqual(0, fhdr.ver_minor)
1749 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001750 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001751 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001752 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001753 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001754 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001755
Simon Glass82059c22021-04-03 11:05:09 +13001756 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001757 self.assertEqual(b'SECTION0', fentry.name)
1758 self.assertEqual(0, fentry.offset)
1759 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001760 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001761
1762 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001763 self.assertEqual(b'RO_U_BOOT', fentry.name)
1764 self.assertEqual(0, fentry.offset)
1765 self.assertEqual(4, fentry.size)
1766 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001767
Simon Glass82059c22021-04-03 11:05:09 +13001768 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001769 self.assertEqual(b'SECTION1', fentry.name)
1770 self.assertEqual(16, fentry.offset)
1771 self.assertEqual(16, fentry.size)
1772 self.assertEqual(0, fentry.flags)
1773
1774 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001775 self.assertEqual(b'RW_U_BOOT', fentry.name)
1776 self.assertEqual(16, fentry.offset)
1777 self.assertEqual(4, fentry.size)
1778 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001779
Simon Glass82059c22021-04-03 11:05:09 +13001780 fentry = next(fiter)
1781 self.assertEqual(b'FMAP', fentry.name)
1782 self.assertEqual(32, fentry.offset)
1783 self.assertEqual(expect_size, fentry.size)
1784 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001785
Simon Glassdb168d42018-07-17 13:25:39 -06001786 def testBlobNamedByArg(self):
1787 """Test we can add a blob with the filename coming from an entry arg"""
1788 entry_args = {
1789 'cros-ec-rw-path': 'ecrw.bin',
1790 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001791 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001792
Simon Glass53f53992018-07-17 13:25:40 -06001793 def testFill(self):
1794 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001795 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001796 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001797 self.assertEqual(expected, data)
1798
1799 def testFillNoSize(self):
1800 """Test for an fill entry type with no size"""
1801 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001802 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001803 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001804 str(e.exception))
1805
Simon Glassc1ae83c2018-07-17 13:25:44 -06001806 def _HandleGbbCommand(self, pipe_list):
1807 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001808 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001809 fname = pipe_list[0][-1]
1810 # Append our GBB data to the file, which will happen every time the
1811 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001812 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001813 fd.write(GBB_DATA)
1814 return command.CommandResult()
1815
1816 def testGbb(self):
1817 """Test for the Chromium OS Google Binary Block"""
1818 command.test_result = self._HandleGbbCommand
1819 entry_args = {
1820 'keydir': 'devkeys',
1821 'bmpblk': 'bmpblk.bin',
1822 }
Simon Glass511f6582018-10-01 12:22:30 -06001823 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001824
1825 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001826 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1827 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001828 self.assertEqual(expected, data)
1829
1830 def testGbbTooSmall(self):
1831 """Test for the Chromium OS Google Binary Block being large enough"""
1832 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001833 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001834 self.assertIn("Node '/binman/gbb': GBB is too small",
1835 str(e.exception))
1836
1837 def testGbbNoSize(self):
1838 """Test for the Chromium OS Google Binary Block having a size"""
1839 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001840 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001841 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1842 str(e.exception))
1843
Simon Glass66152ce2022-01-09 20:14:09 -07001844 def testGbbMissing(self):
1845 """Test that binman still produces an image if futility is missing"""
1846 entry_args = {
1847 'keydir': 'devkeys',
1848 }
1849 with test_util.capture_sys_output() as (_, stderr):
1850 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1851 entry_args=entry_args)
1852 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001853 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001854
Simon Glass5c350162018-07-17 13:25:47 -06001855 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001856 """Fake calls to the futility utility
1857
1858 The expected pipe is:
1859
1860 [('futility', 'vbutil_firmware', '--vblock',
1861 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1862 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1863 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1864 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1865
1866 This writes to the output file (here, 'vblock.vblock'). If
1867 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1868 of the input data (here, 'input.vblock').
1869 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001870 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001871 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001872 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001873 if self._hash_data:
1874 infile = pipe_list[0][11]
1875 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001876 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001877 m.update(data)
1878 fd.write(m.digest())
1879 else:
1880 fd.write(VBLOCK_DATA)
1881
Simon Glass5c350162018-07-17 13:25:47 -06001882 return command.CommandResult()
1883
1884 def testVblock(self):
1885 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001886 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001887 command.test_result = self._HandleVblockCommand
1888 entry_args = {
1889 'keydir': 'devkeys',
1890 }
Simon Glass511f6582018-10-01 12:22:30 -06001891 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001892 entry_args=entry_args)
1893 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1894 self.assertEqual(expected, data)
1895
1896 def testVblockNoContent(self):
1897 """Test we detect a vblock which has no content to sign"""
1898 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001899 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001900 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001901 'property', str(e.exception))
1902
1903 def testVblockBadPhandle(self):
1904 """Test that we detect a vblock with an invalid phandle in contents"""
1905 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001906 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001907 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1908 '1000', str(e.exception))
1909
1910 def testVblockBadEntry(self):
1911 """Test that we detect an entry that points to a non-entry"""
1912 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001913 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001914 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1915 "'other'", str(e.exception))
1916
Simon Glass220c6222021-01-06 21:35:17 -07001917 def testVblockContent(self):
1918 """Test that the vblock signs the right data"""
1919 self._hash_data = True
1920 command.test_result = self._HandleVblockCommand
1921 entry_args = {
1922 'keydir': 'devkeys',
1923 }
1924 data = self._DoReadFileDtb(
1925 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1926 entry_args=entry_args)[0]
1927 hashlen = 32 # SHA256 hash is 32 bytes
1928 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1929 hashval = data[-hashlen:]
1930 dtb = data[len(U_BOOT_DATA):-hashlen]
1931
1932 expected_data = U_BOOT_DATA + dtb
1933
1934 # The hashval should be a hash of the dtb
1935 m = hashlib.sha256()
1936 m.update(expected_data)
1937 expected_hashval = m.digest()
1938 self.assertEqual(expected_hashval, hashval)
1939
Simon Glass66152ce2022-01-09 20:14:09 -07001940 def testVblockMissing(self):
1941 """Test that binman still produces an image if futility is missing"""
1942 entry_args = {
1943 'keydir': 'devkeys',
1944 }
1945 with test_util.capture_sys_output() as (_, stderr):
1946 self._DoTestFile('074_vblock.dts',
1947 force_missing_bintools='futility',
1948 entry_args=entry_args)
1949 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001950 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001951
Simon Glass8425a1f2018-07-17 13:25:48 -06001952 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001953 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001954 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001955 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001956 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001957 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1958
Simon Glass24b97442018-07-17 13:25:51 -06001959 def testUsesPos(self):
1960 """Test that the 'pos' property cannot be used anymore"""
1961 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001962 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001963 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1964 "'pos'", str(e.exception))
1965
Simon Glass274bf092018-09-14 04:57:08 -06001966 def testFillZero(self):
1967 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001968 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001969 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001970
Simon Glass267de432018-09-14 04:57:09 -06001971 def testTextMissing(self):
1972 """Test for a text entry type where there is no text"""
1973 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001974 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001975 self.assertIn("Node '/binman/text': No value provided for text label "
1976 "'test-id'", str(e.exception))
1977
Simon Glassed40e962018-09-14 04:57:10 -06001978 def testPackStart16Tpl(self):
1979 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001980 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001981 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1982
Simon Glass3b376c32018-09-14 04:57:12 -06001983 def testSelectImage(self):
1984 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001985 expected = 'Skipping images: image1'
1986
1987 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001988 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001989 with test_util.capture_sys_output() as (stdout, stderr):
1990 retcode = self._DoTestFile('006_dual_image.dts',
1991 verbosity=verbosity,
1992 images=['image2'])
1993 self.assertEqual(0, retcode)
1994 if verbosity:
1995 self.assertIn(expected, stdout.getvalue())
1996 else:
1997 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001998
Simon Glass80025522022-01-29 14:14:04 -07001999 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2000 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06002001 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06002002
Simon Glasse219aa42018-09-14 04:57:24 -06002003 def testUpdateFdtAll(self):
2004 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06002005 self._SetupSplElf()
2006 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06002007 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06002008
2009 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06002010 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002011 'image-pos': 0,
2012 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06002013 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002014 'section:image-pos': 0,
2015 'section:size': 565,
2016 'section/u-boot-dtb:offset': 0,
2017 'section/u-boot-dtb:image-pos': 0,
2018 'section/u-boot-dtb:size': 565,
2019 'u-boot-spl-dtb:offset': 565,
2020 'u-boot-spl-dtb:image-pos': 565,
2021 'u-boot-spl-dtb:size': 585,
2022 'u-boot-tpl-dtb:offset': 1150,
2023 'u-boot-tpl-dtb:image-pos': 1150,
2024 'u-boot-tpl-dtb:size': 585,
2025 'u-boot-vpl-dtb:image-pos': 1735,
2026 'u-boot-vpl-dtb:offset': 1735,
2027 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002028 }
2029
2030 # We expect three device-tree files in the output, one after the other.
2031 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2032 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2033 # main U-Boot tree. All three should have the same postions and offset.
2034 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002035 self.maxDiff = None
2036 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002037 dtb = fdt.Fdt.FromData(data[start:])
2038 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002039 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002040 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002041 expected = dict(base_expected)
2042 if item:
2043 expected[item] = 0
2044 self.assertEqual(expected, props)
2045 start += dtb._fdt_obj.totalsize()
2046
2047 def testUpdateFdtOutput(self):
2048 """Test that output DTB files are updated"""
2049 try:
Simon Glass511f6582018-10-01 12:22:30 -06002050 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002051 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2052
2053 # Unfortunately, compiling a source file always results in a file
2054 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002055 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002056 # binman as a file called u-boot.dtb. To fix this, copy the file
2057 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002058 start = 0
2059 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002060 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002061 dtb = fdt.Fdt.FromData(data[start:])
2062 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002063 pathname = tools.get_output_filename(os.path.split(fname)[1])
2064 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002065 name = os.path.split(fname)[0]
2066
2067 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002068 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002069 else:
2070 orig_indata = dtb_data
2071 self.assertNotEqual(outdata, orig_indata,
2072 "Expected output file '%s' be updated" % pathname)
2073 self.assertEqual(outdata, data[start:start + size],
2074 "Expected output file '%s' to match output image" %
2075 pathname)
2076 start += size
2077 finally:
2078 self._ResetDtbs()
2079
Simon Glass7ba33592018-09-14 04:57:26 -06002080 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002081 bintool = self.comp_bintools['lz4']
2082 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002083
2084 def testCompress(self):
2085 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002086 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002087 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002088 use_real_dtb=True, update_dtb=True)
2089 dtb = fdt.Fdt(out_dtb_fname)
2090 dtb.Scan()
2091 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2092 orig = self._decompress(data)
2093 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002094
2095 # Do a sanity check on various fields
2096 image = control.images['image']
2097 entries = image.GetEntries()
2098 self.assertEqual(1, len(entries))
2099
2100 entry = entries['blob']
2101 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2102 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2103 orig = self._decompress(entry.data)
2104 self.assertEqual(orig, entry.uncomp_data)
2105
Simon Glass72eeff12020-10-26 17:40:16 -06002106 self.assertEqual(image.data, entry.data)
2107
Simon Glass7ba33592018-09-14 04:57:26 -06002108 expected = {
2109 'blob:uncomp-size': len(COMPRESS_DATA),
2110 'blob:size': len(data),
2111 'size': len(data),
2112 }
2113 self.assertEqual(expected, props)
2114
Simon Glassac6328c2018-09-14 04:57:28 -06002115 def testFiles(self):
2116 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002117 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002118 self.assertEqual(FILES_DATA, data)
2119
2120 def testFilesCompress(self):
2121 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002122 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002123 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002124
2125 image = control.images['image']
2126 entries = image.GetEntries()
2127 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002128 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002129
Simon Glass303f62f2019-05-17 22:00:46 -06002130 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002131 for i in range(1, 3):
2132 key = '%d.dat' % i
2133 start = entries[key].image_pos
2134 len = entries[key].size
2135 chunk = data[start:start + len]
2136 orig += self._decompress(chunk)
2137
2138 self.assertEqual(FILES_DATA, orig)
2139
2140 def testFilesMissing(self):
2141 """Test missing files"""
2142 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002143 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002144 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2145 'no files', str(e.exception))
2146
2147 def testFilesNoPattern(self):
2148 """Test missing files"""
2149 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002150 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002151 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2152 str(e.exception))
2153
Simon Glassdd156a42022-03-05 20:18:59 -07002154 def testExtendSize(self):
2155 """Test an extending entry"""
2156 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002157 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002158 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2159 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2160 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2161 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002162 self.assertEqual(expect, data)
2163 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700216400000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600216500000000 00000000 00000008 fill
216600000008 00000008 00000004 u-boot
21670000000c 0000000c 00000004 section
21680000000c 00000000 00000003 intel-mrc
216900000010 00000010 00000004 u-boot2
217000000014 00000014 0000000c section2
217100000014 00000000 00000008 fill
21720000001c 00000008 00000004 u-boot
217300000020 00000020 00000008 fill2
2174''', map_data)
2175
Simon Glassdd156a42022-03-05 20:18:59 -07002176 def testExtendSizeBad(self):
2177 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002178 with test_util.capture_sys_output() as (stdout, stderr):
2179 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002180 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002181 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2182 'expanding entry', str(e.exception))
2183
Simon Glassae7cf032018-09-14 04:57:31 -06002184 def testHash(self):
2185 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002186 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002187 use_real_dtb=True, update_dtb=True)
2188 dtb = fdt.Fdt(out_dtb_fname)
2189 dtb.Scan()
2190 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2191 m = hashlib.sha256()
2192 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002193 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002194
2195 def testHashNoAlgo(self):
2196 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002197 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002198 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2199 'hash node', str(e.exception))
2200
2201 def testHashBadAlgo(self):
2202 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002203 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002204 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002205 str(e.exception))
2206
2207 def testHashSection(self):
2208 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002209 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002210 use_real_dtb=True, update_dtb=True)
2211 dtb = fdt.Fdt(out_dtb_fname)
2212 dtb.Scan()
2213 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2214 m = hashlib.sha256()
2215 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002216 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002217 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002218
Simon Glass3fb4f422018-09-14 04:57:32 -06002219 def testPackUBootTplMicrocode(self):
2220 """Test that x86 microcode can be handled correctly in TPL
2221
2222 We expect to see the following in the image, in order:
2223 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2224 place
2225 u-boot-tpl.dtb with the microcode removed
2226 the microcode
2227 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002228 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002229 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002230 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002231 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2232 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002233
Simon Glassc64aea52018-09-14 04:57:34 -06002234 def testFmapX86(self):
2235 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002236 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002237 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002238 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002239 self.assertEqual(expected, data[:32])
2240 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2241
2242 self.assertEqual(0x100, fhdr.image_size)
2243
2244 self.assertEqual(0, fentries[0].offset)
2245 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002246 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002247
2248 self.assertEqual(4, fentries[1].offset)
2249 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002250 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002251
2252 self.assertEqual(32, fentries[2].offset)
2253 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2254 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002255 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002256
2257 def testFmapX86Section(self):
2258 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002259 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002260 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002261 self.assertEqual(expected, data[:32])
2262 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2263
Simon Glassb1d414c2021-04-03 11:05:10 +13002264 self.assertEqual(0x180, fhdr.image_size)
2265 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002266 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002267
Simon Glass82059c22021-04-03 11:05:09 +13002268 fentry = next(fiter)
2269 self.assertEqual(b'U_BOOT', fentry.name)
2270 self.assertEqual(0, fentry.offset)
2271 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002272
Simon Glass82059c22021-04-03 11:05:09 +13002273 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002274 self.assertEqual(b'SECTION', fentry.name)
2275 self.assertEqual(4, fentry.offset)
2276 self.assertEqual(0x20 + expect_size, fentry.size)
2277
2278 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002279 self.assertEqual(b'INTEL_MRC', fentry.name)
2280 self.assertEqual(4, fentry.offset)
2281 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002282
Simon Glass82059c22021-04-03 11:05:09 +13002283 fentry = next(fiter)
2284 self.assertEqual(b'FMAP', fentry.name)
2285 self.assertEqual(36, fentry.offset)
2286 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002287
Simon Glassb1714232018-09-14 04:57:35 -06002288 def testElf(self):
2289 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002290 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002291 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002292 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002293 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002294 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002295
Simon Glass0d673792019-07-08 13:18:25 -06002296 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002297 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002298 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002299 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002300 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002301 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002302
Simon Glasscd817d52018-09-14 04:57:36 -06002303 def testPackOverlapMap(self):
2304 """Test that overlapping regions are detected"""
2305 with test_util.capture_sys_output() as (stdout, stderr):
2306 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002307 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002308 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002309 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2310 stdout.getvalue())
2311
2312 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002313 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002314 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002315 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002316 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002317<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002318<none> 00000000 00000004 u-boot
2319<none> 00000003 00000004 u-boot-align
2320''', map_data)
2321
Simon Glass0d673792019-07-08 13:18:25 -06002322 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002323 """Test that an image with an Intel Reference code binary works"""
2324 data = self._DoReadFile('100_intel_refcode.dts')
2325 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2326
Simon Glasseb023b32019-04-25 21:58:39 -06002327 def testSectionOffset(self):
2328 """Tests use of a section with an offset"""
2329 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2330 map=True)
2331 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700233200000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600233300000004 00000004 00000010 section@0
233400000004 00000000 00000004 u-boot
233500000018 00000018 00000010 section@1
233600000018 00000000 00000004 u-boot
23370000002c 0000002c 00000004 section@2
23380000002c 00000000 00000004 u-boot
2339''', map_data)
2340 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002341 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2342 tools.get_bytes(0x21, 12) +
2343 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2344 tools.get_bytes(0x61, 12) +
2345 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2346 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002347
Simon Glass1de34482019-07-08 13:18:53 -06002348 def testCbfsRaw(self):
2349 """Test base handling of a Coreboot Filesystem (CBFS)
2350
2351 The exact contents of the CBFS is verified by similar tests in
2352 cbfs_util_test.py. The tests here merely check that the files added to
2353 the CBFS can be found in the final image.
2354 """
2355 data = self._DoReadFile('102_cbfs_raw.dts')
2356 size = 0xb0
2357
2358 cbfs = cbfs_util.CbfsReader(data)
2359 self.assertEqual(size, cbfs.rom_size)
2360
2361 self.assertIn('u-boot-dtb', cbfs.files)
2362 cfile = cbfs.files['u-boot-dtb']
2363 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2364
2365 def testCbfsArch(self):
2366 """Test on non-x86 architecture"""
2367 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2368 size = 0x100
2369
2370 cbfs = cbfs_util.CbfsReader(data)
2371 self.assertEqual(size, cbfs.rom_size)
2372
2373 self.assertIn('u-boot-dtb', cbfs.files)
2374 cfile = cbfs.files['u-boot-dtb']
2375 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2376
2377 def testCbfsStage(self):
2378 """Tests handling of a Coreboot Filesystem (CBFS)"""
2379 if not elf.ELF_TOOLS:
2380 self.skipTest('Python elftools not available')
2381 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2382 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2383 size = 0xb0
2384
2385 data = self._DoReadFile('104_cbfs_stage.dts')
2386 cbfs = cbfs_util.CbfsReader(data)
2387 self.assertEqual(size, cbfs.rom_size)
2388
2389 self.assertIn('u-boot', cbfs.files)
2390 cfile = cbfs.files['u-boot']
2391 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2392
2393 def testCbfsRawCompress(self):
2394 """Test handling of compressing raw files"""
2395 self._CheckLz4()
2396 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2397 size = 0x140
2398
2399 cbfs = cbfs_util.CbfsReader(data)
2400 self.assertIn('u-boot', cbfs.files)
2401 cfile = cbfs.files['u-boot']
2402 self.assertEqual(COMPRESS_DATA, cfile.data)
2403
2404 def testCbfsBadArch(self):
2405 """Test handling of a bad architecture"""
2406 with self.assertRaises(ValueError) as e:
2407 self._DoReadFile('106_cbfs_bad_arch.dts')
2408 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2409
2410 def testCbfsNoSize(self):
2411 """Test handling of a missing size property"""
2412 with self.assertRaises(ValueError) as e:
2413 self._DoReadFile('107_cbfs_no_size.dts')
2414 self.assertIn('entry must have a size property', str(e.exception))
2415
Simon Glass3e28f4f2021-11-23 11:03:54 -07002416 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002417 """Test handling of a CBFS entry which does not provide contentsy"""
2418 with self.assertRaises(ValueError) as e:
2419 self._DoReadFile('108_cbfs_no_contents.dts')
2420 self.assertIn('Could not complete processing of contents',
2421 str(e.exception))
2422
2423 def testCbfsBadCompress(self):
2424 """Test handling of a bad architecture"""
2425 with self.assertRaises(ValueError) as e:
2426 self._DoReadFile('109_cbfs_bad_compress.dts')
2427 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2428 str(e.exception))
2429
2430 def testCbfsNamedEntries(self):
2431 """Test handling of named entries"""
2432 data = self._DoReadFile('110_cbfs_name.dts')
2433
2434 cbfs = cbfs_util.CbfsReader(data)
2435 self.assertIn('FRED', cbfs.files)
2436 cfile1 = cbfs.files['FRED']
2437 self.assertEqual(U_BOOT_DATA, cfile1.data)
2438
2439 self.assertIn('hello', cbfs.files)
2440 cfile2 = cbfs.files['hello']
2441 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2442
Simon Glass759af872019-07-08 13:18:54 -06002443 def _SetupIfwi(self, fname):
2444 """Set up to run an IFWI test
2445
2446 Args:
2447 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2448 """
2449 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002450 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002451
2452 # Intel Integrated Firmware Image (IFWI) file
2453 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2454 data = fd.read()
2455 TestFunctional._MakeInputFile(fname,data)
2456
2457 def _CheckIfwi(self, data):
2458 """Check that an image with an IFWI contains the correct output
2459
2460 Args:
2461 data: Conents of output file
2462 """
Simon Glass80025522022-01-29 14:14:04 -07002463 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002464 if data[:0x1000] != expected_desc:
2465 self.fail('Expected descriptor binary at start of image')
2466
2467 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002468 image_fname = tools.get_output_filename('image.bin')
2469 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002470 ifwitool = bintool.Bintool.create('ifwitool')
2471 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002472
Simon Glass80025522022-01-29 14:14:04 -07002473 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002474 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002475
2476 def testPackX86RomIfwi(self):
2477 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2478 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002479 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002480 self._CheckIfwi(data)
2481
2482 def testPackX86RomIfwiNoDesc(self):
2483 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2484 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002485 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002486 self._CheckIfwi(data)
2487
2488 def testPackX86RomIfwiNoData(self):
2489 """Test that an x86 ROM with IFWI handles missing data"""
2490 self._SetupIfwi('ifwi.bin')
2491 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002492 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002493 self.assertIn('Could not complete processing of contents',
2494 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002495
Simon Glass66152ce2022-01-09 20:14:09 -07002496 def testIfwiMissing(self):
2497 """Test that binman still produces an image if ifwitool is missing"""
2498 self._SetupIfwi('fitimage.bin')
2499 with test_util.capture_sys_output() as (_, stderr):
2500 self._DoTestFile('111_x86_rom_ifwi.dts',
2501 force_missing_bintools='ifwitool')
2502 err = stderr.getvalue()
2503 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002504 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002505
Simon Glassc2f1aed2019-07-08 13:18:56 -06002506 def testCbfsOffset(self):
2507 """Test a CBFS with files at particular offsets
2508
2509 Like all CFBS tests, this is just checking the logic that calls
2510 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2511 """
2512 data = self._DoReadFile('114_cbfs_offset.dts')
2513 size = 0x200
2514
2515 cbfs = cbfs_util.CbfsReader(data)
2516 self.assertEqual(size, cbfs.rom_size)
2517
2518 self.assertIn('u-boot', cbfs.files)
2519 cfile = cbfs.files['u-boot']
2520 self.assertEqual(U_BOOT_DATA, cfile.data)
2521 self.assertEqual(0x40, cfile.cbfs_offset)
2522
2523 self.assertIn('u-boot-dtb', cbfs.files)
2524 cfile2 = cbfs.files['u-boot-dtb']
2525 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2526 self.assertEqual(0x140, cfile2.cbfs_offset)
2527
Simon Glass0f621332019-07-08 14:25:27 -06002528 def testFdtmap(self):
2529 """Test an FDT map can be inserted in the image"""
2530 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2531 fdtmap_data = data[len(U_BOOT_DATA):]
2532 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002533 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002534 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002535
2536 fdt_data = fdtmap_data[16:]
2537 dtb = fdt.Fdt.FromData(fdt_data)
2538 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002539 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002540 self.assertEqual({
2541 'image-pos': 0,
2542 'offset': 0,
2543 'u-boot:offset': 0,
2544 'u-boot:size': len(U_BOOT_DATA),
2545 'u-boot:image-pos': 0,
2546 'fdtmap:image-pos': 4,
2547 'fdtmap:offset': 4,
2548 'fdtmap:size': len(fdtmap_data),
2549 'size': len(data),
2550 }, props)
2551
2552 def testFdtmapNoMatch(self):
2553 """Check handling of an FDT map when the section cannot be found"""
2554 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2555
2556 # Mangle the section name, which should cause a mismatch between the
2557 # correct FDT path and the one expected by the section
2558 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002559 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002560 entries = image.GetEntries()
2561 fdtmap = entries['fdtmap']
2562 with self.assertRaises(ValueError) as e:
2563 fdtmap._GetFdtmap()
2564 self.assertIn("Cannot locate node for path '/binman-suffix'",
2565 str(e.exception))
2566
Simon Glasscec34ba2019-07-08 14:25:28 -06002567 def testFdtmapHeader(self):
2568 """Test an FDT map and image header can be inserted in the image"""
2569 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2570 fdtmap_pos = len(U_BOOT_DATA)
2571 fdtmap_data = data[fdtmap_pos:]
2572 fdt_data = fdtmap_data[16:]
2573 dtb = fdt.Fdt.FromData(fdt_data)
2574 fdt_size = dtb.GetFdtObj().totalsize()
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] & 0xffffffff
2578 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2579
2580 def testFdtmapHeaderStart(self):
2581 """Test an image header can be inserted at the image start"""
2582 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2583 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2584 hdr_data = data[:8]
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 testFdtmapHeaderPos(self):
2590 """Test an image header can be inserted at a chosen position"""
2591 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2592 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2593 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002594 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002595 offset = struct.unpack('<I', hdr_data[4:])[0]
2596 self.assertEqual(fdtmap_pos, offset)
2597
2598 def testHeaderMissingFdtmap(self):
2599 """Test an image header requires an fdtmap"""
2600 with self.assertRaises(ValueError) as e:
2601 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2602 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2603 str(e.exception))
2604
2605 def testHeaderNoLocation(self):
2606 """Test an image header with a no specified location is detected"""
2607 with self.assertRaises(ValueError) as e:
2608 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2609 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2610 str(e.exception))
2611
Simon Glasse61b6f62019-07-08 14:25:37 -06002612 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002613 """Test extending an entry after it is packed"""
2614 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002615 self.assertEqual(b'aaa', data[:3])
2616 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2617 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002618
Simon Glassdd156a42022-03-05 20:18:59 -07002619 def testEntryExtendBad(self):
2620 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002621 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002622 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002623 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002624 str(e.exception))
2625
Simon Glassdd156a42022-03-05 20:18:59 -07002626 def testEntryExtendSection(self):
2627 """Test extending an entry within a section after it is packed"""
2628 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002629 self.assertEqual(b'aaa', data[:3])
2630 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2631 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002632
Simon Glass90d29682019-07-08 14:25:38 -06002633 def testCompressDtb(self):
2634 """Test that compress of device-tree files is supported"""
2635 self._CheckLz4()
2636 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2637 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2638 comp_data = data[len(U_BOOT_DATA):]
2639 orig = self._decompress(comp_data)
2640 dtb = fdt.Fdt.FromData(orig)
2641 dtb.Scan()
2642 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2643 expected = {
2644 'u-boot:size': len(U_BOOT_DATA),
2645 'u-boot-dtb:uncomp-size': len(orig),
2646 'u-boot-dtb:size': len(comp_data),
2647 'size': len(data),
2648 }
2649 self.assertEqual(expected, props)
2650
Simon Glass151bbbf2019-07-08 14:25:41 -06002651 def testCbfsUpdateFdt(self):
2652 """Test that we can update the device tree with CBFS offset/size info"""
2653 self._CheckLz4()
2654 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2655 update_dtb=True)
2656 dtb = fdt.Fdt(out_dtb_fname)
2657 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002658 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002659 del props['cbfs/u-boot:size']
2660 self.assertEqual({
2661 'offset': 0,
2662 'size': len(data),
2663 'image-pos': 0,
2664 'cbfs:offset': 0,
2665 'cbfs:size': len(data),
2666 'cbfs:image-pos': 0,
2667 'cbfs/u-boot:offset': 0x38,
2668 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2669 'cbfs/u-boot:image-pos': 0x38,
2670 'cbfs/u-boot-dtb:offset': 0xb8,
2671 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2672 'cbfs/u-boot-dtb:image-pos': 0xb8,
2673 }, props)
2674
Simon Glass3c9b4f22019-07-08 14:25:42 -06002675 def testCbfsBadType(self):
2676 """Test an image header with a no specified location is detected"""
2677 with self.assertRaises(ValueError) as e:
2678 self._DoReadFile('126_cbfs_bad_type.dts')
2679 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2680
Simon Glass6b156f82019-07-08 14:25:43 -06002681 def testList(self):
2682 """Test listing the files in an image"""
2683 self._CheckLz4()
2684 data = self._DoReadFile('127_list.dts')
2685 image = control.images['image']
2686 entries = image.BuildEntryList()
2687 self.assertEqual(7, len(entries))
2688
2689 ent = entries[0]
2690 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002691 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002692 self.assertEqual('section', ent.etype)
2693 self.assertEqual(len(data), ent.size)
2694 self.assertEqual(0, ent.image_pos)
2695 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002696 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002697
2698 ent = entries[1]
2699 self.assertEqual(1, ent.indent)
2700 self.assertEqual('u-boot', ent.name)
2701 self.assertEqual('u-boot', ent.etype)
2702 self.assertEqual(len(U_BOOT_DATA), ent.size)
2703 self.assertEqual(0, ent.image_pos)
2704 self.assertEqual(None, ent.uncomp_size)
2705 self.assertEqual(0, ent.offset)
2706
2707 ent = entries[2]
2708 self.assertEqual(1, ent.indent)
2709 self.assertEqual('section', ent.name)
2710 self.assertEqual('section', ent.etype)
2711 section_size = ent.size
2712 self.assertEqual(0x100, ent.image_pos)
2713 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002714 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002715
2716 ent = entries[3]
2717 self.assertEqual(2, ent.indent)
2718 self.assertEqual('cbfs', ent.name)
2719 self.assertEqual('cbfs', ent.etype)
2720 self.assertEqual(0x400, ent.size)
2721 self.assertEqual(0x100, ent.image_pos)
2722 self.assertEqual(None, ent.uncomp_size)
2723 self.assertEqual(0, ent.offset)
2724
2725 ent = entries[4]
2726 self.assertEqual(3, ent.indent)
2727 self.assertEqual('u-boot', ent.name)
2728 self.assertEqual('u-boot', ent.etype)
2729 self.assertEqual(len(U_BOOT_DATA), ent.size)
2730 self.assertEqual(0x138, ent.image_pos)
2731 self.assertEqual(None, ent.uncomp_size)
2732 self.assertEqual(0x38, ent.offset)
2733
2734 ent = entries[5]
2735 self.assertEqual(3, ent.indent)
2736 self.assertEqual('u-boot-dtb', ent.name)
2737 self.assertEqual('text', ent.etype)
2738 self.assertGreater(len(COMPRESS_DATA), ent.size)
2739 self.assertEqual(0x178, ent.image_pos)
2740 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2741 self.assertEqual(0x78, ent.offset)
2742
2743 ent = entries[6]
2744 self.assertEqual(2, ent.indent)
2745 self.assertEqual('u-boot-dtb', ent.name)
2746 self.assertEqual('u-boot-dtb', ent.etype)
2747 self.assertEqual(0x500, ent.image_pos)
2748 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2749 dtb_size = ent.size
2750 # Compressing this data expands it since headers are added
2751 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2752 self.assertEqual(0x400, ent.offset)
2753
2754 self.assertEqual(len(data), 0x100 + section_size)
2755 self.assertEqual(section_size, 0x400 + dtb_size)
2756
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002757 def testFindFdtmap(self):
2758 """Test locating an FDT map in an image"""
2759 self._CheckLz4()
2760 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2761 image = control.images['image']
2762 entries = image.GetEntries()
2763 entry = entries['fdtmap']
2764 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2765
2766 def testFindFdtmapMissing(self):
2767 """Test failing to locate an FDP map"""
2768 data = self._DoReadFile('005_simple.dts')
2769 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2770
Simon Glassed39a3c2019-07-08 14:25:45 -06002771 def testFindImageHeader(self):
2772 """Test locating a image header"""
2773 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002774 data = self.data = self._DoReadFileRealDtb('128_decode_image.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 testFindImageHeaderStart(self):
2782 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002783 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002784 image = control.images['image']
2785 entries = image.GetEntries()
2786 entry = entries['fdtmap']
2787 # The header should point to the FDT map
2788 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2789
2790 def testFindImageHeaderMissing(self):
2791 """Test failing to locate an image header"""
2792 data = self._DoReadFile('005_simple.dts')
2793 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2794
Simon Glassb8424fa2019-07-08 14:25:46 -06002795 def testReadImage(self):
2796 """Test reading an image and accessing its FDT map"""
2797 self._CheckLz4()
2798 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002799 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002800 orig_image = control.images['image']
2801 image = Image.FromFile(image_fname)
2802 self.assertEqual(orig_image.GetEntries().keys(),
2803 image.GetEntries().keys())
2804
2805 orig_entry = orig_image.GetEntries()['fdtmap']
2806 entry = image.GetEntries()['fdtmap']
2807 self.assertEquals(orig_entry.offset, entry.offset)
2808 self.assertEquals(orig_entry.size, entry.size)
2809 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2810
2811 def testReadImageNoHeader(self):
2812 """Test accessing an image's FDT map without an image header"""
2813 self._CheckLz4()
2814 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002815 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002816 image = Image.FromFile(image_fname)
2817 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002818 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002819
2820 def testReadImageFail(self):
2821 """Test failing to read an image image's FDT map"""
2822 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002823 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002824 with self.assertRaises(ValueError) as e:
2825 image = Image.FromFile(image_fname)
2826 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002827
Simon Glassb2fd11d2019-07-08 14:25:48 -06002828 def testListCmd(self):
2829 """Test listing the files in an image using an Fdtmap"""
2830 self._CheckLz4()
2831 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2832
2833 # lz4 compression size differs depending on the version
2834 image = control.images['image']
2835 entries = image.GetEntries()
2836 section_size = entries['section'].size
2837 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2838 fdtmap_offset = entries['fdtmap'].offset
2839
Simon Glassb3d6fc72019-07-20 12:24:10 -06002840 try:
2841 tmpdir, updated_fname = self._SetupImageInTmpdir()
2842 with test_util.capture_sys_output() as (stdout, stderr):
2843 self._DoBinman('ls', '-i', updated_fname)
2844 finally:
2845 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002846 lines = stdout.getvalue().splitlines()
2847 expected = [
2848'Name Image-pos Size Entry-type Offset Uncomp-size',
2849'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002850'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002851' u-boot 0 4 u-boot 0',
2852' section 100 %x section 100' % section_size,
2853' cbfs 100 400 cbfs 0',
2854' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002855' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002856' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002857' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002858 (fdtmap_offset, fdtmap_offset),
2859' image-header bf8 8 image-header bf8',
2860 ]
2861 self.assertEqual(expected, lines)
2862
2863 def testListCmdFail(self):
2864 """Test failing to list an image"""
2865 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002866 try:
2867 tmpdir, updated_fname = self._SetupImageInTmpdir()
2868 with self.assertRaises(ValueError) as e:
2869 self._DoBinman('ls', '-i', updated_fname)
2870 finally:
2871 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002872 self.assertIn("Cannot find FDT map in image", str(e.exception))
2873
2874 def _RunListCmd(self, paths, expected):
2875 """List out entries and check the result
2876
2877 Args:
2878 paths: List of paths to pass to the list command
2879 expected: Expected list of filenames to be returned, in order
2880 """
2881 self._CheckLz4()
2882 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002883 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002884 image = Image.FromFile(image_fname)
2885 lines = image.GetListEntries(paths)[1]
2886 files = [line[0].strip() for line in lines[1:]]
2887 self.assertEqual(expected, files)
2888
2889 def testListCmdSection(self):
2890 """Test listing the files in a section"""
2891 self._RunListCmd(['section'],
2892 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2893
2894 def testListCmdFile(self):
2895 """Test listing a particular file"""
2896 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2897
2898 def testListCmdWildcard(self):
2899 """Test listing a wildcarded file"""
2900 self._RunListCmd(['*boot*'],
2901 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2902
2903 def testListCmdWildcardMulti(self):
2904 """Test listing a wildcarded file"""
2905 self._RunListCmd(['*cb*', '*head*'],
2906 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2907
2908 def testListCmdEmpty(self):
2909 """Test listing a wildcarded file"""
2910 self._RunListCmd(['nothing'], [])
2911
2912 def testListCmdPath(self):
2913 """Test listing the files in a sub-entry of a section"""
2914 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2915
Simon Glass4c613bf2019-07-08 14:25:50 -06002916 def _RunExtractCmd(self, entry_name, decomp=True):
2917 """Extract an entry from an image
2918
2919 Args:
2920 entry_name: Entry name to extract
2921 decomp: True to decompress the data if compressed, False to leave
2922 it in its raw uncompressed format
2923
2924 Returns:
2925 data from entry
2926 """
2927 self._CheckLz4()
2928 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002929 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002930 return control.ReadEntry(image_fname, entry_name, decomp)
2931
2932 def testExtractSimple(self):
2933 """Test extracting a single file"""
2934 data = self._RunExtractCmd('u-boot')
2935 self.assertEqual(U_BOOT_DATA, data)
2936
Simon Glass980a2842019-07-08 14:25:52 -06002937 def testExtractSection(self):
2938 """Test extracting the files in a section"""
2939 data = self._RunExtractCmd('section')
2940 cbfs_data = data[:0x400]
2941 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002942 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002943 dtb_data = data[0x400:]
2944 dtb = self._decompress(dtb_data)
2945 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2946
2947 def testExtractCompressed(self):
2948 """Test extracting compressed data"""
2949 data = self._RunExtractCmd('section/u-boot-dtb')
2950 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2951
2952 def testExtractRaw(self):
2953 """Test extracting compressed data without decompressing it"""
2954 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2955 dtb = self._decompress(data)
2956 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2957
2958 def testExtractCbfs(self):
2959 """Test extracting CBFS data"""
2960 data = self._RunExtractCmd('section/cbfs/u-boot')
2961 self.assertEqual(U_BOOT_DATA, data)
2962
2963 def testExtractCbfsCompressed(self):
2964 """Test extracting CBFS compressed data"""
2965 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2966 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2967
2968 def testExtractCbfsRaw(self):
2969 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002970 bintool = self.comp_bintools['lzma_alone']
2971 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06002972 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002973 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06002974 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2975
Simon Glass4c613bf2019-07-08 14:25:50 -06002976 def testExtractBadEntry(self):
2977 """Test extracting a bad section path"""
2978 with self.assertRaises(ValueError) as e:
2979 self._RunExtractCmd('section/does-not-exist')
2980 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2981 str(e.exception))
2982
2983 def testExtractMissingFile(self):
2984 """Test extracting file that does not exist"""
2985 with self.assertRaises(IOError) as e:
2986 control.ReadEntry('missing-file', 'name')
2987
2988 def testExtractBadFile(self):
2989 """Test extracting an invalid file"""
2990 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002991 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002992 with self.assertRaises(ValueError) as e:
2993 control.ReadEntry(fname, 'name')
2994
Simon Glass980a2842019-07-08 14:25:52 -06002995 def testExtractCmd(self):
2996 """Test extracting a file fron an image on the command line"""
2997 self._CheckLz4()
2998 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002999 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06003000 try:
3001 tmpdir, updated_fname = self._SetupImageInTmpdir()
3002 with test_util.capture_sys_output() as (stdout, stderr):
3003 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3004 '-f', fname)
3005 finally:
3006 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07003007 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003008 self.assertEqual(U_BOOT_DATA, data)
3009
3010 def testExtractOneEntry(self):
3011 """Test extracting a single entry fron an image """
3012 self._CheckLz4()
3013 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003014 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003015 fname = os.path.join(self._indir, 'output.extact')
3016 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003017 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003018 self.assertEqual(U_BOOT_DATA, data)
3019
3020 def _CheckExtractOutput(self, decomp):
3021 """Helper to test file output with and without decompression
3022
3023 Args:
3024 decomp: True to decompress entry data, False to output it raw
3025 """
3026 def _CheckPresent(entry_path, expect_data, expect_size=None):
3027 """Check and remove expected file
3028
3029 This checks the data/size of a file and removes the file both from
3030 the outfiles set and from the output directory. Once all files are
3031 processed, both the set and directory should be empty.
3032
3033 Args:
3034 entry_path: Entry path
3035 expect_data: Data to expect in file, or None to skip check
3036 expect_size: Size of data to expect in file, or None to skip
3037 """
3038 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003039 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003040 os.remove(path)
3041 if expect_data:
3042 self.assertEqual(expect_data, data)
3043 elif expect_size:
3044 self.assertEqual(expect_size, len(data))
3045 outfiles.remove(path)
3046
3047 def _CheckDirPresent(name):
3048 """Remove expected directory
3049
3050 This gives an error if the directory does not exist as expected
3051
3052 Args:
3053 name: Name of directory to remove
3054 """
3055 path = os.path.join(outdir, name)
3056 os.rmdir(path)
3057
3058 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003059 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003060 outdir = os.path.join(self._indir, 'extract')
3061 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3062
3063 # Create a set of all file that were output (should be 9)
3064 outfiles = set()
3065 for root, dirs, files in os.walk(outdir):
3066 outfiles |= set([os.path.join(root, fname) for fname in files])
3067 self.assertEqual(9, len(outfiles))
3068 self.assertEqual(9, len(einfos))
3069
3070 image = control.images['image']
3071 entries = image.GetEntries()
3072
3073 # Check the 9 files in various ways
3074 section = entries['section']
3075 section_entries = section.GetEntries()
3076 cbfs_entries = section_entries['cbfs'].GetEntries()
3077 _CheckPresent('u-boot', U_BOOT_DATA)
3078 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3079 dtb_len = EXTRACT_DTB_SIZE
3080 if not decomp:
3081 dtb_len = cbfs_entries['u-boot-dtb'].size
3082 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3083 if not decomp:
3084 dtb_len = section_entries['u-boot-dtb'].size
3085 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3086
3087 fdtmap = entries['fdtmap']
3088 _CheckPresent('fdtmap', fdtmap.data)
3089 hdr = entries['image-header']
3090 _CheckPresent('image-header', hdr.data)
3091
3092 _CheckPresent('section/root', section.data)
3093 cbfs = section_entries['cbfs']
3094 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003095 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003096 _CheckPresent('root', data)
3097
3098 # There should be no files left. Remove all the directories to check.
3099 # If there are any files/dirs remaining, one of these checks will fail.
3100 self.assertEqual(0, len(outfiles))
3101 _CheckDirPresent('section/cbfs')
3102 _CheckDirPresent('section')
3103 _CheckDirPresent('')
3104 self.assertFalse(os.path.exists(outdir))
3105
3106 def testExtractAllEntries(self):
3107 """Test extracting all entries"""
3108 self._CheckLz4()
3109 self._CheckExtractOutput(decomp=True)
3110
3111 def testExtractAllEntriesRaw(self):
3112 """Test extracting all entries without decompressing them"""
3113 self._CheckLz4()
3114 self._CheckExtractOutput(decomp=False)
3115
3116 def testExtractSelectedEntries(self):
3117 """Test extracting some entries"""
3118 self._CheckLz4()
3119 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003120 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003121 outdir = os.path.join(self._indir, 'extract')
3122 einfos = control.ExtractEntries(image_fname, None, outdir,
3123 ['*cb*', '*head*'])
3124
3125 # File output is tested by testExtractAllEntries(), so just check that
3126 # the expected entries are selected
3127 names = [einfo.name for einfo in einfos]
3128 self.assertEqual(names,
3129 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3130
3131 def testExtractNoEntryPaths(self):
3132 """Test extracting some entries"""
3133 self._CheckLz4()
3134 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003135 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003136 with self.assertRaises(ValueError) as e:
3137 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003138 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003139 str(e.exception))
3140
3141 def testExtractTooManyEntryPaths(self):
3142 """Test extracting some entries"""
3143 self._CheckLz4()
3144 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003145 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003146 with self.assertRaises(ValueError) as e:
3147 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003148 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003149 str(e.exception))
3150
Simon Glass52d06212019-07-08 14:25:53 -06003151 def testPackAlignSection(self):
3152 """Test that sections can have alignment"""
3153 self._DoReadFile('131_pack_align_section.dts')
3154
3155 self.assertIn('image', control.images)
3156 image = control.images['image']
3157 entries = image.GetEntries()
3158 self.assertEqual(3, len(entries))
3159
3160 # First u-boot
3161 self.assertIn('u-boot', entries)
3162 entry = entries['u-boot']
3163 self.assertEqual(0, entry.offset)
3164 self.assertEqual(0, entry.image_pos)
3165 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3166 self.assertEqual(len(U_BOOT_DATA), entry.size)
3167
3168 # Section0
3169 self.assertIn('section0', entries)
3170 section0 = entries['section0']
3171 self.assertEqual(0x10, section0.offset)
3172 self.assertEqual(0x10, section0.image_pos)
3173 self.assertEqual(len(U_BOOT_DATA), section0.size)
3174
3175 # Second u-boot
3176 section_entries = section0.GetEntries()
3177 self.assertIn('u-boot', section_entries)
3178 entry = section_entries['u-boot']
3179 self.assertEqual(0, entry.offset)
3180 self.assertEqual(0x10, entry.image_pos)
3181 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3182 self.assertEqual(len(U_BOOT_DATA), entry.size)
3183
3184 # Section1
3185 self.assertIn('section1', entries)
3186 section1 = entries['section1']
3187 self.assertEqual(0x14, section1.offset)
3188 self.assertEqual(0x14, section1.image_pos)
3189 self.assertEqual(0x20, section1.size)
3190
3191 # Second u-boot
3192 section_entries = section1.GetEntries()
3193 self.assertIn('u-boot', section_entries)
3194 entry = section_entries['u-boot']
3195 self.assertEqual(0, entry.offset)
3196 self.assertEqual(0x14, entry.image_pos)
3197 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3198 self.assertEqual(len(U_BOOT_DATA), entry.size)
3199
3200 # Section2
3201 self.assertIn('section2', section_entries)
3202 section2 = section_entries['section2']
3203 self.assertEqual(0x4, section2.offset)
3204 self.assertEqual(0x18, section2.image_pos)
3205 self.assertEqual(4, section2.size)
3206
3207 # Third u-boot
3208 section_entries = section2.GetEntries()
3209 self.assertIn('u-boot', section_entries)
3210 entry = section_entries['u-boot']
3211 self.assertEqual(0, entry.offset)
3212 self.assertEqual(0x18, entry.image_pos)
3213 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3214 self.assertEqual(len(U_BOOT_DATA), entry.size)
3215
Simon Glassf8a54bc2019-07-20 12:23:56 -06003216 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3217 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003218 """Replace an entry in an image
3219
3220 This writes the entry data to update it, then opens the updated file and
3221 returns the value that it now finds there.
3222
3223 Args:
3224 entry_name: Entry name to replace
3225 data: Data to replace it with
3226 decomp: True to compress the data if needed, False if data is
3227 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003228 allow_resize: True to allow entries to change size, False to raise
3229 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003230
3231 Returns:
3232 Tuple:
3233 data from entry
3234 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003235 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003236 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003237 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003238 update_dtb=True)[1]
3239
3240 self.assertIn('image', control.images)
3241 image = control.images['image']
3242 entries = image.GetEntries()
3243 orig_dtb_data = entries['u-boot-dtb'].data
3244 orig_fdtmap_data = entries['fdtmap'].data
3245
Simon Glass80025522022-01-29 14:14:04 -07003246 image_fname = tools.get_output_filename('image.bin')
3247 updated_fname = tools.get_output_filename('image-updated.bin')
3248 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003249 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3250 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003251 data = control.ReadEntry(updated_fname, entry_name, decomp)
3252
Simon Glassf8a54bc2019-07-20 12:23:56 -06003253 # The DT data should not change unless resized:
3254 if not allow_resize:
3255 new_dtb_data = entries['u-boot-dtb'].data
3256 self.assertEqual(new_dtb_data, orig_dtb_data)
3257 new_fdtmap_data = entries['fdtmap'].data
3258 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003259
Simon Glassf8a54bc2019-07-20 12:23:56 -06003260 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003261
3262 def testReplaceSimple(self):
3263 """Test replacing a single file"""
3264 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003265 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3266 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003267 self.assertEqual(expected, data)
3268
3269 # Test that the state looks right. There should be an FDT for the fdtmap
3270 # that we jsut read back in, and it should match what we find in the
3271 # 'control' tables. Checking for an FDT that does not exist should
3272 # return None.
3273 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003274 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003275 self.assertEqual(expected_fdtmap, fdtmap)
3276
3277 dtb = state.GetFdtForEtype('fdtmap')
3278 self.assertEqual(dtb.GetContents(), fdtmap)
3279
3280 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3281 self.assertIsNone(missing_path)
3282 self.assertIsNone(missing_fdtmap)
3283
3284 missing_dtb = state.GetFdtForEtype('missing')
3285 self.assertIsNone(missing_dtb)
3286
3287 self.assertEqual('/binman', state.fdt_path_prefix)
3288
3289 def testReplaceResizeFail(self):
3290 """Test replacing a file by something larger"""
3291 expected = U_BOOT_DATA + b'x'
3292 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003293 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3294 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003295 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3296 str(e.exception))
3297
3298 def testReplaceMulti(self):
3299 """Test replacing entry data where multiple images are generated"""
3300 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3301 update_dtb=True)[0]
3302 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003303 updated_fname = tools.get_output_filename('image-updated.bin')
3304 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003305 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003306 control.WriteEntry(updated_fname, entry_name, expected,
3307 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003308 data = control.ReadEntry(updated_fname, entry_name)
3309 self.assertEqual(expected, data)
3310
3311 # Check the state looks right.
3312 self.assertEqual('/binman/image', state.fdt_path_prefix)
3313
3314 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003315 image_fname = tools.get_output_filename('first-image.bin')
3316 updated_fname = tools.get_output_filename('first-updated.bin')
3317 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003318 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003319 control.WriteEntry(updated_fname, entry_name, expected,
3320 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003321 data = control.ReadEntry(updated_fname, entry_name)
3322 self.assertEqual(expected, data)
3323
3324 # Check the state looks right.
3325 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003326
Simon Glassfb30e292019-07-20 12:23:51 -06003327 def testUpdateFdtAllRepack(self):
3328 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003329 self._SetupSplElf()
3330 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003331 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3332 SECTION_SIZE = 0x300
3333 DTB_SIZE = 602
3334 FDTMAP_SIZE = 608
3335 base_expected = {
3336 'offset': 0,
3337 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3338 'image-pos': 0,
3339 'section:offset': 0,
3340 'section:size': SECTION_SIZE,
3341 'section:image-pos': 0,
3342 'section/u-boot-dtb:offset': 4,
3343 'section/u-boot-dtb:size': 636,
3344 'section/u-boot-dtb:image-pos': 4,
3345 'u-boot-spl-dtb:offset': SECTION_SIZE,
3346 'u-boot-spl-dtb:size': DTB_SIZE,
3347 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3348 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3349 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3350 'u-boot-tpl-dtb:size': DTB_SIZE,
3351 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3352 'fdtmap:size': FDTMAP_SIZE,
3353 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3354 }
3355 main_expected = {
3356 'section:orig-size': SECTION_SIZE,
3357 'section/u-boot-dtb:orig-offset': 4,
3358 }
3359
3360 # We expect three device-tree files in the output, with the first one
3361 # within a fixed-size section.
3362 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3363 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3364 # main U-Boot tree. All three should have the same positions and offset
3365 # except that the main tree should include the main_expected properties
3366 start = 4
3367 for item in ['', 'spl', 'tpl', None]:
3368 if item is None:
3369 start += 16 # Move past fdtmap header
3370 dtb = fdt.Fdt.FromData(data[start:])
3371 dtb.Scan()
3372 props = self._GetPropTree(dtb,
3373 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3374 prefix='/' if item is None else '/binman/')
3375 expected = dict(base_expected)
3376 if item:
3377 expected[item] = 0
3378 else:
3379 # Main DTB and fdtdec should include the 'orig-' properties
3380 expected.update(main_expected)
3381 # Helpful for debugging:
3382 #for prop in sorted(props):
3383 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3384 self.assertEqual(expected, props)
3385 if item == '':
3386 start = SECTION_SIZE
3387 else:
3388 start += dtb._fdt_obj.totalsize()
3389
Simon Glass11453762019-07-20 12:23:55 -06003390 def testFdtmapHeaderMiddle(self):
3391 """Test an FDT map in the middle of an image when it should be at end"""
3392 with self.assertRaises(ValueError) as e:
3393 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3394 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3395 str(e.exception))
3396
3397 def testFdtmapHeaderStartBad(self):
3398 """Test an FDT map in middle of an image when it should be at start"""
3399 with self.assertRaises(ValueError) as e:
3400 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3401 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3402 str(e.exception))
3403
3404 def testFdtmapHeaderEndBad(self):
3405 """Test an FDT map at the start of an image when it should be at end"""
3406 with self.assertRaises(ValueError) as e:
3407 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3408 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3409 str(e.exception))
3410
3411 def testFdtmapHeaderNoSize(self):
3412 """Test an image header at the end of an image with undefined size"""
3413 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3414
Simon Glassf8a54bc2019-07-20 12:23:56 -06003415 def testReplaceResize(self):
3416 """Test replacing a single file in an entry with a larger file"""
3417 expected = U_BOOT_DATA + b'x'
3418 data, _, image = self._RunReplaceCmd('u-boot', expected,
3419 dts='139_replace_repack.dts')
3420 self.assertEqual(expected, data)
3421
3422 entries = image.GetEntries()
3423 dtb_data = entries['u-boot-dtb'].data
3424 dtb = fdt.Fdt.FromData(dtb_data)
3425 dtb.Scan()
3426
3427 # The u-boot section should now be larger in the dtb
3428 node = dtb.GetNode('/binman/u-boot')
3429 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3430
3431 # Same for the fdtmap
3432 fdata = entries['fdtmap'].data
3433 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3434 fdtb.Scan()
3435 fnode = fdtb.GetNode('/u-boot')
3436 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3437
3438 def testReplaceResizeNoRepack(self):
3439 """Test replacing an entry with a larger file when not allowed"""
3440 expected = U_BOOT_DATA + b'x'
3441 with self.assertRaises(ValueError) as e:
3442 self._RunReplaceCmd('u-boot', expected)
3443 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3444 str(e.exception))
3445
Simon Glass9d8ee322019-07-20 12:23:58 -06003446 def testEntryShrink(self):
3447 """Test contracting an entry after it is packed"""
3448 try:
3449 state.SetAllowEntryContraction(True)
3450 data = self._DoReadFileDtb('140_entry_shrink.dts',
3451 update_dtb=True)[0]
3452 finally:
3453 state.SetAllowEntryContraction(False)
3454 self.assertEqual(b'a', data[:1])
3455 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3456 self.assertEqual(b'a', data[-1:])
3457
3458 def testEntryShrinkFail(self):
3459 """Test not being allowed to contract an entry after it is packed"""
3460 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3461
3462 # In this case there is a spare byte at the end of the data. The size of
3463 # the contents is only 1 byte but we still have the size before it
3464 # shrunk.
3465 self.assertEqual(b'a\0', data[:2])
3466 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3467 self.assertEqual(b'a\0', data[-2:])
3468
Simon Glass70e32982019-07-20 12:24:01 -06003469 def testDescriptorOffset(self):
3470 """Test that the Intel descriptor is always placed at at the start"""
3471 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3472 image = control.images['image']
3473 entries = image.GetEntries()
3474 desc = entries['intel-descriptor']
3475 self.assertEqual(0xff800000, desc.offset);
3476 self.assertEqual(0xff800000, desc.image_pos);
3477
Simon Glass37fdd142019-07-20 12:24:06 -06003478 def testReplaceCbfs(self):
3479 """Test replacing a single file in CBFS without changing the size"""
3480 self._CheckLz4()
3481 expected = b'x' * len(U_BOOT_DATA)
3482 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003483 updated_fname = tools.get_output_filename('image-updated.bin')
3484 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003485 entry_name = 'section/cbfs/u-boot'
3486 control.WriteEntry(updated_fname, entry_name, expected,
3487 allow_resize=True)
3488 data = control.ReadEntry(updated_fname, entry_name)
3489 self.assertEqual(expected, data)
3490
3491 def testReplaceResizeCbfs(self):
3492 """Test replacing a single file in CBFS with one of a different size"""
3493 self._CheckLz4()
3494 expected = U_BOOT_DATA + b'x'
3495 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003496 updated_fname = tools.get_output_filename('image-updated.bin')
3497 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003498 entry_name = 'section/cbfs/u-boot'
3499 control.WriteEntry(updated_fname, entry_name, expected,
3500 allow_resize=True)
3501 data = control.ReadEntry(updated_fname, entry_name)
3502 self.assertEqual(expected, data)
3503
Simon Glass30033c22019-07-20 12:24:15 -06003504 def _SetupForReplace(self):
3505 """Set up some files to use to replace entries
3506
3507 This generates an image, copies it to a new file, extracts all the files
3508 in it and updates some of them
3509
3510 Returns:
3511 List
3512 Image filename
3513 Output directory
3514 Expected values for updated entries, each a string
3515 """
3516 data = self._DoReadFileRealDtb('143_replace_all.dts')
3517
Simon Glass80025522022-01-29 14:14:04 -07003518 updated_fname = tools.get_output_filename('image-updated.bin')
3519 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003520
3521 outdir = os.path.join(self._indir, 'extract')
3522 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3523
3524 expected1 = b'x' + U_BOOT_DATA + b'y'
3525 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003526 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003527
3528 expected2 = b'a' + U_BOOT_DATA + b'b'
3529 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003530 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003531
3532 expected_text = b'not the same text'
3533 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003534 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003535
3536 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3537 dtb = fdt.FdtScan(dtb_fname)
3538 node = dtb.GetNode('/binman/text')
3539 node.AddString('my-property', 'the value')
3540 dtb.Sync(auto_resize=True)
3541 dtb.Flush()
3542
3543 return updated_fname, outdir, expected1, expected2, expected_text
3544
3545 def _CheckReplaceMultiple(self, entry_paths):
3546 """Handle replacing the contents of multiple entries
3547
3548 Args:
3549 entry_paths: List of entry paths to replace
3550
3551 Returns:
3552 List
3553 Dict of entries in the image:
3554 key: Entry name
3555 Value: Entry object
3556 Expected values for updated entries, each a string
3557 """
3558 updated_fname, outdir, expected1, expected2, expected_text = (
3559 self._SetupForReplace())
3560 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3561
3562 image = Image.FromFile(updated_fname)
3563 image.LoadData()
3564 return image.GetEntries(), expected1, expected2, expected_text
3565
3566 def testReplaceAll(self):
3567 """Test replacing the contents of all entries"""
3568 entries, expected1, expected2, expected_text = (
3569 self._CheckReplaceMultiple([]))
3570 data = entries['u-boot'].data
3571 self.assertEqual(expected1, data)
3572
3573 data = entries['u-boot2'].data
3574 self.assertEqual(expected2, data)
3575
3576 data = entries['text'].data
3577 self.assertEqual(expected_text, data)
3578
3579 # Check that the device tree is updated
3580 data = entries['u-boot-dtb'].data
3581 dtb = fdt.Fdt.FromData(data)
3582 dtb.Scan()
3583 node = dtb.GetNode('/binman/text')
3584 self.assertEqual('the value', node.props['my-property'].value)
3585
3586 def testReplaceSome(self):
3587 """Test replacing the contents of a few entries"""
3588 entries, expected1, expected2, expected_text = (
3589 self._CheckReplaceMultiple(['u-boot2', 'text']))
3590
3591 # This one should not change
3592 data = entries['u-boot'].data
3593 self.assertEqual(U_BOOT_DATA, data)
3594
3595 data = entries['u-boot2'].data
3596 self.assertEqual(expected2, data)
3597
3598 data = entries['text'].data
3599 self.assertEqual(expected_text, data)
3600
3601 def testReplaceCmd(self):
3602 """Test replacing a file fron an image on the command line"""
3603 self._DoReadFileRealDtb('143_replace_all.dts')
3604
3605 try:
3606 tmpdir, updated_fname = self._SetupImageInTmpdir()
3607
3608 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3609 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003610 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003611
3612 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003613 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003614 self.assertEqual(expected, data[:len(expected)])
3615 map_fname = os.path.join(tmpdir, 'image-updated.map')
3616 self.assertFalse(os.path.exists(map_fname))
3617 finally:
3618 shutil.rmtree(tmpdir)
3619
3620 def testReplaceCmdSome(self):
3621 """Test replacing some files fron an image on the command line"""
3622 updated_fname, outdir, expected1, expected2, expected_text = (
3623 self._SetupForReplace())
3624
3625 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3626 'u-boot2', 'text')
3627
Simon Glass80025522022-01-29 14:14:04 -07003628 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003629 image = Image.FromFile(updated_fname)
3630 image.LoadData()
3631 entries = image.GetEntries()
3632
3633 # This one should not change
3634 data = entries['u-boot'].data
3635 self.assertEqual(U_BOOT_DATA, data)
3636
3637 data = entries['u-boot2'].data
3638 self.assertEqual(expected2, data)
3639
3640 data = entries['text'].data
3641 self.assertEqual(expected_text, data)
3642
3643 def testReplaceMissing(self):
3644 """Test replacing entries where the file is missing"""
3645 updated_fname, outdir, expected1, expected2, expected_text = (
3646 self._SetupForReplace())
3647
3648 # Remove one of the files, to generate a warning
3649 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3650 os.remove(u_boot_fname1)
3651
3652 with test_util.capture_sys_output() as (stdout, stderr):
3653 control.ReplaceEntries(updated_fname, None, outdir, [])
3654 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003655 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003656
3657 def testReplaceCmdMap(self):
3658 """Test replacing a file fron an image on the command line"""
3659 self._DoReadFileRealDtb('143_replace_all.dts')
3660
3661 try:
3662 tmpdir, updated_fname = self._SetupImageInTmpdir()
3663
3664 fname = os.path.join(self._indir, 'update-u-boot.bin')
3665 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003666 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003667
3668 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3669 '-f', fname, '-m')
3670 map_fname = os.path.join(tmpdir, 'image-updated.map')
3671 self.assertTrue(os.path.exists(map_fname))
3672 finally:
3673 shutil.rmtree(tmpdir)
3674
3675 def testReplaceNoEntryPaths(self):
3676 """Test replacing an entry without an entry path"""
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, [])
3681 self.assertIn('Must specify an entry path to read with -f',
3682 str(e.exception))
3683
3684 def testReplaceTooManyEntryPaths(self):
3685 """Test extracting some entries"""
3686 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003687 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003688 with self.assertRaises(ValueError) as e:
3689 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3690 self.assertIn('Must specify exactly one entry path to write with -f',
3691 str(e.exception))
3692
Simon Glass0b074d62019-08-24 07:22:48 -06003693 def testPackReset16(self):
3694 """Test that an image with an x86 reset16 region can be created"""
3695 data = self._DoReadFile('144_x86_reset16.dts')
3696 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3697
3698 def testPackReset16Spl(self):
3699 """Test that an image with an x86 reset16-spl region can be created"""
3700 data = self._DoReadFile('145_x86_reset16_spl.dts')
3701 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3702
3703 def testPackReset16Tpl(self):
3704 """Test that an image with an x86 reset16-tpl region can be created"""
3705 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3706 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3707
Simon Glass232f90c2019-08-24 07:22:50 -06003708 def testPackIntelFit(self):
3709 """Test that an image with an Intel FIT and pointer can be created"""
3710 data = self._DoReadFile('147_intel_fit.dts')
3711 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3712 fit = data[16:32];
3713 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3714 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3715
3716 image = control.images['image']
3717 entries = image.GetEntries()
3718 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3719 self.assertEqual(expected_ptr, ptr)
3720
3721 def testPackIntelFitMissing(self):
3722 """Test detection of a FIT pointer with not FIT region"""
3723 with self.assertRaises(ValueError) as e:
3724 self._DoReadFile('148_intel_fit_missing.dts')
3725 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3726 str(e.exception))
3727
Simon Glass72555fa2019-11-06 17:22:44 -07003728 def _CheckSymbolsTplSection(self, dts, expected_vals):
3729 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003730 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003731 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003732 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003733 self.assertEqual(expected1, data[:upto1])
3734
3735 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003736 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003737 self.assertEqual(expected2, data[upto1:upto2])
3738
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003739 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003740 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003741 self.assertEqual(expected3, data[upto2:upto3])
3742
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003743 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003744 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3745
3746 def testSymbolsTplSection(self):
3747 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3748 self._SetupSplElf('u_boot_binman_syms')
3749 self._SetupTplElf('u_boot_binman_syms')
3750 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003751 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003752
3753 def testSymbolsTplSectionX86(self):
3754 """Test binman can assign symbols in a section with end-at-4gb"""
3755 self._SetupSplElf('u_boot_binman_syms_x86')
3756 self._SetupTplElf('u_boot_binman_syms_x86')
3757 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003758 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003759 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003760
Simon Glass98c59572019-08-24 07:23:03 -06003761 def testPackX86RomIfwiSectiom(self):
3762 """Test that a section can be placed in an IFWI region"""
3763 self._SetupIfwi('fitimage.bin')
3764 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3765 self._CheckIfwi(data)
3766
Simon Glassba7985d2019-08-24 07:23:07 -06003767 def testPackFspM(self):
3768 """Test that an image with a FSP memory-init binary can be created"""
3769 data = self._DoReadFile('152_intel_fsp_m.dts')
3770 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3771
Simon Glass4d9086d2019-10-20 21:31:35 -06003772 def testPackFspS(self):
3773 """Test that an image with a FSP silicon-init binary can be created"""
3774 data = self._DoReadFile('153_intel_fsp_s.dts')
3775 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003776
Simon Glass9ea87b22019-10-20 21:31:36 -06003777 def testPackFspT(self):
3778 """Test that an image with a FSP temp-ram-init binary can be created"""
3779 data = self._DoReadFile('154_intel_fsp_t.dts')
3780 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3781
Simon Glass48f3aad2020-07-09 18:39:31 -06003782 def testMkimage(self):
3783 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003784 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003785 data = self._DoReadFile('156_mkimage.dts')
3786
3787 # Just check that the data appears in the file somewhere
3788 self.assertIn(U_BOOT_SPL_DATA, data)
3789
Simon Glass66152ce2022-01-09 20:14:09 -07003790 def testMkimageMissing(self):
3791 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003792 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003793 with test_util.capture_sys_output() as (_, stderr):
3794 self._DoTestFile('156_mkimage.dts',
3795 force_missing_bintools='mkimage')
3796 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003797 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003798
Simon Glass5e560182020-07-09 18:39:36 -06003799 def testExtblob(self):
3800 """Test an image with an external blob"""
3801 data = self._DoReadFile('157_blob_ext.dts')
3802 self.assertEqual(REFCODE_DATA, data)
3803
3804 def testExtblobMissing(self):
3805 """Test an image with a missing external blob"""
3806 with self.assertRaises(ValueError) as e:
3807 self._DoReadFile('158_blob_ext_missing.dts')
3808 self.assertIn("Filename 'missing-file' not found in input path",
3809 str(e.exception))
3810
Simon Glass5d94cc62020-07-09 18:39:38 -06003811 def testExtblobMissingOk(self):
3812 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003813 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003814 ret = self._DoTestFile('158_blob_ext_missing.dts',
3815 allow_missing=True)
3816 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003817 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003818 self.assertIn('(missing-file)', err)
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)
3821
3822 def testExtblobMissingOkFlag(self):
3823 """Test an image with an missing external blob allowed with -W"""
3824 with test_util.capture_sys_output() as (stdout, stderr):
3825 ret = self._DoTestFile('158_blob_ext_missing.dts',
3826 allow_missing=True, ignore_missing=True)
3827 self.assertEqual(0, ret)
3828 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003829 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003830 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003831 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003832
3833 def testExtblobMissingOkSect(self):
3834 """Test an image with an missing external blob that is allowed"""
3835 with test_util.capture_sys_output() as (stdout, stderr):
3836 self._DoTestFile('159_blob_ext_missing_sect.dts',
3837 allow_missing=True)
3838 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003839 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003840
Simon Glasse88cef92020-07-09 18:39:41 -06003841 def testPackX86RomMeMissingDesc(self):
3842 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003843 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003844 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003845 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003846 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003847
3848 def testPackX86RomMissingIfwi(self):
3849 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3850 self._SetupIfwi('fitimage.bin')
3851 pathname = os.path.join(self._indir, 'fitimage.bin')
3852 os.remove(pathname)
3853 with test_util.capture_sys_output() as (stdout, stderr):
3854 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3855 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003856 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003857
Simon Glass2a0fa982022-02-11 13:23:21 -07003858 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003859 """Test that zero-size overlapping regions are ignored"""
3860 self._DoTestFile('160_pack_overlap_zero.dts')
3861
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003862 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003863 # The data should be inside the FIT
3864 dtb = fdt.Fdt.FromData(fit_data)
3865 dtb.Scan()
3866 fnode = dtb.GetNode('/images/kernel')
3867 self.assertIn('data', fnode.props)
3868
3869 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003870 tools.write_file(fname, fit_data)
3871 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003872
3873 # Check a few features to make sure the plumbing works. We don't need
3874 # to test the operation of mkimage or dumpimage here. First convert the
3875 # output into a dict where the keys are the fields printed by dumpimage
3876 # and the values are a list of values for each field
3877 lines = out.splitlines()
3878
3879 # Converts "Compression: gzip compressed" into two groups:
3880 # 'Compression' and 'gzip compressed'
3881 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3882 vals = collections.defaultdict(list)
3883 for line in lines:
3884 mat = re_line.match(line)
3885 vals[mat.group(1)].append(mat.group(2))
3886
3887 self.assertEquals('FIT description: test-desc', lines[0])
3888 self.assertIn('Created:', lines[1])
3889 self.assertIn('Image 0 (kernel)', vals)
3890 self.assertIn('Hash value', vals)
3891 data_sizes = vals.get('Data Size')
3892 self.assertIsNotNone(data_sizes)
3893 self.assertEqual(2, len(data_sizes))
3894 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003895 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3896 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3897
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003898 # Check if entry listing correctly omits /images/
3899 image = control.images['image']
3900 fit_entry = image.GetEntries()['fit']
3901 subentries = list(fit_entry.GetEntries().keys())
3902 expected = ['kernel', 'fdt-1']
3903 self.assertEqual(expected, subentries)
3904
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003905 def testSimpleFit(self):
3906 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003907 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003908 data = self._DoReadFile('161_fit.dts')
3909 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3910 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3911 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3912
3913 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3914
3915 def testSimpleFitExpandsSubentries(self):
3916 """Test that FIT images expand their subentries"""
3917 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3918 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3919 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3920 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3921
3922 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003923
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003924 def testSimpleFitImagePos(self):
3925 """Test that we have correct image-pos for FIT subentries"""
3926 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3927 update_dtb=True)
3928 dtb = fdt.Fdt(out_dtb_fname)
3929 dtb.Scan()
3930 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3931
Simon Glassb7bad182022-03-05 20:19:01 -07003932 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003933 self.assertEqual({
3934 'image-pos': 0,
3935 'offset': 0,
3936 'size': 1890,
3937
3938 'u-boot:image-pos': 0,
3939 'u-boot:offset': 0,
3940 'u-boot:size': 4,
3941
3942 'fit:image-pos': 4,
3943 'fit:offset': 4,
3944 'fit:size': 1840,
3945
Simon Glassb7bad182022-03-05 20:19:01 -07003946 'fit/images/kernel:image-pos': 304,
3947 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003948 'fit/images/kernel:size': 4,
3949
Simon Glassb7bad182022-03-05 20:19:01 -07003950 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003951 'fit/images/kernel/u-boot:offset': 0,
3952 'fit/images/kernel/u-boot:size': 4,
3953
Simon Glassb7bad182022-03-05 20:19:01 -07003954 'fit/images/fdt-1:image-pos': 552,
3955 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003956 'fit/images/fdt-1:size': 6,
3957
Simon Glassb7bad182022-03-05 20:19:01 -07003958 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003959 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3960 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3961
3962 'u-boot-nodtb:image-pos': 1844,
3963 'u-boot-nodtb:offset': 1844,
3964 'u-boot-nodtb:size': 46,
3965 }, props)
3966
3967 # Actually check the data is where we think it is
3968 for node, expected in [
3969 ("u-boot", U_BOOT_DATA),
3970 ("fit/images/kernel", U_BOOT_DATA),
3971 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3972 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3973 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3974 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3975 ]:
3976 image_pos = props[f"{node}:image-pos"]
3977 size = props[f"{node}:size"]
3978 self.assertEqual(len(expected), size)
3979 self.assertEqual(expected, data[image_pos:image_pos+size])
3980
Simon Glass45d556d2020-07-09 18:39:45 -06003981 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003982 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003983 data = self._DoReadFile('162_fit_external.dts')
3984 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3985
Simon Glass7932c882022-01-09 20:13:39 -07003986 # Size of the external-data region as set up by mkimage
3987 external_data_size = len(U_BOOT_DATA) + 2
3988 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003989 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003990 len(U_BOOT_NODTB_DATA))
3991
Simon Glass45d556d2020-07-09 18:39:45 -06003992 # The data should be outside the FIT
3993 dtb = fdt.Fdt.FromData(fit_data)
3994 dtb.Scan()
3995 fnode = dtb.GetNode('/images/kernel')
3996 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003997 self.assertEqual(len(U_BOOT_DATA),
3998 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3999 fit_pos = 0x400;
4000 self.assertEqual(
4001 fit_pos,
4002 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4003
4004 self.assertEquals(expected_size, len(data))
4005 actual_pos = len(U_BOOT_DATA) + fit_pos
4006 self.assertEqual(U_BOOT_DATA + b'aa',
4007 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004008
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004009 def testFitExternalImagePos(self):
4010 """Test that we have correct image-pos for external FIT subentries"""
4011 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4012 update_dtb=True)
4013 dtb = fdt.Fdt(out_dtb_fname)
4014 dtb.Scan()
4015 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4016
4017 self.assertEqual({
4018 'image-pos': 0,
4019 'offset': 0,
4020 'size': 1082,
4021
4022 'u-boot:image-pos': 0,
4023 'u-boot:offset': 0,
4024 'u-boot:size': 4,
4025
4026 'fit:size': 1032,
4027 'fit:offset': 4,
4028 'fit:image-pos': 4,
4029
4030 'fit/images/kernel:size': 4,
4031 'fit/images/kernel:offset': 1024,
4032 'fit/images/kernel:image-pos': 1028,
4033
4034 'fit/images/kernel/u-boot:size': 4,
4035 'fit/images/kernel/u-boot:offset': 0,
4036 'fit/images/kernel/u-boot:image-pos': 1028,
4037
4038 'fit/images/fdt-1:size': 2,
4039 'fit/images/fdt-1:offset': 1028,
4040 'fit/images/fdt-1:image-pos': 1032,
4041
4042 'fit/images/fdt-1/_testing:size': 2,
4043 'fit/images/fdt-1/_testing:offset': 0,
4044 'fit/images/fdt-1/_testing:image-pos': 1032,
4045
4046 'u-boot-nodtb:image-pos': 1036,
4047 'u-boot-nodtb:offset': 1036,
4048 'u-boot-nodtb:size': 46,
4049 }, props)
4050
4051 # Actually check the data is where we think it is
4052 for node, expected in [
4053 ("u-boot", U_BOOT_DATA),
4054 ("fit/images/kernel", U_BOOT_DATA),
4055 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4056 ("fit/images/fdt-1", b'aa'),
4057 ("fit/images/fdt-1/_testing", b'aa'),
4058 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4059 ]:
4060 image_pos = props[f"{node}:image-pos"]
4061 size = props[f"{node}:size"]
4062 self.assertEqual(len(expected), size)
4063 self.assertEqual(expected, data[image_pos:image_pos+size])
4064
Simon Glass66152ce2022-01-09 20:14:09 -07004065 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004066 """Test that binman complains if mkimage is missing"""
4067 with self.assertRaises(ValueError) as e:
4068 self._DoTestFile('162_fit_external.dts',
4069 force_missing_bintools='mkimage')
4070 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4071 str(e.exception))
4072
4073 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004074 """Test that binman still produces a FIT image if mkimage is missing"""
4075 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004076 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004077 force_missing_bintools='mkimage')
4078 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004079 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004080
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004081 def testSectionIgnoreHashSignature(self):
4082 """Test that sections ignore hash, signature nodes for its data"""
4083 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4084 expected = (U_BOOT_DATA + U_BOOT_DATA)
4085 self.assertEqual(expected, data)
4086
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004087 def testPadInSections(self):
4088 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004089 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4090 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004091 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4092 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004093 U_BOOT_DATA)
4094 self.assertEqual(expected, data)
4095
Simon Glassd12599d2020-10-26 17:40:09 -06004096 dtb = fdt.Fdt(out_dtb_fname)
4097 dtb.Scan()
4098 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4099 expected = {
4100 'image-pos': 0,
4101 'offset': 0,
4102 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4103
4104 'section:image-pos': 0,
4105 'section:offset': 0,
4106 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4107
4108 'section/before:image-pos': 0,
4109 'section/before:offset': 0,
4110 'section/before:size': len(U_BOOT_DATA),
4111
4112 'section/u-boot:image-pos': 4,
4113 'section/u-boot:offset': 4,
4114 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4115
4116 'section/after:image-pos': 26,
4117 'section/after:offset': 26,
4118 'section/after:size': len(U_BOOT_DATA),
4119 }
4120 self.assertEqual(expected, props)
4121
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004122 def testFitImageSubentryAlignment(self):
4123 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004124 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004125 entry_args = {
4126 'test-id': TEXT_DATA,
4127 }
4128 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4129 entry_args=entry_args)
4130 dtb = fdt.Fdt.FromData(data)
4131 dtb.Scan()
4132
4133 node = dtb.GetNode('/images/kernel')
4134 data = dtb.GetProps(node)["data"].bytes
4135 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004136 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4137 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004138 self.assertEqual(expected, data)
4139
4140 node = dtb.GetNode('/images/fdt-1')
4141 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004142 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4143 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004144 U_BOOT_DTB_DATA)
4145 self.assertEqual(expected, data)
4146
4147 def testFitExtblobMissingOk(self):
4148 """Test a FIT with a missing external blob that is allowed"""
4149 with test_util.capture_sys_output() as (stdout, stderr):
4150 self._DoTestFile('168_fit_missing_blob.dts',
4151 allow_missing=True)
4152 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004153 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004154
Simon Glass21db0ff2020-09-01 05:13:54 -06004155 def testBlobNamedByArgMissing(self):
4156 """Test handling of a missing entry arg"""
4157 with self.assertRaises(ValueError) as e:
4158 self._DoReadFile('068_blob_named_by_arg.dts')
4159 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4160 str(e.exception))
4161
Simon Glass559c4de2020-09-01 05:13:58 -06004162 def testPackBl31(self):
4163 """Test that an image with an ATF BL31 binary can be created"""
4164 data = self._DoReadFile('169_atf_bl31.dts')
4165 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4166
Samuel Holland9d8cc632020-10-21 21:12:15 -05004167 def testPackScp(self):
4168 """Test that an image with an SCP binary can be created"""
4169 data = self._DoReadFile('172_scp.dts')
4170 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4171
Simon Glassa435cd12020-09-01 05:13:59 -06004172 def testFitFdt(self):
4173 """Test an image with an FIT with multiple FDT images"""
4174 def _CheckFdt(seq, expected_data):
4175 """Check the FDT nodes
4176
4177 Args:
4178 seq: Sequence number to check (0 or 1)
4179 expected_data: Expected contents of 'data' property
4180 """
4181 name = 'fdt-%d' % seq
4182 fnode = dtb.GetNode('/images/%s' % name)
4183 self.assertIsNotNone(fnode)
4184 self.assertEqual({'description','type', 'compression', 'data'},
4185 set(fnode.props.keys()))
4186 self.assertEqual(expected_data, fnode.props['data'].bytes)
4187 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4188 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004189 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004190
4191 def _CheckConfig(seq, expected_data):
4192 """Check the configuration nodes
4193
4194 Args:
4195 seq: Sequence number to check (0 or 1)
4196 expected_data: Expected contents of 'data' property
4197 """
4198 cnode = dtb.GetNode('/configurations')
4199 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004200 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004201
4202 name = 'config-%d' % seq
4203 fnode = dtb.GetNode('/configurations/%s' % name)
4204 self.assertIsNotNone(fnode)
4205 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4206 set(fnode.props.keys()))
4207 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4208 fnode.props['description'].value)
4209 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4210
4211 entry_args = {
4212 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004213 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004214 }
4215 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004216 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004217 entry_args=entry_args,
4218 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4219 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4220 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4221
4222 dtb = fdt.Fdt.FromData(fit_data)
4223 dtb.Scan()
4224 fnode = dtb.GetNode('/images/kernel')
4225 self.assertIn('data', fnode.props)
4226
4227 # Check all the properties in fdt-1 and fdt-2
4228 _CheckFdt(1, TEST_FDT1_DATA)
4229 _CheckFdt(2, TEST_FDT2_DATA)
4230
4231 # Check configurations
4232 _CheckConfig(1, TEST_FDT1_DATA)
4233 _CheckConfig(2, TEST_FDT2_DATA)
4234
4235 def testFitFdtMissingList(self):
4236 """Test handling of a missing 'of-list' entry arg"""
4237 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004238 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004239 self.assertIn("Generator node requires 'of-list' entry argument",
4240 str(e.exception))
4241
4242 def testFitFdtEmptyList(self):
4243 """Test handling of an empty 'of-list' entry arg"""
4244 entry_args = {
4245 'of-list': '',
4246 }
4247 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4248
4249 def testFitFdtMissingProp(self):
4250 """Test handling of a missing 'fit,fdt-list' property"""
4251 with self.assertRaises(ValueError) as e:
4252 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4253 self.assertIn("Generator node requires 'fit,fdt-list' property",
4254 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004255
Simon Glass1032acc2020-09-06 10:39:08 -06004256 def testFitFdtMissing(self):
4257 """Test handling of a missing 'default-dt' entry arg"""
4258 entry_args = {
4259 'of-list': 'test-fdt1 test-fdt2',
4260 }
4261 with self.assertRaises(ValueError) as e:
4262 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004263 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004264 entry_args=entry_args,
4265 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4266 self.assertIn("Generated 'default' node requires default-dt entry argument",
4267 str(e.exception))
4268
4269 def testFitFdtNotInList(self):
4270 """Test handling of a default-dt that is not in the of-list"""
4271 entry_args = {
4272 'of-list': 'test-fdt1 test-fdt2',
4273 'default-dt': 'test-fdt3',
4274 }
4275 with self.assertRaises(ValueError) as e:
4276 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004277 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004278 entry_args=entry_args,
4279 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4280 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4281 str(e.exception))
4282
Simon Glassa820af72020-09-06 10:39:09 -06004283 def testFitExtblobMissingHelp(self):
4284 """Test display of help messages when an external blob is missing"""
4285 control.missing_blob_help = control._ReadMissingBlobHelp()
4286 control.missing_blob_help['wibble'] = 'Wibble test'
4287 control.missing_blob_help['another'] = 'Another test'
4288 with test_util.capture_sys_output() as (stdout, stderr):
4289 self._DoTestFile('168_fit_missing_blob.dts',
4290 allow_missing=True)
4291 err = stderr.getvalue()
4292
4293 # We can get the tag from the name, the type or the missing-msg
4294 # property. Check all three.
4295 self.assertIn('You may need to build ARM Trusted', err)
4296 self.assertIn('Wibble test', err)
4297 self.assertIn('Another test', err)
4298
Simon Glass6f1f4d42020-09-06 10:35:32 -06004299 def testMissingBlob(self):
4300 """Test handling of a blob containing a missing file"""
4301 with self.assertRaises(ValueError) as e:
4302 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4303 self.assertIn("Filename 'missing' not found in input path",
4304 str(e.exception))
4305
Simon Glassa0729502020-09-06 10:35:33 -06004306 def testEnvironment(self):
4307 """Test adding a U-Boot environment"""
4308 data = self._DoReadFile('174_env.dts')
4309 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4310 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4311 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4312 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4313 env)
4314
4315 def testEnvironmentNoSize(self):
4316 """Test that a missing 'size' property is detected"""
4317 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004318 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004319 self.assertIn("'u-boot-env' entry must have a size property",
4320 str(e.exception))
4321
4322 def testEnvironmentTooSmall(self):
4323 """Test handling of an environment that does not fit"""
4324 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004325 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004326
4327 # checksum, start byte, environment with \0 terminator, final \0
4328 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4329 short = need - 0x8
4330 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4331 str(e.exception))
4332
Simon Glassd1fdf752020-10-26 17:40:01 -06004333 def testSkipAtStart(self):
4334 """Test handling of skip-at-start section"""
4335 data = self._DoReadFile('177_skip_at_start.dts')
4336 self.assertEqual(U_BOOT_DATA, data)
4337
4338 image = control.images['image']
4339 entries = image.GetEntries()
4340 section = entries['section']
4341 self.assertEqual(0, section.offset)
4342 self.assertEqual(len(U_BOOT_DATA), section.size)
4343 self.assertEqual(U_BOOT_DATA, section.GetData())
4344
4345 entry = section.GetEntries()['u-boot']
4346 self.assertEqual(16, entry.offset)
4347 self.assertEqual(len(U_BOOT_DATA), entry.size)
4348 self.assertEqual(U_BOOT_DATA, entry.data)
4349
4350 def testSkipAtStartPad(self):
4351 """Test handling of skip-at-start section with padded entry"""
4352 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004353 before = tools.get_bytes(0, 8)
4354 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004355 all = before + U_BOOT_DATA + after
4356 self.assertEqual(all, data)
4357
4358 image = control.images['image']
4359 entries = image.GetEntries()
4360 section = entries['section']
4361 self.assertEqual(0, section.offset)
4362 self.assertEqual(len(all), section.size)
4363 self.assertEqual(all, section.GetData())
4364
4365 entry = section.GetEntries()['u-boot']
4366 self.assertEqual(16, entry.offset)
4367 self.assertEqual(len(all), entry.size)
4368 self.assertEqual(U_BOOT_DATA, entry.data)
4369
4370 def testSkipAtStartSectionPad(self):
4371 """Test handling of skip-at-start section with padding"""
4372 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004373 before = tools.get_bytes(0, 8)
4374 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004375 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004376 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004377
4378 image = control.images['image']
4379 entries = image.GetEntries()
4380 section = entries['section']
4381 self.assertEqual(0, section.offset)
4382 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004383 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004384 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004385
4386 entry = section.GetEntries()['u-boot']
4387 self.assertEqual(16, entry.offset)
4388 self.assertEqual(len(U_BOOT_DATA), entry.size)
4389 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004390
Simon Glassbb395742020-10-26 17:40:14 -06004391 def testSectionPad(self):
4392 """Testing padding with sections"""
4393 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004394 expected = (tools.get_bytes(ord('&'), 3) +
4395 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004396 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004397 tools.get_bytes(ord('!'), 1) +
4398 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004399 self.assertEqual(expected, data)
4400
4401 def testSectionAlign(self):
4402 """Testing alignment with sections"""
4403 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4404 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004405 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004406 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004407 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004408 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004409 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4410 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004411 self.assertEqual(expected, data)
4412
Simon Glassd92c8362020-10-26 17:40:25 -06004413 def testCompressImage(self):
4414 """Test compression of the entire image"""
4415 self._CheckLz4()
4416 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4417 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4418 dtb = fdt.Fdt(out_dtb_fname)
4419 dtb.Scan()
4420 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4421 'uncomp-size'])
4422 orig = self._decompress(data)
4423 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4424
4425 # Do a sanity check on various fields
4426 image = control.images['image']
4427 entries = image.GetEntries()
4428 self.assertEqual(2, len(entries))
4429
4430 entry = entries['blob']
4431 self.assertEqual(COMPRESS_DATA, entry.data)
4432 self.assertEqual(len(COMPRESS_DATA), entry.size)
4433
4434 entry = entries['u-boot']
4435 self.assertEqual(U_BOOT_DATA, entry.data)
4436 self.assertEqual(len(U_BOOT_DATA), entry.size)
4437
4438 self.assertEqual(len(data), image.size)
4439 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4440 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4441 orig = self._decompress(image.data)
4442 self.assertEqual(orig, image.uncomp_data)
4443
4444 expected = {
4445 'blob:offset': 0,
4446 'blob:size': len(COMPRESS_DATA),
4447 'u-boot:offset': len(COMPRESS_DATA),
4448 'u-boot:size': len(U_BOOT_DATA),
4449 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4450 'offset': 0,
4451 'image-pos': 0,
4452 'size': len(data),
4453 }
4454 self.assertEqual(expected, props)
4455
4456 def testCompressImageLess(self):
4457 """Test compression where compression reduces the image size"""
4458 self._CheckLz4()
4459 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4460 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4461 dtb = fdt.Fdt(out_dtb_fname)
4462 dtb.Scan()
4463 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4464 'uncomp-size'])
4465 orig = self._decompress(data)
4466
4467 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4468
4469 # Do a sanity check on various fields
4470 image = control.images['image']
4471 entries = image.GetEntries()
4472 self.assertEqual(2, len(entries))
4473
4474 entry = entries['blob']
4475 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4476 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4477
4478 entry = entries['u-boot']
4479 self.assertEqual(U_BOOT_DATA, entry.data)
4480 self.assertEqual(len(U_BOOT_DATA), entry.size)
4481
4482 self.assertEqual(len(data), image.size)
4483 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4484 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4485 image.uncomp_size)
4486 orig = self._decompress(image.data)
4487 self.assertEqual(orig, image.uncomp_data)
4488
4489 expected = {
4490 'blob:offset': 0,
4491 'blob:size': len(COMPRESS_DATA_BIG),
4492 'u-boot:offset': len(COMPRESS_DATA_BIG),
4493 'u-boot:size': len(U_BOOT_DATA),
4494 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4495 'offset': 0,
4496 'image-pos': 0,
4497 'size': len(data),
4498 }
4499 self.assertEqual(expected, props)
4500
4501 def testCompressSectionSize(self):
4502 """Test compression of a section with a fixed size"""
4503 self._CheckLz4()
4504 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4505 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4506 dtb = fdt.Fdt(out_dtb_fname)
4507 dtb.Scan()
4508 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4509 'uncomp-size'])
4510 orig = self._decompress(data)
4511 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4512 expected = {
4513 'section/blob:offset': 0,
4514 'section/blob:size': len(COMPRESS_DATA),
4515 'section/u-boot:offset': len(COMPRESS_DATA),
4516 'section/u-boot:size': len(U_BOOT_DATA),
4517 'section:offset': 0,
4518 'section:image-pos': 0,
4519 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4520 'section:size': 0x30,
4521 'offset': 0,
4522 'image-pos': 0,
4523 'size': 0x30,
4524 }
4525 self.assertEqual(expected, props)
4526
4527 def testCompressSection(self):
4528 """Test compression of a section with no fixed size"""
4529 self._CheckLz4()
4530 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4531 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4532 dtb = fdt.Fdt(out_dtb_fname)
4533 dtb.Scan()
4534 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4535 'uncomp-size'])
4536 orig = self._decompress(data)
4537 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4538 expected = {
4539 'section/blob:offset': 0,
4540 'section/blob:size': len(COMPRESS_DATA),
4541 'section/u-boot:offset': len(COMPRESS_DATA),
4542 'section/u-boot:size': len(U_BOOT_DATA),
4543 'section:offset': 0,
4544 'section:image-pos': 0,
4545 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4546 'section:size': len(data),
4547 'offset': 0,
4548 'image-pos': 0,
4549 'size': len(data),
4550 }
4551 self.assertEqual(expected, props)
4552
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004553 def testLz4Missing(self):
4554 """Test that binman still produces an image if lz4 is missing"""
4555 with test_util.capture_sys_output() as (_, stderr):
4556 self._DoTestFile('185_compress_section.dts',
4557 force_missing_bintools='lz4')
4558 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004559 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004560
Simon Glassd92c8362020-10-26 17:40:25 -06004561 def testCompressExtra(self):
4562 """Test compression of a section with no fixed size"""
4563 self._CheckLz4()
4564 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4565 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4566 dtb = fdt.Fdt(out_dtb_fname)
4567 dtb.Scan()
4568 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4569 'uncomp-size'])
4570
4571 base = data[len(U_BOOT_DATA):]
4572 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4573 rest = base[len(U_BOOT_DATA):]
4574
4575 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004576 bintool = self.comp_bintools['lz4']
4577 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004578 data1 = rest[:len(expect1)]
4579 section1 = self._decompress(data1)
4580 self.assertEquals(expect1, data1)
Simon Glassd92c8362020-10-26 17:40:25 -06004581 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4582 rest1 = rest[len(expect1):]
4583
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004584 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004585 data2 = rest1[:len(expect2)]
4586 section2 = self._decompress(data2)
4587 self.assertEquals(expect2, data2)
Simon Glassd92c8362020-10-26 17:40:25 -06004588 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4589 rest2 = rest1[len(expect2):]
4590
4591 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4592 len(expect2) + len(U_BOOT_DATA))
4593 #self.assertEquals(expect_size, len(data))
4594
4595 #self.assertEquals(U_BOOT_DATA, rest2)
4596
4597 self.maxDiff = None
4598 expected = {
4599 'u-boot:offset': 0,
4600 'u-boot:image-pos': 0,
4601 'u-boot:size': len(U_BOOT_DATA),
4602
4603 'base:offset': len(U_BOOT_DATA),
4604 'base:image-pos': len(U_BOOT_DATA),
4605 'base:size': len(data) - len(U_BOOT_DATA),
4606 'base/u-boot:offset': 0,
4607 'base/u-boot:image-pos': len(U_BOOT_DATA),
4608 'base/u-boot:size': len(U_BOOT_DATA),
4609 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4610 len(expect2),
4611 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4612 len(expect2),
4613 'base/u-boot2:size': len(U_BOOT_DATA),
4614
4615 'base/section:offset': len(U_BOOT_DATA),
4616 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4617 'base/section:size': len(expect1),
4618 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4619 'base/section/blob:offset': 0,
4620 'base/section/blob:size': len(COMPRESS_DATA),
4621 'base/section/u-boot:offset': len(COMPRESS_DATA),
4622 'base/section/u-boot:size': len(U_BOOT_DATA),
4623
4624 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4625 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4626 'base/section2:size': len(expect2),
4627 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4628 'base/section2/blob:offset': 0,
4629 'base/section2/blob:size': len(COMPRESS_DATA),
4630 'base/section2/blob2:offset': len(COMPRESS_DATA),
4631 'base/section2/blob2:size': len(COMPRESS_DATA),
4632
4633 'offset': 0,
4634 'image-pos': 0,
4635 'size': len(data),
4636 }
4637 self.assertEqual(expected, props)
4638
Simon Glassecbe4732021-01-06 21:35:15 -07004639 def testSymbolsSubsection(self):
4640 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004641 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004642
Simon Glass3fb25402021-01-06 21:35:16 -07004643 def testReadImageEntryArg(self):
4644 """Test reading an image that would need an entry arg to generate"""
4645 entry_args = {
4646 'cros-ec-rw-path': 'ecrw.bin',
4647 }
4648 data = self.data = self._DoReadFileDtb(
4649 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4650 entry_args=entry_args)
4651
Simon Glass80025522022-01-29 14:14:04 -07004652 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004653 orig_image = control.images['image']
4654
4655 # This should not generate an error about the missing 'cros-ec-rw-path'
4656 # since we are reading the image from a file. Compare with
4657 # testEntryArgsRequired()
4658 image = Image.FromFile(image_fname)
4659 self.assertEqual(orig_image.GetEntries().keys(),
4660 image.GetEntries().keys())
4661
Simon Glassa2af7302021-01-06 21:35:18 -07004662 def testFilesAlign(self):
4663 """Test alignment with files"""
4664 data = self._DoReadFile('190_files_align.dts')
4665
4666 # The first string is 15 bytes so will align to 16
4667 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4668 self.assertEqual(expect, data)
4669
Simon Glassdb84b562021-01-06 21:35:19 -07004670 def testReadImageSkip(self):
4671 """Test reading an image and accessing its FDT map"""
4672 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004673 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004674 orig_image = control.images['image']
4675 image = Image.FromFile(image_fname)
4676 self.assertEqual(orig_image.GetEntries().keys(),
4677 image.GetEntries().keys())
4678
4679 orig_entry = orig_image.GetEntries()['fdtmap']
4680 entry = image.GetEntries()['fdtmap']
4681 self.assertEqual(orig_entry.offset, entry.offset)
4682 self.assertEqual(orig_entry.size, entry.size)
4683 self.assertEqual(16, entry.image_pos)
4684
4685 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4686
4687 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4688
Simon Glassc98de972021-03-18 20:24:57 +13004689 def testTplNoDtb(self):
4690 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004691 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004692 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4693 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4694 data[:len(U_BOOT_TPL_NODTB_DATA)])
4695
Simon Glass63f41d42021-03-18 20:24:58 +13004696 def testTplBssPad(self):
4697 """Test that we can pad TPL's BSS with zeros"""
4698 # ELF file with a '__bss_size' symbol
4699 self._SetupTplElf()
4700 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004701 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004702 data)
4703
4704 def testTplBssPadMissing(self):
4705 """Test that a missing symbol is detected"""
4706 self._SetupTplElf('u_boot_ucode_ptr')
4707 with self.assertRaises(ValueError) as e:
4708 self._DoReadFile('193_tpl_bss_pad.dts')
4709 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4710 str(e.exception))
4711
Simon Glass718b5292021-03-18 20:25:07 +13004712 def checkDtbSizes(self, data, pad_len, start):
4713 """Check the size arguments in a dtb embedded in an image
4714
4715 Args:
4716 data: The image data
4717 pad_len: Length of the pad section in the image, in bytes
4718 start: Start offset of the devicetree to examine, within the image
4719
4720 Returns:
4721 Size of the devicetree in bytes
4722 """
4723 dtb_data = data[start:]
4724 dtb = fdt.Fdt.FromData(dtb_data)
4725 fdt_size = dtb.GetFdtObj().totalsize()
4726 dtb.Scan()
4727 props = self._GetPropTree(dtb, 'size')
4728 self.assertEqual({
4729 'size': len(data),
4730 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4731 'u-boot-spl/u-boot-spl-dtb:size': 801,
4732 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4733 'u-boot-spl:size': 860,
4734 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4735 'u-boot/u-boot-dtb:size': 781,
4736 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4737 'u-boot:size': 827,
4738 }, props)
4739 return fdt_size
4740
4741 def testExpanded(self):
4742 """Test that an expanded entry type is selected when needed"""
4743 self._SetupSplElf()
4744 self._SetupTplElf()
4745
4746 # SPL has a devicetree, TPL does not
4747 entry_args = {
4748 'spl-dtb': '1',
4749 'spl-bss-pad': 'y',
4750 'tpl-dtb': '',
4751 }
4752 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4753 entry_args=entry_args)
4754 image = control.images['image']
4755 entries = image.GetEntries()
4756 self.assertEqual(3, len(entries))
4757
4758 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4759 self.assertIn('u-boot', entries)
4760 entry = entries['u-boot']
4761 self.assertEqual('u-boot-expanded', entry.etype)
4762 subent = entry.GetEntries()
4763 self.assertEqual(2, len(subent))
4764 self.assertIn('u-boot-nodtb', subent)
4765 self.assertIn('u-boot-dtb', subent)
4766
4767 # Second, u-boot-spl, which should be expanded into three parts
4768 self.assertIn('u-boot-spl', entries)
4769 entry = entries['u-boot-spl']
4770 self.assertEqual('u-boot-spl-expanded', entry.etype)
4771 subent = entry.GetEntries()
4772 self.assertEqual(3, len(subent))
4773 self.assertIn('u-boot-spl-nodtb', subent)
4774 self.assertIn('u-boot-spl-bss-pad', subent)
4775 self.assertIn('u-boot-spl-dtb', subent)
4776
4777 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4778 # devicetree
4779 self.assertIn('u-boot-tpl', entries)
4780 entry = entries['u-boot-tpl']
4781 self.assertEqual('u-boot-tpl', entry.etype)
4782 self.assertEqual(None, entry.GetEntries())
4783
4784 def testExpandedTpl(self):
4785 """Test that an expanded entry type is selected for TPL when needed"""
4786 self._SetupTplElf()
4787
4788 entry_args = {
4789 'tpl-bss-pad': 'y',
4790 'tpl-dtb': 'y',
4791 }
4792 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4793 entry_args=entry_args)
4794 image = control.images['image']
4795 entries = image.GetEntries()
4796 self.assertEqual(1, len(entries))
4797
4798 # We only have u-boot-tpl, which be expanded
4799 self.assertIn('u-boot-tpl', entries)
4800 entry = entries['u-boot-tpl']
4801 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4802 subent = entry.GetEntries()
4803 self.assertEqual(3, len(subent))
4804 self.assertIn('u-boot-tpl-nodtb', subent)
4805 self.assertIn('u-boot-tpl-bss-pad', subent)
4806 self.assertIn('u-boot-tpl-dtb', subent)
4807
4808 def testExpandedNoPad(self):
4809 """Test an expanded entry without BSS pad enabled"""
4810 self._SetupSplElf()
4811 self._SetupTplElf()
4812
4813 # SPL has a devicetree, TPL does not
4814 entry_args = {
4815 'spl-dtb': 'something',
4816 'spl-bss-pad': 'n',
4817 'tpl-dtb': '',
4818 }
4819 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4820 entry_args=entry_args)
4821 image = control.images['image']
4822 entries = image.GetEntries()
4823
4824 # Just check u-boot-spl, which should be expanded into two parts
4825 self.assertIn('u-boot-spl', entries)
4826 entry = entries['u-boot-spl']
4827 self.assertEqual('u-boot-spl-expanded', entry.etype)
4828 subent = entry.GetEntries()
4829 self.assertEqual(2, len(subent))
4830 self.assertIn('u-boot-spl-nodtb', subent)
4831 self.assertIn('u-boot-spl-dtb', subent)
4832
4833 def testExpandedTplNoPad(self):
4834 """Test that an expanded entry type with padding disabled in TPL"""
4835 self._SetupTplElf()
4836
4837 entry_args = {
4838 'tpl-bss-pad': '',
4839 'tpl-dtb': 'y',
4840 }
4841 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4842 entry_args=entry_args)
4843 image = control.images['image']
4844 entries = image.GetEntries()
4845 self.assertEqual(1, len(entries))
4846
4847 # We only have u-boot-tpl, which be expanded
4848 self.assertIn('u-boot-tpl', entries)
4849 entry = entries['u-boot-tpl']
4850 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4851 subent = entry.GetEntries()
4852 self.assertEqual(2, len(subent))
4853 self.assertIn('u-boot-tpl-nodtb', subent)
4854 self.assertIn('u-boot-tpl-dtb', subent)
4855
4856 def testFdtInclude(self):
4857 """Test that an Fdt is update within all binaries"""
4858 self._SetupSplElf()
4859 self._SetupTplElf()
4860
4861 # SPL has a devicetree, TPL does not
4862 self.maxDiff = None
4863 entry_args = {
4864 'spl-dtb': '1',
4865 'spl-bss-pad': 'y',
4866 'tpl-dtb': '',
4867 }
4868 # Build the image. It includes two separate devicetree binaries, each
4869 # with their own contents, but all contain the binman definition.
4870 data = self._DoReadFileDtb(
4871 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4872 update_dtb=True, entry_args=entry_args)[0]
4873 pad_len = 10
4874
4875 # Check the U-Boot dtb
4876 start = len(U_BOOT_NODTB_DATA)
4877 fdt_size = self.checkDtbSizes(data, pad_len, start)
4878
4879 # Now check SPL
4880 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4881 fdt_size = self.checkDtbSizes(data, pad_len, start)
4882
4883 # TPL has no devicetree
4884 start += fdt_size + len(U_BOOT_TPL_DATA)
4885 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004886
Simon Glass7098b7f2021-03-21 18:24:30 +13004887 def testSymbolsExpanded(self):
4888 """Test binman can assign symbols in expanded entries"""
4889 entry_args = {
4890 'spl-dtb': '1',
4891 }
4892 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4893 U_BOOT_SPL_DTB_DATA, 0x38,
4894 entry_args=entry_args, use_expanded=True)
4895
Simon Glasse1915782021-03-21 18:24:31 +13004896 def testCollection(self):
4897 """Test a collection"""
4898 data = self._DoReadFile('198_collection.dts')
4899 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004900 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4901 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004902 data)
4903
Simon Glass27a7f772021-03-21 18:24:32 +13004904 def testCollectionSection(self):
4905 """Test a collection where a section must be built first"""
4906 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004907 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004908 # building the contents, producing an error is anything is still
4909 # missing.
4910 data = self._DoReadFile('199_collection_section.dts')
4911 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004912 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4913 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004914 data)
4915
Simon Glassf427c5f2021-03-21 18:24:33 +13004916 def testAlignDefault(self):
4917 """Test that default alignment works on sections"""
4918 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004919 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004920 U_BOOT_DATA)
4921 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004922 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004923 # No alignment within the nested section
4924 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4925 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004926 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004927 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004928
Bin Mengc0b15742021-05-10 20:23:33 +08004929 def testPackOpenSBI(self):
4930 """Test that an image with an OpenSBI binary can be created"""
4931 data = self._DoReadFile('201_opensbi.dts')
4932 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4933
Simon Glass76f496d2021-07-06 10:36:37 -06004934 def testSectionsSingleThread(self):
4935 """Test sections without multithreading"""
4936 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004937 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4938 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4939 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004940 self.assertEqual(expected, data)
4941
4942 def testThreadTimeout(self):
4943 """Test handling a thread that takes too long"""
4944 with self.assertRaises(ValueError) as e:
4945 self._DoTestFile('202_section_timeout.dts',
4946 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004947 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004948
Simon Glass748a1d42021-07-06 10:36:41 -06004949 def testTiming(self):
4950 """Test output of timing information"""
4951 data = self._DoReadFile('055_sections.dts')
4952 with test_util.capture_sys_output() as (stdout, stderr):
4953 state.TimingShow()
4954 self.assertIn('read:', stdout.getvalue())
4955 self.assertIn('compress:', stdout.getvalue())
4956
Simon Glassadfb8492021-11-03 21:09:18 -06004957 def testUpdateFdtInElf(self):
4958 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004959 if not elf.ELF_TOOLS:
4960 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004961 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4962 outfile = os.path.join(self._indir, 'u-boot.out')
4963 begin_sym = 'dtb_embed_begin'
4964 end_sym = 'dtb_embed_end'
4965 retcode = self._DoTestFile(
4966 '060_fdt_update.dts', update_dtb=True,
4967 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4968 self.assertEqual(0, retcode)
4969
4970 # Check that the output file does in fact contact a dtb with the binman
4971 # definition in the correct place
4972 syms = elf.GetSymbolFileOffset(infile,
4973 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004974 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004975 dtb_data = data[syms['dtb_embed_begin'].offset:
4976 syms['dtb_embed_end'].offset]
4977
4978 dtb = fdt.Fdt.FromData(dtb_data)
4979 dtb.Scan()
4980 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4981 self.assertEqual({
4982 'image-pos': 0,
4983 'offset': 0,
4984 '_testing:offset': 32,
4985 '_testing:size': 2,
4986 '_testing:image-pos': 32,
4987 'section@0/u-boot:offset': 0,
4988 'section@0/u-boot:size': len(U_BOOT_DATA),
4989 'section@0/u-boot:image-pos': 0,
4990 'section@0:offset': 0,
4991 'section@0:size': 16,
4992 'section@0:image-pos': 0,
4993
4994 'section@1/u-boot:offset': 0,
4995 'section@1/u-boot:size': len(U_BOOT_DATA),
4996 'section@1/u-boot:image-pos': 16,
4997 'section@1:offset': 16,
4998 'section@1:size': 16,
4999 'section@1:image-pos': 16,
5000 'size': 40
5001 }, props)
5002
5003 def testUpdateFdtInElfInvalid(self):
5004 """Test that invalid args are detected with --update-fdt-in-elf"""
5005 with self.assertRaises(ValueError) as e:
5006 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5007 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5008 str(e.exception))
5009
5010 def testUpdateFdtInElfNoSyms(self):
5011 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005012 if not elf.ELF_TOOLS:
5013 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005014 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5015 outfile = ''
5016 begin_sym = 'wrong_begin'
5017 end_sym = 'wrong_end'
5018 with self.assertRaises(ValueError) as e:
5019 self._DoTestFile(
5020 '060_fdt_update.dts',
5021 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5022 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5023 str(e.exception))
5024
5025 def testUpdateFdtInElfTooSmall(self):
5026 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005027 if not elf.ELF_TOOLS:
5028 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005029 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5030 outfile = os.path.join(self._indir, 'u-boot.out')
5031 begin_sym = 'dtb_embed_begin'
5032 end_sym = 'dtb_embed_end'
5033 with self.assertRaises(ValueError) as e:
5034 self._DoTestFile(
5035 '060_fdt_update.dts', update_dtb=True,
5036 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5037 self.assertRegex(
5038 str(e.exception),
5039 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5040
Simon Glass88e04da2021-11-23 11:03:42 -07005041 def testVersion(self):
5042 """Test we can get the binman version"""
5043 version = '(unreleased)'
5044 self.assertEqual(version, state.GetVersion(self._indir))
5045
5046 with self.assertRaises(SystemExit):
5047 with test_util.capture_sys_output() as (_, stderr):
5048 self._DoBinman('-V')
5049 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5050
5051 # Try running the tool too, just to be safe
5052 result = self._RunBinman('-V')
5053 self.assertEqual('Binman %s\n' % version, result.stderr)
5054
5055 # Set up a version file to make sure that works
5056 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005057 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005058 binary=False)
5059 self.assertEqual(version, state.GetVersion(self._indir))
5060
Simon Glass637958f2021-11-23 21:09:50 -07005061 def testAltFormat(self):
5062 """Test that alternative formats can be used to extract"""
5063 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5064
5065 try:
5066 tmpdir, updated_fname = self._SetupImageInTmpdir()
5067 with test_util.capture_sys_output() as (stdout, _):
5068 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5069 self.assertEqual(
5070 '''Flag (-F) Entry type Description
5071fdt fdtmap Extract the devicetree blob from the fdtmap
5072''',
5073 stdout.getvalue())
5074
5075 dtb = os.path.join(tmpdir, 'fdt.dtb')
5076 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5077 dtb, 'fdtmap')
5078
5079 # Check that we can read it and it can be scanning, meaning it does
5080 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005081 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005082 dtb = fdt.Fdt.FromData(data)
5083 dtb.Scan()
5084
5085 # Now check u-boot which has no alt_format
5086 fname = os.path.join(tmpdir, 'fdt.dtb')
5087 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5088 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005089 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005090 self.assertEqual(U_BOOT_DATA, data)
5091
5092 finally:
5093 shutil.rmtree(tmpdir)
5094
Simon Glass0b00ae62021-11-23 21:09:52 -07005095 def testExtblobList(self):
5096 """Test an image with an external blob list"""
5097 data = self._DoReadFile('215_blob_ext_list.dts')
5098 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5099
5100 def testExtblobListMissing(self):
5101 """Test an image with a missing external blob"""
5102 with self.assertRaises(ValueError) as e:
5103 self._DoReadFile('216_blob_ext_list_missing.dts')
5104 self.assertIn("Filename 'missing-file' not found in input path",
5105 str(e.exception))
5106
5107 def testExtblobListMissingOk(self):
5108 """Test an image with an missing external blob that is allowed"""
5109 with test_util.capture_sys_output() as (stdout, stderr):
5110 self._DoTestFile('216_blob_ext_list_missing.dts',
5111 allow_missing=True)
5112 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005113 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005114
Simon Glass3efb2972021-11-23 21:08:59 -07005115 def testFip(self):
5116 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5117 data = self._DoReadFile('203_fip.dts')
5118 hdr, fents = fip_util.decode_fip(data)
5119 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5120 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5121 self.assertEqual(0x123, hdr.flags)
5122
5123 self.assertEqual(2, len(fents))
5124
5125 fent = fents[0]
5126 self.assertEqual(
5127 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5128 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5129 self.assertEqual('soc-fw', fent.fip_type)
5130 self.assertEqual(0x88, fent.offset)
5131 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5132 self.assertEqual(0x123456789abcdef, fent.flags)
5133 self.assertEqual(ATF_BL31_DATA, fent.data)
5134 self.assertEqual(True, fent.valid)
5135
5136 fent = fents[1]
5137 self.assertEqual(
5138 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5139 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5140 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5141 self.assertEqual(0x8c, fent.offset)
5142 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5143 self.assertEqual(0, fent.flags)
5144 self.assertEqual(ATF_BL2U_DATA, fent.data)
5145 self.assertEqual(True, fent.valid)
5146
5147 def testFipOther(self):
5148 """Basic FIP with something that isn't a external blob"""
5149 data = self._DoReadFile('204_fip_other.dts')
5150 hdr, fents = fip_util.decode_fip(data)
5151
5152 self.assertEqual(2, len(fents))
5153 fent = fents[1]
5154 self.assertEqual('rot-cert', fent.fip_type)
5155 self.assertEqual(b'aa', fent.data)
5156
Simon Glass3efb2972021-11-23 21:08:59 -07005157 def testFipNoType(self):
5158 """FIP with an entry of an unknown type"""
5159 with self.assertRaises(ValueError) as e:
5160 self._DoReadFile('205_fip_no_type.dts')
5161 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5162 str(e.exception))
5163
5164 def testFipUuid(self):
5165 """Basic FIP with a manual uuid"""
5166 data = self._DoReadFile('206_fip_uuid.dts')
5167 hdr, fents = fip_util.decode_fip(data)
5168
5169 self.assertEqual(2, len(fents))
5170 fent = fents[1]
5171 self.assertEqual(None, fent.fip_type)
5172 self.assertEqual(
5173 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5174 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5175 fent.uuid)
5176 self.assertEqual(U_BOOT_DATA, fent.data)
5177
5178 def testFipLs(self):
5179 """Test listing a FIP"""
5180 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5181 hdr, fents = fip_util.decode_fip(data)
5182
5183 try:
5184 tmpdir, updated_fname = self._SetupImageInTmpdir()
5185 with test_util.capture_sys_output() as (stdout, stderr):
5186 self._DoBinman('ls', '-i', updated_fname)
5187 finally:
5188 shutil.rmtree(tmpdir)
5189 lines = stdout.getvalue().splitlines()
5190 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005191'Name Image-pos Size Entry-type Offset Uncomp-size',
5192'--------------------------------------------------------------',
5193'image 0 2d3 section 0',
5194' atf-fip 0 90 atf-fip 0',
5195' soc-fw 88 4 blob-ext 88',
5196' u-boot 8c 4 u-boot 8c',
5197' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005198]
5199 self.assertEqual(expected, lines)
5200
5201 image = control.images['image']
5202 entries = image.GetEntries()
5203 fdtmap = entries['fdtmap']
5204
5205 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5206 magic = fdtmap_data[:8]
5207 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005208 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005209
5210 fdt_data = fdtmap_data[16:]
5211 dtb = fdt.Fdt.FromData(fdt_data)
5212 dtb.Scan()
5213 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5214 self.assertEqual({
5215 'atf-fip/soc-fw:image-pos': 136,
5216 'atf-fip/soc-fw:offset': 136,
5217 'atf-fip/soc-fw:size': 4,
5218 'atf-fip/u-boot:image-pos': 140,
5219 'atf-fip/u-boot:offset': 140,
5220 'atf-fip/u-boot:size': 4,
5221 'atf-fip:image-pos': 0,
5222 'atf-fip:offset': 0,
5223 'atf-fip:size': 144,
5224 'image-pos': 0,
5225 'offset': 0,
5226 'fdtmap:image-pos': fdtmap.image_pos,
5227 'fdtmap:offset': fdtmap.offset,
5228 'fdtmap:size': len(fdtmap_data),
5229 'size': len(data),
5230 }, props)
5231
5232 def testFipExtractOneEntry(self):
5233 """Test extracting a single entry fron an FIP"""
5234 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005235 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005236 fname = os.path.join(self._indir, 'output.extact')
5237 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005238 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005239 self.assertEqual(U_BOOT_DATA, data)
5240
5241 def testFipReplace(self):
5242 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005243 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005244 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005245 updated_fname = tools.get_output_filename('image-updated.bin')
5246 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005247 entry_name = 'atf-fip/u-boot'
5248 control.WriteEntry(updated_fname, entry_name, expected,
5249 allow_resize=True)
5250 actual = control.ReadEntry(updated_fname, entry_name)
5251 self.assertEqual(expected, actual)
5252
Simon Glass80025522022-01-29 14:14:04 -07005253 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005254 hdr, fents = fip_util.decode_fip(new_data)
5255
5256 self.assertEqual(2, len(fents))
5257
5258 # Check that the FIP entry is updated
5259 fent = fents[1]
5260 self.assertEqual(0x8c, fent.offset)
5261 self.assertEqual(len(expected), fent.size)
5262 self.assertEqual(0, fent.flags)
5263 self.assertEqual(expected, fent.data)
5264 self.assertEqual(True, fent.valid)
5265
5266 def testFipMissing(self):
5267 with test_util.capture_sys_output() as (stdout, stderr):
5268 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5269 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005270 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005271
5272 def testFipSize(self):
5273 """Test a FIP with a size property"""
5274 data = self._DoReadFile('210_fip_size.dts')
5275 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5276 hdr, fents = fip_util.decode_fip(data)
5277 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5278 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5279
5280 self.assertEqual(1, len(fents))
5281
5282 fent = fents[0]
5283 self.assertEqual('soc-fw', fent.fip_type)
5284 self.assertEqual(0x60, fent.offset)
5285 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5286 self.assertEqual(ATF_BL31_DATA, fent.data)
5287 self.assertEqual(True, fent.valid)
5288
5289 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005290 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005291
5292 def testFipBadAlign(self):
5293 """Test that an invalid alignment value in a FIP is detected"""
5294 with self.assertRaises(ValueError) as e:
5295 self._DoTestFile('211_fip_bad_align.dts')
5296 self.assertIn(
5297 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5298 str(e.exception))
5299
5300 def testFipCollection(self):
5301 """Test using a FIP in a collection"""
5302 data = self._DoReadFile('212_fip_collection.dts')
5303 entry1 = control.images['image'].GetEntries()['collection']
5304 data1 = data[:entry1.size]
5305 hdr1, fents2 = fip_util.decode_fip(data1)
5306
5307 entry2 = control.images['image'].GetEntries()['atf-fip']
5308 data2 = data[entry2.offset:entry2.offset + entry2.size]
5309 hdr1, fents2 = fip_util.decode_fip(data2)
5310
5311 # The 'collection' entry should have U-Boot included at the end
5312 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5313 self.assertEqual(data1, data2 + U_BOOT_DATA)
5314 self.assertEqual(U_BOOT_DATA, data1[-4:])
5315
5316 # There should be a U-Boot after the final FIP
5317 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005318
Simon Glassccae6862022-01-12 13:10:35 -07005319 def testFakeBlob(self):
5320 """Test handling of faking an external blob"""
5321 with test_util.capture_sys_output() as (stdout, stderr):
5322 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5323 allow_fake_blobs=True)
5324 err = stderr.getvalue()
5325 self.assertRegex(
5326 err,
5327 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005328
Simon Glassceb5f912022-01-09 20:13:46 -07005329 def testExtblobListFaked(self):
5330 """Test an extblob with missing external blob that are faked"""
5331 with test_util.capture_sys_output() as (stdout, stderr):
5332 self._DoTestFile('216_blob_ext_list_missing.dts',
5333 allow_fake_blobs=True)
5334 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005335 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005336
Simon Glass162017b2022-01-09 20:13:57 -07005337 def testListBintools(self):
5338 args = ['tool', '--list']
5339 with test_util.capture_sys_output() as (stdout, _):
5340 self._DoBinman(*args)
5341 out = stdout.getvalue().splitlines()
5342 self.assertTrue(len(out) >= 2)
5343
5344 def testFetchBintools(self):
5345 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005346 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005347 raise urllib.error.URLError('my error')
5348
5349 args = ['tool']
5350 with self.assertRaises(ValueError) as e:
5351 self._DoBinman(*args)
5352 self.assertIn("Invalid arguments to 'tool' subcommand",
5353 str(e.exception))
5354
5355 args = ['tool', '--fetch']
5356 with self.assertRaises(ValueError) as e:
5357 self._DoBinman(*args)
5358 self.assertIn('Please specify bintools to fetch', str(e.exception))
5359
5360 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005361 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005362 side_effect=fail_download):
5363 with test_util.capture_sys_output() as (stdout, _):
5364 self._DoBinman(*args)
5365 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5366
Simon Glass620c4462022-01-09 20:14:11 -07005367 def testBintoolDocs(self):
5368 """Test for creation of bintool documentation"""
5369 with test_util.capture_sys_output() as (stdout, stderr):
5370 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5371 self.assertTrue(len(stdout.getvalue()) > 0)
5372
5373 def testBintoolDocsMissing(self):
5374 """Test handling of missing bintool documentation"""
5375 with self.assertRaises(ValueError) as e:
5376 with test_util.capture_sys_output() as (stdout, stderr):
5377 control.write_bintool_docs(
5378 control.bintool.Bintool.get_tool_list(), 'mkimage')
5379 self.assertIn('Documentation is missing for modules: mkimage',
5380 str(e.exception))
5381
Jan Kiszka58c407f2022-01-28 20:37:53 +01005382 def testListWithGenNode(self):
5383 """Check handling of an FDT map when the section cannot be found"""
5384 entry_args = {
5385 'of-list': 'test-fdt1 test-fdt2',
5386 }
5387 data = self._DoReadFileDtb(
5388 '219_fit_gennode.dts',
5389 entry_args=entry_args,
5390 use_real_dtb=True,
5391 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5392
5393 try:
5394 tmpdir, updated_fname = self._SetupImageInTmpdir()
5395 with test_util.capture_sys_output() as (stdout, stderr):
5396 self._RunBinman('ls', '-i', updated_fname)
5397 finally:
5398 shutil.rmtree(tmpdir)
5399
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005400 def testFitSubentryUsesBintool(self):
5401 """Test that binman FIT subentries can use bintools"""
5402 command.test_result = self._HandleGbbCommand
5403 entry_args = {
5404 'keydir': 'devkeys',
5405 'bmpblk': 'bmpblk.bin',
5406 }
5407 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5408 entry_args=entry_args)
5409
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005410 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5411 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005412 self.assertIn(expected, data)
5413
5414 def testFitSubentryMissingBintool(self):
5415 """Test that binman reports missing bintools for FIT subentries"""
5416 entry_args = {
5417 'keydir': 'devkeys',
5418 }
5419 with test_util.capture_sys_output() as (_, stderr):
5420 self._DoTestFile('220_fit_subentry_bintool.dts',
5421 force_missing_bintools='futility', entry_args=entry_args)
5422 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005423 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005424
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005425 def testFitSubentryHashSubnode(self):
5426 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005427 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005428 data, _, _, out_dtb_name = self._DoReadFileDtb(
5429 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5430
5431 mkimage_dtb = fdt.Fdt.FromData(data)
5432 mkimage_dtb.Scan()
5433 binman_dtb = fdt.Fdt(out_dtb_name)
5434 binman_dtb.Scan()
5435
5436 # Check that binman didn't add hash values
5437 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5438 self.assertNotIn('value', fnode.props)
5439
5440 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5441 self.assertNotIn('value', fnode.props)
5442
5443 # Check that mkimage added hash values
5444 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5445 self.assertIn('value', fnode.props)
5446
5447 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5448 self.assertIn('value', fnode.props)
5449
Roger Quadros5cdcea02022-02-19 20:50:04 +02005450 def testPackTeeOs(self):
5451 """Test that an image with an TEE binary can be created"""
5452 data = self._DoReadFile('222_tee_os.dts')
5453 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5454
Simon Glass912339f2022-02-08 11:50:03 -07005455 def testFitFdtOper(self):
5456 """Check handling of a specified FIT operation"""
5457 entry_args = {
5458 'of-list': 'test-fdt1 test-fdt2',
5459 'default-dt': 'test-fdt2',
5460 }
5461 self._DoReadFileDtb(
5462 '223_fit_fdt_oper.dts',
5463 entry_args=entry_args,
5464 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5465
5466 def testFitFdtBadOper(self):
5467 """Check handling of an FDT map when the section cannot be found"""
5468 with self.assertRaises(ValueError) as exc:
5469 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005470 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005471 str(exc.exception))
5472
Simon Glassdd156a42022-03-05 20:18:59 -07005473 def test_uses_expand_size(self):
5474 """Test that the 'expand-size' property cannot be used anymore"""
5475 with self.assertRaises(ValueError) as e:
5476 data = self._DoReadFile('225_expand_size_bad.dts')
5477 self.assertIn(
5478 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5479 str(e.exception))
5480
Simon Glass5f423422022-03-05 20:19:12 -07005481 def testFitSplitElf(self):
5482 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005483 if not elf.ELF_TOOLS:
5484 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005485 entry_args = {
5486 'of-list': 'test-fdt1 test-fdt2',
5487 'default-dt': 'test-fdt2',
5488 'atf-bl31-path': 'bl31.elf',
5489 'tee-os-path': 'tee.elf',
5490 }
5491 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5492 data = self._DoReadFileDtb(
5493 '226_fit_split_elf.dts',
5494 entry_args=entry_args,
5495 extra_indirs=[test_subdir])[0]
5496
5497 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5498 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5499
5500 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5501 'data', 'load'}
5502 dtb = fdt.Fdt.FromData(fit_data)
5503 dtb.Scan()
5504
5505 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5506 segments, entry = elf.read_loadable_segments(elf_data)
5507
5508 # We assume there are two segments
5509 self.assertEquals(2, len(segments))
5510
5511 atf1 = dtb.GetNode('/images/atf-1')
5512 _, start, data = segments[0]
5513 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5514 self.assertEqual(entry,
5515 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5516 self.assertEqual(start,
5517 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5518 self.assertEqual(data, atf1.props['data'].bytes)
5519
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005520 hash_node = atf1.FindNode('hash')
5521 self.assertIsNotNone(hash_node)
5522 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5523
Simon Glass5f423422022-03-05 20:19:12 -07005524 atf2 = dtb.GetNode('/images/atf-2')
5525 self.assertEqual(base_keys, atf2.props.keys())
5526 _, start, data = segments[1]
5527 self.assertEqual(start,
5528 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5529 self.assertEqual(data, atf2.props['data'].bytes)
5530
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005531 hash_node = atf2.FindNode('hash')
5532 self.assertIsNotNone(hash_node)
5533 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5534
5535 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5536 self.assertIsNotNone(hash_node)
5537 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5538
Simon Glass5f423422022-03-05 20:19:12 -07005539 conf = dtb.GetNode('/configurations')
5540 self.assertEqual({'default'}, conf.props.keys())
5541
5542 for subnode in conf.subnodes:
5543 self.assertEqual({'description', 'fdt', 'loadables'},
5544 subnode.props.keys())
5545 self.assertEqual(
5546 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5547 fdt_util.GetStringList(subnode, 'loadables'))
5548
5549 def _check_bad_fit(self, dts):
5550 """Check a bad FIT
5551
5552 This runs with the given dts and returns the assertion raised
5553
5554 Args:
5555 dts (str): dts filename to use
5556
5557 Returns:
5558 str: Assertion string raised
5559 """
5560 entry_args = {
5561 'of-list': 'test-fdt1 test-fdt2',
5562 'default-dt': 'test-fdt2',
5563 'atf-bl31-path': 'bl31.elf',
5564 'tee-os-path': 'tee.elf',
5565 }
5566 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5567 with self.assertRaises(ValueError) as exc:
5568 self._DoReadFileDtb(dts, entry_args=entry_args,
5569 extra_indirs=[test_subdir])[0]
5570 return str(exc.exception)
5571
5572 def testFitSplitElfBadElf(self):
5573 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005574 if not elf.ELF_TOOLS:
5575 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005576 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5577 entry_args = {
5578 'of-list': 'test-fdt1 test-fdt2',
5579 'default-dt': 'test-fdt2',
5580 'atf-bl31-path': 'bad.elf',
5581 'tee-os-path': 'tee.elf',
5582 }
5583 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5584 with self.assertRaises(ValueError) as exc:
5585 self._DoReadFileDtb(
5586 '226_fit_split_elf.dts',
5587 entry_args=entry_args,
5588 extra_indirs=[test_subdir])[0]
5589 self.assertIn(
5590 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5591 str(exc.exception))
5592
Simon Glass5f423422022-03-05 20:19:12 -07005593 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005594 """Test an split-elf FIT with a missing ELF file
5595
5596 Args:
5597 kwargs (dict of str): Arguments to pass to _DoTestFile()
5598
5599 Returns:
5600 tuple:
5601 str: stdout result
5602 str: stderr result
5603 """
Simon Glass5f423422022-03-05 20:19:12 -07005604 entry_args = {
5605 'of-list': 'test-fdt1 test-fdt2',
5606 'default-dt': 'test-fdt2',
5607 'atf-bl31-path': 'bl31.elf',
5608 'tee-os-path': 'missing.elf',
5609 }
5610 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5611 with test_util.capture_sys_output() as (stdout, stderr):
5612 self._DoTestFile(
5613 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005614 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5615 out = stdout.getvalue()
5616 err = stderr.getvalue()
5617 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005618
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005619 def testFitSplitElfBadDirective(self):
5620 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5621 if not elf.ELF_TOOLS:
5622 self.skipTest('Python elftools not available')
5623 err = self._check_bad_fit('227_fit_bad_dir.dts')
5624 self.assertIn(
5625 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5626 err)
5627
5628 def testFitSplitElfBadDirectiveConfig(self):
5629 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5630 if not elf.ELF_TOOLS:
5631 self.skipTest('Python elftools not available')
5632 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5633 self.assertEqual(
5634 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5635 err)
5636
5637
Simon Glass5f423422022-03-05 20:19:12 -07005638 def testFitSplitElfMissing(self):
5639 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005640 if not elf.ELF_TOOLS:
5641 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005642 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005643 self.assertRegex(
5644 err,
5645 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005646 self.assertNotRegex(out, '.*Faked blob.*')
5647 fname = tools.get_output_filename('binman-fake/missing.elf')
5648 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005649
5650 def testFitSplitElfFaked(self):
5651 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005652 if not elf.ELF_TOOLS:
5653 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005654 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005655 self.assertRegex(
5656 err,
5657 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005658 self.assertRegex(
5659 out,
5660 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5661 fname = tools.get_output_filename('binman-fake/missing.elf')
5662 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005663
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005664 def testMkimageMissingBlob(self):
5665 """Test using mkimage to build an image"""
5666 with test_util.capture_sys_output() as (stdout, stderr):
5667 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5668 allow_fake_blobs=True)
5669 err = stderr.getvalue()
5670 self.assertRegex(
5671 err,
5672 "Image '.*' has faked external blobs and is non-functional: .*")
5673
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005674 def testPreLoad(self):
5675 """Test an image with a pre-load header"""
5676 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005677 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005678 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005679 data = self._DoReadFileDtb(
5680 '230_pre_load.dts', entry_args=entry_args,
5681 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005682 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5683 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5684 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Simon Glasse2dfb962023-07-24 09:19:57 -06005685
5686 def testPreLoadNoKey(self):
5687 """Test an image with a pre-load heade0r with missing key"""
5688 with self.assertRaises(FileNotFoundError) as exc:
5689 self._DoReadFile('230_pre_load.dts')
5690 self.assertIn("No such file or directory: 'dev.key'",
5691 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005692
5693 def testPreLoadPkcs(self):
5694 """Test an image with a pre-load header with padding pkcs"""
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('231_pre_load_pkcs.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 testPreLoadPss(self):
5705 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005706 entry_args = {
5707 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5708 }
5709 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5710 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005711 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5712 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5713 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5714
5715 def testPreLoadInvalidPadding(self):
5716 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005717 entry_args = {
5718 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5719 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005720 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005721 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5722 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005723
5724 def testPreLoadInvalidSha(self):
5725 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005726 entry_args = {
5727 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5728 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005729 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005730 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5731 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005732
5733 def testPreLoadInvalidAlgo(self):
5734 """Test an image with a pre-load header with an invalid algo"""
5735 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005736 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005737
5738 def testPreLoadInvalidKey(self):
5739 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005740 entry_args = {
5741 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5742 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005743 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005744 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5745 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005746
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005747 def _CheckSafeUniqueNames(self, *images):
5748 """Check all entries of given images for unsafe unique names"""
5749 for image in images:
5750 entries = {}
5751 image._CollectEntries(entries, {}, image)
5752 for entry in entries.values():
5753 uniq = entry.GetUniqueName()
5754
5755 # Used as part of a filename, so must not be absolute paths.
5756 self.assertFalse(os.path.isabs(uniq))
5757
5758 def testSafeUniqueNames(self):
5759 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005760 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005761
5762 orig_image = control.images['image']
5763 image_fname = tools.get_output_filename('image.bin')
5764 image = Image.FromFile(image_fname)
5765
5766 self._CheckSafeUniqueNames(orig_image, image)
5767
5768 def testSafeUniqueNamesMulti(self):
5769 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005770 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005771
5772 orig_image = control.images['image']
5773 image_fname = tools.get_output_filename('image.bin')
5774 image = Image.FromFile(image_fname)
5775
5776 self._CheckSafeUniqueNames(orig_image, image)
5777
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005778 def testReplaceCmdWithBintool(self):
5779 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005780 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005781 expected = U_BOOT_DATA + b'aa'
5782 self.assertEqual(expected, data[:len(expected)])
5783
5784 try:
5785 tmpdir, updated_fname = self._SetupImageInTmpdir()
5786 fname = os.path.join(tmpdir, 'update-testing.bin')
5787 tools.write_file(fname, b'zz')
5788 self._DoBinman('replace', '-i', updated_fname,
5789 '_testing', '-f', fname)
5790
5791 data = tools.read_file(updated_fname)
5792 expected = U_BOOT_DATA + b'zz'
5793 self.assertEqual(expected, data[:len(expected)])
5794 finally:
5795 shutil.rmtree(tmpdir)
5796
5797 def testReplaceCmdOtherWithBintool(self):
5798 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005799 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005800 expected = U_BOOT_DATA + b'aa'
5801 self.assertEqual(expected, data[:len(expected)])
5802
5803 try:
5804 tmpdir, updated_fname = self._SetupImageInTmpdir()
5805 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5806 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5807 self._DoBinman('replace', '-i', updated_fname,
5808 'u-boot', '-f', fname)
5809
5810 data = tools.read_file(updated_fname)
5811 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5812 self.assertEqual(expected, data[:len(expected)])
5813 finally:
5814 shutil.rmtree(tmpdir)
5815
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005816 def testReplaceResizeNoRepackSameSize(self):
5817 """Test replacing entries with same-size data without repacking"""
5818 expected = b'x' * len(U_BOOT_DATA)
5819 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5820 self.assertEqual(expected, data)
5821
5822 path, fdtmap = state.GetFdtContents('fdtmap')
5823 self.assertIsNotNone(path)
5824 self.assertEqual(expected_fdtmap, fdtmap)
5825
5826 def testReplaceResizeNoRepackSmallerSize(self):
5827 """Test replacing entries with smaller-size data without repacking"""
5828 new_data = b'x'
5829 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5830 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5831 self.assertEqual(expected, data)
5832
5833 path, fdtmap = state.GetFdtContents('fdtmap')
5834 self.assertIsNotNone(path)
5835 self.assertEqual(expected_fdtmap, fdtmap)
5836
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005837 def testExtractFit(self):
5838 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005839 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005840 image_fname = tools.get_output_filename('image.bin')
5841
5842 fit_data = control.ReadEntry(image_fname, 'fit')
5843 fit = fdt.Fdt.FromData(fit_data)
5844 fit.Scan()
5845
5846 # Check subentry data inside the extracted fit
5847 for node_path, expected in [
5848 ('/images/kernel', U_BOOT_DATA),
5849 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5850 ('/images/scr-1', COMPRESS_DATA),
5851 ]:
5852 node = fit.GetNode(node_path)
5853 data = fit.GetProps(node)['data'].bytes
5854 self.assertEqual(expected, data)
5855
5856 def testExtractFitSubentries(self):
5857 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005858 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005859 image_fname = tools.get_output_filename('image.bin')
5860
5861 for entry_path, expected in [
5862 ('fit/kernel', U_BOOT_DATA),
5863 ('fit/kernel/u-boot', U_BOOT_DATA),
5864 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5865 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5866 ('fit/scr-1', COMPRESS_DATA),
5867 ('fit/scr-1/blob', COMPRESS_DATA),
5868 ]:
5869 data = control.ReadEntry(image_fname, entry_path)
5870 self.assertEqual(expected, data)
5871
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005872 def testReplaceFitSubentryLeafSameSize(self):
5873 """Test replacing a FIT leaf subentry with same-size data"""
5874 new_data = b'x' * len(U_BOOT_DATA)
5875 data, expected_fdtmap, _ = self._RunReplaceCmd(
5876 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005877 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005878 self.assertEqual(new_data, data)
5879
5880 path, fdtmap = state.GetFdtContents('fdtmap')
5881 self.assertIsNotNone(path)
5882 self.assertEqual(expected_fdtmap, fdtmap)
5883
5884 def testReplaceFitSubentryLeafBiggerSize(self):
5885 """Test replacing a FIT leaf subentry with bigger-size data"""
5886 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5887 data, expected_fdtmap, _ = self._RunReplaceCmd(
5888 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005889 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005890 self.assertEqual(new_data, data)
5891
5892 # Will be repacked, so fdtmap must change
5893 path, fdtmap = state.GetFdtContents('fdtmap')
5894 self.assertIsNotNone(path)
5895 self.assertNotEqual(expected_fdtmap, fdtmap)
5896
5897 def testReplaceFitSubentryLeafSmallerSize(self):
5898 """Test replacing a FIT leaf subentry with smaller-size data"""
5899 new_data = b'x'
5900 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5901 data, expected_fdtmap, _ = self._RunReplaceCmd(
5902 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005903 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005904 self.assertEqual(expected, data)
5905
5906 path, fdtmap = state.GetFdtContents('fdtmap')
5907 self.assertIsNotNone(path)
5908 self.assertEqual(expected_fdtmap, fdtmap)
5909
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005910 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005911 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005912 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005913 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5914 new_data, dts='241_replace_section_simple.dts')
5915 self.assertEqual(new_data, data)
5916
5917 entries = image.GetEntries()
5918 self.assertIn('section', entries)
5919 entry = entries['section']
5920 self.assertEqual(len(new_data), entry.size)
5921
5922 def testReplaceSectionLarger(self):
5923 """Test replacing a simple section with larger data"""
5924 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5925 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5926 new_data, dts='241_replace_section_simple.dts')
5927 self.assertEqual(new_data, data)
5928
5929 entries = image.GetEntries()
5930 self.assertIn('section', entries)
5931 entry = entries['section']
5932 self.assertEqual(len(new_data), entry.size)
5933 fentry = entries['fdtmap']
5934 self.assertEqual(entry.offset + entry.size, fentry.offset)
5935
5936 def testReplaceSectionSmaller(self):
5937 """Test replacing a simple section with smaller data"""
5938 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5939 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5940 new_data, dts='241_replace_section_simple.dts')
5941 self.assertEqual(new_data, data)
5942
5943 # The new size is the same as the old, just with a pad byte at the end
5944 entries = image.GetEntries()
5945 self.assertIn('section', entries)
5946 entry = entries['section']
5947 self.assertEqual(len(new_data), entry.size)
5948
5949 def testReplaceSectionSmallerAllow(self):
5950 """Test failing to replace a simple section with smaller data"""
5951 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5952 try:
5953 state.SetAllowEntryContraction(True)
5954 with self.assertRaises(ValueError) as exc:
5955 self._RunReplaceCmd('section', new_data,
5956 dts='241_replace_section_simple.dts')
5957 finally:
5958 state.SetAllowEntryContraction(False)
5959
5960 # Since we have no information about the position of things within the
5961 # section, we cannot adjust the position of /section-u-boot so it ends
5962 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06005963 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07005964 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5965 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06005966 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005967
Simon Glass8fbca772022-08-13 11:40:48 -06005968 def testMkimageImagename(self):
5969 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005970 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005971 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005972
5973 # Check that the data appears in the file somewhere
5974 self.assertIn(U_BOOT_SPL_DATA, data)
5975
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005976 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005977 name = data[0x20:0x40]
5978
5979 # Build the filename that we expect to be placed in there, by virtue of
5980 # the -n paraameter
5981 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5982
5983 # Check that the image name is set to the temporary filename used
5984 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5985
Simon Glassb1669752022-08-13 11:40:49 -06005986 def testMkimageImage(self):
5987 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005988 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005989 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005990
5991 # Check that the data appears in the file somewhere
5992 self.assertIn(U_BOOT_SPL_DATA, data)
5993
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005994 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06005995 name = data[0x20:0x40]
5996
5997 # Build the filename that we expect to be placed in there, by virtue of
5998 # the -n paraameter
5999 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6000
6001 # Check that the image name is set to the temporary filename used
6002 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6003
6004 # Check the corect data is in the imagename file
6005 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6006
6007 def testMkimageImageNoContent(self):
6008 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006009 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006010 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006011 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006012 self.assertIn('Could not complete processing of contents',
6013 str(exc.exception))
6014
6015 def testMkimageImageBad(self):
6016 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006017 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006018 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006019 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006020 self.assertIn('Cannot use both imagename node and data-to-imagename',
6021 str(exc.exception))
6022
Simon Glassbd5cd882022-08-13 11:40:50 -06006023 def testCollectionOther(self):
6024 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006025 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006026 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6027 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6028 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6029 data)
6030
6031 def testMkimageCollection(self):
6032 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006033 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006034 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006035 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6036 self.assertEqual(expect, data[:len(expect)])
6037
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006038 def testCompressDtbPrependInvalid(self):
6039 """Test that invalid header is detected"""
6040 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006041 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006042 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6043 "'u-boot-dtb': 'invalid'", str(e.exception))
6044
6045 def testCompressDtbPrependLength(self):
6046 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006047 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006048 image = control.images['image']
6049 entries = image.GetEntries()
6050 self.assertIn('u-boot-dtb', entries)
6051 u_boot_dtb = entries['u-boot-dtb']
6052 self.assertIn('fdtmap', entries)
6053 fdtmap = entries['fdtmap']
6054
6055 image_fname = tools.get_output_filename('image.bin')
6056 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6057 dtb = fdt.Fdt.FromData(orig)
6058 dtb.Scan()
6059 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6060 expected = {
6061 'u-boot:size': len(U_BOOT_DATA),
6062 'u-boot-dtb:uncomp-size': len(orig),
6063 'u-boot-dtb:size': u_boot_dtb.size,
6064 'fdtmap:size': fdtmap.size,
6065 'size': len(data),
6066 }
6067 self.assertEqual(expected, props)
6068
6069 # Check implementation
6070 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6071 rest = data[len(U_BOOT_DATA):]
6072 comp_data_len = struct.unpack('<I', rest[:4])[0]
6073 comp_data = rest[4:4 + comp_data_len]
6074 orig2 = self._decompress(comp_data)
6075 self.assertEqual(orig, orig2)
6076
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006077 def testInvalidCompress(self):
6078 """Test that invalid compress algorithm is detected"""
6079 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006080 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006081 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6082
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006083 def testCompUtilCompressions(self):
6084 """Test compression algorithms"""
6085 for bintool in self.comp_bintools.values():
6086 self._CheckBintool(bintool)
6087 data = bintool.compress(COMPRESS_DATA)
6088 self.assertNotEqual(COMPRESS_DATA, data)
6089 orig = bintool.decompress(data)
6090 self.assertEquals(COMPRESS_DATA, orig)
6091
6092 def testCompUtilVersions(self):
6093 """Test tool version of compression algorithms"""
6094 for bintool in self.comp_bintools.values():
6095 self._CheckBintool(bintool)
6096 version = bintool.version()
6097 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6098
6099 def testCompUtilPadding(self):
6100 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006101 # Skip zstd because it doesn't support padding
6102 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006103 self._CheckBintool(bintool)
6104 data = bintool.compress(COMPRESS_DATA)
6105 self.assertNotEqual(COMPRESS_DATA, data)
6106 data += tools.get_bytes(0, 64)
6107 orig = bintool.decompress(data)
6108 self.assertEquals(COMPRESS_DATA, orig)
6109
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006110 def testCompressDtbZstd(self):
6111 """Test that zstd compress of device-tree files failed"""
6112 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006113 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006114 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6115 "requires a length header", str(e.exception))
6116
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006117 def testMkimageMultipleDataFiles(self):
6118 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006119 self._SetupSplElf()
6120 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006121 data = self._DoReadFile('252_mkimage_mult_data.dts')
6122 # Size of files are packed in their 4B big-endian format
6123 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6124 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6125 # Size info is always followed by a 4B zero value.
6126 expect += tools.get_bytes(0, 4)
6127 expect += U_BOOT_TPL_DATA
6128 # All but last files are 4B-aligned
6129 align_pad = len(U_BOOT_TPL_DATA) % 4
6130 if align_pad:
6131 expect += tools.get_bytes(0, align_pad)
6132 expect += U_BOOT_SPL_DATA
6133 self.assertEqual(expect, data[-len(expect):])
6134
Marek Vasutf7413f02023-07-18 07:23:58 -06006135 def testMkimageMultipleExpanded(self):
6136 """Test passing multiple files to mkimage in a mkimage entry"""
6137 self._SetupSplElf()
6138 self._SetupTplElf()
6139 entry_args = {
6140 'spl-bss-pad': 'y',
6141 'spl-dtb': 'y',
6142 }
6143 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6144 use_expanded=True, entry_args=entry_args)[0]
6145 pad_len = 10
6146 tpl_expect = U_BOOT_TPL_DATA
6147 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6148 spl_expect += U_BOOT_SPL_DTB_DATA
6149
6150 content = data[0x40:]
6151 lens = struct.unpack('>III', content[:12])
6152
6153 # Size of files are packed in their 4B big-endian format
6154 # Size info is always followed by a 4B zero value.
6155 self.assertEqual(len(tpl_expect), lens[0])
6156 self.assertEqual(len(spl_expect), lens[1])
6157 self.assertEqual(0, lens[2])
6158
6159 rest = content[12:]
6160 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6161
6162 rest = rest[len(tpl_expect):]
6163 align_pad = len(tpl_expect) % 4
6164 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6165 rest = rest[align_pad:]
6166 self.assertEqual(spl_expect, rest)
6167
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006168 def testMkimageMultipleNoContent(self):
6169 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006170 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006171 with self.assertRaises(ValueError) as exc:
6172 self._DoReadFile('253_mkimage_mult_no_content.dts')
6173 self.assertIn('Could not complete processing of contents',
6174 str(exc.exception))
6175
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006176 def testMkimageFilename(self):
6177 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006178 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006179 retcode = self._DoTestFile('254_mkimage_filename.dts')
6180 self.assertEqual(0, retcode)
6181 fname = tools.get_output_filename('mkimage-test.bin')
6182 self.assertTrue(os.path.exists(fname))
6183
Simon Glass56d05412022-02-28 07:16:54 -07006184 def testVpl(self):
6185 """Test that an image with VPL and its device tree can be created"""
6186 # ELF file with a '__bss_size' symbol
6187 self._SetupVplElf()
6188 data = self._DoReadFile('255_u_boot_vpl.dts')
6189 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6190
6191 def testVplNoDtb(self):
6192 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6193 self._SetupVplElf()
6194 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6195 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6196 data[:len(U_BOOT_VPL_NODTB_DATA)])
6197
6198 def testExpandedVpl(self):
6199 """Test that an expanded entry type is selected for TPL when needed"""
6200 self._SetupVplElf()
6201
6202 entry_args = {
6203 'vpl-bss-pad': 'y',
6204 'vpl-dtb': 'y',
6205 }
6206 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6207 entry_args=entry_args)
6208 image = control.images['image']
6209 entries = image.GetEntries()
6210 self.assertEqual(1, len(entries))
6211
6212 # We only have u-boot-vpl, which be expanded
6213 self.assertIn('u-boot-vpl', entries)
6214 entry = entries['u-boot-vpl']
6215 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6216 subent = entry.GetEntries()
6217 self.assertEqual(3, len(subent))
6218 self.assertIn('u-boot-vpl-nodtb', subent)
6219 self.assertIn('u-boot-vpl-bss-pad', subent)
6220 self.assertIn('u-boot-vpl-dtb', subent)
6221
6222 def testVplBssPadMissing(self):
6223 """Test that a missing symbol is detected"""
6224 self._SetupVplElf('u_boot_ucode_ptr')
6225 with self.assertRaises(ValueError) as e:
6226 self._DoReadFile('258_vpl_bss_pad.dts')
6227 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6228 str(e.exception))
6229
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306230 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306231 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306232 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6233 self.assertEqual(0, retcode)
6234 image = control.images['test_image']
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)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006239
Andrew Davis6b463da2023-07-22 00:14:44 +05306240 def testSymlinkOverwrite(self):
6241 """Test that symlinked images can be overwritten"""
6242 testdir = TestFunctional._MakeInputDir('symlinktest')
6243 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6244 # build the same image again in the same directory so that existing symlink is present
6245 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6246 fname = tools.get_output_filename('test_image.bin')
6247 sname = tools.get_output_filename('symlink_to_test.bin')
6248 self.assertTrue(os.path.islink(sname))
6249 self.assertEqual(os.readlink(sname), fname)
6250
Simon Glass37f85de2022-10-20 18:22:47 -06006251 def testSymbolsElf(self):
6252 """Test binman can assign symbols embedded in an ELF file"""
6253 if not elf.ELF_TOOLS:
6254 self.skipTest('Python elftools not available')
6255 self._SetupTplElf('u_boot_binman_syms')
6256 self._SetupVplElf('u_boot_binman_syms')
6257 self._SetupSplElf('u_boot_binman_syms')
6258 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6259 image_fname = tools.get_output_filename('image.bin')
6260
6261 image = control.images['image']
6262 entries = image.GetEntries()
6263
6264 for entry in entries.values():
6265 # No symbols in u-boot and it has faked contents anyway
6266 if entry.name == 'u-boot':
6267 continue
6268 edata = data[entry.image_pos:entry.image_pos + entry.size]
6269 efname = tools.get_output_filename(f'edata-{entry.name}')
6270 tools.write_file(efname, edata)
6271
6272 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6273 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6274 for name, sym in syms.items():
6275 msg = 'test'
6276 val = elf.GetSymbolValue(sym, edata, msg)
6277 entry_m = re_name.match(name)
6278 if entry_m:
6279 ename, prop = entry_m.group(1), entry_m.group(3)
6280 entry, entry_name, prop_name = image.LookupEntry(entries,
6281 name, msg)
6282 if prop_name == 'offset':
6283 expect_val = entry.offset
6284 elif prop_name == 'image_pos':
6285 expect_val = entry.image_pos
6286 elif prop_name == 'size':
6287 expect_val = entry.size
6288 self.assertEqual(expect_val, val)
6289
6290 def testSymbolsElfBad(self):
6291 """Check error when trying to write symbols without the elftools lib"""
6292 if not elf.ELF_TOOLS:
6293 self.skipTest('Python elftools not available')
6294 self._SetupTplElf('u_boot_binman_syms')
6295 self._SetupVplElf('u_boot_binman_syms')
6296 self._SetupSplElf('u_boot_binman_syms')
6297 try:
6298 elf.ELF_TOOLS = False
6299 with self.assertRaises(ValueError) as exc:
6300 self._DoReadFileDtb('260_symbols_elf.dts')
6301 finally:
6302 elf.ELF_TOOLS = True
6303 self.assertIn(
6304 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6305 'Cannot write symbols to an ELF file without Python elftools',
6306 str(exc.exception))
6307
Simon Glassde244162023-01-07 14:07:08 -07006308 def testSectionFilename(self):
6309 """Check writing of section contents to a file"""
6310 data = self._DoReadFile('261_section_fname.dts')
6311 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6312 tools.get_bytes(ord('!'), 7) +
6313 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6314 self.assertEqual(expected, data)
6315
6316 sect_fname = tools.get_output_filename('outfile.bin')
6317 self.assertTrue(os.path.exists(sect_fname))
6318 sect_data = tools.read_file(sect_fname)
6319 self.assertEqual(U_BOOT_DATA, sect_data)
6320
Simon Glass1e9e61c2023-01-07 14:07:12 -07006321 def testAbsent(self):
6322 """Check handling of absent entries"""
6323 data = self._DoReadFile('262_absent.dts')
6324 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6325
Simon Glassad5cfe12023-01-07 14:07:14 -07006326 def testPackTeeOsOptional(self):
6327 """Test that an image with an optional TEE binary can be created"""
6328 entry_args = {
6329 'tee-os-path': 'tee.elf',
6330 }
6331 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6332 entry_args=entry_args)[0]
6333 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6334
6335 def checkFitTee(self, dts, tee_fname):
6336 """Check that a tee-os entry works and returns data
6337
6338 Args:
6339 dts (str): Device tree filename to use
6340 tee_fname (str): filename containing tee-os
6341
6342 Returns:
6343 bytes: Image contents
6344 """
6345 if not elf.ELF_TOOLS:
6346 self.skipTest('Python elftools not available')
6347 entry_args = {
6348 'of-list': 'test-fdt1 test-fdt2',
6349 'default-dt': 'test-fdt2',
6350 'tee-os-path': tee_fname,
6351 }
6352 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6353 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6354 extra_indirs=[test_subdir])[0]
6355 return data
6356
6357 def testFitTeeOsOptionalFit(self):
6358 """Test an image with a FIT with an optional OP-TEE binary"""
6359 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6360
6361 # There should be only one node, holding the data set up in SetUpClass()
6362 # for tee.bin
6363 dtb = fdt.Fdt.FromData(data)
6364 dtb.Scan()
6365 node = dtb.GetNode('/images/tee-1')
6366 self.assertEqual(TEE_ADDR,
6367 fdt_util.fdt32_to_cpu(node.props['load'].value))
6368 self.assertEqual(TEE_ADDR,
6369 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6370 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6371
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006372 with test_util.capture_sys_output() as (stdout, stderr):
6373 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6374 err = stderr.getvalue()
6375 self.assertRegex(
6376 err,
6377 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6378
Simon Glassad5cfe12023-01-07 14:07:14 -07006379 def testFitTeeOsOptionalFitBad(self):
6380 """Test an image with a FIT with an optional OP-TEE binary"""
6381 with self.assertRaises(ValueError) as exc:
6382 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6383 self.assertIn(
6384 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6385 str(exc.exception))
6386
6387 def testFitTeeOsBad(self):
6388 """Test an OP-TEE binary with wrong formats"""
6389 self.make_tee_bin('tee.bad1', 123)
6390 with self.assertRaises(ValueError) as exc:
6391 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6392 self.assertIn(
6393 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6394 str(exc.exception))
6395
6396 self.make_tee_bin('tee.bad2', 0, b'extra data')
6397 with self.assertRaises(ValueError) as exc:
6398 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6399 self.assertIn(
6400 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6401 str(exc.exception))
6402
Simon Glass63328f12023-01-07 14:07:15 -07006403 def testExtblobOptional(self):
6404 """Test an image with an external blob that is optional"""
6405 with test_util.capture_sys_output() as (stdout, stderr):
6406 data = self._DoReadFile('266_blob_ext_opt.dts')
6407 self.assertEqual(REFCODE_DATA, data)
6408 err = stderr.getvalue()
6409 self.assertRegex(
6410 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006411 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006412
Simon Glass7447a9d2023-01-11 16:10:12 -07006413 def testSectionInner(self):
6414 """Test an inner section with a size"""
6415 data = self._DoReadFile('267_section_inner.dts')
6416 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6417 self.assertEqual(expected, data)
6418
Simon Glassa4948b22023-01-11 16:10:14 -07006419 def testNull(self):
6420 """Test an image with a null entry"""
6421 data = self._DoReadFile('268_null.dts')
6422 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6423
Simon Glassf1ee03b2023-01-11 16:10:16 -07006424 def testOverlap(self):
6425 """Test an image with a overlapping entry"""
6426 data = self._DoReadFile('269_overlap.dts')
6427 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6428
6429 image = control.images['image']
6430 entries = image.GetEntries()
6431
6432 self.assertIn('inset', entries)
6433 inset = entries['inset']
6434 self.assertEqual(1, inset.offset);
6435 self.assertEqual(1, inset.image_pos);
6436 self.assertEqual(2, inset.size);
6437
6438 def testOverlapNull(self):
6439 """Test an image with a null overlap"""
6440 data = self._DoReadFile('270_overlap_null.dts')
6441 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6442
6443 # Check the FMAP
6444 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6445 self.assertEqual(4, fhdr.nareas)
6446 fiter = iter(fentries)
6447
6448 fentry = next(fiter)
6449 self.assertEqual(b'SECTION', fentry.name)
6450 self.assertEqual(0, fentry.offset)
6451 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6452 self.assertEqual(0, fentry.flags)
6453
6454 fentry = next(fiter)
6455 self.assertEqual(b'U_BOOT', fentry.name)
6456 self.assertEqual(0, fentry.offset)
6457 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6458 self.assertEqual(0, fentry.flags)
6459
6460 # Make sure that the NULL entry appears in the FMAP
6461 fentry = next(fiter)
6462 self.assertEqual(b'NULL', fentry.name)
6463 self.assertEqual(1, fentry.offset)
6464 self.assertEqual(2, fentry.size)
6465 self.assertEqual(0, fentry.flags)
6466
6467 fentry = next(fiter)
6468 self.assertEqual(b'FMAP', fentry.name)
6469 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6470
6471 def testOverlapBad(self):
6472 """Test an image with a bad overlapping entry"""
6473 with self.assertRaises(ValueError) as exc:
6474 self._DoReadFile('271_overlap_bad.dts')
6475 self.assertIn(
6476 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6477 str(exc.exception))
6478
6479 def testOverlapNoOffset(self):
6480 """Test an image with a bad overlapping entry"""
6481 with self.assertRaises(ValueError) as exc:
6482 self._DoReadFile('272_overlap_no_size.dts')
6483 self.assertIn(
6484 "Node '/binman/inset': 'fill' entry is missing properties: size",
6485 str(exc.exception))
6486
Simon Glasse0035c92023-01-11 16:10:17 -07006487 def testBlobSymbol(self):
6488 """Test a blob with symbols read from an ELF file"""
6489 elf_fname = self.ElfTestFile('blob_syms')
6490 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6491 TestFunctional._MakeInputFile('blob_syms.bin',
6492 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6493
6494 data = self._DoReadFile('273_blob_symbol.dts')
6495
6496 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6497 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6498 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6499 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6500 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6501
6502 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6503 expected = sym_values
6504 self.assertEqual(expected, data[:len(expected)])
6505
Simon Glass49e9c002023-01-11 16:10:19 -07006506 def testOffsetFromElf(self):
6507 """Test a blob with symbols read from an ELF file"""
6508 elf_fname = self.ElfTestFile('blob_syms')
6509 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6510 TestFunctional._MakeInputFile('blob_syms.bin',
6511 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6512
6513 data = self._DoReadFile('274_offset_from_elf.dts')
6514
6515 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6516 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6517
6518 image = control.images['image']
6519 entries = image.GetEntries()
6520
6521 self.assertIn('inset', entries)
6522 inset = entries['inset']
6523
6524 self.assertEqual(base + 4, inset.offset);
6525 self.assertEqual(base + 4, inset.image_pos);
6526 self.assertEqual(4, inset.size);
6527
6528 self.assertIn('inset2', entries)
6529 inset = entries['inset2']
6530 self.assertEqual(base + 8, inset.offset);
6531 self.assertEqual(base + 8, inset.image_pos);
6532 self.assertEqual(4, inset.size);
6533
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006534 def testFitAlign(self):
6535 """Test an image with an FIT with aligned external data"""
6536 data = self._DoReadFile('275_fit_align.dts')
6537 self.assertEqual(4096, len(data))
6538
6539 dtb = fdt.Fdt.FromData(data)
6540 dtb.Scan()
6541
6542 props = self._GetPropTree(dtb, ['data-position'])
6543 expected = {
6544 'u-boot:data-position': 1024,
6545 'fdt-1:data-position': 2048,
6546 'fdt-2:data-position': 3072,
6547 }
6548 self.assertEqual(expected, props)
6549
Jonas Karlman490f73c2023-01-21 19:02:12 +00006550 def testFitFirmwareLoadables(self):
6551 """Test an image with an FIT that use fit,firmware"""
6552 if not elf.ELF_TOOLS:
6553 self.skipTest('Python elftools not available')
6554 entry_args = {
6555 'of-list': 'test-fdt1',
6556 'default-dt': 'test-fdt1',
6557 'atf-bl31-path': 'bl31.elf',
6558 'tee-os-path': 'missing.bin',
6559 }
6560 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006561 with test_util.capture_sys_output() as (stdout, stderr):
6562 data = self._DoReadFileDtb(
6563 '276_fit_firmware_loadables.dts',
6564 entry_args=entry_args,
6565 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006566
6567 dtb = fdt.Fdt.FromData(data)
6568 dtb.Scan()
6569
6570 node = dtb.GetNode('/configurations/conf-uboot-1')
6571 self.assertEqual('u-boot', node.props['firmware'].value)
6572 self.assertEqual(['atf-1', 'atf-2'],
6573 fdt_util.GetStringList(node, 'loadables'))
6574
6575 node = dtb.GetNode('/configurations/conf-atf-1')
6576 self.assertEqual('atf-1', node.props['firmware'].value)
6577 self.assertEqual(['u-boot', 'atf-2'],
6578 fdt_util.GetStringList(node, 'loadables'))
6579
6580 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6581 self.assertEqual('u-boot', node.props['firmware'].value)
6582 self.assertEqual(['atf-1', 'atf-2'],
6583 fdt_util.GetStringList(node, 'loadables'))
6584
6585 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6586 self.assertEqual('atf-1', node.props['firmware'].value)
6587 self.assertEqual(['u-boot', 'atf-2'],
6588 fdt_util.GetStringList(node, 'loadables'))
6589
6590 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6591 self.assertEqual('atf-1', node.props['firmware'].value)
6592 self.assertEqual(['u-boot', 'atf-2'],
6593 fdt_util.GetStringList(node, 'loadables'))
6594
Simon Glass9a1c7262023-02-22 12:14:49 -07006595 def testTooldir(self):
6596 """Test that we can specify the tooldir"""
6597 with test_util.capture_sys_output() as (stdout, stderr):
6598 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6599 'tool', '-l'))
6600 self.assertEqual('fred', bintool.Bintool.tooldir)
6601
6602 # Check that the toolpath is updated correctly
6603 self.assertEqual(['fred'], tools.tool_search_paths)
6604
6605 # Try with a few toolpaths; the tooldir should be at the end
6606 with test_util.capture_sys_output() as (stdout, stderr):
6607 self.assertEqual(0, self._DoBinman(
6608 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6609 'tool', '-l'))
6610 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6611
Simon Glass49b77e82023-03-02 17:02:44 -07006612 def testReplaceSectionEntry(self):
6613 """Test replacing an entry in a section"""
6614 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6615 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6616 expect_data, dts='241_replace_section_simple.dts')
6617 self.assertEqual(expect_data, entry_data)
6618
6619 entries = image.GetEntries()
6620 self.assertIn('section', entries)
6621 section = entries['section']
6622
6623 sect_entries = section.GetEntries()
6624 self.assertIn('blob', sect_entries)
6625 entry = sect_entries['blob']
6626 self.assertEqual(len(expect_data), entry.size)
6627
6628 fname = tools.get_output_filename('image-updated.bin')
6629 data = tools.read_file(fname)
6630
6631 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6632 self.assertEqual(expect_data, new_blob_data)
6633
6634 self.assertEqual(U_BOOT_DATA,
6635 data[entry.image_pos + len(expect_data):]
6636 [:len(U_BOOT_DATA)])
6637
6638 def testReplaceSectionDeep(self):
6639 """Test replacing an entry in two levels of sections"""
6640 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6641 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6642 'section/section/blob', expect_data,
6643 dts='278_replace_section_deep.dts')
6644 self.assertEqual(expect_data, entry_data)
6645
6646 entries = image.GetEntries()
6647 self.assertIn('section', entries)
6648 section = entries['section']
6649
6650 subentries = section.GetEntries()
6651 self.assertIn('section', subentries)
6652 section = subentries['section']
6653
6654 sect_entries = section.GetEntries()
6655 self.assertIn('blob', sect_entries)
6656 entry = sect_entries['blob']
6657 self.assertEqual(len(expect_data), entry.size)
6658
6659 fname = tools.get_output_filename('image-updated.bin')
6660 data = tools.read_file(fname)
6661
6662 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6663 self.assertEqual(expect_data, new_blob_data)
6664
6665 self.assertEqual(U_BOOT_DATA,
6666 data[entry.image_pos + len(expect_data):]
6667 [:len(U_BOOT_DATA)])
6668
6669 def testReplaceFitSibling(self):
6670 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006671 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006672 fname = TestFunctional._MakeInputFile('once', b'available once')
6673 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6674 os.remove(fname)
6675
6676 try:
6677 tmpdir, updated_fname = self._SetupImageInTmpdir()
6678
6679 fname = os.path.join(tmpdir, 'update-blob')
6680 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6681 tools.write_file(fname, expected)
6682
6683 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6684 data = tools.read_file(updated_fname)
6685 start = len(U_BOOT_DTB_DATA)
6686 self.assertEqual(expected, data[start:start + len(expected)])
6687 map_fname = os.path.join(tmpdir, 'image-updated.map')
6688 self.assertFalse(os.path.exists(map_fname))
6689 finally:
6690 shutil.rmtree(tmpdir)
6691
Simon Glassc3fe97f2023-03-02 17:02:45 -07006692 def testX509Cert(self):
6693 """Test creating an X509 certificate"""
6694 keyfile = self.TestFile('key.key')
6695 entry_args = {
6696 'keyfile': keyfile,
6697 }
6698 data = self._DoReadFileDtb('279_x509_cert.dts',
6699 entry_args=entry_args)[0]
6700 cert = data[:-4]
6701 self.assertEqual(U_BOOT_DATA, data[-4:])
6702
6703 # TODO: verify the signature
6704
6705 def testX509CertMissing(self):
6706 """Test that binman still produces an image if openssl is missing"""
6707 keyfile = self.TestFile('key.key')
6708 entry_args = {
6709 'keyfile': 'keyfile',
6710 }
6711 with test_util.capture_sys_output() as (_, stderr):
6712 self._DoTestFile('279_x509_cert.dts',
6713 force_missing_bintools='openssl',
6714 entry_args=entry_args)
6715 err = stderr.getvalue()
6716 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6717
Jonas Karlman35305492023-02-25 19:01:33 +00006718 def testPackRockchipTpl(self):
6719 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006720 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006721 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6722
Jonas Karlman1016ec72023-02-25 19:01:35 +00006723 def testMkimageMissingBlobMultiple(self):
6724 """Test missing blob with mkimage entry and multiple-data-files"""
6725 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006726 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006727 err = stderr.getvalue()
6728 self.assertIn("is missing external blobs and is non-functional", err)
6729
6730 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006731 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006732 self.assertIn("not found in input path", str(e.exception))
6733
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006734 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6735 """Prepare sign environment
6736
6737 Create private and public keys, add pubkey into dtb.
6738
6739 Returns:
6740 Tuple:
6741 FIT container
6742 Image name
6743 Private key
6744 DTB
6745 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006746 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006747 data = self._DoReadFileRealDtb(dts)
6748 updated_fname = tools.get_output_filename('image-updated.bin')
6749 tools.write_file(updated_fname, data)
6750 dtb = tools.get_output_filename('source.dtb')
6751 private_key = tools.get_output_filename('test_key.key')
6752 public_key = tools.get_output_filename('test_key.crt')
6753 fit = tools.get_output_filename('fit.fit')
6754 key_dir = tools.get_output_dir()
6755
6756 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6757 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6758 private_key, '-out', public_key)
6759 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6760 '-n', 'test_key', '-r', 'conf', dtb)
6761
6762 return fit, updated_fname, private_key, dtb
6763
6764 def testSignSimple(self):
6765 """Test that a FIT container can be signed in image"""
6766 is_signed = False
6767 fit, fname, private_key, dtb = self._PrepareSignEnv()
6768
6769 # do sign with private key
6770 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6771 ['fit'])
6772 is_signed = self._CheckSign(fit, dtb)
6773
6774 self.assertEqual(is_signed, True)
6775
6776 def testSignExactFIT(self):
6777 """Test that a FIT container can be signed and replaced in image"""
6778 is_signed = False
6779 fit, fname, private_key, dtb = self._PrepareSignEnv()
6780
6781 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6782 args = []
6783 if self.toolpath:
6784 for path in self.toolpath:
6785 args += ['--toolpath', path]
6786
6787 # do sign with private key
6788 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6789 'sha256,rsa4096', '-f', fit, 'fit')
6790 is_signed = self._CheckSign(fit, dtb)
6791
6792 self.assertEqual(is_signed, True)
6793
6794 def testSignNonFit(self):
6795 """Test a non-FIT entry cannot be signed"""
6796 is_signed = False
6797 fit, fname, private_key, _ = self._PrepareSignEnv(
6798 '281_sign_non_fit.dts')
6799
6800 # do sign with private key
6801 with self.assertRaises(ValueError) as e:
6802 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6803 'sha256,rsa4096', '-f', fit, 'u-boot')
6804 self.assertIn(
6805 "Node '/u-boot': Updating signatures is not supported with this entry type",
6806 str(e.exception))
6807
6808 def testSignMissingMkimage(self):
6809 """Test that FIT signing handles a missing mkimage tool"""
6810 fit, fname, private_key, _ = self._PrepareSignEnv()
6811
6812 # try to sign with a missing mkimage tool
6813 bintool.Bintool.set_missing_list(['mkimage'])
6814 with self.assertRaises(ValueError) as e:
6815 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6816 ['fit'])
6817 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6818
Simon Glass4abf7842023-07-18 07:23:54 -06006819 def testSymbolNoWrite(self):
6820 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006821 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006822 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6823 no_write_symbols=True)
6824
6825 def testSymbolNoWriteExpanded(self):
6826 """Test disabling of symbol writing in expanded entries"""
6827 entry_args = {
6828 'spl-dtb': '1',
6829 }
6830 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6831 U_BOOT_SPL_DTB_DATA, 0x38,
6832 entry_args=entry_args, use_expanded=True,
6833 no_write_symbols=True)
6834
Marek Vasutf7413f02023-07-18 07:23:58 -06006835 def testMkimageSpecial(self):
6836 """Test mkimage ignores special hash-1 node"""
6837 data = self._DoReadFile('283_mkimage_special.dts')
6838
6839 # Just check that the data appears in the file somewhere
6840 self.assertIn(U_BOOT_DATA, data)
6841
Simon Glass2d94c422023-07-18 07:23:59 -06006842 def testFitFdtList(self):
6843 """Test an image with an FIT with the fit,fdt-list-val option"""
6844 entry_args = {
6845 'default-dt': 'test-fdt2',
6846 }
6847 data = self._DoReadFileDtb(
6848 '284_fit_fdt_list.dts',
6849 entry_args=entry_args,
6850 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6851 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6852 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6853
Simon Glass83b8bfe2023-07-18 07:24:01 -06006854 def testSplEmptyBss(self):
6855 """Test an expanded SPL with a zero-size BSS"""
6856 # ELF file with a '__bss_size' symbol
6857 self._SetupSplElf(src_fname='bss_data_zero')
6858
6859 entry_args = {
6860 'spl-bss-pad': 'y',
6861 'spl-dtb': 'y',
6862 }
6863 data = self._DoReadFileDtb('285_spl_expand.dts',
6864 use_expanded=True, entry_args=entry_args)[0]
6865
Simon Glassfc792842023-07-18 07:24:04 -06006866 def testTemplate(self):
6867 """Test using a template"""
6868 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6869 data = self._DoReadFile('286_template.dts')
6870 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6871 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6872 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6873
Simon Glass09490b02023-07-22 21:43:52 -06006874 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6875 self.assertTrue(os.path.exists(dtb_fname1))
6876 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6877 dtb.Scan()
6878 node1 = dtb.GetNode('/binman/template')
6879 self.assertTrue(node1)
6880 vga = dtb.GetNode('/binman/first/intel-vga')
6881 self.assertTrue(vga)
6882
Simon Glass54825e12023-07-22 21:43:56 -06006883 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6884 self.assertTrue(os.path.exists(dtb_fname2))
6885 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6886 dtb2.Scan()
6887 node2 = dtb2.GetNode('/binman/template')
6888 self.assertFalse(node2)
6889
Simon Glass9909c112023-07-18 07:24:05 -06006890 def testTemplateBlobMulti(self):
6891 """Test using a template with 'multiple-images' enabled"""
6892 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6893 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6894 retcode = self._DoTestFile('287_template_multi.dts')
6895
6896 self.assertEqual(0, retcode)
6897 image = control.images['image']
6898 image_fname = tools.get_output_filename('my-image.bin')
6899 data = tools.read_file(image_fname)
6900 self.assertEqual(b'blob@@@@other', data)
6901
Simon Glass5dc511b2023-07-18 07:24:06 -06006902 def testTemplateFit(self):
6903 """Test using a template in a FIT"""
6904 fit_data = self._DoReadFile('288_template_fit.dts')
6905 fname = os.path.join(self._indir, 'fit_data.fit')
6906 tools.write_file(fname, fit_data)
6907 out = tools.run('dumpimage', '-l', fname)
6908
Simon Glassaa6e0552023-07-18 07:24:07 -06006909 def testTemplateSection(self):
6910 """Test using a template in a section (not at top level)"""
6911 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6912 data = self._DoReadFile('289_template_section.dts')
6913 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6914 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6915 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6916
Simon Glassf53a7bc2023-07-18 07:24:08 -06006917 def testMkimageSymbols(self):
6918 """Test using mkimage to build an image with symbols in it"""
6919 self._SetupSplElf('u_boot_binman_syms')
6920 data = self._DoReadFile('290_mkimage_sym.dts')
6921
6922 image = control.images['image']
6923 entries = image.GetEntries()
6924 self.assertIn('u-boot', entries)
6925 u_boot = entries['u-boot']
6926
6927 mkim = entries['mkimage']
6928 mkim_entries = mkim.GetEntries()
6929 self.assertIn('u-boot-spl', mkim_entries)
6930 spl = mkim_entries['u-boot-spl']
6931 self.assertIn('u-boot-spl2', mkim_entries)
6932 spl2 = mkim_entries['u-boot-spl2']
6933
6934 # skip the mkimage header and the area sizes
6935 mk_data = data[mkim.offset + 0x40:]
6936 size, term = struct.unpack('>LL', mk_data[:8])
6937
6938 # There should be only one image, so check that the zero terminator is
6939 # present
6940 self.assertEqual(0, term)
6941
6942 content = mk_data[8:8 + size]
6943
6944 # The image should contain the symbols from u_boot_binman_syms.c
6945 # Note that image_pos is adjusted by the base address of the image,
6946 # which is 0x10 in our test image
6947 spl_data = content[:0x18]
6948 content = content[0x1b:]
6949
6950 # After the header is a table of offsets for each image. There should
6951 # only be one image, then a 0 terminator, so figure out the real start
6952 # of the image data
6953 base = 0x40 + 8
6954
6955 # Check symbols in both u-boot-spl and u-boot-spl2
6956 for i in range(2):
6957 vals = struct.unpack('<LLQLL', spl_data)
6958
6959 # The image should contain the symbols from u_boot_binman_syms.c
6960 # Note that image_pos is adjusted by the base address of the image,
6961 # which is 0x10 in our 'u_boot_binman_syms' test image
6962 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6963 self.assertEqual(base, vals[1])
6964 self.assertEqual(spl2.offset, vals[2])
6965 # figure out the internal positions of its components
6966 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6967
6968 # Check that spl and spl2 are actually at the indicated positions
6969 self.assertEqual(
6970 elf.BINMAN_SYM_MAGIC_VALUE,
6971 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6972 self.assertEqual(
6973 elf.BINMAN_SYM_MAGIC_VALUE,
6974 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6975
6976 self.assertEqual(len(U_BOOT_DATA), vals[4])
6977
6978 # Move to next
6979 spl_data = content[:0x18]
6980
Simon Glass86b3e472023-07-22 21:43:57 -06006981 def testTemplatePhandle(self):
6982 """Test using a template in a node containing a phandle"""
6983 entry_args = {
6984 'atf-bl31-path': 'bl31.elf',
6985 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06006986 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06006987 entry_args=entry_args)
6988 fname = tools.get_output_filename('image.bin')
6989 out = tools.run('dumpimage', '-l', fname)
6990
6991 # We should see the FIT description and one for each of the two images
6992 lines = out.splitlines()
6993 descs = [line.split()[-1] for line in lines if 'escription' in line]
6994 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
6995
6996 def testTemplatePhandleDup(self):
6997 """Test using a template in a node containing a phandle"""
6998 entry_args = {
6999 'atf-bl31-path': 'bl31.elf',
7000 }
7001 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007002 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007003 entry_args=entry_args)
7004 self.assertIn(
7005 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7006 str(e.exception))
7007
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307008 def testTIBoardConfig(self):
7009 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007010 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307011 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7012
7013 def testTIBoardConfigCombined(self):
7014 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007015 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307016 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7017 self.assertGreater(data, configlen_noheader)
7018
7019 def testTIBoardConfigNoDataType(self):
7020 """Test that error is thrown when data type is not supported"""
7021 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007022 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307023 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007024
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307025 def testPackTiSecure(self):
7026 """Test that an image with a TI secured binary can be created"""
7027 keyfile = self.TestFile('key.key')
7028 entry_args = {
7029 'keyfile': keyfile,
7030 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007031 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307032 entry_args=entry_args)[0]
7033 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7034
7035 def testPackTiSecureMissingTool(self):
7036 """Test that an image with a TI secured binary (non-functional) can be created
7037 when openssl is missing"""
7038 keyfile = self.TestFile('key.key')
7039 entry_args = {
7040 'keyfile': keyfile,
7041 }
7042 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007043 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307044 force_missing_bintools='openssl',
7045 entry_args=entry_args)
7046 err = stderr.getvalue()
7047 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7048
7049 def testPackTiSecureROM(self):
7050 """Test that a ROM image with a TI secured binary can be created"""
7051 keyfile = self.TestFile('key.key')
7052 entry_args = {
7053 'keyfile': keyfile,
7054 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007055 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307056 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007057 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307058 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007059 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307060 entry_args=entry_args)[0]
7061 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7062 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7063 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7064
7065 def testPackTiSecureROMCombined(self):
7066 """Test that a ROM image with a TI secured binary can be created"""
7067 keyfile = self.TestFile('key.key')
7068 entry_args = {
7069 'keyfile': keyfile,
7070 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007071 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307072 entry_args=entry_args)[0]
7073 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7074
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007075 def testEncryptedNoAlgo(self):
7076 """Test encrypted node with missing required properties"""
7077 with self.assertRaises(ValueError) as e:
7078 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7079 self.assertIn(
7080 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7081 str(e.exception))
7082
7083 def testEncryptedInvalidIvfile(self):
7084 """Test encrypted node with invalid iv file"""
7085 with self.assertRaises(ValueError) as e:
7086 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7087 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7088 str(e.exception))
7089
7090 def testEncryptedMissingKey(self):
7091 """Test encrypted node with missing key properties"""
7092 with self.assertRaises(ValueError) as e:
7093 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7094 self.assertIn(
7095 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7096 str(e.exception))
7097
7098 def testEncryptedKeySource(self):
7099 """Test encrypted node with key-source property"""
7100 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7101
7102 dtb = fdt.Fdt.FromData(data)
7103 dtb.Scan()
7104
7105 node = dtb.GetNode('/images/u-boot/cipher')
7106 self.assertEqual('algo-name', node.props['algo'].value)
7107 self.assertEqual('key-source-value', node.props['key-source'].value)
7108 self.assertEqual(ENCRYPTED_IV_DATA,
7109 tools.to_bytes(''.join(node.props['iv'].value)))
7110 self.assertNotIn('key', node.props)
7111
7112 def testEncryptedKeyFile(self):
7113 """Test encrypted node with key-filename property"""
7114 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7115
7116 dtb = fdt.Fdt.FromData(data)
7117 dtb.Scan()
7118
7119 node = dtb.GetNode('/images/u-boot/cipher')
7120 self.assertEqual('algo-name', node.props['algo'].value)
7121 self.assertEqual(ENCRYPTED_IV_DATA,
7122 tools.to_bytes(''.join(node.props['iv'].value)))
7123 self.assertEqual(ENCRYPTED_KEY_DATA,
7124 tools.to_bytes(''.join(node.props['key'].value)))
7125 self.assertNotIn('key-source', node.props)
7126
Lukas Funkee901faf2023-07-18 13:53:13 +02007127
7128 def testSplPubkeyDtb(self):
7129 """Test u_boot_spl_pubkey_dtb etype"""
7130 data = tools.read_file(self.TestFile("key.pem"))
7131 self._MakeInputFile("key.crt", data)
7132 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7133 image = control.images['image']
7134 entries = image.GetEntries()
7135 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7136 dtb_data = dtb_entry.GetData()
7137 dtb = fdt.Fdt.FromData(dtb_data)
7138 dtb.Scan()
7139
7140 signature_node = dtb.GetNode('/signature')
7141 self.assertIsNotNone(signature_node)
7142 key_node = signature_node.FindNode("key-key")
7143 self.assertIsNotNone(key_node)
7144 self.assertEqual(fdt_util.GetString(key_node, "required"),
7145 "conf")
7146 self.assertEqual(fdt_util.GetString(key_node, "algo"),
7147 "sha384,rsa4096")
7148 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"),
7149 "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007150
Lukas Funke712e1062023-08-03 17:22:14 +02007151 def testXilinxBootgenSigning(self):
7152 """Test xilinx-bootgen etype"""
7153 bootgen = bintool.Bintool.create('bootgen')
7154 self._CheckBintool(bootgen)
7155 data = tools.read_file(self.TestFile("key.key"))
7156 self._MakeInputFile("psk.pem", data)
7157 self._MakeInputFile("ssk.pem", data)
7158 self._SetupPmuFwlElf()
7159 self._SetupSplElf()
7160 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7161 image_fname = tools.get_output_filename('image.bin')
7162
7163 # Read partition header table and check if authentication is enabled
7164 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7165 "-read", image_fname, "pht").splitlines()
7166 attributes = {"authentication": None,
7167 "core": None,
7168 "encryption": None}
7169
7170 for l in bootgen_out:
7171 for a in attributes.keys():
7172 if a in l:
7173 m = re.match(fr".*{a} \[([^]]+)\]", l)
7174 attributes[a] = m.group(1)
7175
7176 self.assertTrue(attributes['authentication'] == "rsa")
7177 self.assertTrue(attributes['core'] == "a53-0")
7178 self.assertTrue(attributes['encryption'] == "no")
7179
7180 def testXilinxBootgenSigningEncryption(self):
7181 """Test xilinx-bootgen etype"""
7182 bootgen = bintool.Bintool.create('bootgen')
7183 self._CheckBintool(bootgen)
7184 data = tools.read_file(self.TestFile("key.key"))
7185 self._MakeInputFile("psk.pem", data)
7186 self._MakeInputFile("ssk.pem", data)
7187 self._SetupPmuFwlElf()
7188 self._SetupSplElf()
7189 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7190 image_fname = tools.get_output_filename('image.bin')
7191
7192 # Read boot header in order to verify encryption source and
7193 # encryption parameter
7194 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7195 "-read", image_fname, "bh").splitlines()
7196 attributes = {"auth_only":
7197 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7198 "encryption_keystore":
7199 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7200 "value": None},
7201 }
7202
7203 for l in bootgen_out:
7204 for a in attributes.keys():
7205 if a in l:
7206 m = re.match(attributes[a]['re'], l)
7207 attributes[a] = m.group(1)
7208
7209 # Check if fsbl-attribute is set correctly
7210 self.assertTrue(attributes['auth_only'] == "true")
7211 # Check if key is stored in efuse
7212 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7213
7214 def testXilinxBootgenMissing(self):
7215 """Test that binman still produces an image if bootgen is missing"""
7216 data = tools.read_file(self.TestFile("key.key"))
7217 self._MakeInputFile("psk.pem", data)
7218 self._MakeInputFile("ssk.pem", data)
7219 self._SetupPmuFwlElf()
7220 self._SetupSplElf()
7221 with test_util.capture_sys_output() as (_, stderr):
7222 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7223 force_missing_bintools='bootgen')
7224 err = stderr.getvalue()
7225 self.assertRegex(err,
7226 "Image 'image'.*missing bintools.*: bootgen")
7227
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307228 def _GetCapsuleHeaders(self, data):
7229 """Get the capsule header contents
7230
7231 Args:
7232 data: Capsule file contents
7233
7234 Returns:
7235 Dict:
7236 key: Capsule Header name (str)
7237 value: Header field value (str)
7238 """
7239 capsule_file = os.path.join(self._indir, 'test.capsule')
7240 tools.write_file(capsule_file, data)
7241
7242 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7243 lines = out.splitlines()
7244
7245 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7246 vals = {}
7247 for line in lines:
7248 mat = re_line.match(line)
7249 if mat:
7250 vals[mat.group(1)] = mat.group(2)
7251
7252 return vals
7253
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307254 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7255 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307256 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7257 fmp_size = "00000010"
7258 fmp_fw_version = "00000002"
7259 capsule_image_index = "00000001"
7260 oemflag = "00018000"
7261 auth_hdr_revision = "00000200"
7262 auth_hdr_cert_type = "00000EF1"
7263
7264 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307265
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307266 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307267
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307268 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307269
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307270 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7271 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7272 self.assertEqual(capsule_image_index,
7273 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307274
7275 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307276 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7277
7278 if signed_capsule:
7279 self.assertEqual(auth_hdr_revision,
7280 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7281 self.assertEqual(auth_hdr_cert_type,
7282 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7283 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7284 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7285
7286 if version_check:
7287 self.assertEqual(fmp_signature,
7288 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7289 self.assertEqual(fmp_size,
7290 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7291 self.assertEqual(fmp_fw_version,
7292 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7293
7294 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307295
7296 def testCapsuleGen(self):
7297 """Test generation of EFI capsule"""
7298 data = self._DoReadFile('311_capsule.dts')
7299
7300 self._CheckCapsule(data)
7301
7302 def testSignedCapsuleGen(self):
7303 """Test generation of EFI capsule"""
7304 data = tools.read_file(self.TestFile("key.key"))
7305 self._MakeInputFile("key.key", data)
7306 data = tools.read_file(self.TestFile("key.pem"))
7307 self._MakeInputFile("key.crt", data)
7308
7309 data = self._DoReadFile('312_capsule_signed.dts')
7310
7311 self._CheckCapsule(data, signed_capsule=True)
7312
7313 def testCapsuleGenVersionSupport(self):
7314 """Test generation of EFI capsule with version support"""
7315 data = self._DoReadFile('313_capsule_version.dts')
7316
7317 self._CheckCapsule(data, version_check=True)
7318
7319 def testCapsuleGenSignedVer(self):
7320 """Test generation of signed EFI capsule with version information"""
7321 data = tools.read_file(self.TestFile("key.key"))
7322 self._MakeInputFile("key.key", data)
7323 data = tools.read_file(self.TestFile("key.pem"))
7324 self._MakeInputFile("key.crt", data)
7325
7326 data = self._DoReadFile('314_capsule_signed_ver.dts')
7327
7328 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7329
7330 def testCapsuleGenCapOemFlags(self):
7331 """Test generation of EFI capsule with OEM Flags set"""
7332 data = self._DoReadFile('315_capsule_oemflags.dts')
7333
7334 self._CheckCapsule(data, capoemflags=True)
7335
7336 def testCapsuleGenKeyMissing(self):
7337 """Test that binman errors out on missing key"""
7338 with self.assertRaises(ValueError) as e:
7339 self._DoReadFile('316_capsule_missing_key.dts')
7340
7341 self.assertIn("Both private key and public key certificate need to be provided",
7342 str(e.exception))
7343
7344 def testCapsuleGenIndexMissing(self):
7345 """Test that binman errors out on missing image index"""
7346 with self.assertRaises(ValueError) as e:
7347 self._DoReadFile('317_capsule_missing_index.dts')
7348
7349 self.assertIn("entry is missing properties: image-index",
7350 str(e.exception))
7351
7352 def testCapsuleGenGuidMissing(self):
7353 """Test that binman errors out on missing image GUID"""
7354 with self.assertRaises(ValueError) as e:
7355 self._DoReadFile('318_capsule_missing_guid.dts')
7356
7357 self.assertIn("entry is missing properties: image-guid",
7358 str(e.exception))
7359
Simon Glassac599912017-11-12 21:52:22 -07007360if __name__ == "__main__":
7361 unittest.main()