blob: 92df2a03650bb370ca683773b032da8cfc2cb29b [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 Glassf3598922024-07-20 11:49:45 +010010import glob
Simon Glassc585dd42020-04-17 18:09:03 -060011import gzip
Simon Glassae7cf032018-09-14 04:57:31 -060012import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070013from optparse import OptionParser
14import os
Simon Glass45d556d2020-07-09 18:39:45 -060015import re
Simon Glass57454f42016-11-25 20:15:52 -070016import shutil
17import struct
18import sys
19import tempfile
20import unittest
Simon Glass162017b2022-01-09 20:13:57 -070021import unittest.mock
22import urllib.error
Simon Glass57454f42016-11-25 20:15:52 -070023
Simon Glass4eae9252022-01-09 20:13:50 -070024from binman import bintool
Simon Glassc585dd42020-04-17 18:09:03 -060025from binman import cbfs_util
26from binman import cmdline
27from binman import control
28from binman import elf
29from binman import elf_test
Simon Glass3efb2972021-11-23 21:08:59 -070030from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060031from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060032from binman import state
33from dtoc import fdt
34from dtoc import fdt_util
35from binman.etype import fdtmap
36from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060037from binman.image import Image
Simon Glass131444f2023-02-23 18:18:04 -070038from u_boot_pylib import command
39from u_boot_pylib import test_util
40from u_boot_pylib import tools
41from u_boot_pylib import tout
Simon Glass57454f42016-11-25 20:15:52 -070042
43# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060044U_BOOT_DATA = b'1234'
45U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +030046U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass56d05412022-02-28 07:16:54 -070048U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glass303f62f2019-05-17 22:00:46 -060049BLOB_DATA = b'89'
50ME_DATA = b'0abcd'
51VGA_DATA = b'vga'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +053052EFI_CAPSULE_DATA = b'efi'
Simon Glass303f62f2019-05-17 22:00:46 -060053U_BOOT_DTB_DATA = b'udtb'
54U_BOOT_SPL_DTB_DATA = b'spldtb'
55U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass56d05412022-02-28 07:16:54 -070056U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glass303f62f2019-05-17 22:00:46 -060057X86_START16_DATA = b'start16'
58X86_START16_SPL_DATA = b'start16spl'
59X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060060X86_RESET16_DATA = b'reset16'
61X86_RESET16_SPL_DATA = b'reset16spl'
62X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060063PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
64U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
65U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
66U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass56d05412022-02-28 07:16:54 -070067U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +030068U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
69U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
70U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glass303f62f2019-05-17 22:00:46 -060071FSP_DATA = b'fsp'
72CMC_DATA = b'cmc'
73VBT_DATA = b'vbt'
74MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060075TEXT_DATA = 'text'
76TEXT_DATA2 = 'text2'
77TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060078CROS_EC_RW_DATA = b'ecrw'
79GBB_DATA = b'gbbd'
80BMPBLK_DATA = b'bmp'
81VBLOCK_DATA = b'vblk'
82FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
83 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060084COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060085COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060086REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060087FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060088FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060089FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060090ATF_BL31_DATA = b'bl31'
Roger Quadros5cdcea02022-02-19 20:50:04 +020091TEE_OS_DATA = b'this is some tee OS data'
Neha Malcom Francis59be2552023-12-05 15:12:18 +053092TI_DM_DATA = b'tidmtidm'
Simon Glass3efb2972021-11-23 21:08:59 -070093ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080094OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050095SCP_DATA = b'scp'
Jonas Karlman35305492023-02-25 19:01:33 +000096ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glassa435cd12020-09-01 05:13:59 -060097TEST_FDT1_DATA = b'fdt1'
98TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060099ENV_DATA = b'var1=1\nvar2="2"'
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200100ENCRYPTED_IV_DATA = b'123456'
101ENCRYPTED_KEY_DATA = b'abcde'
Philippe Reynesebe96cb2022-03-28 22:57:04 +0200102PRE_LOAD_MAGIC = b'UBSH'
103PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
104PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530105TI_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 +0530106TI_UNSECURE_DATA = b'unsecuredata'
Simon Glassa435cd12020-09-01 05:13:59 -0600107
108# Subdirectory of the input dir to use to put test FDTs
109TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600110
Simon Glass2c6adba2019-07-20 12:23:47 -0600111# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600112EXTRACT_DTB_SIZE = 0x3c9
113
Simon Glass2c6adba2019-07-20 12:23:47 -0600114# Properties expected to be in the device tree when update_dtb is used
115BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
116
Simon Glassfb30e292019-07-20 12:23:51 -0600117# Extra properties expected to be in the device tree when allow-repack is used
118REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
119
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200120# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200121COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700122
Simon Glassad5cfe12023-01-07 14:07:14 -0700123TEE_ADDR = 0x5678
124
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530125# Firmware Management Protocol(FMP) GUID
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530126FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530127# Image GUID specified in the DTS
Caleb Connolly4bdc9602024-08-30 13:34:35 +0100128CAPSULE_IMAGE_GUID = '985F2937-7C2E-5E9A-8A5E-8E063312964B'
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530129# Windows cert GUID
130WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +0530131# Empty capsule GUIDs
132EMPTY_CAPSULE_ACCEPT_GUID = '0c996046-bcc0-4d04-85ec-e1fcedf1c6f8'
133EMPTY_CAPSULE_REVERT_GUID = 'acd58b4b-c0e8-475f-99b5-6b3f7e07aaf0'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530134
Simon Glass57454f42016-11-25 20:15:52 -0700135class TestFunctional(unittest.TestCase):
136 """Functional tests for binman
137
138 Most of these use a sample .dts file to build an image and then check
139 that it looks correct. The sample files are in the test/ subdirectory
140 and are numbered.
141
142 For each entry type a very small test file is created using fixed
143 string contents. This makes it easy to test that things look right, and
144 debug problems.
145
146 In some cases a 'real' file must be used - these are also supplied in
147 the test/ diurectory.
148 """
149 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600150 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700151 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600152 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700153
Simon Glass57454f42016-11-25 20:15:52 -0700154 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600155 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
156 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700157
158 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600159 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700160
161 # Create some test files
162 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
163 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
164 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600165 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700166 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700167 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700168 TestFunctional._MakeInputFile('me.bin', ME_DATA)
169 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600170 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600171
Jagdish Gediya311d4842018-09-03 21:35:08 +0530172 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600173
Simon Glassabab18c2019-08-24 07:22:49 -0600174 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
175 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700176 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600177 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600178 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600179
180 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
181 X86_RESET16_DATA)
182 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
183 X86_RESET16_SPL_DATA)
184 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
185 X86_RESET16_TPL_DATA)
186
Simon Glass57454f42016-11-25 20:15:52 -0700187 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700188 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
189 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600190 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
191 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700192 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
193 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700194 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
195 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700196 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700197 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600198 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600199 TestFunctional._MakeInputDir('devkeys')
200 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600201 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600202 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600203 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600204 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700205
Simon Glassf6290892019-08-24 07:22:53 -0600206 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
207 elf_test.BuildElfTestFiles(cls._elf_testdir)
208
Simon Glass72232452016-11-25 20:15:53 -0700209 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600210 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700211 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700212
213 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600214 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700215
Simon Glass862f8e22019-08-24 07:22:43 -0600216 shutil.copytree(cls.TestFile('files'),
217 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600218
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530219 shutil.copytree(cls.TestFile('yaml'),
220 os.path.join(cls._indir, 'yaml'))
221
Simon Glass7ba33592018-09-14 04:57:26 -0600222 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600223 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600224 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200225 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Neha Malcom Francis59be2552023-12-05 15:12:18 +0530226 TestFunctional._MakeInputFile('dm.bin', TI_DM_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700227 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800228 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500229 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman35305492023-02-25 19:01:33 +0000230 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530231 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530232 TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600233
Simon Glassa435cd12020-09-01 05:13:59 -0600234 # Add a few .dtb files for testing
235 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
236 TEST_FDT1_DATA)
237 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
238 TEST_FDT2_DATA)
239
Simon Glassa0729502020-09-06 10:35:33 -0600240 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
241
Simon Glass5f423422022-03-05 20:19:12 -0700242 # ELF file with two sections in different parts of memory, used for both
243 # ATF and OP_TEE
244 TestFunctional._MakeInputFile('bl31.elf',
245 tools.read_file(cls.ElfTestFile('elf_sections')))
246 TestFunctional._MakeInputFile('tee.elf',
247 tools.read_file(cls.ElfTestFile('elf_sections')))
248
Simon Glassad5cfe12023-01-07 14:07:14 -0700249 # Newer OP_TEE file in v1 binary format
250 cls.make_tee_bin('tee.bin')
251
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200252 # test files for encrypted tests
253 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
254 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
255
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200256 cls.comp_bintools = {}
257 for name in COMP_BINTOOLS:
258 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600259
Simon Glass57454f42016-11-25 20:15:52 -0700260 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600261 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700262 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600263 if cls.preserve_indir:
264 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600265 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600266 if cls._indir:
267 shutil.rmtree(cls._indir)
268 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700269
Simon Glass1c420c92019-07-08 13:18:49 -0600270 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600271 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600272 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600273 """Accept arguments controlling test execution
274
275 Args:
276 preserve_indir: Preserve the shared input directory used by all
277 tests in this class.
278 preserve_outdir: Preserve the output directories used by tests. Each
279 test has its own, so this is normally only useful when running a
280 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600281 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600282 """
283 cls.preserve_indir = preserve_indir
284 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600285 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600286 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600287
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200288 def _CheckBintool(self, bintool):
289 if not bintool.is_present():
290 self.skipTest('%s not available' % bintool.name)
291
Simon Glass1de34482019-07-08 13:18:53 -0600292 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200293 bintool = self.comp_bintools['lz4']
294 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600295
Simon Glassee9d10d2019-07-20 12:24:09 -0600296 def _CleanupOutputDir(self):
297 """Remove the temporary output directory"""
298 if self.preserve_outdirs:
299 print('Preserving output dir: %s' % tools.outdir)
300 else:
Simon Glass80025522022-01-29 14:14:04 -0700301 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600302
Simon Glass57454f42016-11-25 20:15:52 -0700303 def setUp(self):
304 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700305 # tout.init(tout.DEBUG)
Simon Glass5dc22cf2025-02-03 09:26:42 -0700306 command.TEST_RESULT = None
Simon Glass57454f42016-11-25 20:15:52 -0700307
308 def tearDown(self):
309 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600310 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700311
Simon Glassb3d6fc72019-07-20 12:24:10 -0600312 def _SetupImageInTmpdir(self):
313 """Set up the output image in a new temporary directory
314
315 This is used when an image has been generated in the output directory,
316 but we want to run binman again. This will create a new output
317 directory and fail to delete the original one.
318
319 This creates a new temporary directory, copies the image to it (with a
320 new name) and removes the old output directory.
321
322 Returns:
323 Tuple:
324 Temporary directory to use
325 New image filename
326 """
Simon Glass80025522022-01-29 14:14:04 -0700327 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600328 tmpdir = tempfile.mkdtemp(prefix='binman.')
329 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700330 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600331 self._CleanupOutputDir()
332 return tmpdir, updated_fname
333
Simon Glass8425a1f2018-07-17 13:25:48 -0600334 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600335 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600336 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
337 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
338 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700339 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600340
Simon Glass57454f42016-11-25 20:15:52 -0700341 def _RunBinman(self, *args, **kwargs):
342 """Run binman using the command line
343
344 Args:
345 Arguments to pass, as a list of strings
346 kwargs: Arguments to pass to Command.RunPipe()
347 """
Simon Glass51f55182025-02-03 09:26:45 -0700348 all_args = [self._binman_pathname] + list(args)
349 result = command.run_one(*all_args, capture=True, capture_stderr=True,
350 raise_on_error=False)
Simon Glass57454f42016-11-25 20:15:52 -0700351 if result.return_code and kwargs.get('raise_on_error', True):
352 raise Exception("Error running '%s': %s" % (' '.join(args),
353 result.stdout + result.stderr))
354 return result
355
Simon Glassf46732a2019-07-08 14:25:29 -0600356 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700357 """Run binman using directly (in the same process)
358
359 Args:
360 Arguments to pass, as a list of strings
361 Returns:
362 Return value (0 for success)
363 """
Simon Glassf46732a2019-07-08 14:25:29 -0600364 argv = list(argv)
365 args = cmdline.ParseArgs(argv)
366 args.pager = 'binman-invalid-pager'
367 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700368
369 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600370 # args.verbosity = tout.DEBUG
371 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700372
Simon Glass91710b32018-07-17 13:25:32 -0600373 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600374 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300375 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100376 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700377 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis6b463da2023-07-22 00:14:44 +0530378 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass57454f42016-11-25 20:15:52 -0700379 """Run binman with a given test file
380
381 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600382 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600383 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600384 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600385 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600386 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600387 entry_args: Dict of entry args to supply to binman
388 key: arg name
389 value: value of that arg
390 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600391 use_real_dtb: True to use the test file as the contents of
392 the u-boot-dtb entry. Normally this is not needed and the
393 test contents (the U_BOOT_DTB_DATA string) can be used.
394 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300395 use_expanded: True to use expanded entries where available, e.g.
396 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600397 verbosity: Verbosity level to use (0-3, None=don't set it)
398 allow_missing: Set the '--allow-missing' flag so that missing
399 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100400 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600401 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600402 threads: Number of threads to use (None for default, 0 for
403 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600404 test_section_timeout: True to force the first time to timeout, as
405 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600406 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glassb553e8a2024-08-26 13:11:29 -0600407 force_missing_bintools (str): comma-separated list of bintools to
Simon Glass66152ce2022-01-09 20:14:09 -0700408 regard as missing
Simon Glassb553e8a2024-08-26 13:11:29 -0600409 ignore_missing (bool): True to return success even if there are
410 missing blobs or bintools
Andrew Davis6b463da2023-07-22 00:14:44 +0530411 output_dir: Specific output directory to use for image using -O
Simon Glass9a798402021-11-03 21:09:17 -0600412
413 Returns:
414 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700415 """
Simon Glassf46732a2019-07-08 14:25:29 -0600416 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700417 if debug:
418 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600419 if verbosity is not None:
420 args.append('-v%d' % verbosity)
421 elif self.verbosity:
422 args.append('-v%d' % self.verbosity)
423 if self.toolpath:
424 for path in self.toolpath:
425 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600426 if threads is not None:
427 args.append('-T%d' % threads)
428 if test_section_timeout:
429 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600430 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600431 if map:
432 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600433 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600434 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600435 if not use_real_dtb:
436 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300437 if not use_expanded:
438 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600439 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600440 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600441 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600442 if allow_missing:
443 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700444 if ignore_missing:
445 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100446 if allow_fake_blobs:
447 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700448 if force_missing_bintools:
449 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600450 if update_fdt_in_elf:
451 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600452 if images:
453 for image in images:
454 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600455 if extra_indirs:
456 for indir in extra_indirs:
457 args += ['-I', indir]
Andrew Davis6b463da2023-07-22 00:14:44 +0530458 if output_dir:
459 args += ['-O', output_dir]
Simon Glass075a45c2017-11-13 18:55:00 -0700460 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700461
462 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700463 """Set up a new test device-tree file
464
465 The given file is compiled and set up as the device tree to be used
466 for ths test.
467
468 Args:
469 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600470 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700471
472 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600473 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700474 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600475 tmpdir = tempfile.mkdtemp(prefix='binmant.')
476 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600477 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700478 data = fd.read()
479 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600480 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600481 return data
Simon Glass57454f42016-11-25 20:15:52 -0700482
Simon Glass56d05412022-02-28 07:16:54 -0700483 def _GetDtbContentsForSpls(self, dtb_data, name):
484 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600485
486 For testing we don't actually have different versions of the DTB. With
487 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
488 we don't normally have any unwanted nodes.
489
490 We still want the DTBs for SPL and TPL to be different though, since
491 otherwise it is confusing to know which one we are looking at. So add
492 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600493
494 Args:
495 dtb_data: dtb data to modify (this should be a value devicetree)
496 name: Name of a new property to add
497
498 Returns:
499 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600500 """
501 dtb = fdt.Fdt.FromData(dtb_data)
502 dtb.Scan()
503 dtb.GetNode('/binman').AddZeroProp(name)
504 dtb.Sync(auto_resize=True)
505 dtb.Pack()
506 return dtb.GetContents()
507
Simon Glassed930672021-03-18 20:25:05 +1300508 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
Simon Glass3eb30a42024-08-26 13:11:42 -0600509 verbosity=None, map=False, update_dtb=False,
510 entry_args=None, reset_dtbs=True, extra_indirs=None,
511 threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700512 """Run binman and return the resulting image
513
514 This runs binman with a given test file and then reads the resulting
515 output file. It is a shortcut function since most tests need to do
516 these steps.
517
518 Raises an assertion failure if binman returns a non-zero exit code.
519
520 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600521 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700522 use_real_dtb: True to use the test file as the contents of
523 the u-boot-dtb entry. Normally this is not needed and the
524 test contents (the U_BOOT_DTB_DATA string) can be used.
525 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300526 use_expanded: True to use expanded entries where available, e.g.
527 'u-boot-expanded' instead of 'u-boot'
Simon Glass3eb30a42024-08-26 13:11:42 -0600528 verbosity: Verbosity level to use (0-3, None=don't set it)
Simon Glass30732662018-06-01 09:38:20 -0600529 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600530 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600531 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600532 entry_args: Dict of entry args to supply to binman
533 key: arg name
534 value: value of that arg
535 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
536 function. If reset_dtbs is True, then the original test dtb
537 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600538 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600539 threads: Number of threads to use (None for default, 0 for
540 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700541
542 Returns:
543 Tuple:
544 Resulting image contents
545 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600546 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600547 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700548 """
Simon Glass72232452016-11-25 20:15:53 -0700549 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700550 # Use the compiled test file as the u-boot-dtb input
551 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700552 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600553
554 # For testing purposes, make a copy of the DT for SPL and TPL. Add
Simon Glassd9e01d22024-07-20 11:49:40 +0100555 # a node indicating which it is, to aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700556 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600557 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
558 outfile = os.path.join(self._indir, dtb_fname)
559 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700560 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700561
562 try:
Simon Glass91710b32018-07-17 13:25:32 -0600563 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600564 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass3eb30a42024-08-26 13:11:42 -0600565 use_expanded=use_expanded, verbosity=verbosity,
566 extra_indirs=extra_indirs,
Simon Glass76f496d2021-07-06 10:36:37 -0600567 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700568 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700569 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700570
571 # Find the (only) image, read it and return its contents
572 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700573 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600574 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600575 if map:
Simon Glass80025522022-01-29 14:14:04 -0700576 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600577 with open(map_fname) as fd:
578 map_data = fd.read()
579 else:
580 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600581 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600582 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700583 finally:
584 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600585 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600586 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700587
Simon Glass5b4bce32019-07-08 14:25:26 -0600588 def _DoReadFileRealDtb(self, fname):
589 """Run binman with a real .dtb file and return the resulting data
590
591 Args:
592 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
593
594 Returns:
595 Resulting image contents
596 """
597 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
598
Simon Glass72232452016-11-25 20:15:53 -0700599 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600600 """Helper function which discards the device-tree binary
601
602 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600603 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600604 use_real_dtb: True to use the test file as the contents of
605 the u-boot-dtb entry. Normally this is not needed and the
606 test contents (the U_BOOT_DTB_DATA string) can be used.
607 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600608
609 Returns:
610 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600611 """
Simon Glass72232452016-11-25 20:15:53 -0700612 return self._DoReadFileDtb(fname, use_real_dtb)[0]
613
Simon Glass57454f42016-11-25 20:15:52 -0700614 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600615 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700616 """Create a new test input file, creating directories as needed
617
618 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600619 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700620 contents: File contents to write in to the file
621 Returns:
622 Full pathname of file created
623 """
Simon Glass862f8e22019-08-24 07:22:43 -0600624 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700625 dirname = os.path.dirname(pathname)
626 if dirname and not os.path.exists(dirname):
627 os.makedirs(dirname)
628 with open(pathname, 'wb') as fd:
629 fd.write(contents)
630 return pathname
631
632 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600633 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600634 """Create a new test input directory, creating directories as needed
635
636 Args:
637 dirname: Directory name to create
638
639 Returns:
640 Full pathname of directory created
641 """
Simon Glass862f8e22019-08-24 07:22:43 -0600642 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600643 if not os.path.exists(pathname):
644 os.makedirs(pathname)
645 return pathname
646
647 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600648 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600649 """Set up an ELF file with a '_dt_ucode_base_size' symbol
650
651 Args:
652 Filename of ELF file to use as SPL
653 """
Simon Glass93a806f2019-08-24 07:22:59 -0600654 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700655 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600656
657 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600658 def _SetupTplElf(cls, src_fname='bss_data'):
659 """Set up an ELF file with a '_dt_ucode_base_size' symbol
660
661 Args:
662 Filename of ELF file to use as TPL
663 """
664 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700665 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600666
667 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700668 def _SetupVplElf(cls, src_fname='bss_data'):
669 """Set up an ELF file with a '_dt_ucode_base_size' symbol
670
671 Args:
672 Filename of ELF file to use as VPL
673 """
674 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
675 tools.read_file(cls.ElfTestFile(src_fname)))
676
677 @classmethod
Lukas Funkee901faf2023-07-18 13:53:13 +0200678 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
679 """Set up an ELF file with a '_dt_ucode_base_size' symbol
680
681 Args:
682 Filename of ELF file to use as VPL
683 """
684 TestFunctional._MakeInputFile('pmu-firmware.elf',
685 tools.read_file(cls.ElfTestFile(src_fname)))
686
687 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600688 def _SetupDescriptor(cls):
689 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
690 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
691
692 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600693 def TestFile(cls, fname):
694 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700695
Simon Glassf6290892019-08-24 07:22:53 -0600696 @classmethod
697 def ElfTestFile(cls, fname):
698 return os.path.join(cls._elf_testdir, fname)
699
Simon Glassad5cfe12023-01-07 14:07:14 -0700700 @classmethod
701 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
702 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
703 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
704 dummy, paged_sz) + U_BOOT_DATA
705 data += extra_data
706 TestFunctional._MakeInputFile(fname, data)
707
Simon Glass57454f42016-11-25 20:15:52 -0700708 def AssertInList(self, grep_list, target):
709 """Assert that at least one of a list of things is in a target
710
711 Args:
712 grep_list: List of strings to check
713 target: Target string
714 """
715 for grep in grep_list:
716 if grep in target:
717 return
Simon Glass848cdb52019-05-17 22:00:50 -0600718 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700719
720 def CheckNoGaps(self, entries):
721 """Check that all entries fit together without gaps
722
723 Args:
724 entries: List of entries to check
725 """
Simon Glasse8561af2018-08-01 15:22:37 -0600726 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700727 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600728 self.assertEqual(offset, entry.offset)
729 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700730
Simon Glass72232452016-11-25 20:15:53 -0700731 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600732 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700733
734 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600735 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700736
737 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600738 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700739 """
740 return struct.unpack('>L', dtb[4:8])[0]
741
Simon Glass0f621332019-07-08 14:25:27 -0600742 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600743 def AddNode(node, path):
744 if node.name != '/':
745 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600746 for prop in node.props.values():
747 if prop.name in prop_names:
748 prop_path = path + ':' + prop.name
749 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
750 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600751 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600752 AddNode(subnode, path)
753
754 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600755 AddNode(dtb.GetRoot(), '')
756 return tree
757
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000758 def _CheckSign(self, fit, key):
759 try:
760 tools.run('fit_check_sign', '-k', key, '-f', fit)
761 except:
762 self.fail('Expected signed FIT container')
763 return False
764 return True
765
Paul HENRYS5cf82892025-02-24 22:20:55 +0100766 def _CheckPreload(self, image, key, algo="sha256,rsa2048",
767 padding="pkcs-1.5"):
768 try:
769 tools.run('preload_check_sign', '-k', key, '-a', algo, '-p',
770 padding, '-f', image)
771 except:
772 self.fail('Expected image signed with a pre-load')
773 return False
774 return True
775
Simon Glass57454f42016-11-25 20:15:52 -0700776 def testRun(self):
777 """Test a basic run with valid args"""
778 result = self._RunBinman('-h')
779
780 def testFullHelp(self):
781 """Test that the full help is displayed with -H"""
782 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300783 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500784 # Remove possible extraneous strings
785 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
786 gothelp = result.stdout.replace(extra, '')
787 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700788 self.assertEqual(0, len(result.stderr))
789 self.assertEqual(0, result.return_code)
790
791 def testFullHelpInternal(self):
792 """Test that the full help is displayed with -H"""
793 try:
Simon Glass5dc22cf2025-02-03 09:26:42 -0700794 command.TEST_RESULT = command.CommandResult()
Simon Glass57454f42016-11-25 20:15:52 -0700795 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300796 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700797 finally:
Simon Glass5dc22cf2025-02-03 09:26:42 -0700798 command.TEST_RESULT = None
Simon Glass57454f42016-11-25 20:15:52 -0700799
800 def testHelp(self):
801 """Test that the basic help is displayed with -h"""
802 result = self._RunBinman('-h')
803 self.assertTrue(len(result.stdout) > 200)
804 self.assertEqual(0, len(result.stderr))
805 self.assertEqual(0, result.return_code)
806
Simon Glass57454f42016-11-25 20:15:52 -0700807 def testBoard(self):
808 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600809 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700810 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300811 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700812 self.assertEqual(0, result)
813
814 def testNeedBoard(self):
815 """Test that we get an error when no board ius supplied"""
816 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600817 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700818 self.assertIn("Must provide a board to process (use -b <board>)",
819 str(e.exception))
820
821 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600822 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700823 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600824 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700825 # We get one error from libfdt, and a different one from fdtget.
826 self.AssertInList(["Couldn't open blob from 'missing_file'",
827 'No such file or directory'], str(e.exception))
828
829 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600830 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700831
832 Since this is a source file it should be compiled and the error
833 will come from the device-tree compiler (dtc).
834 """
835 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600836 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700837 self.assertIn("FATAL ERROR: Unable to parse input tree",
838 str(e.exception))
839
840 def testMissingNode(self):
841 """Test that a device tree without a 'binman' node generates an error"""
842 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600843 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700844 self.assertIn("does not have a 'binman' node", str(e.exception))
845
846 def testEmpty(self):
847 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600848 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700849 self.assertEqual(0, len(result.stderr))
850 self.assertEqual(0, result.return_code)
851
852 def testInvalidEntry(self):
853 """Test that an invalid entry is flagged"""
854 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600855 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600856 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700857 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
858 "'/binman/not-a-valid-type'", str(e.exception))
859
860 def testSimple(self):
861 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600862 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700863 self.assertEqual(U_BOOT_DATA, data)
864
Simon Glass075a45c2017-11-13 18:55:00 -0700865 def testSimpleDebug(self):
866 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600867 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700868
Simon Glass57454f42016-11-25 20:15:52 -0700869 def testDual(self):
870 """Test that we can handle creating two images
871
872 This also tests image padding.
873 """
Simon Glass511f6582018-10-01 12:22:30 -0600874 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700875 self.assertEqual(0, retcode)
876
877 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600878 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700879 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700880 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600881 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700882 data = fd.read()
883 self.assertEqual(U_BOOT_DATA, data)
884
885 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600886 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700887 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700888 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600889 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700890 data = fd.read()
891 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700892 self.assertEqual(tools.get_bytes(0, 3), data[:3])
893 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700894
895 def testBadAlign(self):
896 """Test that an invalid alignment value is detected"""
897 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600898 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700899 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
900 "of two", str(e.exception))
901
902 def testPackSimple(self):
903 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600904 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700905 self.assertEqual(0, retcode)
906 self.assertIn('image', control.images)
907 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600908 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700909 self.assertEqual(5, len(entries))
910
911 # First u-boot
912 self.assertIn('u-boot', entries)
913 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600914 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700915 self.assertEqual(len(U_BOOT_DATA), entry.size)
916
917 # Second u-boot, aligned to 16-byte boundary
918 self.assertIn('u-boot-align', entries)
919 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600920 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700921 self.assertEqual(len(U_BOOT_DATA), entry.size)
922
923 # Third u-boot, size 23 bytes
924 self.assertIn('u-boot-size', entries)
925 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600926 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700927 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
928 self.assertEqual(23, entry.size)
929
930 # Fourth u-boot, placed immediate after the above
931 self.assertIn('u-boot-next', entries)
932 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600933 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700934 self.assertEqual(len(U_BOOT_DATA), entry.size)
935
Simon Glasse8561af2018-08-01 15:22:37 -0600936 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700937 self.assertIn('u-boot-fixed', entries)
938 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600939 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700940 self.assertEqual(len(U_BOOT_DATA), entry.size)
941
Simon Glass39dd2152019-07-08 14:25:47 -0600942 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700943
944 def testPackExtra(self):
945 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600946 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
947 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700948
Simon Glass57454f42016-11-25 20:15:52 -0700949 self.assertIn('image', control.images)
950 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600951 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600952 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700953
Samuel Hollande2574022023-01-21 17:25:16 -0600954 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700955 self.assertIn('u-boot', entries)
956 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600957 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700958 self.assertEqual(3, entry.pad_before)
959 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600960 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700961 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
962 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600963 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700964
965 # Second u-boot has an aligned size, but it has no effect
966 self.assertIn('u-boot-align-size-nop', entries)
967 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600968 self.assertEqual(pos, entry.offset)
969 self.assertEqual(len(U_BOOT_DATA), entry.size)
970 self.assertEqual(U_BOOT_DATA, entry.data)
971 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
972 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700973
974 # Third u-boot has an aligned size too
975 self.assertIn('u-boot-align-size', entries)
976 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600977 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700978 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600979 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700980 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600981 data[pos:pos + entry.size])
982 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700983
984 # Fourth u-boot has an aligned end
985 self.assertIn('u-boot-align-end', entries)
986 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600987 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700988 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600989 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700990 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600991 data[pos:pos + entry.size])
992 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700993
994 # Fifth u-boot immediately afterwards
995 self.assertIn('u-boot-align-both', entries)
996 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600997 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700998 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600999 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -07001000 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -06001001 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -07001002
Samuel Hollande2574022023-01-21 17:25:16 -06001003 # Sixth u-boot with both minimum size and aligned size
1004 self.assertIn('u-boot-min-size', entries)
1005 entry = entries['u-boot-min-size']
1006 self.assertEqual(128, entry.offset)
1007 self.assertEqual(32, entry.size)
1008 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
1009 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
1010 data[pos:pos + entry.size])
1011
Simon Glass57454f42016-11-25 20:15:52 -07001012 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -06001013 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001014
Simon Glassafb9caa2020-10-26 17:40:10 -06001015 dtb = fdt.Fdt(out_dtb_fname)
1016 dtb.Scan()
1017 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
1018 expected = {
1019 'image-pos': 0,
1020 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -06001021 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -06001022
1023 'u-boot:image-pos': 0,
1024 'u-boot:offset': 0,
1025 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1026
1027 'u-boot-align-size-nop:image-pos': 12,
1028 'u-boot-align-size-nop:offset': 12,
1029 'u-boot-align-size-nop:size': 4,
1030
1031 'u-boot-align-size:image-pos': 16,
1032 'u-boot-align-size:offset': 16,
1033 'u-boot-align-size:size': 32,
1034
1035 'u-boot-align-end:image-pos': 48,
1036 'u-boot-align-end:offset': 48,
1037 'u-boot-align-end:size': 16,
1038
1039 'u-boot-align-both:image-pos': 64,
1040 'u-boot-align-both:offset': 64,
1041 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -06001042
1043 'u-boot-min-size:image-pos': 128,
1044 'u-boot-min-size:offset': 128,
1045 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -06001046 }
1047 self.assertEqual(expected, props)
1048
Simon Glass57454f42016-11-25 20:15:52 -07001049 def testPackAlignPowerOf2(self):
1050 """Test that invalid entry alignment is detected"""
1051 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001052 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001053 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1054 "of two", str(e.exception))
1055
1056 def testPackAlignSizePowerOf2(self):
1057 """Test that invalid entry size alignment is detected"""
1058 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001059 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001060 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1061 "power of two", str(e.exception))
1062
1063 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001064 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001065 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001066 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001067 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001068 "align 0x4 (4)", str(e.exception))
1069
1070 def testPackInvalidSizeAlign(self):
1071 """Test that invalid entry size alignment is detected"""
1072 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001073 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001074 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1075 "align-size 0x4 (4)", str(e.exception))
1076
1077 def testPackOverlap(self):
1078 """Test that overlapping regions are detected"""
1079 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001080 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001081 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001082 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1083 str(e.exception))
1084
1085 def testPackEntryOverflow(self):
1086 """Test that entries that overflow their size are detected"""
1087 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001088 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001089 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1090 "but entry size is 0x3 (3)", str(e.exception))
1091
1092 def testPackImageOverflow(self):
1093 """Test that entries which overflow the image size are detected"""
1094 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001095 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001096 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001097 "size 0x3 (3)", str(e.exception))
1098
1099 def testPackImageSize(self):
1100 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001101 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001102 self.assertEqual(0, retcode)
1103 self.assertIn('image', control.images)
1104 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001105 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001106
1107 def testPackImageSizeAlign(self):
1108 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001109 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001110 self.assertEqual(0, retcode)
1111 self.assertIn('image', control.images)
1112 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001113 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001114
1115 def testPackInvalidImageAlign(self):
1116 """Test that invalid image alignment is detected"""
1117 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001118 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001119 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001120 "align-size 0x8 (8)", str(e.exception))
1121
Simon Glass2a0fa982022-02-11 13:23:21 -07001122 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001123 """Test that invalid image alignment is detected"""
1124 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001125 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001126 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001127 "two", str(e.exception))
1128
1129 def testImagePadByte(self):
1130 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001131 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001132 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001133 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001134 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001135
1136 def testImageName(self):
1137 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001138 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001139 self.assertEqual(0, retcode)
1140 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001141 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001142 self.assertTrue(os.path.exists(fname))
1143
1144 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001145 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001146 self.assertTrue(os.path.exists(fname))
1147
1148 def testBlobFilename(self):
1149 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001150 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001151 self.assertEqual(BLOB_DATA, data)
1152
1153 def testPackSorted(self):
1154 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001155 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001156 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001157 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1158 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001159
Simon Glasse8561af2018-08-01 15:22:37 -06001160 def testPackZeroOffset(self):
1161 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001162 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001163 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001164 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001165 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001166 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1167 str(e.exception))
1168
1169 def testPackUbootDtb(self):
1170 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001171 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001172 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001173
1174 def testPackX86RomNoSize(self):
1175 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001176 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001177 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001178 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001179 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001180 "using end-at-4gb", str(e.exception))
1181
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301182 def test4gbAndSkipAtStartTogether(self):
1183 """Test that the end-at-4gb and skip-at-size property can't be used
1184 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001185 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301186 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001187 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001188 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301189 "'skip-at-start'", str(e.exception))
1190
Simon Glass72232452016-11-25 20:15:53 -07001191 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001192 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001193 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001194 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001195 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001196 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1197 "is outside the section '/binman' starting at "
1198 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001199 str(e.exception))
1200
1201 def testPackX86Rom(self):
1202 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001203 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001204 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001205 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1206 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001207
1208 def testPackX86RomMeNoDesc(self):
1209 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001210 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001211 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001212 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001213 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001214 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1215 str(e.exception))
1216 finally:
1217 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001218
1219 def testPackX86RomBadDesc(self):
1220 """Test that the Intel requires a descriptor entry"""
1221 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001222 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001223 self.assertIn("Node '/binman/intel-me': No offset set with "
1224 "offset-unset: should another entry provide this correct "
1225 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001226
1227 def testPackX86RomMe(self):
1228 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001229 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001230 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001231 if data[:0x1000] != expected_desc:
1232 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001233 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1234
1235 def testPackVga(self):
1236 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001237 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001238 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1239
1240 def testPackStart16(self):
1241 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001242 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001243 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1244
Jagdish Gediya311d4842018-09-03 21:35:08 +05301245 def testPackPowerpcMpc85xxBootpgResetvec(self):
1246 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1247 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001248 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301249 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1250
Simon Glass6ba679c2018-07-06 10:27:17 -06001251 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001252 """Handle running a test for insertion of microcode
1253
1254 Args:
1255 dts_fname: Name of test .dts file
1256 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001257 ucode_second: True if the microsecond entry is second instead of
1258 third
Simon Glass820af1d2018-07-06 10:27:16 -06001259
1260 Returns:
1261 Tuple:
1262 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001263 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001264 in the above (two 4-byte words)
1265 """
Simon Glass3d274232017-11-12 21:52:27 -07001266 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001267
1268 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001269 if ucode_second:
1270 ucode_content = data[len(nodtb_data):]
1271 ucode_pos = len(nodtb_data)
1272 dtb_with_ucode = ucode_content[16:]
1273 fdt_len = self.GetFdtLen(dtb_with_ucode)
1274 else:
1275 dtb_with_ucode = data[len(nodtb_data):]
1276 fdt_len = self.GetFdtLen(dtb_with_ucode)
1277 ucode_content = dtb_with_ucode[fdt_len:]
1278 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001279 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001280 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001281 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001282 dtb = fdt.FdtScan(fname)
1283 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001284 self.assertTrue(ucode)
1285 for node in ucode.subnodes:
1286 self.assertFalse(node.props.get('data'))
1287
Simon Glass72232452016-11-25 20:15:53 -07001288 # Check that the microcode appears immediately after the Fdt
1289 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001290 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001291 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1292 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001293 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001294
1295 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001296 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001297 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1298 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001299 u_boot = data[:len(nodtb_data)]
1300 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001301
1302 def testPackUbootMicrocode(self):
1303 """Test that x86 microcode can be handled correctly
1304
1305 We expect to see the following in the image, in order:
1306 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1307 place
1308 u-boot.dtb with the microcode removed
1309 the microcode
1310 """
Simon Glass511f6582018-10-01 12:22:30 -06001311 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001312 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001313 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1314 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001315
Simon Glassbac25c82017-05-27 07:38:26 -06001316 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001317 """Test that x86 microcode can be handled correctly
1318
1319 We expect to see the following in the image, in order:
1320 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1321 place
1322 u-boot.dtb with the microcode
1323 an empty microcode region
1324 """
1325 # We need the libfdt library to run this test since only that allows
1326 # finding the offset of a property. This is required by
1327 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001328 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001329
1330 second = data[len(U_BOOT_NODTB_DATA):]
1331
1332 fdt_len = self.GetFdtLen(second)
1333 third = second[fdt_len:]
1334 second = second[:fdt_len]
1335
Simon Glassbac25c82017-05-27 07:38:26 -06001336 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1337 self.assertIn(ucode_data, second)
1338 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001339
Simon Glassbac25c82017-05-27 07:38:26 -06001340 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001341 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001342 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1343 len(ucode_data))
1344 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001345 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1346 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001347
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001348 def testPackUbootSingleMicrocode(self):
1349 """Test that x86 microcode can be handled correctly with fdt_normal.
1350 """
Simon Glassbac25c82017-05-27 07:38:26 -06001351 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001352
Simon Glass996021e2016-11-25 20:15:54 -07001353 def testUBootImg(self):
1354 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001355 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001356 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001357
1358 def testNoMicrocode(self):
1359 """Test that a missing microcode region is detected"""
1360 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001361 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001362 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1363 "node found in ", str(e.exception))
1364
1365 def testMicrocodeWithoutNode(self):
1366 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1367 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001368 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001369 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1370 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1371
1372 def testMicrocodeWithoutNode2(self):
1373 """Test that a missing u-boot-ucode node is detected"""
1374 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001375 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001376 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1377 "microcode region u-boot-ucode", str(e.exception))
1378
1379 def testMicrocodeWithoutPtrInElf(self):
1380 """Test that a U-Boot binary without the microcode symbol is detected"""
1381 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001382 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001383 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001384 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001385
1386 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001387 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001388 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1389 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1390
1391 finally:
1392 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001393 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001394 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001395
1396 def testMicrocodeNotInImage(self):
1397 """Test that microcode must be placed within the image"""
1398 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001399 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001400 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1401 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001402 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001403
1404 def testWithoutMicrocode(self):
1405 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001406 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001407 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001408 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001409
1410 # Now check the device tree has no microcode
1411 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1412 second = data[len(U_BOOT_NODTB_DATA):]
1413
1414 fdt_len = self.GetFdtLen(second)
1415 self.assertEqual(dtb, second[:fdt_len])
1416
1417 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1418 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001419 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001420
1421 def testUnknownPosSize(self):
1422 """Test that microcode must be placed within the image"""
1423 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001424 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001425 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001426 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001427
1428 def testPackFsp(self):
1429 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001430 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001431 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1432
1433 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001434 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001435 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001436 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001437
1438 def testPackVbt(self):
1439 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001440 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001441 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001442
Simon Glass7f94e832017-11-12 21:52:25 -07001443 def testSplBssPad(self):
1444 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001445 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001446 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001447 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001448 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001449 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001450
Simon Glass04cda032018-10-01 21:12:42 -06001451 def testSplBssPadMissing(self):
1452 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001453 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001454 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001455 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001456 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1457 str(e.exception))
1458
Simon Glasse83679d2017-11-12 21:52:26 -07001459 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001460 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001461 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001462 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1463
Simon Glass6ba679c2018-07-06 10:27:17 -06001464 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1465 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001466
1467 We expect to see the following in the image, in order:
1468 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1469 correct place
1470 u-boot.dtb with the microcode removed
1471 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001472
1473 Args:
1474 dts: Device tree file to use for test
1475 ucode_second: True if the microsecond entry is second instead of
1476 third
Simon Glass3d274232017-11-12 21:52:27 -07001477 """
Simon Glass7057d022018-10-01 21:12:47 -06001478 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001479 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1480 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001481 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1482 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001483
Simon Glass6ba679c2018-07-06 10:27:17 -06001484 def testPackUbootSplMicrocode(self):
1485 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001486 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001487 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001488
1489 def testPackUbootSplMicrocodeReorder(self):
1490 """Test that order doesn't matter for microcode entries
1491
1492 This is the same as testPackUbootSplMicrocode but when we process the
1493 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1494 entry, so we reply on binman to try later.
1495 """
Simon Glass511f6582018-10-01 12:22:30 -06001496 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001497 ucode_second=True)
1498
Simon Glassa409c932017-11-12 21:52:28 -07001499 def testPackMrc(self):
1500 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001501 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001502 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1503
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001504 def testSplDtb(self):
1505 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001506 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001507 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001508 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1509
Simon Glass0a6da312017-11-13 18:54:56 -07001510 def testSplNoDtb(self):
1511 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001512 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001513 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001514 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1515
Simon Glass7098b7f2021-03-21 18:24:30 +13001516 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4b0f4142024-08-26 13:11:40 -06001517 use_expanded=False, no_write_symbols=False,
1518 symbols_base=None):
Simon Glass31e04cb2021-03-18 20:24:56 +13001519 """Check the image contains the expected symbol values
1520
1521 Args:
1522 dts: Device tree file to use for test
1523 base_data: Data before and after 'u-boot' section
Simon Glass3eb30a42024-08-26 13:11:42 -06001524 u_boot_offset (int): Offset of 'u-boot' section in image, or None if
1525 the offset not available due to it being in a compressed section
Simon Glass7098b7f2021-03-21 18:24:30 +13001526 entry_args: Dict of entry args to supply to binman
1527 key: arg name
1528 value: value of that arg
1529 use_expanded: True to use expanded entries where available, e.g.
1530 'u-boot-expanded' instead of 'u-boot'
Simon Glass4b0f4142024-08-26 13:11:40 -06001531 symbols_base (int): Value to expect for symbols-base in u-boot-spl,
1532 None if none
Simon Glass31e04cb2021-03-18 20:24:56 +13001533 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001534 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001535 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1536 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001537 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001538 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001539 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001540
Simon Glass7057d022018-10-01 21:12:47 -06001541 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001542 data = self._DoReadFileDtb(dts, entry_args=entry_args,
Simon Glass3eb30a42024-08-26 13:11:42 -06001543 use_expanded=use_expanded,
1544 verbosity=None if u_boot_offset else 3)[0]
1545
1546 # The lz4-compressed version of the U-Boot data is 19 bytes long
1547 comp_uboot_len = 19
1548
Simon Glass31e04cb2021-03-18 20:24:56 +13001549 # The image should contain the symbols from u_boot_binman_syms.c
1550 # Note that image_pos is adjusted by the base address of the image,
1551 # which is 0x10 in our test image
Simon Glass3eb30a42024-08-26 13:11:42 -06001552 # If u_boot_offset is None, Binman should write -1U into the image
Simon Glass4b0f4142024-08-26 13:11:40 -06001553 vals2 = (elf.BINMAN_SYM_MAGIC_VALUE, 0x00,
Simon Glass3eb30a42024-08-26 13:11:42 -06001554 u_boot_offset + len(U_BOOT_DATA) if u_boot_offset else
1555 len(U_BOOT_SPL_DATA) + 1 + comp_uboot_len,
1556 0x10 + u_boot_offset if u_boot_offset else 0xffffffff, 0x04)
Simon Glass4b0f4142024-08-26 13:11:40 -06001557
1558 # u-boot-spl has a symbols-base property, so take that into account if
1559 # required. The caller must supply the value
1560 vals = list(vals2)
1561 if symbols_base is not None:
1562 vals[3] = symbols_base + u_boot_offset
1563 vals = tuple(vals)
1564
Simon Glass4b4049e2024-08-26 13:11:39 -06001565 sym_values = struct.pack('<LLQLL', *vals)
Simon Glass4b0f4142024-08-26 13:11:40 -06001566 sym_values2 = struct.pack('<LLQLL', *vals2)
Simon Glass4abf7842023-07-18 07:23:54 -06001567 if no_write_symbols:
Simon Glass4b4049e2024-08-26 13:11:39 -06001568 self.assertEqual(
1569 base_data +
1570 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1571 U_BOOT_DATA + base_data, data)
Simon Glass4abf7842023-07-18 07:23:54 -06001572 else:
Simon Glass4b4049e2024-08-26 13:11:39 -06001573 got_vals = struct.unpack('<LLQLL', data[:24])
1574
1575 # For debugging:
1576 #print('expect:', list(f'{v:x}' for v in vals))
1577 #print(' got:', list(f'{v:x}' for v in got_vals))
1578
1579 self.assertEqual(vals, got_vals)
1580 self.assertEqual(sym_values, data[:24])
1581
1582 blen = len(base_data)
1583 self.assertEqual(base_data[24:], data[24:blen])
1584 self.assertEqual(0xff, data[blen])
1585
Simon Glass3eb30a42024-08-26 13:11:42 -06001586 if u_boot_offset:
1587 ofs = blen + 1 + len(U_BOOT_DATA)
1588 self.assertEqual(U_BOOT_DATA, data[blen + 1:ofs])
1589 else:
1590 ofs = blen + 1 + comp_uboot_len
Simon Glass4b4049e2024-08-26 13:11:39 -06001591
Simon Glass4b0f4142024-08-26 13:11:40 -06001592 self.assertEqual(sym_values2, data[ofs:ofs + 24])
Simon Glass4b4049e2024-08-26 13:11:39 -06001593 self.assertEqual(base_data[24:], data[ofs + 24:])
1594
1595 # Just repeating the above asserts all at once, for clarity
Simon Glass3eb30a42024-08-26 13:11:42 -06001596 if u_boot_offset:
1597 expected = (sym_values + base_data[24:] +
1598 tools.get_bytes(0xff, 1) + U_BOOT_DATA +
1599 sym_values2 + base_data[24:])
1600 self.assertEqual(expected, data)
Simon Glass4ca8e042017-11-13 18:55:01 -07001601
Simon Glass31e04cb2021-03-18 20:24:56 +13001602 def testSymbols(self):
1603 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001604 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001605
1606 def testSymbolsNoDtb(self):
1607 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001608 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001609 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1610 0x38)
1611
Simon Glasse76a3e62018-06-01 09:38:11 -06001612 def testPackUnitAddress(self):
1613 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001614 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001615 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1616
Simon Glassa91e1152018-06-01 09:38:16 -06001617 def testSections(self):
1618 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001619 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001620 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1621 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1622 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001623 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001624
Simon Glass30732662018-06-01 09:38:20 -06001625 def testMap(self):
1626 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001627 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001628 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700162900000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600163000000000 00000000 00000010 section@0
163100000000 00000000 00000004 u-boot
163200000010 00000010 00000010 section@1
163300000010 00000000 00000004 u-boot
163400000020 00000020 00000004 section@2
163500000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001636''', map_data)
1637
Simon Glass3b78d532018-06-01 09:38:21 -06001638 def testNamePrefix(self):
1639 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001640 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001641 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700164200000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600164300000000 00000000 00000010 section@0
164400000000 00000000 00000004 ro-u-boot
164500000010 00000010 00000010 section@1
164600000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001647''', map_data)
1648
Simon Glass6ba679c2018-07-06 10:27:17 -06001649 def testUnknownContents(self):
1650 """Test that obtaining the contents works as expected"""
1651 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001652 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001653 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001654 "processing of contents: remaining ["
1655 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001656
Simon Glass2e1169f2018-07-06 10:27:19 -06001657 def testBadChangeSize(self):
1658 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001659 try:
1660 state.SetAllowEntryExpansion(False)
1661 with self.assertRaises(ValueError) as e:
1662 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001663 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001664 str(e.exception))
1665 finally:
1666 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001667
Simon Glassa87014e2018-07-06 10:27:42 -06001668 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001669 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001670 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001671 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001672 dtb = fdt.Fdt(out_dtb_fname)
1673 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001674 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001675 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001676 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001677 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001678 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001679 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001680 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001681 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001682 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001683 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001684 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001685 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001686 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001687
Simon Glasse8561af2018-08-01 15:22:37 -06001688 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001689 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001690 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001691 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001692 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001693 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001694 'size': 40
1695 }, props)
1696
1697 def testUpdateFdtBad(self):
1698 """Test that we detect when ProcessFdt never completes"""
1699 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001700 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001701 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001702 '[<binman.etype._testing.Entry__testing',
1703 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001704
Simon Glass91710b32018-07-17 13:25:32 -06001705 def testEntryArgs(self):
1706 """Test passing arguments to entries from the command line"""
1707 entry_args = {
1708 'test-str-arg': 'test1',
1709 'test-int-arg': '456',
1710 }
Simon Glass511f6582018-10-01 12:22:30 -06001711 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001712 self.assertIn('image', control.images)
1713 entry = control.images['image'].GetEntries()['_testing']
1714 self.assertEqual('test0', entry.test_str_fdt)
1715 self.assertEqual('test1', entry.test_str_arg)
1716 self.assertEqual(123, entry.test_int_fdt)
1717 self.assertEqual(456, entry.test_int_arg)
1718
1719 def testEntryArgsMissing(self):
1720 """Test missing arguments and properties"""
1721 entry_args = {
1722 'test-int-arg': '456',
1723 }
Simon Glass511f6582018-10-01 12:22:30 -06001724 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001725 entry = control.images['image'].GetEntries()['_testing']
1726 self.assertEqual('test0', entry.test_str_fdt)
1727 self.assertEqual(None, entry.test_str_arg)
1728 self.assertEqual(None, entry.test_int_fdt)
1729 self.assertEqual(456, entry.test_int_arg)
1730
1731 def testEntryArgsRequired(self):
1732 """Test missing arguments and properties"""
1733 entry_args = {
1734 'test-int-arg': '456',
1735 }
1736 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001737 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001738 self.assertIn("Node '/binman/_testing': "
1739 'Missing required properties/entry args: test-str-arg, '
1740 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001741 str(e.exception))
1742
1743 def testEntryArgsInvalidFormat(self):
1744 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001745 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1746 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001747 with self.assertRaises(ValueError) as e:
1748 self._DoBinman(*args)
1749 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1750
1751 def testEntryArgsInvalidInteger(self):
1752 """Test that an invalid entry-argument integer is detected"""
1753 entry_args = {
1754 'test-int-arg': 'abc',
1755 }
1756 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001757 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001758 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1759 "'test-int-arg' (value 'abc') to integer",
1760 str(e.exception))
1761
1762 def testEntryArgsInvalidDatatype(self):
1763 """Test that an invalid entry-argument datatype is detected
1764
1765 This test could be written in entry_test.py except that it needs
1766 access to control.entry_args, which seems more than that module should
1767 be able to see.
1768 """
1769 entry_args = {
1770 'test-bad-datatype-arg': '12',
1771 }
1772 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001773 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001774 entry_args=entry_args)
1775 self.assertIn('GetArg() internal error: Unknown data type ',
1776 str(e.exception))
1777
Simon Glass2ca52032018-07-17 13:25:33 -06001778 def testText(self):
1779 """Test for a text entry type"""
1780 entry_args = {
1781 'test-id': TEXT_DATA,
1782 'test-id2': TEXT_DATA2,
1783 'test-id3': TEXT_DATA3,
1784 }
Simon Glass511f6582018-10-01 12:22:30 -06001785 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001786 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001787 expected = (tools.to_bytes(TEXT_DATA) +
1788 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1789 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001790 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001791 self.assertEqual(expected, data)
1792
Simon Glass969616c2018-07-17 13:25:36 -06001793 def testEntryDocs(self):
1794 """Test for creation of entry documentation"""
1795 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001796 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001797 self.assertTrue(len(stdout.getvalue()) > 0)
1798
1799 def testEntryDocsMissing(self):
1800 """Test handling of missing entry documentation"""
1801 with self.assertRaises(ValueError) as e:
1802 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001803 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001804 self.assertIn('Documentation is missing for modules: u_boot',
1805 str(e.exception))
1806
Simon Glass704784b2018-07-17 13:25:38 -06001807 def testFmap(self):
1808 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001809 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001810 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001811 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1812 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001813 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001814 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001815 self.assertEqual(1, fhdr.ver_major)
1816 self.assertEqual(0, fhdr.ver_minor)
1817 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001818 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001819 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001820 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001821 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001822 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001823
Simon Glass82059c22021-04-03 11:05:09 +13001824 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001825 self.assertEqual(b'SECTION0', fentry.name)
1826 self.assertEqual(0, fentry.offset)
1827 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001828 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001829
1830 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001831 self.assertEqual(b'RO_U_BOOT', fentry.name)
1832 self.assertEqual(0, fentry.offset)
1833 self.assertEqual(4, fentry.size)
1834 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001835
Simon Glass82059c22021-04-03 11:05:09 +13001836 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001837 self.assertEqual(b'SECTION1', fentry.name)
1838 self.assertEqual(16, fentry.offset)
1839 self.assertEqual(16, fentry.size)
1840 self.assertEqual(0, fentry.flags)
1841
1842 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001843 self.assertEqual(b'RW_U_BOOT', fentry.name)
1844 self.assertEqual(16, fentry.offset)
1845 self.assertEqual(4, fentry.size)
1846 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001847
Simon Glass82059c22021-04-03 11:05:09 +13001848 fentry = next(fiter)
1849 self.assertEqual(b'FMAP', fentry.name)
1850 self.assertEqual(32, fentry.offset)
1851 self.assertEqual(expect_size, fentry.size)
1852 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001853
Simon Glassdb168d42018-07-17 13:25:39 -06001854 def testBlobNamedByArg(self):
1855 """Test we can add a blob with the filename coming from an entry arg"""
1856 entry_args = {
1857 'cros-ec-rw-path': 'ecrw.bin',
1858 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001859 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001860
Simon Glass53f53992018-07-17 13:25:40 -06001861 def testFill(self):
1862 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001863 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001864 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001865 self.assertEqual(expected, data)
1866
1867 def testFillNoSize(self):
1868 """Test for an fill entry type with no size"""
1869 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001870 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001871 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001872 str(e.exception))
1873
Simon Glassc1ae83c2018-07-17 13:25:44 -06001874 def _HandleGbbCommand(self, pipe_list):
1875 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001876 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001877 fname = pipe_list[0][-1]
1878 # Append our GBB data to the file, which will happen every time the
1879 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001880 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001881 fd.write(GBB_DATA)
1882 return command.CommandResult()
1883
1884 def testGbb(self):
1885 """Test for the Chromium OS Google Binary Block"""
Simon Glass5dc22cf2025-02-03 09:26:42 -07001886 command.TEST_RESULT = self._HandleGbbCommand
Simon Glassc1ae83c2018-07-17 13:25:44 -06001887 entry_args = {
1888 'keydir': 'devkeys',
1889 'bmpblk': 'bmpblk.bin',
1890 }
Simon Glass511f6582018-10-01 12:22:30 -06001891 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001892
1893 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001894 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1895 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001896 self.assertEqual(expected, data)
1897
1898 def testGbbTooSmall(self):
1899 """Test for the Chromium OS Google Binary Block being large enough"""
1900 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001901 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001902 self.assertIn("Node '/binman/gbb': GBB is too small",
1903 str(e.exception))
1904
1905 def testGbbNoSize(self):
1906 """Test for the Chromium OS Google Binary Block having a size"""
1907 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001908 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001909 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1910 str(e.exception))
1911
Simon Glass66152ce2022-01-09 20:14:09 -07001912 def testGbbMissing(self):
1913 """Test that binman still produces an image if futility is missing"""
1914 entry_args = {
1915 'keydir': 'devkeys',
1916 }
1917 with test_util.capture_sys_output() as (_, stderr):
1918 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1919 entry_args=entry_args)
1920 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001921 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001922
Simon Glass5c350162018-07-17 13:25:47 -06001923 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001924 """Fake calls to the futility utility
1925
1926 The expected pipe is:
1927
1928 [('futility', 'vbutil_firmware', '--vblock',
1929 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1930 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1931 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1932 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1933
1934 This writes to the output file (here, 'vblock.vblock'). If
1935 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1936 of the input data (here, 'input.vblock').
1937 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001938 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001939 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001940 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001941 if self._hash_data:
1942 infile = pipe_list[0][11]
1943 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001944 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001945 m.update(data)
1946 fd.write(m.digest())
1947 else:
1948 fd.write(VBLOCK_DATA)
1949
Simon Glass5c350162018-07-17 13:25:47 -06001950 return command.CommandResult()
1951
1952 def testVblock(self):
1953 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001954 self._hash_data = False
Simon Glass5dc22cf2025-02-03 09:26:42 -07001955 command.TEST_RESULT = self._HandleVblockCommand
Simon Glass5c350162018-07-17 13:25:47 -06001956 entry_args = {
1957 'keydir': 'devkeys',
1958 }
Simon Glass511f6582018-10-01 12:22:30 -06001959 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001960 entry_args=entry_args)
1961 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1962 self.assertEqual(expected, data)
1963
1964 def testVblockNoContent(self):
1965 """Test we detect a vblock which has no content to sign"""
1966 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001967 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001968 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001969 'property', str(e.exception))
1970
1971 def testVblockBadPhandle(self):
1972 """Test that we detect a vblock with an invalid phandle in contents"""
1973 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001974 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001975 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1976 '1000', str(e.exception))
1977
1978 def testVblockBadEntry(self):
1979 """Test that we detect an entry that points to a non-entry"""
1980 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001981 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001982 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1983 "'other'", str(e.exception))
1984
Simon Glass220c6222021-01-06 21:35:17 -07001985 def testVblockContent(self):
1986 """Test that the vblock signs the right data"""
1987 self._hash_data = True
Simon Glass5dc22cf2025-02-03 09:26:42 -07001988 command.TEST_RESULT = self._HandleVblockCommand
Simon Glass220c6222021-01-06 21:35:17 -07001989 entry_args = {
1990 'keydir': 'devkeys',
1991 }
1992 data = self._DoReadFileDtb(
1993 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1994 entry_args=entry_args)[0]
1995 hashlen = 32 # SHA256 hash is 32 bytes
1996 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1997 hashval = data[-hashlen:]
1998 dtb = data[len(U_BOOT_DATA):-hashlen]
1999
2000 expected_data = U_BOOT_DATA + dtb
2001
2002 # The hashval should be a hash of the dtb
2003 m = hashlib.sha256()
2004 m.update(expected_data)
2005 expected_hashval = m.digest()
2006 self.assertEqual(expected_hashval, hashval)
2007
Simon Glass66152ce2022-01-09 20:14:09 -07002008 def testVblockMissing(self):
2009 """Test that binman still produces an image if futility is missing"""
2010 entry_args = {
2011 'keydir': 'devkeys',
2012 }
2013 with test_util.capture_sys_output() as (_, stderr):
2014 self._DoTestFile('074_vblock.dts',
2015 force_missing_bintools='futility',
2016 entry_args=entry_args)
2017 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07002018 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07002019
Simon Glass8425a1f2018-07-17 13:25:48 -06002020 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06002021 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06002022 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06002023 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06002024 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06002025 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
2026
Simon Glass24b97442018-07-17 13:25:51 -06002027 def testUsesPos(self):
2028 """Test that the 'pos' property cannot be used anymore"""
2029 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002030 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06002031 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
2032 "'pos'", str(e.exception))
2033
Simon Glass274bf092018-09-14 04:57:08 -06002034 def testFillZero(self):
2035 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06002036 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07002037 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06002038
Simon Glass267de432018-09-14 04:57:09 -06002039 def testTextMissing(self):
2040 """Test for a text entry type where there is no text"""
2041 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002042 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06002043 self.assertIn("Node '/binman/text': No value provided for text label "
2044 "'test-id'", str(e.exception))
2045
Simon Glassed40e962018-09-14 04:57:10 -06002046 def testPackStart16Tpl(self):
2047 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06002048 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06002049 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
2050
Simon Glass3b376c32018-09-14 04:57:12 -06002051 def testSelectImage(self):
2052 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06002053 expected = 'Skipping images: image1'
2054
2055 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06002056 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06002057 with test_util.capture_sys_output() as (stdout, stderr):
2058 retcode = self._DoTestFile('006_dual_image.dts',
2059 verbosity=verbosity,
2060 images=['image2'])
2061 self.assertEqual(0, retcode)
2062 if verbosity:
2063 self.assertIn(expected, stdout.getvalue())
2064 else:
2065 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06002066
Simon Glass80025522022-01-29 14:14:04 -07002067 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2068 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06002069 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06002070
Simon Glasse219aa42018-09-14 04:57:24 -06002071 def testUpdateFdtAll(self):
2072 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06002073 self._SetupSplElf()
2074 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06002075 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06002076
2077 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06002078 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002079 'image-pos': 0,
2080 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06002081 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002082 'section:image-pos': 0,
2083 'section:size': 565,
2084 'section/u-boot-dtb:offset': 0,
2085 'section/u-boot-dtb:image-pos': 0,
2086 'section/u-boot-dtb:size': 565,
2087 'u-boot-spl-dtb:offset': 565,
2088 'u-boot-spl-dtb:image-pos': 565,
2089 'u-boot-spl-dtb:size': 585,
2090 'u-boot-tpl-dtb:offset': 1150,
2091 'u-boot-tpl-dtb:image-pos': 1150,
2092 'u-boot-tpl-dtb:size': 585,
2093 'u-boot-vpl-dtb:image-pos': 1735,
2094 'u-boot-vpl-dtb:offset': 1735,
2095 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002096 }
2097
2098 # We expect three device-tree files in the output, one after the other.
2099 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2100 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2101 # main U-Boot tree. All three should have the same postions and offset.
2102 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002103 self.maxDiff = None
2104 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002105 dtb = fdt.Fdt.FromData(data[start:])
2106 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002107 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002108 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002109 expected = dict(base_expected)
2110 if item:
2111 expected[item] = 0
2112 self.assertEqual(expected, props)
2113 start += dtb._fdt_obj.totalsize()
2114
2115 def testUpdateFdtOutput(self):
2116 """Test that output DTB files are updated"""
2117 try:
Simon Glass511f6582018-10-01 12:22:30 -06002118 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002119 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2120
2121 # Unfortunately, compiling a source file always results in a file
2122 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002123 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002124 # binman as a file called u-boot.dtb. To fix this, copy the file
2125 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002126 start = 0
2127 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002128 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002129 dtb = fdt.Fdt.FromData(data[start:])
2130 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002131 pathname = tools.get_output_filename(os.path.split(fname)[1])
2132 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002133 name = os.path.split(fname)[0]
2134
2135 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002136 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002137 else:
2138 orig_indata = dtb_data
2139 self.assertNotEqual(outdata, orig_indata,
2140 "Expected output file '%s' be updated" % pathname)
2141 self.assertEqual(outdata, data[start:start + size],
2142 "Expected output file '%s' to match output image" %
2143 pathname)
2144 start += size
2145 finally:
2146 self._ResetDtbs()
2147
Simon Glass7ba33592018-09-14 04:57:26 -06002148 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002149 bintool = self.comp_bintools['lz4']
2150 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002151
2152 def testCompress(self):
2153 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002154 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002155 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002156 use_real_dtb=True, update_dtb=True)
2157 dtb = fdt.Fdt(out_dtb_fname)
2158 dtb.Scan()
2159 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2160 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00002161 self.assertEqual(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002162
2163 # Do a sanity check on various fields
2164 image = control.images['image']
2165 entries = image.GetEntries()
2166 self.assertEqual(1, len(entries))
2167
2168 entry = entries['blob']
2169 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2170 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2171 orig = self._decompress(entry.data)
2172 self.assertEqual(orig, entry.uncomp_data)
2173
Simon Glass72eeff12020-10-26 17:40:16 -06002174 self.assertEqual(image.data, entry.data)
2175
Simon Glass7ba33592018-09-14 04:57:26 -06002176 expected = {
2177 'blob:uncomp-size': len(COMPRESS_DATA),
2178 'blob:size': len(data),
2179 'size': len(data),
2180 }
2181 self.assertEqual(expected, props)
2182
Simon Glassac6328c2018-09-14 04:57:28 -06002183 def testFiles(self):
2184 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002185 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002186 self.assertEqual(FILES_DATA, data)
2187
2188 def testFilesCompress(self):
2189 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002190 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002191 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002192
2193 image = control.images['image']
2194 entries = image.GetEntries()
2195 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002196 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002197
Simon Glass303f62f2019-05-17 22:00:46 -06002198 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002199 for i in range(1, 3):
2200 key = '%d.dat' % i
2201 start = entries[key].image_pos
2202 len = entries[key].size
2203 chunk = data[start:start + len]
2204 orig += self._decompress(chunk)
2205
2206 self.assertEqual(FILES_DATA, orig)
2207
2208 def testFilesMissing(self):
2209 """Test missing files"""
2210 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002211 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002212 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2213 'no files', str(e.exception))
2214
2215 def testFilesNoPattern(self):
2216 """Test missing files"""
2217 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002218 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002219 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2220 str(e.exception))
2221
Simon Glassdd156a42022-03-05 20:18:59 -07002222 def testExtendSize(self):
2223 """Test an extending entry"""
2224 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002225 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002226 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2227 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2228 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2229 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002230 self.assertEqual(expect, data)
2231 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700223200000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600223300000000 00000000 00000008 fill
223400000008 00000008 00000004 u-boot
22350000000c 0000000c 00000004 section
22360000000c 00000000 00000003 intel-mrc
223700000010 00000010 00000004 u-boot2
223800000014 00000014 0000000c section2
223900000014 00000000 00000008 fill
22400000001c 00000008 00000004 u-boot
224100000020 00000020 00000008 fill2
2242''', map_data)
2243
Simon Glassdd156a42022-03-05 20:18:59 -07002244 def testExtendSizeBad(self):
2245 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002246 with test_util.capture_sys_output() as (stdout, stderr):
2247 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002248 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002249 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2250 'expanding entry', str(e.exception))
2251
Simon Glassae7cf032018-09-14 04:57:31 -06002252 def testHash(self):
2253 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002254 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002255 use_real_dtb=True, update_dtb=True)
2256 dtb = fdt.Fdt(out_dtb_fname)
2257 dtb.Scan()
2258 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2259 m = hashlib.sha256()
2260 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002261 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002262
2263 def testHashNoAlgo(self):
2264 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002265 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002266 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2267 'hash node', str(e.exception))
2268
2269 def testHashBadAlgo(self):
2270 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002271 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002272 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002273 str(e.exception))
2274
2275 def testHashSection(self):
2276 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002277 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002278 use_real_dtb=True, update_dtb=True)
2279 dtb = fdt.Fdt(out_dtb_fname)
2280 dtb.Scan()
2281 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2282 m = hashlib.sha256()
2283 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002284 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002285 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002286
Simon Glass3fb4f422018-09-14 04:57:32 -06002287 def testPackUBootTplMicrocode(self):
2288 """Test that x86 microcode can be handled correctly in TPL
2289
2290 We expect to see the following in the image, in order:
2291 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2292 place
2293 u-boot-tpl.dtb with the microcode removed
2294 the microcode
2295 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002296 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002297 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002298 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002299 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2300 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002301
Simon Glassc64aea52018-09-14 04:57:34 -06002302 def testFmapX86(self):
2303 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002304 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002305 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002306 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002307 self.assertEqual(expected, data[:32])
2308 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2309
2310 self.assertEqual(0x100, fhdr.image_size)
Simon Glassed836ac2025-02-26 09:26:17 -07002311 base = (1 << 32) - 0x100
Simon Glassc64aea52018-09-14 04:57:34 -06002312
Simon Glassed836ac2025-02-26 09:26:17 -07002313 self.assertEqual(base, fentries[0].offset)
Simon Glassc64aea52018-09-14 04:57:34 -06002314 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002315 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002316
Simon Glassed836ac2025-02-26 09:26:17 -07002317 self.assertEqual(base + 4, fentries[1].offset)
Simon Glassc64aea52018-09-14 04:57:34 -06002318 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002319 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002320
Simon Glassed836ac2025-02-26 09:26:17 -07002321 self.assertEqual(base + 32, fentries[2].offset)
Simon Glassc64aea52018-09-14 04:57:34 -06002322 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2323 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002324 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002325
2326 def testFmapX86Section(self):
2327 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002328 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002329 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002330 self.assertEqual(expected, data[:32])
2331 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2332
Simon Glassb1d414c2021-04-03 11:05:10 +13002333 self.assertEqual(0x180, fhdr.image_size)
Simon Glassed836ac2025-02-26 09:26:17 -07002334 base = (1 << 32) - 0x180
Simon Glassb1d414c2021-04-03 11:05:10 +13002335 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002336 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002337
Simon Glass82059c22021-04-03 11:05:09 +13002338 fentry = next(fiter)
2339 self.assertEqual(b'U_BOOT', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002340 self.assertEqual(base, fentry.offset)
Simon Glass82059c22021-04-03 11:05:09 +13002341 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002342
Simon Glass82059c22021-04-03 11:05:09 +13002343 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002344 self.assertEqual(b'SECTION', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002345 self.assertEqual(base + 4, fentry.offset)
Simon Glassb1d414c2021-04-03 11:05:10 +13002346 self.assertEqual(0x20 + expect_size, fentry.size)
2347
2348 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002349 self.assertEqual(b'INTEL_MRC', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002350 self.assertEqual(base + 4, fentry.offset)
Simon Glass82059c22021-04-03 11:05:09 +13002351 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002352
Simon Glass82059c22021-04-03 11:05:09 +13002353 fentry = next(fiter)
2354 self.assertEqual(b'FMAP', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002355 self.assertEqual(base + 36, fentry.offset)
Simon Glass82059c22021-04-03 11:05:09 +13002356 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002357
Simon Glassb1714232018-09-14 04:57:35 -06002358 def testElf(self):
2359 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002360 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002361 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002362 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002363 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002364 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002365
Simon Glass0d673792019-07-08 13:18:25 -06002366 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002367 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002368 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002369 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002370 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002371 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002372
Simon Glasscd817d52018-09-14 04:57:36 -06002373 def testPackOverlapMap(self):
2374 """Test that overlapping regions are detected"""
2375 with test_util.capture_sys_output() as (stdout, stderr):
2376 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002377 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002378 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002379 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2380 stdout.getvalue())
2381
2382 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002383 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002384 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002385 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002386 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002387<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002388<none> 00000000 00000004 u-boot
2389<none> 00000003 00000004 u-boot-align
2390''', map_data)
2391
Simon Glass0d673792019-07-08 13:18:25 -06002392 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002393 """Test that an image with an Intel Reference code binary works"""
2394 data = self._DoReadFile('100_intel_refcode.dts')
2395 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2396
Simon Glasseb023b32019-04-25 21:58:39 -06002397 def testSectionOffset(self):
2398 """Tests use of a section with an offset"""
2399 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2400 map=True)
2401 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700240200000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600240300000004 00000004 00000010 section@0
240400000004 00000000 00000004 u-boot
240500000018 00000018 00000010 section@1
240600000018 00000000 00000004 u-boot
24070000002c 0000002c 00000004 section@2
24080000002c 00000000 00000004 u-boot
2409''', map_data)
2410 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002411 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2412 tools.get_bytes(0x21, 12) +
2413 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2414 tools.get_bytes(0x61, 12) +
2415 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2416 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002417
Simon Glass1de34482019-07-08 13:18:53 -06002418 def testCbfsRaw(self):
2419 """Test base handling of a Coreboot Filesystem (CBFS)
2420
2421 The exact contents of the CBFS is verified by similar tests in
2422 cbfs_util_test.py. The tests here merely check that the files added to
2423 the CBFS can be found in the final image.
2424 """
2425 data = self._DoReadFile('102_cbfs_raw.dts')
2426 size = 0xb0
2427
2428 cbfs = cbfs_util.CbfsReader(data)
2429 self.assertEqual(size, cbfs.rom_size)
2430
2431 self.assertIn('u-boot-dtb', cbfs.files)
2432 cfile = cbfs.files['u-boot-dtb']
2433 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2434
2435 def testCbfsArch(self):
2436 """Test on non-x86 architecture"""
2437 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2438 size = 0x100
2439
2440 cbfs = cbfs_util.CbfsReader(data)
2441 self.assertEqual(size, cbfs.rom_size)
2442
2443 self.assertIn('u-boot-dtb', cbfs.files)
2444 cfile = cbfs.files['u-boot-dtb']
2445 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2446
2447 def testCbfsStage(self):
2448 """Tests handling of a Coreboot Filesystem (CBFS)"""
2449 if not elf.ELF_TOOLS:
2450 self.skipTest('Python elftools not available')
2451 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2452 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2453 size = 0xb0
2454
2455 data = self._DoReadFile('104_cbfs_stage.dts')
2456 cbfs = cbfs_util.CbfsReader(data)
2457 self.assertEqual(size, cbfs.rom_size)
2458
2459 self.assertIn('u-boot', cbfs.files)
2460 cfile = cbfs.files['u-boot']
2461 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2462
2463 def testCbfsRawCompress(self):
2464 """Test handling of compressing raw files"""
2465 self._CheckLz4()
2466 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2467 size = 0x140
2468
2469 cbfs = cbfs_util.CbfsReader(data)
2470 self.assertIn('u-boot', cbfs.files)
2471 cfile = cbfs.files['u-boot']
2472 self.assertEqual(COMPRESS_DATA, cfile.data)
2473
2474 def testCbfsBadArch(self):
2475 """Test handling of a bad architecture"""
2476 with self.assertRaises(ValueError) as e:
2477 self._DoReadFile('106_cbfs_bad_arch.dts')
2478 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2479
2480 def testCbfsNoSize(self):
2481 """Test handling of a missing size property"""
2482 with self.assertRaises(ValueError) as e:
2483 self._DoReadFile('107_cbfs_no_size.dts')
2484 self.assertIn('entry must have a size property', str(e.exception))
2485
Simon Glass3e28f4f2021-11-23 11:03:54 -07002486 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002487 """Test handling of a CBFS entry which does not provide contentsy"""
2488 with self.assertRaises(ValueError) as e:
2489 self._DoReadFile('108_cbfs_no_contents.dts')
2490 self.assertIn('Could not complete processing of contents',
2491 str(e.exception))
2492
2493 def testCbfsBadCompress(self):
2494 """Test handling of a bad architecture"""
2495 with self.assertRaises(ValueError) as e:
2496 self._DoReadFile('109_cbfs_bad_compress.dts')
2497 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2498 str(e.exception))
2499
2500 def testCbfsNamedEntries(self):
2501 """Test handling of named entries"""
2502 data = self._DoReadFile('110_cbfs_name.dts')
2503
2504 cbfs = cbfs_util.CbfsReader(data)
2505 self.assertIn('FRED', cbfs.files)
2506 cfile1 = cbfs.files['FRED']
2507 self.assertEqual(U_BOOT_DATA, cfile1.data)
2508
2509 self.assertIn('hello', cbfs.files)
2510 cfile2 = cbfs.files['hello']
2511 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2512
Simon Glass759af872019-07-08 13:18:54 -06002513 def _SetupIfwi(self, fname):
2514 """Set up to run an IFWI test
2515
2516 Args:
2517 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2518 """
2519 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002520 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002521
2522 # Intel Integrated Firmware Image (IFWI) file
2523 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2524 data = fd.read()
2525 TestFunctional._MakeInputFile(fname,data)
2526
2527 def _CheckIfwi(self, data):
2528 """Check that an image with an IFWI contains the correct output
2529
2530 Args:
2531 data: Conents of output file
2532 """
Simon Glass80025522022-01-29 14:14:04 -07002533 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002534 if data[:0x1000] != expected_desc:
2535 self.fail('Expected descriptor binary at start of image')
2536
2537 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002538 image_fname = tools.get_output_filename('image.bin')
2539 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002540 ifwitool = bintool.Bintool.create('ifwitool')
2541 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002542
Simon Glass80025522022-01-29 14:14:04 -07002543 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002544 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002545
2546 def testPackX86RomIfwi(self):
2547 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2548 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002549 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002550 self._CheckIfwi(data)
2551
2552 def testPackX86RomIfwiNoDesc(self):
2553 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2554 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002555 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002556 self._CheckIfwi(data)
2557
2558 def testPackX86RomIfwiNoData(self):
2559 """Test that an x86 ROM with IFWI handles missing data"""
2560 self._SetupIfwi('ifwi.bin')
2561 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002562 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002563 self.assertIn('Could not complete processing of contents',
2564 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002565
Simon Glass66152ce2022-01-09 20:14:09 -07002566 def testIfwiMissing(self):
2567 """Test that binman still produces an image if ifwitool is missing"""
2568 self._SetupIfwi('fitimage.bin')
2569 with test_util.capture_sys_output() as (_, stderr):
2570 self._DoTestFile('111_x86_rom_ifwi.dts',
2571 force_missing_bintools='ifwitool')
2572 err = stderr.getvalue()
2573 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002574 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002575
Simon Glassc2f1aed2019-07-08 13:18:56 -06002576 def testCbfsOffset(self):
2577 """Test a CBFS with files at particular offsets
2578
2579 Like all CFBS tests, this is just checking the logic that calls
2580 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2581 """
2582 data = self._DoReadFile('114_cbfs_offset.dts')
2583 size = 0x200
2584
2585 cbfs = cbfs_util.CbfsReader(data)
2586 self.assertEqual(size, cbfs.rom_size)
2587
2588 self.assertIn('u-boot', cbfs.files)
2589 cfile = cbfs.files['u-boot']
2590 self.assertEqual(U_BOOT_DATA, cfile.data)
2591 self.assertEqual(0x40, cfile.cbfs_offset)
2592
2593 self.assertIn('u-boot-dtb', cbfs.files)
2594 cfile2 = cbfs.files['u-boot-dtb']
2595 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2596 self.assertEqual(0x140, cfile2.cbfs_offset)
2597
Simon Glass0f621332019-07-08 14:25:27 -06002598 def testFdtmap(self):
2599 """Test an FDT map can be inserted in the image"""
2600 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2601 fdtmap_data = data[len(U_BOOT_DATA):]
2602 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002603 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002604 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002605
2606 fdt_data = fdtmap_data[16:]
2607 dtb = fdt.Fdt.FromData(fdt_data)
2608 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002609 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002610 self.assertEqual({
2611 'image-pos': 0,
2612 'offset': 0,
2613 'u-boot:offset': 0,
2614 'u-boot:size': len(U_BOOT_DATA),
2615 'u-boot:image-pos': 0,
2616 'fdtmap:image-pos': 4,
2617 'fdtmap:offset': 4,
2618 'fdtmap:size': len(fdtmap_data),
2619 'size': len(data),
2620 }, props)
2621
2622 def testFdtmapNoMatch(self):
2623 """Check handling of an FDT map when the section cannot be found"""
2624 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2625
2626 # Mangle the section name, which should cause a mismatch between the
2627 # correct FDT path and the one expected by the section
2628 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002629 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002630 entries = image.GetEntries()
2631 fdtmap = entries['fdtmap']
2632 with self.assertRaises(ValueError) as e:
2633 fdtmap._GetFdtmap()
2634 self.assertIn("Cannot locate node for path '/binman-suffix'",
2635 str(e.exception))
2636
Simon Glasscec34ba2019-07-08 14:25:28 -06002637 def testFdtmapHeader(self):
2638 """Test an FDT map and image header can be inserted in the image"""
2639 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2640 fdtmap_pos = len(U_BOOT_DATA)
2641 fdtmap_data = data[fdtmap_pos:]
2642 fdt_data = fdtmap_data[16:]
2643 dtb = fdt.Fdt.FromData(fdt_data)
2644 fdt_size = dtb.GetFdtObj().totalsize()
2645 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002646 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002647 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2648 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2649
2650 def testFdtmapHeaderStart(self):
2651 """Test an image header can be inserted at the image start"""
2652 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2653 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2654 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002655 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002656 offset = struct.unpack('<I', hdr_data[4:])[0]
2657 self.assertEqual(fdtmap_pos, offset)
2658
2659 def testFdtmapHeaderPos(self):
2660 """Test an image header can be inserted at a chosen position"""
2661 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2662 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2663 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002664 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002665 offset = struct.unpack('<I', hdr_data[4:])[0]
2666 self.assertEqual(fdtmap_pos, offset)
2667
2668 def testHeaderMissingFdtmap(self):
2669 """Test an image header requires an fdtmap"""
2670 with self.assertRaises(ValueError) as e:
2671 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2672 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2673 str(e.exception))
2674
2675 def testHeaderNoLocation(self):
2676 """Test an image header with a no specified location is detected"""
2677 with self.assertRaises(ValueError) as e:
2678 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2679 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2680 str(e.exception))
2681
Simon Glasse61b6f62019-07-08 14:25:37 -06002682 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002683 """Test extending an entry after it is packed"""
2684 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002685 self.assertEqual(b'aaa', data[:3])
2686 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2687 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002688
Simon Glassdd156a42022-03-05 20:18:59 -07002689 def testEntryExtendBad(self):
2690 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002691 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002692 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002693 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002694 str(e.exception))
2695
Simon Glassdd156a42022-03-05 20:18:59 -07002696 def testEntryExtendSection(self):
2697 """Test extending an entry within a section after it is packed"""
2698 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002699 self.assertEqual(b'aaa', data[:3])
2700 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2701 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002702
Simon Glass90d29682019-07-08 14:25:38 -06002703 def testCompressDtb(self):
2704 """Test that compress of device-tree files is supported"""
2705 self._CheckLz4()
2706 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2707 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2708 comp_data = data[len(U_BOOT_DATA):]
2709 orig = self._decompress(comp_data)
2710 dtb = fdt.Fdt.FromData(orig)
2711 dtb.Scan()
2712 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2713 expected = {
2714 'u-boot:size': len(U_BOOT_DATA),
2715 'u-boot-dtb:uncomp-size': len(orig),
2716 'u-boot-dtb:size': len(comp_data),
2717 'size': len(data),
2718 }
2719 self.assertEqual(expected, props)
2720
Simon Glass151bbbf2019-07-08 14:25:41 -06002721 def testCbfsUpdateFdt(self):
2722 """Test that we can update the device tree with CBFS offset/size info"""
2723 self._CheckLz4()
2724 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2725 update_dtb=True)
2726 dtb = fdt.Fdt(out_dtb_fname)
2727 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002728 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002729 del props['cbfs/u-boot:size']
2730 self.assertEqual({
2731 'offset': 0,
2732 'size': len(data),
2733 'image-pos': 0,
2734 'cbfs:offset': 0,
2735 'cbfs:size': len(data),
2736 'cbfs:image-pos': 0,
Simon Glassfa144222023-10-14 14:40:28 -06002737 'cbfs/u-boot:offset': 0x30,
Simon Glass151bbbf2019-07-08 14:25:41 -06002738 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002739 'cbfs/u-boot:image-pos': 0x30,
2740 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002741 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002742 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002743 }, props)
2744
Simon Glass3c9b4f22019-07-08 14:25:42 -06002745 def testCbfsBadType(self):
2746 """Test an image header with a no specified location is detected"""
2747 with self.assertRaises(ValueError) as e:
2748 self._DoReadFile('126_cbfs_bad_type.dts')
2749 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2750
Simon Glass6b156f82019-07-08 14:25:43 -06002751 def testList(self):
2752 """Test listing the files in an image"""
2753 self._CheckLz4()
2754 data = self._DoReadFile('127_list.dts')
2755 image = control.images['image']
2756 entries = image.BuildEntryList()
2757 self.assertEqual(7, len(entries))
2758
2759 ent = entries[0]
2760 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002761 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002762 self.assertEqual('section', ent.etype)
2763 self.assertEqual(len(data), ent.size)
2764 self.assertEqual(0, ent.image_pos)
2765 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002766 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002767
2768 ent = entries[1]
2769 self.assertEqual(1, ent.indent)
2770 self.assertEqual('u-boot', ent.name)
2771 self.assertEqual('u-boot', ent.etype)
2772 self.assertEqual(len(U_BOOT_DATA), ent.size)
2773 self.assertEqual(0, ent.image_pos)
2774 self.assertEqual(None, ent.uncomp_size)
2775 self.assertEqual(0, ent.offset)
2776
2777 ent = entries[2]
2778 self.assertEqual(1, ent.indent)
2779 self.assertEqual('section', ent.name)
2780 self.assertEqual('section', ent.etype)
2781 section_size = ent.size
2782 self.assertEqual(0x100, ent.image_pos)
2783 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002784 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002785
2786 ent = entries[3]
2787 self.assertEqual(2, ent.indent)
2788 self.assertEqual('cbfs', ent.name)
2789 self.assertEqual('cbfs', ent.etype)
2790 self.assertEqual(0x400, ent.size)
2791 self.assertEqual(0x100, ent.image_pos)
2792 self.assertEqual(None, ent.uncomp_size)
2793 self.assertEqual(0, ent.offset)
2794
2795 ent = entries[4]
2796 self.assertEqual(3, ent.indent)
2797 self.assertEqual('u-boot', ent.name)
2798 self.assertEqual('u-boot', ent.etype)
2799 self.assertEqual(len(U_BOOT_DATA), ent.size)
2800 self.assertEqual(0x138, ent.image_pos)
2801 self.assertEqual(None, ent.uncomp_size)
2802 self.assertEqual(0x38, ent.offset)
2803
2804 ent = entries[5]
2805 self.assertEqual(3, ent.indent)
2806 self.assertEqual('u-boot-dtb', ent.name)
2807 self.assertEqual('text', ent.etype)
2808 self.assertGreater(len(COMPRESS_DATA), ent.size)
2809 self.assertEqual(0x178, ent.image_pos)
2810 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2811 self.assertEqual(0x78, ent.offset)
2812
2813 ent = entries[6]
2814 self.assertEqual(2, ent.indent)
2815 self.assertEqual('u-boot-dtb', ent.name)
2816 self.assertEqual('u-boot-dtb', ent.etype)
2817 self.assertEqual(0x500, ent.image_pos)
2818 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2819 dtb_size = ent.size
2820 # Compressing this data expands it since headers are added
2821 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2822 self.assertEqual(0x400, ent.offset)
2823
2824 self.assertEqual(len(data), 0x100 + section_size)
2825 self.assertEqual(section_size, 0x400 + dtb_size)
2826
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002827 def testFindFdtmap(self):
2828 """Test locating an FDT map in an image"""
2829 self._CheckLz4()
2830 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2831 image = control.images['image']
2832 entries = image.GetEntries()
2833 entry = entries['fdtmap']
2834 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2835
2836 def testFindFdtmapMissing(self):
2837 """Test failing to locate an FDP map"""
2838 data = self._DoReadFile('005_simple.dts')
2839 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2840
Simon Glassed39a3c2019-07-08 14:25:45 -06002841 def testFindImageHeader(self):
2842 """Test locating a image header"""
2843 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002844 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002845 image = control.images['image']
2846 entries = image.GetEntries()
2847 entry = entries['fdtmap']
2848 # The header should point to the FDT map
2849 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2850
2851 def testFindImageHeaderStart(self):
2852 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002853 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002854 image = control.images['image']
2855 entries = image.GetEntries()
2856 entry = entries['fdtmap']
2857 # The header should point to the FDT map
2858 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2859
2860 def testFindImageHeaderMissing(self):
2861 """Test failing to locate an image header"""
2862 data = self._DoReadFile('005_simple.dts')
2863 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2864
Simon Glassb8424fa2019-07-08 14:25:46 -06002865 def testReadImage(self):
2866 """Test reading an image and accessing its FDT map"""
2867 self._CheckLz4()
2868 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002869 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002870 orig_image = control.images['image']
2871 image = Image.FromFile(image_fname)
2872 self.assertEqual(orig_image.GetEntries().keys(),
2873 image.GetEntries().keys())
2874
2875 orig_entry = orig_image.GetEntries()['fdtmap']
2876 entry = image.GetEntries()['fdtmap']
Brandon Maiera657bc62024-06-04 16:16:05 +00002877 self.assertEqual(orig_entry.offset, entry.offset)
2878 self.assertEqual(orig_entry.size, entry.size)
2879 self.assertEqual(orig_entry.image_pos, entry.image_pos)
Simon Glassb8424fa2019-07-08 14:25:46 -06002880
2881 def testReadImageNoHeader(self):
2882 """Test accessing an image's FDT map without an image header"""
2883 self._CheckLz4()
2884 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002885 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002886 image = Image.FromFile(image_fname)
2887 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002888 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002889
2890 def testReadImageFail(self):
2891 """Test failing to read an image image's FDT map"""
2892 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002893 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002894 with self.assertRaises(ValueError) as e:
2895 image = Image.FromFile(image_fname)
2896 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002897
Simon Glassb2fd11d2019-07-08 14:25:48 -06002898 def testListCmd(self):
2899 """Test listing the files in an image using an Fdtmap"""
2900 self._CheckLz4()
2901 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2902
2903 # lz4 compression size differs depending on the version
2904 image = control.images['image']
2905 entries = image.GetEntries()
2906 section_size = entries['section'].size
2907 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2908 fdtmap_offset = entries['fdtmap'].offset
2909
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002910 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002911 try:
2912 tmpdir, updated_fname = self._SetupImageInTmpdir()
2913 with test_util.capture_sys_output() as (stdout, stderr):
2914 self._DoBinman('ls', '-i', updated_fname)
2915 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002916 if tmpdir:
2917 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002918 lines = stdout.getvalue().splitlines()
2919 expected = [
2920'Name Image-pos Size Entry-type Offset Uncomp-size',
2921'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002922'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002923' u-boot 0 4 u-boot 0',
2924' section 100 %x section 100' % section_size,
2925' cbfs 100 400 cbfs 0',
Simon Glassfa144222023-10-14 14:40:28 -06002926' u-boot 120 4 u-boot 20',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002927' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002928' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002929' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002930 (fdtmap_offset, fdtmap_offset),
2931' image-header bf8 8 image-header bf8',
2932 ]
2933 self.assertEqual(expected, lines)
2934
2935 def testListCmdFail(self):
2936 """Test failing to list an image"""
2937 self._DoReadFile('005_simple.dts')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002938 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002939 try:
2940 tmpdir, updated_fname = self._SetupImageInTmpdir()
2941 with self.assertRaises(ValueError) as e:
2942 self._DoBinman('ls', '-i', updated_fname)
2943 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002944 if tmpdir:
2945 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002946 self.assertIn("Cannot find FDT map in image", str(e.exception))
2947
2948 def _RunListCmd(self, paths, expected):
2949 """List out entries and check the result
2950
2951 Args:
2952 paths: List of paths to pass to the list command
2953 expected: Expected list of filenames to be returned, in order
2954 """
2955 self._CheckLz4()
2956 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002957 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002958 image = Image.FromFile(image_fname)
2959 lines = image.GetListEntries(paths)[1]
2960 files = [line[0].strip() for line in lines[1:]]
2961 self.assertEqual(expected, files)
2962
2963 def testListCmdSection(self):
2964 """Test listing the files in a section"""
2965 self._RunListCmd(['section'],
2966 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2967
2968 def testListCmdFile(self):
2969 """Test listing a particular file"""
2970 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2971
2972 def testListCmdWildcard(self):
2973 """Test listing a wildcarded file"""
2974 self._RunListCmd(['*boot*'],
2975 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2976
2977 def testListCmdWildcardMulti(self):
2978 """Test listing a wildcarded file"""
2979 self._RunListCmd(['*cb*', '*head*'],
2980 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2981
2982 def testListCmdEmpty(self):
2983 """Test listing a wildcarded file"""
2984 self._RunListCmd(['nothing'], [])
2985
2986 def testListCmdPath(self):
2987 """Test listing the files in a sub-entry of a section"""
2988 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2989
Simon Glass4c613bf2019-07-08 14:25:50 -06002990 def _RunExtractCmd(self, entry_name, decomp=True):
2991 """Extract an entry from an image
2992
2993 Args:
2994 entry_name: Entry name to extract
2995 decomp: True to decompress the data if compressed, False to leave
2996 it in its raw uncompressed format
2997
2998 Returns:
2999 data from entry
3000 """
3001 self._CheckLz4()
3002 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003003 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06003004 return control.ReadEntry(image_fname, entry_name, decomp)
3005
3006 def testExtractSimple(self):
3007 """Test extracting a single file"""
3008 data = self._RunExtractCmd('u-boot')
3009 self.assertEqual(U_BOOT_DATA, data)
3010
Simon Glass980a2842019-07-08 14:25:52 -06003011 def testExtractSection(self):
3012 """Test extracting the files in a section"""
3013 data = self._RunExtractCmd('section')
3014 cbfs_data = data[:0x400]
3015 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06003016 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06003017 dtb_data = data[0x400:]
3018 dtb = self._decompress(dtb_data)
3019 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3020
3021 def testExtractCompressed(self):
3022 """Test extracting compressed data"""
3023 data = self._RunExtractCmd('section/u-boot-dtb')
3024 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3025
3026 def testExtractRaw(self):
3027 """Test extracting compressed data without decompressing it"""
3028 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
3029 dtb = self._decompress(data)
3030 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3031
3032 def testExtractCbfs(self):
3033 """Test extracting CBFS data"""
3034 data = self._RunExtractCmd('section/cbfs/u-boot')
3035 self.assertEqual(U_BOOT_DATA, data)
3036
3037 def testExtractCbfsCompressed(self):
3038 """Test extracting CBFS compressed data"""
3039 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
3040 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3041
3042 def testExtractCbfsRaw(self):
3043 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003044 bintool = self.comp_bintools['lzma_alone']
3045 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06003046 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003047 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06003048 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3049
Simon Glass4c613bf2019-07-08 14:25:50 -06003050 def testExtractBadEntry(self):
3051 """Test extracting a bad section path"""
3052 with self.assertRaises(ValueError) as e:
3053 self._RunExtractCmd('section/does-not-exist')
3054 self.assertIn("Entry 'does-not-exist' not found in '/section'",
3055 str(e.exception))
3056
3057 def testExtractMissingFile(self):
3058 """Test extracting file that does not exist"""
3059 with self.assertRaises(IOError) as e:
3060 control.ReadEntry('missing-file', 'name')
3061
3062 def testExtractBadFile(self):
3063 """Test extracting an invalid file"""
3064 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07003065 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06003066 with self.assertRaises(ValueError) as e:
3067 control.ReadEntry(fname, 'name')
3068
Simon Glass980a2842019-07-08 14:25:52 -06003069 def testExtractCmd(self):
3070 """Test extracting a file fron an image on the command line"""
3071 self._CheckLz4()
3072 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06003073 fname = os.path.join(self._indir, 'output.extact')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003074 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06003075 try:
3076 tmpdir, updated_fname = self._SetupImageInTmpdir()
3077 with test_util.capture_sys_output() as (stdout, stderr):
3078 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3079 '-f', fname)
3080 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003081 if tmpdir:
3082 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07003083 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003084 self.assertEqual(U_BOOT_DATA, data)
3085
3086 def testExtractOneEntry(self):
3087 """Test extracting a single entry fron an image """
3088 self._CheckLz4()
3089 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003090 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003091 fname = os.path.join(self._indir, 'output.extact')
3092 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003093 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003094 self.assertEqual(U_BOOT_DATA, data)
3095
3096 def _CheckExtractOutput(self, decomp):
3097 """Helper to test file output with and without decompression
3098
3099 Args:
3100 decomp: True to decompress entry data, False to output it raw
3101 """
3102 def _CheckPresent(entry_path, expect_data, expect_size=None):
3103 """Check and remove expected file
3104
3105 This checks the data/size of a file and removes the file both from
3106 the outfiles set and from the output directory. Once all files are
3107 processed, both the set and directory should be empty.
3108
3109 Args:
3110 entry_path: Entry path
3111 expect_data: Data to expect in file, or None to skip check
3112 expect_size: Size of data to expect in file, or None to skip
3113 """
3114 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003115 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003116 os.remove(path)
3117 if expect_data:
3118 self.assertEqual(expect_data, data)
3119 elif expect_size:
3120 self.assertEqual(expect_size, len(data))
3121 outfiles.remove(path)
3122
3123 def _CheckDirPresent(name):
3124 """Remove expected directory
3125
3126 This gives an error if the directory does not exist as expected
3127
3128 Args:
3129 name: Name of directory to remove
3130 """
3131 path = os.path.join(outdir, name)
3132 os.rmdir(path)
3133
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 outdir = os.path.join(self._indir, 'extract')
3137 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3138
3139 # Create a set of all file that were output (should be 9)
3140 outfiles = set()
3141 for root, dirs, files in os.walk(outdir):
3142 outfiles |= set([os.path.join(root, fname) for fname in files])
3143 self.assertEqual(9, len(outfiles))
3144 self.assertEqual(9, len(einfos))
3145
3146 image = control.images['image']
3147 entries = image.GetEntries()
3148
3149 # Check the 9 files in various ways
3150 section = entries['section']
3151 section_entries = section.GetEntries()
3152 cbfs_entries = section_entries['cbfs'].GetEntries()
3153 _CheckPresent('u-boot', U_BOOT_DATA)
3154 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3155 dtb_len = EXTRACT_DTB_SIZE
3156 if not decomp:
3157 dtb_len = cbfs_entries['u-boot-dtb'].size
3158 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3159 if not decomp:
3160 dtb_len = section_entries['u-boot-dtb'].size
3161 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3162
3163 fdtmap = entries['fdtmap']
3164 _CheckPresent('fdtmap', fdtmap.data)
3165 hdr = entries['image-header']
3166 _CheckPresent('image-header', hdr.data)
3167
3168 _CheckPresent('section/root', section.data)
3169 cbfs = section_entries['cbfs']
3170 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003171 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003172 _CheckPresent('root', data)
3173
3174 # There should be no files left. Remove all the directories to check.
3175 # If there are any files/dirs remaining, one of these checks will fail.
3176 self.assertEqual(0, len(outfiles))
3177 _CheckDirPresent('section/cbfs')
3178 _CheckDirPresent('section')
3179 _CheckDirPresent('')
3180 self.assertFalse(os.path.exists(outdir))
3181
3182 def testExtractAllEntries(self):
3183 """Test extracting all entries"""
3184 self._CheckLz4()
3185 self._CheckExtractOutput(decomp=True)
3186
3187 def testExtractAllEntriesRaw(self):
3188 """Test extracting all entries without decompressing them"""
3189 self._CheckLz4()
3190 self._CheckExtractOutput(decomp=False)
3191
3192 def testExtractSelectedEntries(self):
3193 """Test extracting some entries"""
3194 self._CheckLz4()
3195 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003196 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003197 outdir = os.path.join(self._indir, 'extract')
3198 einfos = control.ExtractEntries(image_fname, None, outdir,
3199 ['*cb*', '*head*'])
3200
3201 # File output is tested by testExtractAllEntries(), so just check that
3202 # the expected entries are selected
3203 names = [einfo.name for einfo in einfos]
3204 self.assertEqual(names,
3205 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3206
3207 def testExtractNoEntryPaths(self):
3208 """Test extracting some entries"""
3209 self._CheckLz4()
3210 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003211 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003212 with self.assertRaises(ValueError) as e:
3213 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003214 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003215 str(e.exception))
3216
3217 def testExtractTooManyEntryPaths(self):
3218 """Test extracting some entries"""
3219 self._CheckLz4()
3220 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003221 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003222 with self.assertRaises(ValueError) as e:
3223 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003224 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003225 str(e.exception))
3226
Simon Glass52d06212019-07-08 14:25:53 -06003227 def testPackAlignSection(self):
3228 """Test that sections can have alignment"""
3229 self._DoReadFile('131_pack_align_section.dts')
3230
3231 self.assertIn('image', control.images)
3232 image = control.images['image']
3233 entries = image.GetEntries()
3234 self.assertEqual(3, len(entries))
3235
3236 # First u-boot
3237 self.assertIn('u-boot', entries)
3238 entry = entries['u-boot']
3239 self.assertEqual(0, entry.offset)
3240 self.assertEqual(0, entry.image_pos)
3241 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3242 self.assertEqual(len(U_BOOT_DATA), entry.size)
3243
3244 # Section0
3245 self.assertIn('section0', entries)
3246 section0 = entries['section0']
3247 self.assertEqual(0x10, section0.offset)
3248 self.assertEqual(0x10, section0.image_pos)
3249 self.assertEqual(len(U_BOOT_DATA), section0.size)
3250
3251 # Second u-boot
3252 section_entries = section0.GetEntries()
3253 self.assertIn('u-boot', section_entries)
3254 entry = section_entries['u-boot']
3255 self.assertEqual(0, entry.offset)
3256 self.assertEqual(0x10, entry.image_pos)
3257 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3258 self.assertEqual(len(U_BOOT_DATA), entry.size)
3259
3260 # Section1
3261 self.assertIn('section1', entries)
3262 section1 = entries['section1']
3263 self.assertEqual(0x14, section1.offset)
3264 self.assertEqual(0x14, section1.image_pos)
3265 self.assertEqual(0x20, section1.size)
3266
3267 # Second u-boot
3268 section_entries = section1.GetEntries()
3269 self.assertIn('u-boot', section_entries)
3270 entry = section_entries['u-boot']
3271 self.assertEqual(0, entry.offset)
3272 self.assertEqual(0x14, entry.image_pos)
3273 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3274 self.assertEqual(len(U_BOOT_DATA), entry.size)
3275
3276 # Section2
3277 self.assertIn('section2', section_entries)
3278 section2 = section_entries['section2']
3279 self.assertEqual(0x4, section2.offset)
3280 self.assertEqual(0x18, section2.image_pos)
3281 self.assertEqual(4, section2.size)
3282
3283 # Third u-boot
3284 section_entries = section2.GetEntries()
3285 self.assertIn('u-boot', section_entries)
3286 entry = section_entries['u-boot']
3287 self.assertEqual(0, entry.offset)
3288 self.assertEqual(0x18, entry.image_pos)
3289 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3290 self.assertEqual(len(U_BOOT_DATA), entry.size)
3291
Simon Glassf8a54bc2019-07-20 12:23:56 -06003292 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3293 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003294 """Replace an entry in an image
3295
3296 This writes the entry data to update it, then opens the updated file and
3297 returns the value that it now finds there.
3298
3299 Args:
3300 entry_name: Entry name to replace
3301 data: Data to replace it with
3302 decomp: True to compress the data if needed, False if data is
3303 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003304 allow_resize: True to allow entries to change size, False to raise
3305 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003306
3307 Returns:
3308 Tuple:
3309 data from entry
3310 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003311 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003312 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003313 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003314 update_dtb=True)[1]
3315
3316 self.assertIn('image', control.images)
3317 image = control.images['image']
3318 entries = image.GetEntries()
3319 orig_dtb_data = entries['u-boot-dtb'].data
3320 orig_fdtmap_data = entries['fdtmap'].data
3321
Simon Glass80025522022-01-29 14:14:04 -07003322 image_fname = tools.get_output_filename('image.bin')
3323 updated_fname = tools.get_output_filename('image-updated.bin')
3324 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003325 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3326 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003327 data = control.ReadEntry(updated_fname, entry_name, decomp)
3328
Simon Glassf8a54bc2019-07-20 12:23:56 -06003329 # The DT data should not change unless resized:
3330 if not allow_resize:
3331 new_dtb_data = entries['u-boot-dtb'].data
3332 self.assertEqual(new_dtb_data, orig_dtb_data)
3333 new_fdtmap_data = entries['fdtmap'].data
3334 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003335
Simon Glassf8a54bc2019-07-20 12:23:56 -06003336 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003337
3338 def testReplaceSimple(self):
3339 """Test replacing a single file"""
3340 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003341 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3342 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003343 self.assertEqual(expected, data)
3344
3345 # Test that the state looks right. There should be an FDT for the fdtmap
3346 # that we jsut read back in, and it should match what we find in the
3347 # 'control' tables. Checking for an FDT that does not exist should
3348 # return None.
3349 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003350 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003351 self.assertEqual(expected_fdtmap, fdtmap)
3352
3353 dtb = state.GetFdtForEtype('fdtmap')
3354 self.assertEqual(dtb.GetContents(), fdtmap)
3355
3356 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3357 self.assertIsNone(missing_path)
3358 self.assertIsNone(missing_fdtmap)
3359
3360 missing_dtb = state.GetFdtForEtype('missing')
3361 self.assertIsNone(missing_dtb)
3362
3363 self.assertEqual('/binman', state.fdt_path_prefix)
3364
3365 def testReplaceResizeFail(self):
3366 """Test replacing a file by something larger"""
3367 expected = U_BOOT_DATA + b'x'
3368 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003369 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3370 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003371 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3372 str(e.exception))
3373
3374 def testReplaceMulti(self):
3375 """Test replacing entry data where multiple images are generated"""
3376 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3377 update_dtb=True)[0]
3378 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003379 updated_fname = tools.get_output_filename('image-updated.bin')
3380 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003381 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003382 control.WriteEntry(updated_fname, entry_name, expected,
3383 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003384 data = control.ReadEntry(updated_fname, entry_name)
3385 self.assertEqual(expected, data)
3386
3387 # Check the state looks right.
3388 self.assertEqual('/binman/image', state.fdt_path_prefix)
3389
3390 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003391 image_fname = tools.get_output_filename('first-image.bin')
3392 updated_fname = tools.get_output_filename('first-updated.bin')
3393 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003394 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003395 control.WriteEntry(updated_fname, entry_name, expected,
3396 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003397 data = control.ReadEntry(updated_fname, entry_name)
3398 self.assertEqual(expected, data)
3399
3400 # Check the state looks right.
3401 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003402
Simon Glassfb30e292019-07-20 12:23:51 -06003403 def testUpdateFdtAllRepack(self):
3404 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003405 self._SetupSplElf()
3406 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003407 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3408 SECTION_SIZE = 0x300
3409 DTB_SIZE = 602
3410 FDTMAP_SIZE = 608
3411 base_expected = {
3412 'offset': 0,
3413 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3414 'image-pos': 0,
3415 'section:offset': 0,
3416 'section:size': SECTION_SIZE,
3417 'section:image-pos': 0,
3418 'section/u-boot-dtb:offset': 4,
3419 'section/u-boot-dtb:size': 636,
3420 'section/u-boot-dtb:image-pos': 4,
3421 'u-boot-spl-dtb:offset': SECTION_SIZE,
3422 'u-boot-spl-dtb:size': DTB_SIZE,
3423 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3424 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3425 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3426 'u-boot-tpl-dtb:size': DTB_SIZE,
3427 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3428 'fdtmap:size': FDTMAP_SIZE,
3429 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3430 }
3431 main_expected = {
3432 'section:orig-size': SECTION_SIZE,
3433 'section/u-boot-dtb:orig-offset': 4,
3434 }
3435
3436 # We expect three device-tree files in the output, with the first one
3437 # within a fixed-size section.
3438 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3439 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3440 # main U-Boot tree. All three should have the same positions and offset
3441 # except that the main tree should include the main_expected properties
3442 start = 4
3443 for item in ['', 'spl', 'tpl', None]:
3444 if item is None:
3445 start += 16 # Move past fdtmap header
3446 dtb = fdt.Fdt.FromData(data[start:])
3447 dtb.Scan()
3448 props = self._GetPropTree(dtb,
3449 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3450 prefix='/' if item is None else '/binman/')
3451 expected = dict(base_expected)
3452 if item:
3453 expected[item] = 0
3454 else:
3455 # Main DTB and fdtdec should include the 'orig-' properties
3456 expected.update(main_expected)
3457 # Helpful for debugging:
3458 #for prop in sorted(props):
3459 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3460 self.assertEqual(expected, props)
3461 if item == '':
3462 start = SECTION_SIZE
3463 else:
3464 start += dtb._fdt_obj.totalsize()
3465
Simon Glass11453762019-07-20 12:23:55 -06003466 def testFdtmapHeaderMiddle(self):
3467 """Test an FDT map in the middle of an image when it should be at end"""
3468 with self.assertRaises(ValueError) as e:
3469 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3470 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3471 str(e.exception))
3472
3473 def testFdtmapHeaderStartBad(self):
3474 """Test an FDT map in middle of an image when it should be at start"""
3475 with self.assertRaises(ValueError) as e:
3476 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3477 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3478 str(e.exception))
3479
3480 def testFdtmapHeaderEndBad(self):
3481 """Test an FDT map at the start of an image when it should be at end"""
3482 with self.assertRaises(ValueError) as e:
3483 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3484 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3485 str(e.exception))
3486
3487 def testFdtmapHeaderNoSize(self):
3488 """Test an image header at the end of an image with undefined size"""
3489 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3490
Simon Glassf8a54bc2019-07-20 12:23:56 -06003491 def testReplaceResize(self):
3492 """Test replacing a single file in an entry with a larger file"""
3493 expected = U_BOOT_DATA + b'x'
3494 data, _, image = self._RunReplaceCmd('u-boot', expected,
3495 dts='139_replace_repack.dts')
3496 self.assertEqual(expected, data)
3497
3498 entries = image.GetEntries()
3499 dtb_data = entries['u-boot-dtb'].data
3500 dtb = fdt.Fdt.FromData(dtb_data)
3501 dtb.Scan()
3502
3503 # The u-boot section should now be larger in the dtb
3504 node = dtb.GetNode('/binman/u-boot')
3505 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3506
3507 # Same for the fdtmap
3508 fdata = entries['fdtmap'].data
3509 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3510 fdtb.Scan()
3511 fnode = fdtb.GetNode('/u-boot')
3512 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3513
3514 def testReplaceResizeNoRepack(self):
3515 """Test replacing an entry with a larger file when not allowed"""
3516 expected = U_BOOT_DATA + b'x'
3517 with self.assertRaises(ValueError) as e:
3518 self._RunReplaceCmd('u-boot', expected)
3519 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3520 str(e.exception))
3521
Simon Glass9d8ee322019-07-20 12:23:58 -06003522 def testEntryShrink(self):
3523 """Test contracting an entry after it is packed"""
3524 try:
3525 state.SetAllowEntryContraction(True)
3526 data = self._DoReadFileDtb('140_entry_shrink.dts',
3527 update_dtb=True)[0]
3528 finally:
3529 state.SetAllowEntryContraction(False)
3530 self.assertEqual(b'a', data[:1])
3531 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3532 self.assertEqual(b'a', data[-1:])
3533
3534 def testEntryShrinkFail(self):
3535 """Test not being allowed to contract an entry after it is packed"""
3536 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3537
3538 # In this case there is a spare byte at the end of the data. The size of
3539 # the contents is only 1 byte but we still have the size before it
3540 # shrunk.
3541 self.assertEqual(b'a\0', data[:2])
3542 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3543 self.assertEqual(b'a\0', data[-2:])
3544
Simon Glass70e32982019-07-20 12:24:01 -06003545 def testDescriptorOffset(self):
3546 """Test that the Intel descriptor is always placed at at the start"""
3547 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3548 image = control.images['image']
3549 entries = image.GetEntries()
3550 desc = entries['intel-descriptor']
Simon Glassed836ac2025-02-26 09:26:17 -07003551 self.assertEqual(0xff800000, desc.offset)
3552 self.assertEqual(0xff800000, desc.image_pos)
Simon Glass70e32982019-07-20 12:24:01 -06003553
Simon Glass37fdd142019-07-20 12:24:06 -06003554 def testReplaceCbfs(self):
3555 """Test replacing a single file in CBFS without changing the size"""
3556 self._CheckLz4()
3557 expected = b'x' * len(U_BOOT_DATA)
3558 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003559 updated_fname = tools.get_output_filename('image-updated.bin')
3560 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003561 entry_name = 'section/cbfs/u-boot'
3562 control.WriteEntry(updated_fname, entry_name, expected,
3563 allow_resize=True)
3564 data = control.ReadEntry(updated_fname, entry_name)
3565 self.assertEqual(expected, data)
3566
3567 def testReplaceResizeCbfs(self):
3568 """Test replacing a single file in CBFS with one of a different size"""
3569 self._CheckLz4()
3570 expected = U_BOOT_DATA + b'x'
3571 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003572 updated_fname = tools.get_output_filename('image-updated.bin')
3573 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003574 entry_name = 'section/cbfs/u-boot'
3575 control.WriteEntry(updated_fname, entry_name, expected,
3576 allow_resize=True)
3577 data = control.ReadEntry(updated_fname, entry_name)
3578 self.assertEqual(expected, data)
3579
Simon Glass30033c22019-07-20 12:24:15 -06003580 def _SetupForReplace(self):
3581 """Set up some files to use to replace entries
3582
3583 This generates an image, copies it to a new file, extracts all the files
3584 in it and updates some of them
3585
3586 Returns:
3587 List
3588 Image filename
3589 Output directory
3590 Expected values for updated entries, each a string
3591 """
3592 data = self._DoReadFileRealDtb('143_replace_all.dts')
3593
Simon Glass80025522022-01-29 14:14:04 -07003594 updated_fname = tools.get_output_filename('image-updated.bin')
3595 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003596
3597 outdir = os.path.join(self._indir, 'extract')
3598 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3599
3600 expected1 = b'x' + U_BOOT_DATA + b'y'
3601 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003602 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003603
3604 expected2 = b'a' + U_BOOT_DATA + b'b'
3605 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003606 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003607
3608 expected_text = b'not the same text'
3609 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003610 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003611
3612 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3613 dtb = fdt.FdtScan(dtb_fname)
3614 node = dtb.GetNode('/binman/text')
3615 node.AddString('my-property', 'the value')
3616 dtb.Sync(auto_resize=True)
3617 dtb.Flush()
3618
3619 return updated_fname, outdir, expected1, expected2, expected_text
3620
3621 def _CheckReplaceMultiple(self, entry_paths):
3622 """Handle replacing the contents of multiple entries
3623
3624 Args:
3625 entry_paths: List of entry paths to replace
3626
3627 Returns:
3628 List
3629 Dict of entries in the image:
3630 key: Entry name
3631 Value: Entry object
3632 Expected values for updated entries, each a string
3633 """
3634 updated_fname, outdir, expected1, expected2, expected_text = (
3635 self._SetupForReplace())
3636 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3637
3638 image = Image.FromFile(updated_fname)
3639 image.LoadData()
3640 return image.GetEntries(), expected1, expected2, expected_text
3641
3642 def testReplaceAll(self):
3643 """Test replacing the contents of all entries"""
3644 entries, expected1, expected2, expected_text = (
3645 self._CheckReplaceMultiple([]))
3646 data = entries['u-boot'].data
3647 self.assertEqual(expected1, data)
3648
3649 data = entries['u-boot2'].data
3650 self.assertEqual(expected2, data)
3651
3652 data = entries['text'].data
3653 self.assertEqual(expected_text, data)
3654
3655 # Check that the device tree is updated
3656 data = entries['u-boot-dtb'].data
3657 dtb = fdt.Fdt.FromData(data)
3658 dtb.Scan()
3659 node = dtb.GetNode('/binman/text')
3660 self.assertEqual('the value', node.props['my-property'].value)
3661
3662 def testReplaceSome(self):
3663 """Test replacing the contents of a few entries"""
3664 entries, expected1, expected2, expected_text = (
3665 self._CheckReplaceMultiple(['u-boot2', 'text']))
3666
3667 # This one should not change
3668 data = entries['u-boot'].data
3669 self.assertEqual(U_BOOT_DATA, data)
3670
3671 data = entries['u-boot2'].data
3672 self.assertEqual(expected2, data)
3673
3674 data = entries['text'].data
3675 self.assertEqual(expected_text, data)
3676
3677 def testReplaceCmd(self):
3678 """Test replacing a file fron an image on the command line"""
3679 self._DoReadFileRealDtb('143_replace_all.dts')
3680
3681 try:
3682 tmpdir, updated_fname = self._SetupImageInTmpdir()
3683
3684 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3685 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003686 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003687
3688 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003689 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003690 self.assertEqual(expected, data[:len(expected)])
3691 map_fname = os.path.join(tmpdir, 'image-updated.map')
3692 self.assertFalse(os.path.exists(map_fname))
3693 finally:
3694 shutil.rmtree(tmpdir)
3695
3696 def testReplaceCmdSome(self):
3697 """Test replacing some files fron an image on the command line"""
3698 updated_fname, outdir, expected1, expected2, expected_text = (
3699 self._SetupForReplace())
3700
3701 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3702 'u-boot2', 'text')
3703
Simon Glass80025522022-01-29 14:14:04 -07003704 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003705 image = Image.FromFile(updated_fname)
3706 image.LoadData()
3707 entries = image.GetEntries()
3708
3709 # This one should not change
3710 data = entries['u-boot'].data
3711 self.assertEqual(U_BOOT_DATA, data)
3712
3713 data = entries['u-boot2'].data
3714 self.assertEqual(expected2, data)
3715
3716 data = entries['text'].data
3717 self.assertEqual(expected_text, data)
3718
3719 def testReplaceMissing(self):
3720 """Test replacing entries where the file is missing"""
3721 updated_fname, outdir, expected1, expected2, expected_text = (
3722 self._SetupForReplace())
3723
3724 # Remove one of the files, to generate a warning
3725 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3726 os.remove(u_boot_fname1)
3727
3728 with test_util.capture_sys_output() as (stdout, stderr):
3729 control.ReplaceEntries(updated_fname, None, outdir, [])
3730 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003731 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003732
3733 def testReplaceCmdMap(self):
3734 """Test replacing a file fron an image on the command line"""
3735 self._DoReadFileRealDtb('143_replace_all.dts')
3736
3737 try:
3738 tmpdir, updated_fname = self._SetupImageInTmpdir()
3739
3740 fname = os.path.join(self._indir, 'update-u-boot.bin')
3741 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003742 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003743
3744 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3745 '-f', fname, '-m')
3746 map_fname = os.path.join(tmpdir, 'image-updated.map')
3747 self.assertTrue(os.path.exists(map_fname))
3748 finally:
3749 shutil.rmtree(tmpdir)
3750
3751 def testReplaceNoEntryPaths(self):
3752 """Test replacing an entry without an entry path"""
3753 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003754 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003755 with self.assertRaises(ValueError) as e:
3756 control.ReplaceEntries(image_fname, 'fname', None, [])
3757 self.assertIn('Must specify an entry path to read with -f',
3758 str(e.exception))
3759
3760 def testReplaceTooManyEntryPaths(self):
3761 """Test extracting some entries"""
3762 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003763 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003764 with self.assertRaises(ValueError) as e:
3765 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3766 self.assertIn('Must specify exactly one entry path to write with -f',
3767 str(e.exception))
3768
Simon Glass0b074d62019-08-24 07:22:48 -06003769 def testPackReset16(self):
3770 """Test that an image with an x86 reset16 region can be created"""
3771 data = self._DoReadFile('144_x86_reset16.dts')
3772 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3773
3774 def testPackReset16Spl(self):
3775 """Test that an image with an x86 reset16-spl region can be created"""
3776 data = self._DoReadFile('145_x86_reset16_spl.dts')
3777 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3778
3779 def testPackReset16Tpl(self):
3780 """Test that an image with an x86 reset16-tpl region can be created"""
3781 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3782 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3783
Simon Glass232f90c2019-08-24 07:22:50 -06003784 def testPackIntelFit(self):
3785 """Test that an image with an Intel FIT and pointer can be created"""
3786 data = self._DoReadFile('147_intel_fit.dts')
3787 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3788 fit = data[16:32];
3789 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3790 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3791
3792 image = control.images['image']
3793 entries = image.GetEntries()
Simon Glassed836ac2025-02-26 09:26:17 -07003794 expected_ptr = entries['intel-fit'].image_pos #- (1 << 32)
3795 self.assertEqual(expected_ptr, ptr + (1 << 32))
Simon Glass232f90c2019-08-24 07:22:50 -06003796
3797 def testPackIntelFitMissing(self):
3798 """Test detection of a FIT pointer with not FIT region"""
3799 with self.assertRaises(ValueError) as e:
3800 self._DoReadFile('148_intel_fit_missing.dts')
3801 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3802 str(e.exception))
3803
Simon Glass72555fa2019-11-06 17:22:44 -07003804 def _CheckSymbolsTplSection(self, dts, expected_vals):
3805 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003806 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003807 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003808 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003809 self.assertEqual(expected1, data[:upto1])
3810
3811 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003812 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003813 self.assertEqual(expected2, data[upto1:upto2])
3814
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003815 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003816 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003817 self.assertEqual(expected3, data[upto2:upto3])
3818
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003819 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003820 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3821
3822 def testSymbolsTplSection(self):
3823 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3824 self._SetupSplElf('u_boot_binman_syms')
3825 self._SetupTplElf('u_boot_binman_syms')
3826 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003827 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003828
3829 def testSymbolsTplSectionX86(self):
3830 """Test binman can assign symbols in a section with end-at-4gb"""
3831 self._SetupSplElf('u_boot_binman_syms_x86')
3832 self._SetupTplElf('u_boot_binman_syms_x86')
3833 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003834 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003835 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003836
Simon Glass98c59572019-08-24 07:23:03 -06003837 def testPackX86RomIfwiSectiom(self):
3838 """Test that a section can be placed in an IFWI region"""
3839 self._SetupIfwi('fitimage.bin')
3840 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3841 self._CheckIfwi(data)
3842
Simon Glassba7985d2019-08-24 07:23:07 -06003843 def testPackFspM(self):
3844 """Test that an image with a FSP memory-init binary can be created"""
3845 data = self._DoReadFile('152_intel_fsp_m.dts')
3846 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3847
Simon Glass4d9086d2019-10-20 21:31:35 -06003848 def testPackFspS(self):
3849 """Test that an image with a FSP silicon-init binary can be created"""
3850 data = self._DoReadFile('153_intel_fsp_s.dts')
3851 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003852
Simon Glass9ea87b22019-10-20 21:31:36 -06003853 def testPackFspT(self):
3854 """Test that an image with a FSP temp-ram-init binary can be created"""
3855 data = self._DoReadFile('154_intel_fsp_t.dts')
3856 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3857
Simon Glass48f3aad2020-07-09 18:39:31 -06003858 def testMkimage(self):
3859 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003860 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003861 data = self._DoReadFile('156_mkimage.dts')
3862
3863 # Just check that the data appears in the file somewhere
3864 self.assertIn(U_BOOT_SPL_DATA, data)
3865
Simon Glass66152ce2022-01-09 20:14:09 -07003866 def testMkimageMissing(self):
3867 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003868 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003869 with test_util.capture_sys_output() as (_, stderr):
3870 self._DoTestFile('156_mkimage.dts',
3871 force_missing_bintools='mkimage')
3872 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003873 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003874
Simon Glass5e560182020-07-09 18:39:36 -06003875 def testExtblob(self):
3876 """Test an image with an external blob"""
3877 data = self._DoReadFile('157_blob_ext.dts')
3878 self.assertEqual(REFCODE_DATA, data)
3879
3880 def testExtblobMissing(self):
3881 """Test an image with a missing external blob"""
3882 with self.assertRaises(ValueError) as e:
3883 self._DoReadFile('158_blob_ext_missing.dts')
3884 self.assertIn("Filename 'missing-file' not found in input path",
3885 str(e.exception))
3886
Simon Glass5d94cc62020-07-09 18:39:38 -06003887 def testExtblobMissingOk(self):
3888 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003889 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003890 ret = self._DoTestFile('158_blob_ext_missing.dts',
3891 allow_missing=True)
3892 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003893 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003894 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003895 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003896 self.assertIn('Some images are invalid', err)
3897
3898 def testExtblobMissingOkFlag(self):
3899 """Test an image with an missing external blob allowed with -W"""
3900 with test_util.capture_sys_output() as (stdout, stderr):
3901 ret = self._DoTestFile('158_blob_ext_missing.dts',
3902 allow_missing=True, ignore_missing=True)
3903 self.assertEqual(0, ret)
3904 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003905 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003906 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003907 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003908
3909 def testExtblobMissingOkSect(self):
3910 """Test an image with an missing external blob that is allowed"""
3911 with test_util.capture_sys_output() as (stdout, stderr):
3912 self._DoTestFile('159_blob_ext_missing_sect.dts',
3913 allow_missing=True)
3914 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003915 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003916
Simon Glasse88cef92020-07-09 18:39:41 -06003917 def testPackX86RomMeMissingDesc(self):
3918 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003919 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003920 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003921 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003922 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003923
3924 def testPackX86RomMissingIfwi(self):
3925 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3926 self._SetupIfwi('fitimage.bin')
3927 pathname = os.path.join(self._indir, 'fitimage.bin')
3928 os.remove(pathname)
3929 with test_util.capture_sys_output() as (stdout, stderr):
3930 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3931 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003932 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003933
Simon Glass2a0fa982022-02-11 13:23:21 -07003934 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003935 """Test that zero-size overlapping regions are ignored"""
3936 self._DoTestFile('160_pack_overlap_zero.dts')
3937
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003938 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003939 # The data should be inside the FIT
3940 dtb = fdt.Fdt.FromData(fit_data)
3941 dtb.Scan()
3942 fnode = dtb.GetNode('/images/kernel')
3943 self.assertIn('data', fnode.props)
3944
3945 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003946 tools.write_file(fname, fit_data)
3947 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003948
3949 # Check a few features to make sure the plumbing works. We don't need
3950 # to test the operation of mkimage or dumpimage here. First convert the
3951 # output into a dict where the keys are the fields printed by dumpimage
3952 # and the values are a list of values for each field
3953 lines = out.splitlines()
3954
3955 # Converts "Compression: gzip compressed" into two groups:
3956 # 'Compression' and 'gzip compressed'
3957 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3958 vals = collections.defaultdict(list)
3959 for line in lines:
3960 mat = re_line.match(line)
3961 vals[mat.group(1)].append(mat.group(2))
3962
Brandon Maiera657bc62024-06-04 16:16:05 +00003963 self.assertEqual('FIT description: test-desc', lines[0])
Simon Glass45d556d2020-07-09 18:39:45 -06003964 self.assertIn('Created:', lines[1])
3965 self.assertIn('Image 0 (kernel)', vals)
3966 self.assertIn('Hash value', vals)
3967 data_sizes = vals.get('Data Size')
3968 self.assertIsNotNone(data_sizes)
3969 self.assertEqual(2, len(data_sizes))
3970 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003971 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3972 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3973
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003974 # Check if entry listing correctly omits /images/
3975 image = control.images['image']
3976 fit_entry = image.GetEntries()['fit']
3977 subentries = list(fit_entry.GetEntries().keys())
3978 expected = ['kernel', 'fdt-1']
3979 self.assertEqual(expected, subentries)
3980
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003981 def testSimpleFit(self):
3982 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003983 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003984 data = self._DoReadFile('161_fit.dts')
3985 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3986 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3987 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3988
3989 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3990
3991 def testSimpleFitExpandsSubentries(self):
3992 """Test that FIT images expand their subentries"""
3993 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3994 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3995 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3996 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3997
3998 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003999
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004000 def testSimpleFitImagePos(self):
4001 """Test that we have correct image-pos for FIT subentries"""
4002 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
4003 update_dtb=True)
4004 dtb = fdt.Fdt(out_dtb_fname)
4005 dtb.Scan()
4006 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4007
Simon Glassb7bad182022-03-05 20:19:01 -07004008 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004009 self.assertEqual({
4010 'image-pos': 0,
4011 'offset': 0,
4012 'size': 1890,
4013
4014 'u-boot:image-pos': 0,
4015 'u-boot:offset': 0,
4016 'u-boot:size': 4,
4017
4018 'fit:image-pos': 4,
4019 'fit:offset': 4,
4020 'fit:size': 1840,
4021
Simon Glassb7bad182022-03-05 20:19:01 -07004022 'fit/images/kernel:image-pos': 304,
4023 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004024 'fit/images/kernel:size': 4,
4025
Simon Glassb7bad182022-03-05 20:19:01 -07004026 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004027 'fit/images/kernel/u-boot:offset': 0,
4028 'fit/images/kernel/u-boot:size': 4,
4029
Simon Glassb7bad182022-03-05 20:19:01 -07004030 'fit/images/fdt-1:image-pos': 552,
4031 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004032 'fit/images/fdt-1:size': 6,
4033
Simon Glassb7bad182022-03-05 20:19:01 -07004034 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004035 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
4036 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
4037
4038 'u-boot-nodtb:image-pos': 1844,
4039 'u-boot-nodtb:offset': 1844,
4040 'u-boot-nodtb:size': 46,
4041 }, props)
4042
4043 # Actually check the data is where we think it is
4044 for node, expected in [
4045 ("u-boot", U_BOOT_DATA),
4046 ("fit/images/kernel", U_BOOT_DATA),
4047 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4048 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
4049 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
4050 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4051 ]:
4052 image_pos = props[f"{node}:image-pos"]
4053 size = props[f"{node}:size"]
4054 self.assertEqual(len(expected), size)
4055 self.assertEqual(expected, data[image_pos:image_pos+size])
4056
Simon Glass45d556d2020-07-09 18:39:45 -06004057 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06004058 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06004059 data = self._DoReadFile('162_fit_external.dts')
4060 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
4061
Simon Glass7932c882022-01-09 20:13:39 -07004062 # Size of the external-data region as set up by mkimage
4063 external_data_size = len(U_BOOT_DATA) + 2
4064 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07004065 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07004066 len(U_BOOT_NODTB_DATA))
4067
Simon Glass45d556d2020-07-09 18:39:45 -06004068 # The data should be outside the FIT
4069 dtb = fdt.Fdt.FromData(fit_data)
4070 dtb.Scan()
4071 fnode = dtb.GetNode('/images/kernel')
4072 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07004073 self.assertEqual(len(U_BOOT_DATA),
4074 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4075 fit_pos = 0x400;
4076 self.assertEqual(
4077 fit_pos,
4078 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4079
Brandon Maiera657bc62024-06-04 16:16:05 +00004080 self.assertEqual(expected_size, len(data))
Simon Glass7932c882022-01-09 20:13:39 -07004081 actual_pos = len(U_BOOT_DATA) + fit_pos
4082 self.assertEqual(U_BOOT_DATA + b'aa',
4083 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004084
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004085 def testFitExternalImagePos(self):
4086 """Test that we have correct image-pos for external FIT subentries"""
4087 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4088 update_dtb=True)
4089 dtb = fdt.Fdt(out_dtb_fname)
4090 dtb.Scan()
4091 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4092
4093 self.assertEqual({
4094 'image-pos': 0,
4095 'offset': 0,
4096 'size': 1082,
4097
4098 'u-boot:image-pos': 0,
4099 'u-boot:offset': 0,
4100 'u-boot:size': 4,
4101
4102 'fit:size': 1032,
4103 'fit:offset': 4,
4104 'fit:image-pos': 4,
4105
4106 'fit/images/kernel:size': 4,
4107 'fit/images/kernel:offset': 1024,
4108 'fit/images/kernel:image-pos': 1028,
4109
4110 'fit/images/kernel/u-boot:size': 4,
4111 'fit/images/kernel/u-boot:offset': 0,
4112 'fit/images/kernel/u-boot:image-pos': 1028,
4113
4114 'fit/images/fdt-1:size': 2,
4115 'fit/images/fdt-1:offset': 1028,
4116 'fit/images/fdt-1:image-pos': 1032,
4117
4118 'fit/images/fdt-1/_testing:size': 2,
4119 'fit/images/fdt-1/_testing:offset': 0,
4120 'fit/images/fdt-1/_testing:image-pos': 1032,
4121
4122 'u-boot-nodtb:image-pos': 1036,
4123 'u-boot-nodtb:offset': 1036,
4124 'u-boot-nodtb:size': 46,
4125 }, props)
4126
4127 # Actually check the data is where we think it is
4128 for node, expected in [
4129 ("u-boot", U_BOOT_DATA),
4130 ("fit/images/kernel", U_BOOT_DATA),
4131 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4132 ("fit/images/fdt-1", b'aa'),
4133 ("fit/images/fdt-1/_testing", b'aa'),
4134 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4135 ]:
4136 image_pos = props[f"{node}:image-pos"]
4137 size = props[f"{node}:size"]
4138 self.assertEqual(len(expected), size)
4139 self.assertEqual(expected, data[image_pos:image_pos+size])
4140
Simon Glass66152ce2022-01-09 20:14:09 -07004141 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004142 """Test that binman complains if mkimage is missing"""
4143 with self.assertRaises(ValueError) as e:
4144 self._DoTestFile('162_fit_external.dts',
4145 force_missing_bintools='mkimage')
4146 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4147 str(e.exception))
4148
4149 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004150 """Test that binman still produces a FIT image if mkimage is missing"""
4151 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004152 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004153 force_missing_bintools='mkimage')
4154 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004155 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004156
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004157 def testSectionIgnoreHashSignature(self):
4158 """Test that sections ignore hash, signature nodes for its data"""
4159 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4160 expected = (U_BOOT_DATA + U_BOOT_DATA)
4161 self.assertEqual(expected, data)
4162
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004163 def testPadInSections(self):
4164 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004165 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4166 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004167 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4168 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004169 U_BOOT_DATA)
4170 self.assertEqual(expected, data)
4171
Simon Glassd12599d2020-10-26 17:40:09 -06004172 dtb = fdt.Fdt(out_dtb_fname)
4173 dtb.Scan()
4174 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4175 expected = {
4176 'image-pos': 0,
4177 'offset': 0,
4178 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4179
4180 'section:image-pos': 0,
4181 'section:offset': 0,
4182 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4183
4184 'section/before:image-pos': 0,
4185 'section/before:offset': 0,
4186 'section/before:size': len(U_BOOT_DATA),
4187
4188 'section/u-boot:image-pos': 4,
4189 'section/u-boot:offset': 4,
4190 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4191
4192 'section/after:image-pos': 26,
4193 'section/after:offset': 26,
4194 'section/after:size': len(U_BOOT_DATA),
4195 }
4196 self.assertEqual(expected, props)
4197
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004198 def testFitImageSubentryAlignment(self):
4199 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004200 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004201 entry_args = {
4202 'test-id': TEXT_DATA,
4203 }
4204 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4205 entry_args=entry_args)
4206 dtb = fdt.Fdt.FromData(data)
4207 dtb.Scan()
4208
4209 node = dtb.GetNode('/images/kernel')
4210 data = dtb.GetProps(node)["data"].bytes
4211 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004212 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4213 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004214 self.assertEqual(expected, data)
4215
4216 node = dtb.GetNode('/images/fdt-1')
4217 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004218 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4219 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004220 U_BOOT_DTB_DATA)
4221 self.assertEqual(expected, data)
4222
4223 def testFitExtblobMissingOk(self):
4224 """Test a FIT with a missing external blob that is allowed"""
4225 with test_util.capture_sys_output() as (stdout, stderr):
4226 self._DoTestFile('168_fit_missing_blob.dts',
4227 allow_missing=True)
4228 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004229 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004230
Simon Glass21db0ff2020-09-01 05:13:54 -06004231 def testBlobNamedByArgMissing(self):
4232 """Test handling of a missing entry arg"""
4233 with self.assertRaises(ValueError) as e:
4234 self._DoReadFile('068_blob_named_by_arg.dts')
4235 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4236 str(e.exception))
4237
Simon Glass559c4de2020-09-01 05:13:58 -06004238 def testPackBl31(self):
4239 """Test that an image with an ATF BL31 binary can be created"""
4240 data = self._DoReadFile('169_atf_bl31.dts')
4241 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4242
Samuel Holland9d8cc632020-10-21 21:12:15 -05004243 def testPackScp(self):
4244 """Test that an image with an SCP binary can be created"""
4245 data = self._DoReadFile('172_scp.dts')
4246 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4247
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004248 def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True,
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004249 default_dt=None, use_seq_num=True):
Simon Glasscd2783e2024-07-20 11:49:46 +01004250 """Check an image with an FIT with multiple FDT images"""
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004251 def _CheckFdt(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004252 """Check the FDT nodes
4253
4254 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004255 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004256 expected_data: Expected contents of 'data' property
4257 """
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004258 name = 'fdt-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004259 fnode = dtb.GetNode('/images/%s' % name)
4260 self.assertIsNotNone(fnode)
4261 self.assertEqual({'description','type', 'compression', 'data'},
4262 set(fnode.props.keys()))
4263 self.assertEqual(expected_data, fnode.props['data'].bytes)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004264 description = (
4265 'fdt-test-fdt%s.dtb' % val if len(val) == 1 else
4266 'fdt-%s.dtb' % val
4267 )
4268 self.assertEqual(description, fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004269 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004270
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004271 def _CheckConfig(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004272 """Check the configuration nodes
4273
4274 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004275 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004276 expected_data: Expected contents of 'data' property
4277 """
4278 cnode = dtb.GetNode('/configurations')
4279 self.assertIn('default', cnode.props)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004280 default = (
4281 'config-2' if len(val) == 1 else
4282 'config-test-fdt2'
4283 )
4284 self.assertEqual(default, cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004285
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004286 name = 'config-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004287 fnode = dtb.GetNode('/configurations/%s' % name)
4288 self.assertIsNotNone(fnode)
4289 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4290 set(fnode.props.keys()))
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004291 description = (
4292 'conf-test-fdt%s.dtb' % val if len(val) == 1 else
4293 'conf-%s.dtb' % val
4294 )
4295 self.assertEqual(description, fnode.props['description'].value)
4296 self.assertEqual('fdt-%s' % val, fnode.props['fdt'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004297
4298 entry_args = {
Simon Glass1032acc2020-09-06 10:39:08 -06004299 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004300 }
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004301 extra_indirs = None
Simon Glasscd2783e2024-07-20 11:49:46 +01004302 if use_fdt_list:
4303 entry_args['of-list'] = 'test-fdt1 test-fdt2'
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004304 if default_dt:
4305 entry_args['default-dt'] = default_dt
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004306 if use_fdt_list:
4307 extra_indirs = [os.path.join(self._indir, TEST_FDT_SUBDIR)]
Simon Glassa435cd12020-09-01 05:13:59 -06004308 data = self._DoReadFileDtb(
Simon Glasscd2783e2024-07-20 11:49:46 +01004309 dts,
Simon Glassa435cd12020-09-01 05:13:59 -06004310 entry_args=entry_args,
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004311 extra_indirs=extra_indirs)[0]
Simon Glassa435cd12020-09-01 05:13:59 -06004312 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4313 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4314
4315 dtb = fdt.Fdt.FromData(fit_data)
4316 dtb.Scan()
4317 fnode = dtb.GetNode('/images/kernel')
4318 self.assertIn('data', fnode.props)
4319
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004320 if use_seq_num == True:
4321 # Check all the properties in fdt-1 and fdt-2
4322 _CheckFdt('1', TEST_FDT1_DATA)
4323 _CheckFdt('2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004324
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004325 # Check configurations
4326 _CheckConfig('1', TEST_FDT1_DATA)
4327 _CheckConfig('2', TEST_FDT2_DATA)
4328 else:
4329 # Check all the properties in fdt-1 and fdt-2
4330 _CheckFdt('test-fdt1', TEST_FDT1_DATA)
4331 _CheckFdt('test-fdt2', TEST_FDT2_DATA)
4332
4333 # Check configurations
4334 _CheckConfig('test-fdt1', TEST_FDT1_DATA)
4335 _CheckConfig('test-fdt2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004336
Simon Glasscd2783e2024-07-20 11:49:46 +01004337 def testFitFdt(self):
4338 """Test an image with an FIT with multiple FDT images"""
4339 self.CheckFitFdt()
4340
Simon Glassa435cd12020-09-01 05:13:59 -06004341 def testFitFdtMissingList(self):
4342 """Test handling of a missing 'of-list' entry arg"""
4343 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004344 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004345 self.assertIn("Generator node requires 'of-list' entry argument",
4346 str(e.exception))
4347
4348 def testFitFdtEmptyList(self):
4349 """Test handling of an empty 'of-list' entry arg"""
4350 entry_args = {
4351 'of-list': '',
4352 }
4353 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4354
4355 def testFitFdtMissingProp(self):
4356 """Test handling of a missing 'fit,fdt-list' property"""
4357 with self.assertRaises(ValueError) as e:
4358 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4359 self.assertIn("Generator node requires 'fit,fdt-list' property",
4360 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004361
Simon Glass1032acc2020-09-06 10:39:08 -06004362 def testFitFdtMissing(self):
4363 """Test handling of a missing 'default-dt' entry arg"""
4364 entry_args = {
4365 'of-list': 'test-fdt1 test-fdt2',
4366 }
4367 with self.assertRaises(ValueError) as e:
4368 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004369 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004370 entry_args=entry_args,
4371 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4372 self.assertIn("Generated 'default' node requires default-dt entry argument",
4373 str(e.exception))
4374
4375 def testFitFdtNotInList(self):
4376 """Test handling of a default-dt that is not in the of-list"""
4377 entry_args = {
4378 'of-list': 'test-fdt1 test-fdt2',
4379 'default-dt': 'test-fdt3',
4380 }
4381 with self.assertRaises(ValueError) as e:
4382 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004383 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004384 entry_args=entry_args,
4385 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4386 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4387 str(e.exception))
4388
Simon Glassa820af72020-09-06 10:39:09 -06004389 def testFitExtblobMissingHelp(self):
4390 """Test display of help messages when an external blob is missing"""
4391 control.missing_blob_help = control._ReadMissingBlobHelp()
4392 control.missing_blob_help['wibble'] = 'Wibble test'
4393 control.missing_blob_help['another'] = 'Another test'
4394 with test_util.capture_sys_output() as (stdout, stderr):
4395 self._DoTestFile('168_fit_missing_blob.dts',
4396 allow_missing=True)
4397 err = stderr.getvalue()
4398
4399 # We can get the tag from the name, the type or the missing-msg
4400 # property. Check all three.
4401 self.assertIn('You may need to build ARM Trusted', err)
4402 self.assertIn('Wibble test', err)
4403 self.assertIn('Another test', err)
4404
Simon Glass6f1f4d42020-09-06 10:35:32 -06004405 def testMissingBlob(self):
4406 """Test handling of a blob containing a missing file"""
4407 with self.assertRaises(ValueError) as e:
4408 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4409 self.assertIn("Filename 'missing' not found in input path",
4410 str(e.exception))
4411
Simon Glassa0729502020-09-06 10:35:33 -06004412 def testEnvironment(self):
4413 """Test adding a U-Boot environment"""
4414 data = self._DoReadFile('174_env.dts')
4415 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4416 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4417 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4418 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4419 env)
4420
4421 def testEnvironmentNoSize(self):
4422 """Test that a missing 'size' property is detected"""
4423 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004424 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004425 self.assertIn("'u-boot-env' entry must have a size property",
4426 str(e.exception))
4427
4428 def testEnvironmentTooSmall(self):
4429 """Test handling of an environment that does not fit"""
4430 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004431 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004432
4433 # checksum, start byte, environment with \0 terminator, final \0
4434 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4435 short = need - 0x8
4436 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4437 str(e.exception))
4438
Simon Glassd1fdf752020-10-26 17:40:01 -06004439 def testSkipAtStart(self):
4440 """Test handling of skip-at-start section"""
4441 data = self._DoReadFile('177_skip_at_start.dts')
4442 self.assertEqual(U_BOOT_DATA, data)
4443
4444 image = control.images['image']
4445 entries = image.GetEntries()
4446 section = entries['section']
4447 self.assertEqual(0, section.offset)
4448 self.assertEqual(len(U_BOOT_DATA), section.size)
4449 self.assertEqual(U_BOOT_DATA, section.GetData())
4450
4451 entry = section.GetEntries()['u-boot']
4452 self.assertEqual(16, entry.offset)
4453 self.assertEqual(len(U_BOOT_DATA), entry.size)
4454 self.assertEqual(U_BOOT_DATA, entry.data)
4455
4456 def testSkipAtStartPad(self):
4457 """Test handling of skip-at-start section with padded entry"""
4458 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004459 before = tools.get_bytes(0, 8)
4460 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004461 all = before + U_BOOT_DATA + after
4462 self.assertEqual(all, data)
4463
4464 image = control.images['image']
4465 entries = image.GetEntries()
4466 section = entries['section']
4467 self.assertEqual(0, section.offset)
4468 self.assertEqual(len(all), section.size)
4469 self.assertEqual(all, section.GetData())
4470
4471 entry = section.GetEntries()['u-boot']
4472 self.assertEqual(16, entry.offset)
4473 self.assertEqual(len(all), entry.size)
4474 self.assertEqual(U_BOOT_DATA, entry.data)
4475
4476 def testSkipAtStartSectionPad(self):
4477 """Test handling of skip-at-start section with padding"""
4478 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004479 before = tools.get_bytes(0, 8)
4480 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004481 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004482 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004483
4484 image = control.images['image']
4485 entries = image.GetEntries()
4486 section = entries['section']
4487 self.assertEqual(0, section.offset)
4488 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004489 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004490 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004491
4492 entry = section.GetEntries()['u-boot']
4493 self.assertEqual(16, entry.offset)
4494 self.assertEqual(len(U_BOOT_DATA), entry.size)
4495 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004496
Simon Glassbb395742020-10-26 17:40:14 -06004497 def testSectionPad(self):
4498 """Testing padding with sections"""
4499 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004500 expected = (tools.get_bytes(ord('&'), 3) +
4501 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004502 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004503 tools.get_bytes(ord('!'), 1) +
4504 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004505 self.assertEqual(expected, data)
4506
4507 def testSectionAlign(self):
4508 """Testing alignment with sections"""
4509 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4510 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004511 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004512 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004513 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004514 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004515 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4516 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004517 self.assertEqual(expected, data)
4518
Simon Glassd92c8362020-10-26 17:40:25 -06004519 def testCompressImage(self):
4520 """Test compression of the entire image"""
4521 self._CheckLz4()
4522 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4523 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4524 dtb = fdt.Fdt(out_dtb_fname)
4525 dtb.Scan()
4526 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4527 'uncomp-size'])
4528 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004529 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004530
4531 # Do a sanity check on various fields
4532 image = control.images['image']
4533 entries = image.GetEntries()
4534 self.assertEqual(2, len(entries))
4535
4536 entry = entries['blob']
4537 self.assertEqual(COMPRESS_DATA, entry.data)
4538 self.assertEqual(len(COMPRESS_DATA), entry.size)
4539
4540 entry = entries['u-boot']
4541 self.assertEqual(U_BOOT_DATA, entry.data)
4542 self.assertEqual(len(U_BOOT_DATA), entry.size)
4543
4544 self.assertEqual(len(data), image.size)
4545 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4546 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4547 orig = self._decompress(image.data)
4548 self.assertEqual(orig, image.uncomp_data)
4549
4550 expected = {
4551 'blob:offset': 0,
4552 'blob:size': len(COMPRESS_DATA),
4553 'u-boot:offset': len(COMPRESS_DATA),
4554 'u-boot:size': len(U_BOOT_DATA),
4555 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4556 'offset': 0,
4557 'image-pos': 0,
4558 'size': len(data),
4559 }
4560 self.assertEqual(expected, props)
4561
4562 def testCompressImageLess(self):
4563 """Test compression where compression reduces the image size"""
4564 self._CheckLz4()
4565 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4566 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4567 dtb = fdt.Fdt(out_dtb_fname)
4568 dtb.Scan()
4569 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4570 'uncomp-size'])
4571 orig = self._decompress(data)
4572
Brandon Maiera657bc62024-06-04 16:16:05 +00004573 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004574
4575 # Do a sanity check on various fields
4576 image = control.images['image']
4577 entries = image.GetEntries()
4578 self.assertEqual(2, len(entries))
4579
4580 entry = entries['blob']
4581 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4582 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4583
4584 entry = entries['u-boot']
4585 self.assertEqual(U_BOOT_DATA, entry.data)
4586 self.assertEqual(len(U_BOOT_DATA), entry.size)
4587
4588 self.assertEqual(len(data), image.size)
4589 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4590 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4591 image.uncomp_size)
4592 orig = self._decompress(image.data)
4593 self.assertEqual(orig, image.uncomp_data)
4594
4595 expected = {
4596 'blob:offset': 0,
4597 'blob:size': len(COMPRESS_DATA_BIG),
4598 'u-boot:offset': len(COMPRESS_DATA_BIG),
4599 'u-boot:size': len(U_BOOT_DATA),
4600 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4601 'offset': 0,
4602 'image-pos': 0,
4603 'size': len(data),
4604 }
4605 self.assertEqual(expected, props)
4606
4607 def testCompressSectionSize(self):
4608 """Test compression of a section with a fixed size"""
4609 self._CheckLz4()
4610 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4611 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4612 dtb = fdt.Fdt(out_dtb_fname)
4613 dtb.Scan()
4614 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4615 'uncomp-size'])
Jiaxun Yangc6931742025-04-10 06:43:03 -06004616 data = data[:0x30]
4617 data = data.rstrip(b'\xff')
Simon Glassd92c8362020-10-26 17:40:25 -06004618 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004619 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004620 expected = {
4621 'section/blob:offset': 0,
4622 'section/blob:size': len(COMPRESS_DATA),
4623 'section/u-boot:offset': len(COMPRESS_DATA),
4624 'section/u-boot:size': len(U_BOOT_DATA),
4625 'section:offset': 0,
4626 'section:image-pos': 0,
4627 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4628 'section:size': 0x30,
4629 'offset': 0,
4630 'image-pos': 0,
4631 'size': 0x30,
4632 }
4633 self.assertEqual(expected, props)
4634
4635 def testCompressSection(self):
4636 """Test compression of a section with no fixed size"""
4637 self._CheckLz4()
4638 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4639 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4640 dtb = fdt.Fdt(out_dtb_fname)
4641 dtb.Scan()
4642 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4643 'uncomp-size'])
4644 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004645 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004646 expected = {
4647 'section/blob:offset': 0,
4648 'section/blob:size': len(COMPRESS_DATA),
4649 'section/u-boot:offset': len(COMPRESS_DATA),
4650 'section/u-boot:size': len(U_BOOT_DATA),
4651 'section:offset': 0,
4652 'section:image-pos': 0,
4653 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4654 'section:size': len(data),
4655 'offset': 0,
4656 'image-pos': 0,
4657 'size': len(data),
4658 }
4659 self.assertEqual(expected, props)
4660
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004661 def testLz4Missing(self):
4662 """Test that binman still produces an image if lz4 is missing"""
4663 with test_util.capture_sys_output() as (_, stderr):
4664 self._DoTestFile('185_compress_section.dts',
4665 force_missing_bintools='lz4')
4666 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004667 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004668
Simon Glassd92c8362020-10-26 17:40:25 -06004669 def testCompressExtra(self):
4670 """Test compression of a section with no fixed size"""
4671 self._CheckLz4()
4672 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4673 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4674 dtb = fdt.Fdt(out_dtb_fname)
4675 dtb.Scan()
4676 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4677 'uncomp-size'])
4678
4679 base = data[len(U_BOOT_DATA):]
Brandon Maiera657bc62024-06-04 16:16:05 +00004680 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glassd92c8362020-10-26 17:40:25 -06004681 rest = base[len(U_BOOT_DATA):]
4682
4683 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004684 bintool = self.comp_bintools['lz4']
4685 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004686 data1 = rest[:len(expect1)]
4687 section1 = self._decompress(data1)
Brandon Maiera657bc62024-06-04 16:16:05 +00004688 self.assertEqual(expect1, data1)
4689 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glassd92c8362020-10-26 17:40:25 -06004690 rest1 = rest[len(expect1):]
4691
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004692 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004693 data2 = rest1[:len(expect2)]
4694 section2 = self._decompress(data2)
Brandon Maiera657bc62024-06-04 16:16:05 +00004695 self.assertEqual(expect2, data2)
4696 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glassd92c8362020-10-26 17:40:25 -06004697 rest2 = rest1[len(expect2):]
4698
4699 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4700 len(expect2) + len(U_BOOT_DATA))
Brandon Maiera657bc62024-06-04 16:16:05 +00004701 #self.assertEqual(expect_size, len(data))
Simon Glassd92c8362020-10-26 17:40:25 -06004702
Brandon Maiera657bc62024-06-04 16:16:05 +00004703 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glassd92c8362020-10-26 17:40:25 -06004704
4705 self.maxDiff = None
4706 expected = {
4707 'u-boot:offset': 0,
4708 'u-boot:image-pos': 0,
4709 'u-boot:size': len(U_BOOT_DATA),
4710
4711 'base:offset': len(U_BOOT_DATA),
4712 'base:image-pos': len(U_BOOT_DATA),
4713 'base:size': len(data) - len(U_BOOT_DATA),
4714 'base/u-boot:offset': 0,
4715 'base/u-boot:image-pos': len(U_BOOT_DATA),
4716 'base/u-boot:size': len(U_BOOT_DATA),
4717 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4718 len(expect2),
4719 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4720 len(expect2),
4721 'base/u-boot2:size': len(U_BOOT_DATA),
4722
4723 'base/section:offset': len(U_BOOT_DATA),
4724 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4725 'base/section:size': len(expect1),
4726 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4727 'base/section/blob:offset': 0,
4728 'base/section/blob:size': len(COMPRESS_DATA),
4729 'base/section/u-boot:offset': len(COMPRESS_DATA),
4730 'base/section/u-boot:size': len(U_BOOT_DATA),
4731
4732 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4733 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4734 'base/section2:size': len(expect2),
4735 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4736 'base/section2/blob:offset': 0,
4737 'base/section2/blob:size': len(COMPRESS_DATA),
4738 'base/section2/blob2:offset': len(COMPRESS_DATA),
4739 'base/section2/blob2:size': len(COMPRESS_DATA),
4740
4741 'offset': 0,
4742 'image-pos': 0,
4743 'size': len(data),
4744 }
4745 self.assertEqual(expected, props)
4746
Simon Glassecbe4732021-01-06 21:35:15 -07004747 def testSymbolsSubsection(self):
4748 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004749 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004750
Simon Glass3fb25402021-01-06 21:35:16 -07004751 def testReadImageEntryArg(self):
4752 """Test reading an image that would need an entry arg to generate"""
4753 entry_args = {
4754 'cros-ec-rw-path': 'ecrw.bin',
4755 }
4756 data = self.data = self._DoReadFileDtb(
4757 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4758 entry_args=entry_args)
4759
Simon Glass80025522022-01-29 14:14:04 -07004760 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004761 orig_image = control.images['image']
4762
4763 # This should not generate an error about the missing 'cros-ec-rw-path'
4764 # since we are reading the image from a file. Compare with
4765 # testEntryArgsRequired()
4766 image = Image.FromFile(image_fname)
4767 self.assertEqual(orig_image.GetEntries().keys(),
4768 image.GetEntries().keys())
4769
Simon Glassa2af7302021-01-06 21:35:18 -07004770 def testFilesAlign(self):
4771 """Test alignment with files"""
4772 data = self._DoReadFile('190_files_align.dts')
4773
4774 # The first string is 15 bytes so will align to 16
4775 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4776 self.assertEqual(expect, data)
4777
Simon Glassdb84b562021-01-06 21:35:19 -07004778 def testReadImageSkip(self):
4779 """Test reading an image and accessing its FDT map"""
4780 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004781 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004782 orig_image = control.images['image']
4783 image = Image.FromFile(image_fname)
4784 self.assertEqual(orig_image.GetEntries().keys(),
4785 image.GetEntries().keys())
4786
4787 orig_entry = orig_image.GetEntries()['fdtmap']
4788 entry = image.GetEntries()['fdtmap']
4789 self.assertEqual(orig_entry.offset, entry.offset)
4790 self.assertEqual(orig_entry.size, entry.size)
Simon Glassed836ac2025-02-26 09:26:17 -07004791 self.assertEqual((1 << 32) - 0x400 + 16, entry.image_pos)
Simon Glassdb84b562021-01-06 21:35:19 -07004792
4793 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4794
Brandon Maiera657bc62024-06-04 16:16:05 +00004795 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glassdb84b562021-01-06 21:35:19 -07004796
Simon Glassc98de972021-03-18 20:24:57 +13004797 def testTplNoDtb(self):
4798 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004799 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004800 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4801 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4802 data[:len(U_BOOT_TPL_NODTB_DATA)])
4803
Simon Glass63f41d42021-03-18 20:24:58 +13004804 def testTplBssPad(self):
4805 """Test that we can pad TPL's BSS with zeros"""
4806 # ELF file with a '__bss_size' symbol
4807 self._SetupTplElf()
4808 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004809 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004810 data)
4811
4812 def testTplBssPadMissing(self):
4813 """Test that a missing symbol is detected"""
4814 self._SetupTplElf('u_boot_ucode_ptr')
4815 with self.assertRaises(ValueError) as e:
4816 self._DoReadFile('193_tpl_bss_pad.dts')
4817 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4818 str(e.exception))
4819
Simon Glass718b5292021-03-18 20:25:07 +13004820 def checkDtbSizes(self, data, pad_len, start):
4821 """Check the size arguments in a dtb embedded in an image
4822
4823 Args:
4824 data: The image data
4825 pad_len: Length of the pad section in the image, in bytes
4826 start: Start offset of the devicetree to examine, within the image
4827
4828 Returns:
4829 Size of the devicetree in bytes
4830 """
4831 dtb_data = data[start:]
4832 dtb = fdt.Fdt.FromData(dtb_data)
4833 fdt_size = dtb.GetFdtObj().totalsize()
4834 dtb.Scan()
4835 props = self._GetPropTree(dtb, 'size')
4836 self.assertEqual({
4837 'size': len(data),
4838 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4839 'u-boot-spl/u-boot-spl-dtb:size': 801,
4840 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4841 'u-boot-spl:size': 860,
4842 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4843 'u-boot/u-boot-dtb:size': 781,
4844 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4845 'u-boot:size': 827,
4846 }, props)
4847 return fdt_size
4848
4849 def testExpanded(self):
4850 """Test that an expanded entry type is selected when needed"""
4851 self._SetupSplElf()
4852 self._SetupTplElf()
4853
4854 # SPL has a devicetree, TPL does not
4855 entry_args = {
4856 'spl-dtb': '1',
4857 'spl-bss-pad': 'y',
4858 'tpl-dtb': '',
4859 }
4860 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4861 entry_args=entry_args)
4862 image = control.images['image']
4863 entries = image.GetEntries()
4864 self.assertEqual(3, len(entries))
4865
4866 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4867 self.assertIn('u-boot', entries)
4868 entry = entries['u-boot']
4869 self.assertEqual('u-boot-expanded', entry.etype)
4870 subent = entry.GetEntries()
4871 self.assertEqual(2, len(subent))
4872 self.assertIn('u-boot-nodtb', subent)
4873 self.assertIn('u-boot-dtb', subent)
4874
4875 # Second, u-boot-spl, which should be expanded into three parts
4876 self.assertIn('u-boot-spl', entries)
4877 entry = entries['u-boot-spl']
4878 self.assertEqual('u-boot-spl-expanded', entry.etype)
4879 subent = entry.GetEntries()
4880 self.assertEqual(3, len(subent))
4881 self.assertIn('u-boot-spl-nodtb', subent)
4882 self.assertIn('u-boot-spl-bss-pad', subent)
4883 self.assertIn('u-boot-spl-dtb', subent)
4884
4885 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4886 # devicetree
4887 self.assertIn('u-boot-tpl', entries)
4888 entry = entries['u-boot-tpl']
4889 self.assertEqual('u-boot-tpl', entry.etype)
4890 self.assertEqual(None, entry.GetEntries())
4891
4892 def testExpandedTpl(self):
4893 """Test that an expanded entry type is selected for TPL when needed"""
4894 self._SetupTplElf()
4895
4896 entry_args = {
4897 'tpl-bss-pad': 'y',
4898 'tpl-dtb': 'y',
4899 }
4900 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4901 entry_args=entry_args)
4902 image = control.images['image']
4903 entries = image.GetEntries()
4904 self.assertEqual(1, len(entries))
4905
4906 # We only have u-boot-tpl, which be expanded
4907 self.assertIn('u-boot-tpl', entries)
4908 entry = entries['u-boot-tpl']
4909 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4910 subent = entry.GetEntries()
4911 self.assertEqual(3, len(subent))
4912 self.assertIn('u-boot-tpl-nodtb', subent)
4913 self.assertIn('u-boot-tpl-bss-pad', subent)
4914 self.assertIn('u-boot-tpl-dtb', subent)
4915
4916 def testExpandedNoPad(self):
4917 """Test an expanded entry without BSS pad enabled"""
4918 self._SetupSplElf()
4919 self._SetupTplElf()
4920
4921 # SPL has a devicetree, TPL does not
4922 entry_args = {
4923 'spl-dtb': 'something',
4924 'spl-bss-pad': 'n',
4925 'tpl-dtb': '',
4926 }
4927 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4928 entry_args=entry_args)
4929 image = control.images['image']
4930 entries = image.GetEntries()
4931
4932 # Just check u-boot-spl, which should be expanded into two parts
4933 self.assertIn('u-boot-spl', entries)
4934 entry = entries['u-boot-spl']
4935 self.assertEqual('u-boot-spl-expanded', entry.etype)
4936 subent = entry.GetEntries()
4937 self.assertEqual(2, len(subent))
4938 self.assertIn('u-boot-spl-nodtb', subent)
4939 self.assertIn('u-boot-spl-dtb', subent)
4940
4941 def testExpandedTplNoPad(self):
4942 """Test that an expanded entry type with padding disabled in TPL"""
4943 self._SetupTplElf()
4944
4945 entry_args = {
4946 'tpl-bss-pad': '',
4947 'tpl-dtb': 'y',
4948 }
4949 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4950 entry_args=entry_args)
4951 image = control.images['image']
4952 entries = image.GetEntries()
4953 self.assertEqual(1, len(entries))
4954
4955 # We only have u-boot-tpl, which be expanded
4956 self.assertIn('u-boot-tpl', entries)
4957 entry = entries['u-boot-tpl']
4958 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4959 subent = entry.GetEntries()
4960 self.assertEqual(2, len(subent))
4961 self.assertIn('u-boot-tpl-nodtb', subent)
4962 self.assertIn('u-boot-tpl-dtb', subent)
4963
4964 def testFdtInclude(self):
4965 """Test that an Fdt is update within all binaries"""
4966 self._SetupSplElf()
4967 self._SetupTplElf()
4968
4969 # SPL has a devicetree, TPL does not
4970 self.maxDiff = None
4971 entry_args = {
4972 'spl-dtb': '1',
4973 'spl-bss-pad': 'y',
4974 'tpl-dtb': '',
4975 }
4976 # Build the image. It includes two separate devicetree binaries, each
4977 # with their own contents, but all contain the binman definition.
4978 data = self._DoReadFileDtb(
4979 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4980 update_dtb=True, entry_args=entry_args)[0]
4981 pad_len = 10
4982
4983 # Check the U-Boot dtb
4984 start = len(U_BOOT_NODTB_DATA)
4985 fdt_size = self.checkDtbSizes(data, pad_len, start)
4986
4987 # Now check SPL
4988 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4989 fdt_size = self.checkDtbSizes(data, pad_len, start)
4990
4991 # TPL has no devicetree
4992 start += fdt_size + len(U_BOOT_TPL_DATA)
4993 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004994
Simon Glass7098b7f2021-03-21 18:24:30 +13004995 def testSymbolsExpanded(self):
4996 """Test binman can assign symbols in expanded entries"""
4997 entry_args = {
4998 'spl-dtb': '1',
4999 }
5000 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
5001 U_BOOT_SPL_DTB_DATA, 0x38,
5002 entry_args=entry_args, use_expanded=True)
5003
Simon Glasse1915782021-03-21 18:24:31 +13005004 def testCollection(self):
5005 """Test a collection"""
5006 data = self._DoReadFile('198_collection.dts')
5007 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07005008 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5009 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13005010 data)
5011
Simon Glass27a7f772021-03-21 18:24:32 +13005012 def testCollectionSection(self):
5013 """Test a collection where a section must be built first"""
5014 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07005015 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13005016 # building the contents, producing an error is anything is still
5017 # missing.
5018 data = self._DoReadFile('199_collection_section.dts')
5019 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07005020 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
5021 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13005022 data)
5023
Simon Glassf427c5f2021-03-21 18:24:33 +13005024 def testAlignDefault(self):
5025 """Test that default alignment works on sections"""
5026 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07005027 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13005028 U_BOOT_DATA)
5029 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07005030 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13005031 # No alignment within the nested section
5032 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
5033 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07005034 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13005035 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13005036
Bin Mengc0b15742021-05-10 20:23:33 +08005037 def testPackOpenSBI(self):
5038 """Test that an image with an OpenSBI binary can be created"""
5039 data = self._DoReadFile('201_opensbi.dts')
5040 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
5041
Simon Glass76f496d2021-07-06 10:36:37 -06005042 def testSectionsSingleThread(self):
5043 """Test sections without multithreading"""
5044 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07005045 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
5046 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
5047 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06005048 self.assertEqual(expected, data)
5049
5050 def testThreadTimeout(self):
5051 """Test handling a thread that takes too long"""
5052 with self.assertRaises(ValueError) as e:
5053 self._DoTestFile('202_section_timeout.dts',
5054 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06005055 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06005056
Simon Glass748a1d42021-07-06 10:36:41 -06005057 def testTiming(self):
5058 """Test output of timing information"""
5059 data = self._DoReadFile('055_sections.dts')
5060 with test_util.capture_sys_output() as (stdout, stderr):
5061 state.TimingShow()
5062 self.assertIn('read:', stdout.getvalue())
5063 self.assertIn('compress:', stdout.getvalue())
5064
Simon Glassadfb8492021-11-03 21:09:18 -06005065 def testUpdateFdtInElf(self):
5066 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005067 if not elf.ELF_TOOLS:
5068 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005069 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5070 outfile = os.path.join(self._indir, 'u-boot.out')
5071 begin_sym = 'dtb_embed_begin'
5072 end_sym = 'dtb_embed_end'
5073 retcode = self._DoTestFile(
5074 '060_fdt_update.dts', update_dtb=True,
5075 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5076 self.assertEqual(0, retcode)
5077
5078 # Check that the output file does in fact contact a dtb with the binman
5079 # definition in the correct place
5080 syms = elf.GetSymbolFileOffset(infile,
5081 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07005082 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06005083 dtb_data = data[syms['dtb_embed_begin'].offset:
5084 syms['dtb_embed_end'].offset]
5085
5086 dtb = fdt.Fdt.FromData(dtb_data)
5087 dtb.Scan()
5088 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
5089 self.assertEqual({
5090 'image-pos': 0,
5091 'offset': 0,
5092 '_testing:offset': 32,
5093 '_testing:size': 2,
5094 '_testing:image-pos': 32,
5095 'section@0/u-boot:offset': 0,
5096 'section@0/u-boot:size': len(U_BOOT_DATA),
5097 'section@0/u-boot:image-pos': 0,
5098 'section@0:offset': 0,
5099 'section@0:size': 16,
5100 'section@0:image-pos': 0,
5101
5102 'section@1/u-boot:offset': 0,
5103 'section@1/u-boot:size': len(U_BOOT_DATA),
5104 'section@1/u-boot:image-pos': 16,
5105 'section@1:offset': 16,
5106 'section@1:size': 16,
5107 'section@1:image-pos': 16,
5108 'size': 40
5109 }, props)
5110
5111 def testUpdateFdtInElfInvalid(self):
5112 """Test that invalid args are detected with --update-fdt-in-elf"""
5113 with self.assertRaises(ValueError) as e:
5114 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5115 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5116 str(e.exception))
5117
5118 def testUpdateFdtInElfNoSyms(self):
5119 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005120 if not elf.ELF_TOOLS:
5121 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005122 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5123 outfile = ''
5124 begin_sym = 'wrong_begin'
5125 end_sym = 'wrong_end'
5126 with self.assertRaises(ValueError) as e:
5127 self._DoTestFile(
5128 '060_fdt_update.dts',
5129 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5130 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5131 str(e.exception))
5132
5133 def testUpdateFdtInElfTooSmall(self):
5134 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005135 if not elf.ELF_TOOLS:
5136 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005137 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5138 outfile = os.path.join(self._indir, 'u-boot.out')
5139 begin_sym = 'dtb_embed_begin'
5140 end_sym = 'dtb_embed_end'
5141 with self.assertRaises(ValueError) as e:
5142 self._DoTestFile(
5143 '060_fdt_update.dts', update_dtb=True,
5144 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5145 self.assertRegex(
5146 str(e.exception),
5147 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5148
Simon Glass88e04da2021-11-23 11:03:42 -07005149 def testVersion(self):
5150 """Test we can get the binman version"""
5151 version = '(unreleased)'
5152 self.assertEqual(version, state.GetVersion(self._indir))
5153
5154 with self.assertRaises(SystemExit):
5155 with test_util.capture_sys_output() as (_, stderr):
5156 self._DoBinman('-V')
5157 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5158
5159 # Try running the tool too, just to be safe
5160 result = self._RunBinman('-V')
5161 self.assertEqual('Binman %s\n' % version, result.stderr)
5162
5163 # Set up a version file to make sure that works
5164 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005165 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005166 binary=False)
5167 self.assertEqual(version, state.GetVersion(self._indir))
5168
Simon Glass637958f2021-11-23 21:09:50 -07005169 def testAltFormat(self):
5170 """Test that alternative formats can be used to extract"""
5171 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5172
5173 try:
5174 tmpdir, updated_fname = self._SetupImageInTmpdir()
5175 with test_util.capture_sys_output() as (stdout, _):
5176 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5177 self.assertEqual(
5178 '''Flag (-F) Entry type Description
5179fdt fdtmap Extract the devicetree blob from the fdtmap
5180''',
5181 stdout.getvalue())
5182
5183 dtb = os.path.join(tmpdir, 'fdt.dtb')
5184 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5185 dtb, 'fdtmap')
5186
5187 # Check that we can read it and it can be scanning, meaning it does
5188 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005189 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005190 dtb = fdt.Fdt.FromData(data)
5191 dtb.Scan()
5192
5193 # Now check u-boot which has no alt_format
5194 fname = os.path.join(tmpdir, 'fdt.dtb')
5195 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5196 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005197 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005198 self.assertEqual(U_BOOT_DATA, data)
5199
5200 finally:
5201 shutil.rmtree(tmpdir)
5202
Simon Glass0b00ae62021-11-23 21:09:52 -07005203 def testExtblobList(self):
5204 """Test an image with an external blob list"""
5205 data = self._DoReadFile('215_blob_ext_list.dts')
5206 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5207
5208 def testExtblobListMissing(self):
5209 """Test an image with a missing external blob"""
5210 with self.assertRaises(ValueError) as e:
5211 self._DoReadFile('216_blob_ext_list_missing.dts')
5212 self.assertIn("Filename 'missing-file' not found in input path",
5213 str(e.exception))
5214
5215 def testExtblobListMissingOk(self):
5216 """Test an image with an missing external blob that is allowed"""
5217 with test_util.capture_sys_output() as (stdout, stderr):
5218 self._DoTestFile('216_blob_ext_list_missing.dts',
5219 allow_missing=True)
5220 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005221 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005222
Simon Glass3efb2972021-11-23 21:08:59 -07005223 def testFip(self):
5224 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5225 data = self._DoReadFile('203_fip.dts')
5226 hdr, fents = fip_util.decode_fip(data)
5227 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5228 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5229 self.assertEqual(0x123, hdr.flags)
5230
5231 self.assertEqual(2, len(fents))
5232
5233 fent = fents[0]
5234 self.assertEqual(
5235 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5236 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5237 self.assertEqual('soc-fw', fent.fip_type)
5238 self.assertEqual(0x88, fent.offset)
5239 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5240 self.assertEqual(0x123456789abcdef, fent.flags)
5241 self.assertEqual(ATF_BL31_DATA, fent.data)
5242 self.assertEqual(True, fent.valid)
5243
5244 fent = fents[1]
5245 self.assertEqual(
5246 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5247 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5248 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5249 self.assertEqual(0x8c, fent.offset)
5250 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5251 self.assertEqual(0, fent.flags)
5252 self.assertEqual(ATF_BL2U_DATA, fent.data)
5253 self.assertEqual(True, fent.valid)
5254
5255 def testFipOther(self):
5256 """Basic FIP with something that isn't a external blob"""
5257 data = self._DoReadFile('204_fip_other.dts')
5258 hdr, fents = fip_util.decode_fip(data)
5259
5260 self.assertEqual(2, len(fents))
5261 fent = fents[1]
5262 self.assertEqual('rot-cert', fent.fip_type)
5263 self.assertEqual(b'aa', fent.data)
5264
Simon Glass3efb2972021-11-23 21:08:59 -07005265 def testFipNoType(self):
5266 """FIP with an entry of an unknown type"""
5267 with self.assertRaises(ValueError) as e:
5268 self._DoReadFile('205_fip_no_type.dts')
5269 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5270 str(e.exception))
5271
5272 def testFipUuid(self):
5273 """Basic FIP with a manual uuid"""
5274 data = self._DoReadFile('206_fip_uuid.dts')
5275 hdr, fents = fip_util.decode_fip(data)
5276
5277 self.assertEqual(2, len(fents))
5278 fent = fents[1]
5279 self.assertEqual(None, fent.fip_type)
5280 self.assertEqual(
5281 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5282 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5283 fent.uuid)
5284 self.assertEqual(U_BOOT_DATA, fent.data)
5285
5286 def testFipLs(self):
5287 """Test listing a FIP"""
5288 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5289 hdr, fents = fip_util.decode_fip(data)
5290
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005291 tmpdir = None
Simon Glass3efb2972021-11-23 21:08:59 -07005292 try:
5293 tmpdir, updated_fname = self._SetupImageInTmpdir()
5294 with test_util.capture_sys_output() as (stdout, stderr):
5295 self._DoBinman('ls', '-i', updated_fname)
5296 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005297 if tmpdir:
5298 shutil.rmtree(tmpdir)
Simon Glass3efb2972021-11-23 21:08:59 -07005299 lines = stdout.getvalue().splitlines()
5300 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005301'Name Image-pos Size Entry-type Offset Uncomp-size',
5302'--------------------------------------------------------------',
5303'image 0 2d3 section 0',
5304' atf-fip 0 90 atf-fip 0',
5305' soc-fw 88 4 blob-ext 88',
5306' u-boot 8c 4 u-boot 8c',
5307' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005308]
5309 self.assertEqual(expected, lines)
5310
5311 image = control.images['image']
5312 entries = image.GetEntries()
5313 fdtmap = entries['fdtmap']
5314
5315 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5316 magic = fdtmap_data[:8]
5317 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005318 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005319
5320 fdt_data = fdtmap_data[16:]
5321 dtb = fdt.Fdt.FromData(fdt_data)
5322 dtb.Scan()
5323 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5324 self.assertEqual({
5325 'atf-fip/soc-fw:image-pos': 136,
5326 'atf-fip/soc-fw:offset': 136,
5327 'atf-fip/soc-fw:size': 4,
5328 'atf-fip/u-boot:image-pos': 140,
5329 'atf-fip/u-boot:offset': 140,
5330 'atf-fip/u-boot:size': 4,
5331 'atf-fip:image-pos': 0,
5332 'atf-fip:offset': 0,
5333 'atf-fip:size': 144,
5334 'image-pos': 0,
5335 'offset': 0,
5336 'fdtmap:image-pos': fdtmap.image_pos,
5337 'fdtmap:offset': fdtmap.offset,
5338 'fdtmap:size': len(fdtmap_data),
5339 'size': len(data),
5340 }, props)
5341
5342 def testFipExtractOneEntry(self):
5343 """Test extracting a single entry fron an FIP"""
5344 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005345 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005346 fname = os.path.join(self._indir, 'output.extact')
5347 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005348 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005349 self.assertEqual(U_BOOT_DATA, data)
5350
5351 def testFipReplace(self):
5352 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005353 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005354 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005355 updated_fname = tools.get_output_filename('image-updated.bin')
5356 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005357 entry_name = 'atf-fip/u-boot'
5358 control.WriteEntry(updated_fname, entry_name, expected,
5359 allow_resize=True)
5360 actual = control.ReadEntry(updated_fname, entry_name)
5361 self.assertEqual(expected, actual)
5362
Simon Glass80025522022-01-29 14:14:04 -07005363 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005364 hdr, fents = fip_util.decode_fip(new_data)
5365
5366 self.assertEqual(2, len(fents))
5367
5368 # Check that the FIP entry is updated
5369 fent = fents[1]
5370 self.assertEqual(0x8c, fent.offset)
5371 self.assertEqual(len(expected), fent.size)
5372 self.assertEqual(0, fent.flags)
5373 self.assertEqual(expected, fent.data)
5374 self.assertEqual(True, fent.valid)
5375
5376 def testFipMissing(self):
5377 with test_util.capture_sys_output() as (stdout, stderr):
5378 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5379 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005380 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005381
5382 def testFipSize(self):
5383 """Test a FIP with a size property"""
5384 data = self._DoReadFile('210_fip_size.dts')
5385 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5386 hdr, fents = fip_util.decode_fip(data)
5387 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5388 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5389
5390 self.assertEqual(1, len(fents))
5391
5392 fent = fents[0]
5393 self.assertEqual('soc-fw', fent.fip_type)
5394 self.assertEqual(0x60, fent.offset)
5395 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5396 self.assertEqual(ATF_BL31_DATA, fent.data)
5397 self.assertEqual(True, fent.valid)
5398
5399 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005400 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005401
5402 def testFipBadAlign(self):
5403 """Test that an invalid alignment value in a FIP is detected"""
5404 with self.assertRaises(ValueError) as e:
5405 self._DoTestFile('211_fip_bad_align.dts')
5406 self.assertIn(
5407 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5408 str(e.exception))
5409
5410 def testFipCollection(self):
5411 """Test using a FIP in a collection"""
5412 data = self._DoReadFile('212_fip_collection.dts')
5413 entry1 = control.images['image'].GetEntries()['collection']
5414 data1 = data[:entry1.size]
5415 hdr1, fents2 = fip_util.decode_fip(data1)
5416
5417 entry2 = control.images['image'].GetEntries()['atf-fip']
5418 data2 = data[entry2.offset:entry2.offset + entry2.size]
5419 hdr1, fents2 = fip_util.decode_fip(data2)
5420
5421 # The 'collection' entry should have U-Boot included at the end
5422 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5423 self.assertEqual(data1, data2 + U_BOOT_DATA)
5424 self.assertEqual(U_BOOT_DATA, data1[-4:])
5425
5426 # There should be a U-Boot after the final FIP
5427 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005428
Simon Glassccae6862022-01-12 13:10:35 -07005429 def testFakeBlob(self):
5430 """Test handling of faking an external blob"""
5431 with test_util.capture_sys_output() as (stdout, stderr):
5432 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5433 allow_fake_blobs=True)
5434 err = stderr.getvalue()
5435 self.assertRegex(
5436 err,
5437 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005438
Simon Glassceb5f912022-01-09 20:13:46 -07005439 def testExtblobListFaked(self):
5440 """Test an extblob with missing external blob that are faked"""
5441 with test_util.capture_sys_output() as (stdout, stderr):
5442 self._DoTestFile('216_blob_ext_list_missing.dts',
5443 allow_fake_blobs=True)
5444 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005445 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005446
Simon Glass162017b2022-01-09 20:13:57 -07005447 def testListBintools(self):
5448 args = ['tool', '--list']
5449 with test_util.capture_sys_output() as (stdout, _):
5450 self._DoBinman(*args)
5451 out = stdout.getvalue().splitlines()
5452 self.assertTrue(len(out) >= 2)
5453
5454 def testFetchBintools(self):
5455 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005456 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005457 raise urllib.error.URLError('my error')
5458
5459 args = ['tool']
5460 with self.assertRaises(ValueError) as e:
5461 self._DoBinman(*args)
5462 self.assertIn("Invalid arguments to 'tool' subcommand",
5463 str(e.exception))
5464
5465 args = ['tool', '--fetch']
5466 with self.assertRaises(ValueError) as e:
5467 self._DoBinman(*args)
5468 self.assertIn('Please specify bintools to fetch', str(e.exception))
5469
5470 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005471 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005472 side_effect=fail_download):
5473 with test_util.capture_sys_output() as (stdout, _):
5474 self._DoBinman(*args)
5475 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5476
Simon Glass620c4462022-01-09 20:14:11 -07005477 def testBintoolDocs(self):
5478 """Test for creation of bintool documentation"""
5479 with test_util.capture_sys_output() as (stdout, stderr):
5480 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5481 self.assertTrue(len(stdout.getvalue()) > 0)
5482
5483 def testBintoolDocsMissing(self):
5484 """Test handling of missing bintool documentation"""
5485 with self.assertRaises(ValueError) as e:
5486 with test_util.capture_sys_output() as (stdout, stderr):
5487 control.write_bintool_docs(
5488 control.bintool.Bintool.get_tool_list(), 'mkimage')
5489 self.assertIn('Documentation is missing for modules: mkimage',
5490 str(e.exception))
5491
Jan Kiszka58c407f2022-01-28 20:37:53 +01005492 def testListWithGenNode(self):
5493 """Check handling of an FDT map when the section cannot be found"""
5494 entry_args = {
5495 'of-list': 'test-fdt1 test-fdt2',
5496 }
5497 data = self._DoReadFileDtb(
5498 '219_fit_gennode.dts',
5499 entry_args=entry_args,
5500 use_real_dtb=True,
5501 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5502
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005503 tmpdir = None
Jan Kiszka58c407f2022-01-28 20:37:53 +01005504 try:
5505 tmpdir, updated_fname = self._SetupImageInTmpdir()
5506 with test_util.capture_sys_output() as (stdout, stderr):
5507 self._RunBinman('ls', '-i', updated_fname)
5508 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005509 if tmpdir:
5510 shutil.rmtree(tmpdir)
Jan Kiszka58c407f2022-01-28 20:37:53 +01005511
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005512 def testFitSubentryUsesBintool(self):
5513 """Test that binman FIT subentries can use bintools"""
Simon Glass5dc22cf2025-02-03 09:26:42 -07005514 command.TEST_RESULT = self._HandleGbbCommand
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005515 entry_args = {
5516 'keydir': 'devkeys',
5517 'bmpblk': 'bmpblk.bin',
5518 }
5519 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5520 entry_args=entry_args)
5521
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005522 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5523 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005524 self.assertIn(expected, data)
5525
5526 def testFitSubentryMissingBintool(self):
5527 """Test that binman reports missing bintools for FIT subentries"""
5528 entry_args = {
5529 'keydir': 'devkeys',
5530 }
5531 with test_util.capture_sys_output() as (_, stderr):
5532 self._DoTestFile('220_fit_subentry_bintool.dts',
5533 force_missing_bintools='futility', entry_args=entry_args)
5534 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005535 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005536
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005537 def testFitSubentryHashSubnode(self):
5538 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005539 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005540 data, _, _, out_dtb_name = self._DoReadFileDtb(
5541 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5542
5543 mkimage_dtb = fdt.Fdt.FromData(data)
5544 mkimage_dtb.Scan()
5545 binman_dtb = fdt.Fdt(out_dtb_name)
5546 binman_dtb.Scan()
5547
5548 # Check that binman didn't add hash values
5549 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5550 self.assertNotIn('value', fnode.props)
5551
5552 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5553 self.assertNotIn('value', fnode.props)
5554
5555 # Check that mkimage added hash values
5556 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5557 self.assertIn('value', fnode.props)
5558
5559 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5560 self.assertIn('value', fnode.props)
5561
Roger Quadros5cdcea02022-02-19 20:50:04 +02005562 def testPackTeeOs(self):
5563 """Test that an image with an TEE binary can be created"""
5564 data = self._DoReadFile('222_tee_os.dts')
5565 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5566
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305567 def testPackTiDm(self):
5568 """Test that an image with a TI DM binary can be created"""
5569 data = self._DoReadFile('225_ti_dm.dts')
5570 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5571
Simon Glass912339f2022-02-08 11:50:03 -07005572 def testFitFdtOper(self):
5573 """Check handling of a specified FIT operation"""
5574 entry_args = {
5575 'of-list': 'test-fdt1 test-fdt2',
5576 'default-dt': 'test-fdt2',
5577 }
5578 self._DoReadFileDtb(
5579 '223_fit_fdt_oper.dts',
5580 entry_args=entry_args,
5581 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5582
5583 def testFitFdtBadOper(self):
5584 """Check handling of an FDT map when the section cannot be found"""
5585 with self.assertRaises(ValueError) as exc:
5586 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005587 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005588 str(exc.exception))
5589
Simon Glassdd156a42022-03-05 20:18:59 -07005590 def test_uses_expand_size(self):
5591 """Test that the 'expand-size' property cannot be used anymore"""
5592 with self.assertRaises(ValueError) as e:
5593 data = self._DoReadFile('225_expand_size_bad.dts')
5594 self.assertIn(
5595 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5596 str(e.exception))
5597
Simon Glass5f423422022-03-05 20:19:12 -07005598 def testFitSplitElf(self):
5599 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005600 if not elf.ELF_TOOLS:
5601 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005602 entry_args = {
5603 'of-list': 'test-fdt1 test-fdt2',
5604 'default-dt': 'test-fdt2',
5605 'atf-bl31-path': 'bl31.elf',
5606 'tee-os-path': 'tee.elf',
5607 }
5608 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5609 data = self._DoReadFileDtb(
5610 '226_fit_split_elf.dts',
5611 entry_args=entry_args,
5612 extra_indirs=[test_subdir])[0]
5613
5614 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5615 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5616
5617 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5618 'data', 'load'}
5619 dtb = fdt.Fdt.FromData(fit_data)
5620 dtb.Scan()
5621
5622 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5623 segments, entry = elf.read_loadable_segments(elf_data)
5624
5625 # We assume there are two segments
Brandon Maiera657bc62024-06-04 16:16:05 +00005626 self.assertEqual(2, len(segments))
Simon Glass5f423422022-03-05 20:19:12 -07005627
5628 atf1 = dtb.GetNode('/images/atf-1')
5629 _, start, data = segments[0]
5630 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5631 self.assertEqual(entry,
5632 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5633 self.assertEqual(start,
5634 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5635 self.assertEqual(data, atf1.props['data'].bytes)
5636
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005637 hash_node = atf1.FindNode('hash')
5638 self.assertIsNotNone(hash_node)
5639 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5640
Simon Glass5f423422022-03-05 20:19:12 -07005641 atf2 = dtb.GetNode('/images/atf-2')
5642 self.assertEqual(base_keys, atf2.props.keys())
5643 _, start, data = segments[1]
5644 self.assertEqual(start,
5645 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5646 self.assertEqual(data, atf2.props['data'].bytes)
5647
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005648 hash_node = atf2.FindNode('hash')
5649 self.assertIsNotNone(hash_node)
5650 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5651
5652 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5653 self.assertIsNotNone(hash_node)
5654 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5655
Simon Glass5f423422022-03-05 20:19:12 -07005656 conf = dtb.GetNode('/configurations')
5657 self.assertEqual({'default'}, conf.props.keys())
5658
5659 for subnode in conf.subnodes:
5660 self.assertEqual({'description', 'fdt', 'loadables'},
5661 subnode.props.keys())
5662 self.assertEqual(
5663 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5664 fdt_util.GetStringList(subnode, 'loadables'))
5665
5666 def _check_bad_fit(self, dts):
5667 """Check a bad FIT
5668
5669 This runs with the given dts and returns the assertion raised
5670
5671 Args:
5672 dts (str): dts filename to use
5673
5674 Returns:
5675 str: Assertion string raised
5676 """
5677 entry_args = {
5678 'of-list': 'test-fdt1 test-fdt2',
5679 'default-dt': 'test-fdt2',
5680 'atf-bl31-path': 'bl31.elf',
5681 'tee-os-path': 'tee.elf',
5682 }
5683 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5684 with self.assertRaises(ValueError) as exc:
5685 self._DoReadFileDtb(dts, entry_args=entry_args,
5686 extra_indirs=[test_subdir])[0]
5687 return str(exc.exception)
5688
5689 def testFitSplitElfBadElf(self):
5690 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005691 if not elf.ELF_TOOLS:
5692 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005693 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5694 entry_args = {
5695 'of-list': 'test-fdt1 test-fdt2',
5696 'default-dt': 'test-fdt2',
5697 'atf-bl31-path': 'bad.elf',
5698 'tee-os-path': 'tee.elf',
5699 }
5700 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5701 with self.assertRaises(ValueError) as exc:
5702 self._DoReadFileDtb(
5703 '226_fit_split_elf.dts',
5704 entry_args=entry_args,
5705 extra_indirs=[test_subdir])[0]
5706 self.assertIn(
5707 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5708 str(exc.exception))
5709
Simon Glass5f423422022-03-05 20:19:12 -07005710 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005711 """Test an split-elf FIT with a missing ELF file
5712
5713 Args:
5714 kwargs (dict of str): Arguments to pass to _DoTestFile()
5715
5716 Returns:
5717 tuple:
5718 str: stdout result
5719 str: stderr result
5720 """
Simon Glass5f423422022-03-05 20:19:12 -07005721 entry_args = {
5722 'of-list': 'test-fdt1 test-fdt2',
5723 'default-dt': 'test-fdt2',
5724 'atf-bl31-path': 'bl31.elf',
5725 'tee-os-path': 'missing.elf',
5726 }
5727 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5728 with test_util.capture_sys_output() as (stdout, stderr):
5729 self._DoTestFile(
5730 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005731 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5732 out = stdout.getvalue()
5733 err = stderr.getvalue()
5734 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005735
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005736 def testFitSplitElfBadDirective(self):
5737 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5738 if not elf.ELF_TOOLS:
5739 self.skipTest('Python elftools not available')
5740 err = self._check_bad_fit('227_fit_bad_dir.dts')
5741 self.assertIn(
5742 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5743 err)
5744
5745 def testFitSplitElfBadDirectiveConfig(self):
5746 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5747 if not elf.ELF_TOOLS:
5748 self.skipTest('Python elftools not available')
5749 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5750 self.assertEqual(
5751 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5752 err)
5753
5754
Simon Glass5f423422022-03-05 20:19:12 -07005755 def testFitSplitElfMissing(self):
5756 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005757 if not elf.ELF_TOOLS:
5758 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005759 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005760 self.assertRegex(
5761 err,
5762 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005763 self.assertNotRegex(out, '.*Faked blob.*')
5764 fname = tools.get_output_filename('binman-fake/missing.elf')
5765 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005766
5767 def testFitSplitElfFaked(self):
5768 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005769 if not elf.ELF_TOOLS:
5770 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005771 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005772 self.assertRegex(
5773 err,
5774 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005775 self.assertRegex(
5776 out,
5777 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5778 fname = tools.get_output_filename('binman-fake/missing.elf')
5779 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005780
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005781 def testMkimageMissingBlob(self):
5782 """Test using mkimage to build an image"""
5783 with test_util.capture_sys_output() as (stdout, stderr):
5784 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5785 allow_fake_blobs=True)
5786 err = stderr.getvalue()
5787 self.assertRegex(
5788 err,
5789 "Image '.*' has faked external blobs and is non-functional: .*")
5790
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005791 def testPreLoad(self):
5792 """Test an image with a pre-load header"""
5793 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005794 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005795 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005796 data = self._DoReadFileDtb(
5797 '230_pre_load.dts', entry_args=entry_args,
5798 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Paul HENRYS5cf82892025-02-24 22:20:55 +01005799
5800 image_fname = tools.get_output_filename('image.bin')
5801 is_signed = self._CheckPreload(image_fname, self.TestFile("dev.key"))
5802
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005803 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5804 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5805 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Paul HENRYS5cf82892025-02-24 22:20:55 +01005806 self.assertEqual(is_signed, True)
Simon Glasse2dfb962023-07-24 09:19:57 -06005807
5808 def testPreLoadNoKey(self):
5809 """Test an image with a pre-load heade0r with missing key"""
5810 with self.assertRaises(FileNotFoundError) as exc:
5811 self._DoReadFile('230_pre_load.dts')
5812 self.assertIn("No such file or directory: 'dev.key'",
5813 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005814
5815 def testPreLoadPkcs(self):
5816 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005817 entry_args = {
5818 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5819 }
5820 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5821 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005822 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5823 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5824 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5825
5826 def testPreLoadPss(self):
5827 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005828 entry_args = {
5829 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5830 }
5831 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5832 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005833 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5834 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5835 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5836
5837 def testPreLoadInvalidPadding(self):
5838 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005839 entry_args = {
5840 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5841 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005842 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005843 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5844 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005845
5846 def testPreLoadInvalidSha(self):
5847 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005848 entry_args = {
5849 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5850 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005851 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005852 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5853 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005854
5855 def testPreLoadInvalidAlgo(self):
5856 """Test an image with a pre-load header with an invalid algo"""
5857 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005858 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005859
5860 def testPreLoadInvalidKey(self):
5861 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005862 entry_args = {
5863 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5864 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005865 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005866 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5867 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005868
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005869 def _CheckSafeUniqueNames(self, *images):
5870 """Check all entries of given images for unsafe unique names"""
5871 for image in images:
5872 entries = {}
5873 image._CollectEntries(entries, {}, image)
5874 for entry in entries.values():
5875 uniq = entry.GetUniqueName()
5876
5877 # Used as part of a filename, so must not be absolute paths.
5878 self.assertFalse(os.path.isabs(uniq))
5879
5880 def testSafeUniqueNames(self):
5881 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005882 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005883
5884 orig_image = control.images['image']
5885 image_fname = tools.get_output_filename('image.bin')
5886 image = Image.FromFile(image_fname)
5887
5888 self._CheckSafeUniqueNames(orig_image, image)
5889
5890 def testSafeUniqueNamesMulti(self):
5891 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005892 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005893
5894 orig_image = control.images['image']
5895 image_fname = tools.get_output_filename('image.bin')
5896 image = Image.FromFile(image_fname)
5897
5898 self._CheckSafeUniqueNames(orig_image, image)
5899
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005900 def testReplaceCmdWithBintool(self):
5901 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005902 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005903 expected = U_BOOT_DATA + b'aa'
5904 self.assertEqual(expected, data[:len(expected)])
5905
5906 try:
5907 tmpdir, updated_fname = self._SetupImageInTmpdir()
5908 fname = os.path.join(tmpdir, 'update-testing.bin')
5909 tools.write_file(fname, b'zz')
5910 self._DoBinman('replace', '-i', updated_fname,
5911 '_testing', '-f', fname)
5912
5913 data = tools.read_file(updated_fname)
5914 expected = U_BOOT_DATA + b'zz'
5915 self.assertEqual(expected, data[:len(expected)])
5916 finally:
5917 shutil.rmtree(tmpdir)
5918
5919 def testReplaceCmdOtherWithBintool(self):
5920 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005921 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005922 expected = U_BOOT_DATA + b'aa'
5923 self.assertEqual(expected, data[:len(expected)])
5924
5925 try:
5926 tmpdir, updated_fname = self._SetupImageInTmpdir()
5927 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5928 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5929 self._DoBinman('replace', '-i', updated_fname,
5930 'u-boot', '-f', fname)
5931
5932 data = tools.read_file(updated_fname)
5933 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5934 self.assertEqual(expected, data[:len(expected)])
5935 finally:
5936 shutil.rmtree(tmpdir)
5937
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005938 def testReplaceResizeNoRepackSameSize(self):
5939 """Test replacing entries with same-size data without repacking"""
5940 expected = b'x' * len(U_BOOT_DATA)
5941 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5942 self.assertEqual(expected, data)
5943
5944 path, fdtmap = state.GetFdtContents('fdtmap')
5945 self.assertIsNotNone(path)
5946 self.assertEqual(expected_fdtmap, fdtmap)
5947
5948 def testReplaceResizeNoRepackSmallerSize(self):
5949 """Test replacing entries with smaller-size data without repacking"""
5950 new_data = b'x'
5951 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5952 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5953 self.assertEqual(expected, data)
5954
5955 path, fdtmap = state.GetFdtContents('fdtmap')
5956 self.assertIsNotNone(path)
5957 self.assertEqual(expected_fdtmap, fdtmap)
5958
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005959 def testExtractFit(self):
5960 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005961 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005962 image_fname = tools.get_output_filename('image.bin')
5963
5964 fit_data = control.ReadEntry(image_fname, 'fit')
5965 fit = fdt.Fdt.FromData(fit_data)
5966 fit.Scan()
5967
5968 # Check subentry data inside the extracted fit
5969 for node_path, expected in [
5970 ('/images/kernel', U_BOOT_DATA),
5971 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5972 ('/images/scr-1', COMPRESS_DATA),
5973 ]:
5974 node = fit.GetNode(node_path)
5975 data = fit.GetProps(node)['data'].bytes
5976 self.assertEqual(expected, data)
5977
5978 def testExtractFitSubentries(self):
5979 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005980 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005981 image_fname = tools.get_output_filename('image.bin')
5982
5983 for entry_path, expected in [
5984 ('fit/kernel', U_BOOT_DATA),
5985 ('fit/kernel/u-boot', U_BOOT_DATA),
5986 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5987 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5988 ('fit/scr-1', COMPRESS_DATA),
5989 ('fit/scr-1/blob', COMPRESS_DATA),
5990 ]:
5991 data = control.ReadEntry(image_fname, entry_path)
5992 self.assertEqual(expected, data)
5993
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005994 def testReplaceFitSubentryLeafSameSize(self):
5995 """Test replacing a FIT leaf subentry with same-size data"""
5996 new_data = b'x' * len(U_BOOT_DATA)
5997 data, expected_fdtmap, _ = self._RunReplaceCmd(
5998 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005999 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006000 self.assertEqual(new_data, data)
6001
6002 path, fdtmap = state.GetFdtContents('fdtmap')
6003 self.assertIsNotNone(path)
6004 self.assertEqual(expected_fdtmap, fdtmap)
6005
6006 def testReplaceFitSubentryLeafBiggerSize(self):
6007 """Test replacing a FIT leaf subentry with bigger-size data"""
6008 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
6009 data, expected_fdtmap, _ = self._RunReplaceCmd(
6010 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006011 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006012 self.assertEqual(new_data, data)
6013
6014 # Will be repacked, so fdtmap must change
6015 path, fdtmap = state.GetFdtContents('fdtmap')
6016 self.assertIsNotNone(path)
6017 self.assertNotEqual(expected_fdtmap, fdtmap)
6018
6019 def testReplaceFitSubentryLeafSmallerSize(self):
6020 """Test replacing a FIT leaf subentry with smaller-size data"""
6021 new_data = b'x'
6022 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
6023 data, expected_fdtmap, _ = self._RunReplaceCmd(
6024 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006025 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006026 self.assertEqual(expected, data)
6027
6028 path, fdtmap = state.GetFdtContents('fdtmap')
6029 self.assertIsNotNone(path)
6030 self.assertEqual(expected_fdtmap, fdtmap)
6031
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006032 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07006033 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006034 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07006035 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6036 new_data, dts='241_replace_section_simple.dts')
6037 self.assertEqual(new_data, data)
6038
6039 entries = image.GetEntries()
6040 self.assertIn('section', entries)
6041 entry = entries['section']
6042 self.assertEqual(len(new_data), entry.size)
6043
6044 def testReplaceSectionLarger(self):
6045 """Test replacing a simple section with larger data"""
6046 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6047 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6048 new_data, dts='241_replace_section_simple.dts')
6049 self.assertEqual(new_data, data)
6050
6051 entries = image.GetEntries()
6052 self.assertIn('section', entries)
6053 entry = entries['section']
6054 self.assertEqual(len(new_data), entry.size)
6055 fentry = entries['fdtmap']
6056 self.assertEqual(entry.offset + entry.size, fentry.offset)
6057
6058 def testReplaceSectionSmaller(self):
6059 """Test replacing a simple section with smaller data"""
6060 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
6061 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6062 new_data, dts='241_replace_section_simple.dts')
6063 self.assertEqual(new_data, data)
6064
6065 # The new size is the same as the old, just with a pad byte at the end
6066 entries = image.GetEntries()
6067 self.assertIn('section', entries)
6068 entry = entries['section']
6069 self.assertEqual(len(new_data), entry.size)
6070
6071 def testReplaceSectionSmallerAllow(self):
6072 """Test failing to replace a simple section with smaller data"""
6073 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
6074 try:
6075 state.SetAllowEntryContraction(True)
6076 with self.assertRaises(ValueError) as exc:
6077 self._RunReplaceCmd('section', new_data,
6078 dts='241_replace_section_simple.dts')
6079 finally:
6080 state.SetAllowEntryContraction(False)
6081
6082 # Since we have no information about the position of things within the
6083 # section, we cannot adjust the position of /section-u-boot so it ends
6084 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06006085 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07006086 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
6087 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06006088 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006089
Simon Glass8fbca772022-08-13 11:40:48 -06006090 def testMkimageImagename(self):
6091 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006092 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006093 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06006094
6095 # Check that the data appears in the file somewhere
6096 self.assertIn(U_BOOT_SPL_DATA, data)
6097
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006098 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06006099 name = data[0x20:0x40]
6100
6101 # Build the filename that we expect to be placed in there, by virtue of
6102 # the -n paraameter
6103 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6104
6105 # Check that the image name is set to the temporary filename used
6106 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6107
Simon Glassb1669752022-08-13 11:40:49 -06006108 def testMkimageImage(self):
6109 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006110 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006111 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006112
6113 # Check that the data appears in the file somewhere
6114 self.assertIn(U_BOOT_SPL_DATA, data)
6115
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006116 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006117 name = data[0x20:0x40]
6118
6119 # Build the filename that we expect to be placed in there, by virtue of
6120 # the -n paraameter
6121 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6122
6123 # Check that the image name is set to the temporary filename used
6124 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6125
6126 # Check the corect data is in the imagename file
6127 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6128
6129 def testMkimageImageNoContent(self):
6130 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006131 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006132 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006133 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006134 self.assertIn('Could not complete processing of contents',
6135 str(exc.exception))
6136
6137 def testMkimageImageBad(self):
6138 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006139 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006140 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006141 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006142 self.assertIn('Cannot use both imagename node and data-to-imagename',
6143 str(exc.exception))
6144
Simon Glassbd5cd882022-08-13 11:40:50 -06006145 def testCollectionOther(self):
6146 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006147 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006148 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6149 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6150 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6151 data)
6152
6153 def testMkimageCollection(self):
6154 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006155 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006156 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006157 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6158 self.assertEqual(expect, data[:len(expect)])
6159
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006160 def testCompressDtbPrependInvalid(self):
6161 """Test that invalid header is detected"""
6162 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006163 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006164 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6165 "'u-boot-dtb': 'invalid'", str(e.exception))
6166
6167 def testCompressDtbPrependLength(self):
6168 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006169 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006170 image = control.images['image']
6171 entries = image.GetEntries()
6172 self.assertIn('u-boot-dtb', entries)
6173 u_boot_dtb = entries['u-boot-dtb']
6174 self.assertIn('fdtmap', entries)
6175 fdtmap = entries['fdtmap']
6176
6177 image_fname = tools.get_output_filename('image.bin')
6178 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6179 dtb = fdt.Fdt.FromData(orig)
6180 dtb.Scan()
6181 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6182 expected = {
6183 'u-boot:size': len(U_BOOT_DATA),
6184 'u-boot-dtb:uncomp-size': len(orig),
6185 'u-boot-dtb:size': u_boot_dtb.size,
6186 'fdtmap:size': fdtmap.size,
6187 'size': len(data),
6188 }
6189 self.assertEqual(expected, props)
6190
6191 # Check implementation
6192 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6193 rest = data[len(U_BOOT_DATA):]
6194 comp_data_len = struct.unpack('<I', rest[:4])[0]
6195 comp_data = rest[4:4 + comp_data_len]
6196 orig2 = self._decompress(comp_data)
6197 self.assertEqual(orig, orig2)
6198
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006199 def testInvalidCompress(self):
6200 """Test that invalid compress algorithm is detected"""
6201 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006202 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006203 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6204
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006205 def testCompUtilCompressions(self):
6206 """Test compression algorithms"""
6207 for bintool in self.comp_bintools.values():
6208 self._CheckBintool(bintool)
6209 data = bintool.compress(COMPRESS_DATA)
6210 self.assertNotEqual(COMPRESS_DATA, data)
6211 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006212 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006213
6214 def testCompUtilVersions(self):
6215 """Test tool version of compression algorithms"""
6216 for bintool in self.comp_bintools.values():
6217 self._CheckBintool(bintool)
6218 version = bintool.version()
6219 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6220
6221 def testCompUtilPadding(self):
6222 """Test padding of compression algorithms"""
Jiaxun Yangc6931742025-04-10 06:43:03 -06006223 # Skip zstd and lz4 because they doesn't support padding
6224 for bintool in [v for k,v in self.comp_bintools.items()
6225 if not k in ['zstd', 'lz4']]:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006226 self._CheckBintool(bintool)
6227 data = bintool.compress(COMPRESS_DATA)
6228 self.assertNotEqual(COMPRESS_DATA, data)
6229 data += tools.get_bytes(0, 64)
6230 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006231 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006232
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006233 def testCompressDtbZstd(self):
6234 """Test that zstd compress of device-tree files failed"""
6235 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006236 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006237 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6238 "requires a length header", str(e.exception))
6239
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006240 def testMkimageMultipleDataFiles(self):
6241 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006242 self._SetupSplElf()
6243 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006244 data = self._DoReadFile('252_mkimage_mult_data.dts')
6245 # Size of files are packed in their 4B big-endian format
6246 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6247 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6248 # Size info is always followed by a 4B zero value.
6249 expect += tools.get_bytes(0, 4)
6250 expect += U_BOOT_TPL_DATA
6251 # All but last files are 4B-aligned
6252 align_pad = len(U_BOOT_TPL_DATA) % 4
6253 if align_pad:
6254 expect += tools.get_bytes(0, align_pad)
6255 expect += U_BOOT_SPL_DATA
6256 self.assertEqual(expect, data[-len(expect):])
6257
Marek Vasutf7413f02023-07-18 07:23:58 -06006258 def testMkimageMultipleExpanded(self):
6259 """Test passing multiple files to mkimage in a mkimage entry"""
6260 self._SetupSplElf()
6261 self._SetupTplElf()
6262 entry_args = {
6263 'spl-bss-pad': 'y',
6264 'spl-dtb': 'y',
6265 }
6266 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6267 use_expanded=True, entry_args=entry_args)[0]
6268 pad_len = 10
6269 tpl_expect = U_BOOT_TPL_DATA
6270 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6271 spl_expect += U_BOOT_SPL_DTB_DATA
6272
6273 content = data[0x40:]
6274 lens = struct.unpack('>III', content[:12])
6275
6276 # Size of files are packed in their 4B big-endian format
6277 # Size info is always followed by a 4B zero value.
6278 self.assertEqual(len(tpl_expect), lens[0])
6279 self.assertEqual(len(spl_expect), lens[1])
6280 self.assertEqual(0, lens[2])
6281
6282 rest = content[12:]
6283 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6284
6285 rest = rest[len(tpl_expect):]
6286 align_pad = len(tpl_expect) % 4
6287 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6288 rest = rest[align_pad:]
6289 self.assertEqual(spl_expect, rest)
6290
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006291 def testMkimageMultipleNoContent(self):
6292 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006293 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006294 with self.assertRaises(ValueError) as exc:
6295 self._DoReadFile('253_mkimage_mult_no_content.dts')
6296 self.assertIn('Could not complete processing of contents',
6297 str(exc.exception))
6298
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006299 def testMkimageFilename(self):
6300 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006301 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006302 retcode = self._DoTestFile('254_mkimage_filename.dts')
6303 self.assertEqual(0, retcode)
6304 fname = tools.get_output_filename('mkimage-test.bin')
6305 self.assertTrue(os.path.exists(fname))
6306
Simon Glass56d05412022-02-28 07:16:54 -07006307 def testVpl(self):
6308 """Test that an image with VPL and its device tree can be created"""
6309 # ELF file with a '__bss_size' symbol
6310 self._SetupVplElf()
6311 data = self._DoReadFile('255_u_boot_vpl.dts')
6312 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6313
6314 def testVplNoDtb(self):
6315 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6316 self._SetupVplElf()
6317 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6318 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6319 data[:len(U_BOOT_VPL_NODTB_DATA)])
6320
6321 def testExpandedVpl(self):
6322 """Test that an expanded entry type is selected for TPL when needed"""
6323 self._SetupVplElf()
6324
6325 entry_args = {
6326 'vpl-bss-pad': 'y',
6327 'vpl-dtb': 'y',
6328 }
6329 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6330 entry_args=entry_args)
6331 image = control.images['image']
6332 entries = image.GetEntries()
6333 self.assertEqual(1, len(entries))
6334
6335 # We only have u-boot-vpl, which be expanded
6336 self.assertIn('u-boot-vpl', entries)
6337 entry = entries['u-boot-vpl']
6338 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6339 subent = entry.GetEntries()
6340 self.assertEqual(3, len(subent))
6341 self.assertIn('u-boot-vpl-nodtb', subent)
6342 self.assertIn('u-boot-vpl-bss-pad', subent)
6343 self.assertIn('u-boot-vpl-dtb', subent)
6344
6345 def testVplBssPadMissing(self):
6346 """Test that a missing symbol is detected"""
6347 self._SetupVplElf('u_boot_ucode_ptr')
6348 with self.assertRaises(ValueError) as e:
6349 self._DoReadFile('258_vpl_bss_pad.dts')
6350 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6351 str(e.exception))
6352
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306353 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306354 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306355 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6356 self.assertEqual(0, retcode)
6357 image = control.images['test_image']
6358 fname = tools.get_output_filename('test_image.bin')
6359 sname = tools.get_output_filename('symlink_to_test.bin')
6360 self.assertTrue(os.path.islink(sname))
6361 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006362
Andrew Davis6b463da2023-07-22 00:14:44 +05306363 def testSymlinkOverwrite(self):
6364 """Test that symlinked images can be overwritten"""
6365 testdir = TestFunctional._MakeInputDir('symlinktest')
6366 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6367 # build the same image again in the same directory so that existing symlink is present
6368 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6369 fname = tools.get_output_filename('test_image.bin')
6370 sname = tools.get_output_filename('symlink_to_test.bin')
6371 self.assertTrue(os.path.islink(sname))
6372 self.assertEqual(os.readlink(sname), fname)
6373
Simon Glass37f85de2022-10-20 18:22:47 -06006374 def testSymbolsElf(self):
6375 """Test binman can assign symbols embedded in an ELF file"""
6376 if not elf.ELF_TOOLS:
6377 self.skipTest('Python elftools not available')
6378 self._SetupTplElf('u_boot_binman_syms')
6379 self._SetupVplElf('u_boot_binman_syms')
6380 self._SetupSplElf('u_boot_binman_syms')
6381 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6382 image_fname = tools.get_output_filename('image.bin')
6383
6384 image = control.images['image']
6385 entries = image.GetEntries()
6386
6387 for entry in entries.values():
6388 # No symbols in u-boot and it has faked contents anyway
6389 if entry.name == 'u-boot':
6390 continue
6391 edata = data[entry.image_pos:entry.image_pos + entry.size]
6392 efname = tools.get_output_filename(f'edata-{entry.name}')
6393 tools.write_file(efname, edata)
6394
6395 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6396 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6397 for name, sym in syms.items():
6398 msg = 'test'
6399 val = elf.GetSymbolValue(sym, edata, msg)
6400 entry_m = re_name.match(name)
6401 if entry_m:
6402 ename, prop = entry_m.group(1), entry_m.group(3)
6403 entry, entry_name, prop_name = image.LookupEntry(entries,
6404 name, msg)
Simon Glassd3d3a102025-02-19 08:11:16 -07006405 expect_val = None
Simon Glass37f85de2022-10-20 18:22:47 -06006406 if prop_name == 'offset':
6407 expect_val = entry.offset
6408 elif prop_name == 'image_pos':
6409 expect_val = entry.image_pos
6410 elif prop_name == 'size':
6411 expect_val = entry.size
6412 self.assertEqual(expect_val, val)
6413
6414 def testSymbolsElfBad(self):
6415 """Check error when trying to write symbols without the elftools lib"""
6416 if not elf.ELF_TOOLS:
6417 self.skipTest('Python elftools not available')
6418 self._SetupTplElf('u_boot_binman_syms')
6419 self._SetupVplElf('u_boot_binman_syms')
6420 self._SetupSplElf('u_boot_binman_syms')
6421 try:
6422 elf.ELF_TOOLS = False
6423 with self.assertRaises(ValueError) as exc:
6424 self._DoReadFileDtb('260_symbols_elf.dts')
6425 finally:
6426 elf.ELF_TOOLS = True
6427 self.assertIn(
6428 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6429 'Cannot write symbols to an ELF file without Python elftools',
6430 str(exc.exception))
6431
Simon Glassde244162023-01-07 14:07:08 -07006432 def testSectionFilename(self):
6433 """Check writing of section contents to a file"""
6434 data = self._DoReadFile('261_section_fname.dts')
6435 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6436 tools.get_bytes(ord('!'), 7) +
6437 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6438 self.assertEqual(expected, data)
6439
6440 sect_fname = tools.get_output_filename('outfile.bin')
6441 self.assertTrue(os.path.exists(sect_fname))
6442 sect_data = tools.read_file(sect_fname)
6443 self.assertEqual(U_BOOT_DATA, sect_data)
6444
Simon Glass1e9e61c2023-01-07 14:07:12 -07006445 def testAbsent(self):
6446 """Check handling of absent entries"""
6447 data = self._DoReadFile('262_absent.dts')
6448 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6449
Simon Glassad5cfe12023-01-07 14:07:14 -07006450 def testPackTeeOsOptional(self):
6451 """Test that an image with an optional TEE binary can be created"""
6452 entry_args = {
6453 'tee-os-path': 'tee.elf',
6454 }
6455 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6456 entry_args=entry_args)[0]
6457 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6458
6459 def checkFitTee(self, dts, tee_fname):
6460 """Check that a tee-os entry works and returns data
6461
6462 Args:
6463 dts (str): Device tree filename to use
6464 tee_fname (str): filename containing tee-os
6465
6466 Returns:
6467 bytes: Image contents
6468 """
6469 if not elf.ELF_TOOLS:
6470 self.skipTest('Python elftools not available')
6471 entry_args = {
6472 'of-list': 'test-fdt1 test-fdt2',
6473 'default-dt': 'test-fdt2',
6474 'tee-os-path': tee_fname,
6475 }
6476 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6477 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6478 extra_indirs=[test_subdir])[0]
6479 return data
6480
6481 def testFitTeeOsOptionalFit(self):
6482 """Test an image with a FIT with an optional OP-TEE binary"""
6483 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6484
6485 # There should be only one node, holding the data set up in SetUpClass()
6486 # for tee.bin
6487 dtb = fdt.Fdt.FromData(data)
6488 dtb.Scan()
6489 node = dtb.GetNode('/images/tee-1')
6490 self.assertEqual(TEE_ADDR,
6491 fdt_util.fdt32_to_cpu(node.props['load'].value))
6492 self.assertEqual(TEE_ADDR,
6493 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6494 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6495
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006496 with test_util.capture_sys_output() as (stdout, stderr):
6497 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6498 err = stderr.getvalue()
6499 self.assertRegex(
6500 err,
6501 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6502
Simon Glassad5cfe12023-01-07 14:07:14 -07006503 def testFitTeeOsOptionalFitBad(self):
6504 """Test an image with a FIT with an optional OP-TEE binary"""
6505 with self.assertRaises(ValueError) as exc:
6506 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6507 self.assertIn(
6508 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6509 str(exc.exception))
6510
6511 def testFitTeeOsBad(self):
6512 """Test an OP-TEE binary with wrong formats"""
6513 self.make_tee_bin('tee.bad1', 123)
6514 with self.assertRaises(ValueError) as exc:
6515 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6516 self.assertIn(
6517 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6518 str(exc.exception))
6519
6520 self.make_tee_bin('tee.bad2', 0, b'extra data')
6521 with self.assertRaises(ValueError) as exc:
6522 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6523 self.assertIn(
6524 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6525 str(exc.exception))
6526
Simon Glass63328f12023-01-07 14:07:15 -07006527 def testExtblobOptional(self):
6528 """Test an image with an external blob that is optional"""
6529 with test_util.capture_sys_output() as (stdout, stderr):
6530 data = self._DoReadFile('266_blob_ext_opt.dts')
6531 self.assertEqual(REFCODE_DATA, data)
6532 err = stderr.getvalue()
6533 self.assertRegex(
6534 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006535 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006536
Simon Glass7447a9d2023-01-11 16:10:12 -07006537 def testSectionInner(self):
6538 """Test an inner section with a size"""
6539 data = self._DoReadFile('267_section_inner.dts')
6540 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6541 self.assertEqual(expected, data)
6542
Simon Glassa4948b22023-01-11 16:10:14 -07006543 def testNull(self):
6544 """Test an image with a null entry"""
6545 data = self._DoReadFile('268_null.dts')
6546 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6547
Simon Glassf1ee03b2023-01-11 16:10:16 -07006548 def testOverlap(self):
6549 """Test an image with a overlapping entry"""
6550 data = self._DoReadFile('269_overlap.dts')
6551 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6552
6553 image = control.images['image']
6554 entries = image.GetEntries()
6555
6556 self.assertIn('inset', entries)
6557 inset = entries['inset']
6558 self.assertEqual(1, inset.offset);
6559 self.assertEqual(1, inset.image_pos);
6560 self.assertEqual(2, inset.size);
6561
6562 def testOverlapNull(self):
6563 """Test an image with a null overlap"""
6564 data = self._DoReadFile('270_overlap_null.dts')
6565 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6566
6567 # Check the FMAP
6568 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6569 self.assertEqual(4, fhdr.nareas)
6570 fiter = iter(fentries)
6571
6572 fentry = next(fiter)
6573 self.assertEqual(b'SECTION', fentry.name)
6574 self.assertEqual(0, fentry.offset)
6575 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6576 self.assertEqual(0, fentry.flags)
6577
6578 fentry = next(fiter)
6579 self.assertEqual(b'U_BOOT', fentry.name)
6580 self.assertEqual(0, fentry.offset)
6581 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6582 self.assertEqual(0, fentry.flags)
6583
6584 # Make sure that the NULL entry appears in the FMAP
6585 fentry = next(fiter)
6586 self.assertEqual(b'NULL', fentry.name)
6587 self.assertEqual(1, fentry.offset)
6588 self.assertEqual(2, fentry.size)
6589 self.assertEqual(0, fentry.flags)
6590
6591 fentry = next(fiter)
6592 self.assertEqual(b'FMAP', fentry.name)
6593 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6594
6595 def testOverlapBad(self):
6596 """Test an image with a bad overlapping entry"""
6597 with self.assertRaises(ValueError) as exc:
6598 self._DoReadFile('271_overlap_bad.dts')
6599 self.assertIn(
6600 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6601 str(exc.exception))
6602
6603 def testOverlapNoOffset(self):
6604 """Test an image with a bad overlapping entry"""
6605 with self.assertRaises(ValueError) as exc:
6606 self._DoReadFile('272_overlap_no_size.dts')
6607 self.assertIn(
6608 "Node '/binman/inset': 'fill' entry is missing properties: size",
6609 str(exc.exception))
6610
Simon Glasse0035c92023-01-11 16:10:17 -07006611 def testBlobSymbol(self):
6612 """Test a blob with symbols read from an ELF file"""
6613 elf_fname = self.ElfTestFile('blob_syms')
6614 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6615 TestFunctional._MakeInputFile('blob_syms.bin',
6616 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6617
6618 data = self._DoReadFile('273_blob_symbol.dts')
6619
6620 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6621 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6622 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6623 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6624 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6625
6626 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6627 expected = sym_values
6628 self.assertEqual(expected, data[:len(expected)])
6629
Simon Glass49e9c002023-01-11 16:10:19 -07006630 def testOffsetFromElf(self):
6631 """Test a blob with symbols read from an ELF file"""
6632 elf_fname = self.ElfTestFile('blob_syms')
6633 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6634 TestFunctional._MakeInputFile('blob_syms.bin',
6635 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6636
6637 data = self._DoReadFile('274_offset_from_elf.dts')
6638
6639 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6640 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6641
6642 image = control.images['image']
6643 entries = image.GetEntries()
6644
6645 self.assertIn('inset', entries)
6646 inset = entries['inset']
6647
6648 self.assertEqual(base + 4, inset.offset);
6649 self.assertEqual(base + 4, inset.image_pos);
6650 self.assertEqual(4, inset.size);
6651
6652 self.assertIn('inset2', entries)
6653 inset = entries['inset2']
6654 self.assertEqual(base + 8, inset.offset);
6655 self.assertEqual(base + 8, inset.image_pos);
6656 self.assertEqual(4, inset.size);
6657
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006658 def testFitAlign(self):
6659 """Test an image with an FIT with aligned external data"""
6660 data = self._DoReadFile('275_fit_align.dts')
6661 self.assertEqual(4096, len(data))
6662
6663 dtb = fdt.Fdt.FromData(data)
6664 dtb.Scan()
6665
6666 props = self._GetPropTree(dtb, ['data-position'])
6667 expected = {
6668 'u-boot:data-position': 1024,
6669 'fdt-1:data-position': 2048,
6670 'fdt-2:data-position': 3072,
6671 }
6672 self.assertEqual(expected, props)
6673
Jonas Karlman490f73c2023-01-21 19:02:12 +00006674 def testFitFirmwareLoadables(self):
6675 """Test an image with an FIT that use fit,firmware"""
6676 if not elf.ELF_TOOLS:
6677 self.skipTest('Python elftools not available')
6678 entry_args = {
6679 'of-list': 'test-fdt1',
6680 'default-dt': 'test-fdt1',
6681 'atf-bl31-path': 'bl31.elf',
6682 'tee-os-path': 'missing.bin',
6683 }
6684 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006685 with test_util.capture_sys_output() as (stdout, stderr):
6686 data = self._DoReadFileDtb(
6687 '276_fit_firmware_loadables.dts',
6688 entry_args=entry_args,
6689 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006690
6691 dtb = fdt.Fdt.FromData(data)
6692 dtb.Scan()
6693
6694 node = dtb.GetNode('/configurations/conf-uboot-1')
6695 self.assertEqual('u-boot', node.props['firmware'].value)
6696 self.assertEqual(['atf-1', 'atf-2'],
6697 fdt_util.GetStringList(node, 'loadables'))
6698
6699 node = dtb.GetNode('/configurations/conf-atf-1')
6700 self.assertEqual('atf-1', node.props['firmware'].value)
6701 self.assertEqual(['u-boot', 'atf-2'],
6702 fdt_util.GetStringList(node, 'loadables'))
6703
6704 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6705 self.assertEqual('u-boot', node.props['firmware'].value)
6706 self.assertEqual(['atf-1', 'atf-2'],
6707 fdt_util.GetStringList(node, 'loadables'))
6708
6709 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6710 self.assertEqual('atf-1', node.props['firmware'].value)
6711 self.assertEqual(['u-boot', 'atf-2'],
6712 fdt_util.GetStringList(node, 'loadables'))
6713
6714 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6715 self.assertEqual('atf-1', node.props['firmware'].value)
6716 self.assertEqual(['u-boot', 'atf-2'],
6717 fdt_util.GetStringList(node, 'loadables'))
6718
Simon Glass9a1c7262023-02-22 12:14:49 -07006719 def testTooldir(self):
6720 """Test that we can specify the tooldir"""
6721 with test_util.capture_sys_output() as (stdout, stderr):
6722 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6723 'tool', '-l'))
6724 self.assertEqual('fred', bintool.Bintool.tooldir)
6725
6726 # Check that the toolpath is updated correctly
6727 self.assertEqual(['fred'], tools.tool_search_paths)
6728
6729 # Try with a few toolpaths; the tooldir should be at the end
6730 with test_util.capture_sys_output() as (stdout, stderr):
6731 self.assertEqual(0, self._DoBinman(
6732 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6733 'tool', '-l'))
6734 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6735
Simon Glass49b77e82023-03-02 17:02:44 -07006736 def testReplaceSectionEntry(self):
6737 """Test replacing an entry in a section"""
6738 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6739 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6740 expect_data, dts='241_replace_section_simple.dts')
6741 self.assertEqual(expect_data, entry_data)
6742
6743 entries = image.GetEntries()
6744 self.assertIn('section', entries)
6745 section = entries['section']
6746
6747 sect_entries = section.GetEntries()
6748 self.assertIn('blob', sect_entries)
6749 entry = sect_entries['blob']
6750 self.assertEqual(len(expect_data), entry.size)
6751
6752 fname = tools.get_output_filename('image-updated.bin')
6753 data = tools.read_file(fname)
6754
6755 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6756 self.assertEqual(expect_data, new_blob_data)
6757
6758 self.assertEqual(U_BOOT_DATA,
6759 data[entry.image_pos + len(expect_data):]
6760 [:len(U_BOOT_DATA)])
6761
6762 def testReplaceSectionDeep(self):
6763 """Test replacing an entry in two levels of sections"""
6764 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6765 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6766 'section/section/blob', expect_data,
6767 dts='278_replace_section_deep.dts')
6768 self.assertEqual(expect_data, entry_data)
6769
6770 entries = image.GetEntries()
6771 self.assertIn('section', entries)
6772 section = entries['section']
6773
6774 subentries = section.GetEntries()
6775 self.assertIn('section', subentries)
6776 section = subentries['section']
6777
6778 sect_entries = section.GetEntries()
6779 self.assertIn('blob', sect_entries)
6780 entry = sect_entries['blob']
6781 self.assertEqual(len(expect_data), entry.size)
6782
6783 fname = tools.get_output_filename('image-updated.bin')
6784 data = tools.read_file(fname)
6785
6786 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6787 self.assertEqual(expect_data, new_blob_data)
6788
6789 self.assertEqual(U_BOOT_DATA,
6790 data[entry.image_pos + len(expect_data):]
6791 [:len(U_BOOT_DATA)])
6792
6793 def testReplaceFitSibling(self):
6794 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006795 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006796 fname = TestFunctional._MakeInputFile('once', b'available once')
6797 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6798 os.remove(fname)
6799
6800 try:
6801 tmpdir, updated_fname = self._SetupImageInTmpdir()
6802
6803 fname = os.path.join(tmpdir, 'update-blob')
6804 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6805 tools.write_file(fname, expected)
6806
6807 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6808 data = tools.read_file(updated_fname)
6809 start = len(U_BOOT_DTB_DATA)
6810 self.assertEqual(expected, data[start:start + len(expected)])
6811 map_fname = os.path.join(tmpdir, 'image-updated.map')
6812 self.assertFalse(os.path.exists(map_fname))
6813 finally:
6814 shutil.rmtree(tmpdir)
6815
Simon Glassc3fe97f2023-03-02 17:02:45 -07006816 def testX509Cert(self):
6817 """Test creating an X509 certificate"""
6818 keyfile = self.TestFile('key.key')
6819 entry_args = {
6820 'keyfile': keyfile,
6821 }
6822 data = self._DoReadFileDtb('279_x509_cert.dts',
6823 entry_args=entry_args)[0]
6824 cert = data[:-4]
6825 self.assertEqual(U_BOOT_DATA, data[-4:])
6826
6827 # TODO: verify the signature
6828
6829 def testX509CertMissing(self):
6830 """Test that binman still produces an image if openssl is missing"""
6831 keyfile = self.TestFile('key.key')
6832 entry_args = {
6833 'keyfile': 'keyfile',
6834 }
6835 with test_util.capture_sys_output() as (_, stderr):
6836 self._DoTestFile('279_x509_cert.dts',
6837 force_missing_bintools='openssl',
6838 entry_args=entry_args)
6839 err = stderr.getvalue()
6840 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6841
Jonas Karlman35305492023-02-25 19:01:33 +00006842 def testPackRockchipTpl(self):
6843 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006844 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006845 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6846
Jonas Karlman1016ec72023-02-25 19:01:35 +00006847 def testMkimageMissingBlobMultiple(self):
6848 """Test missing blob with mkimage entry and multiple-data-files"""
6849 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006850 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006851 err = stderr.getvalue()
6852 self.assertIn("is missing external blobs and is non-functional", err)
6853
6854 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006855 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006856 self.assertIn("not found in input path", str(e.exception))
6857
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006858 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6859 """Prepare sign environment
6860
6861 Create private and public keys, add pubkey into dtb.
6862
6863 Returns:
6864 Tuple:
6865 FIT container
6866 Image name
6867 Private key
6868 DTB
6869 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006870 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006871 data = self._DoReadFileRealDtb(dts)
6872 updated_fname = tools.get_output_filename('image-updated.bin')
6873 tools.write_file(updated_fname, data)
6874 dtb = tools.get_output_filename('source.dtb')
6875 private_key = tools.get_output_filename('test_key.key')
6876 public_key = tools.get_output_filename('test_key.crt')
6877 fit = tools.get_output_filename('fit.fit')
6878 key_dir = tools.get_output_dir()
6879
6880 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6881 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6882 private_key, '-out', public_key)
6883 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6884 '-n', 'test_key', '-r', 'conf', dtb)
6885
6886 return fit, updated_fname, private_key, dtb
6887
6888 def testSignSimple(self):
6889 """Test that a FIT container can be signed in image"""
6890 is_signed = False
6891 fit, fname, private_key, dtb = self._PrepareSignEnv()
6892
6893 # do sign with private key
6894 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6895 ['fit'])
6896 is_signed = self._CheckSign(fit, dtb)
6897
6898 self.assertEqual(is_signed, True)
6899
6900 def testSignExactFIT(self):
6901 """Test that a FIT container can be signed and replaced in image"""
6902 is_signed = False
6903 fit, fname, private_key, dtb = self._PrepareSignEnv()
6904
6905 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6906 args = []
6907 if self.toolpath:
6908 for path in self.toolpath:
6909 args += ['--toolpath', path]
6910
6911 # do sign with private key
6912 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6913 'sha256,rsa4096', '-f', fit, 'fit')
6914 is_signed = self._CheckSign(fit, dtb)
6915
6916 self.assertEqual(is_signed, True)
6917
6918 def testSignNonFit(self):
6919 """Test a non-FIT entry cannot be signed"""
6920 is_signed = False
6921 fit, fname, private_key, _ = self._PrepareSignEnv(
6922 '281_sign_non_fit.dts')
6923
6924 # do sign with private key
6925 with self.assertRaises(ValueError) as e:
6926 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6927 'sha256,rsa4096', '-f', fit, 'u-boot')
6928 self.assertIn(
6929 "Node '/u-boot': Updating signatures is not supported with this entry type",
6930 str(e.exception))
6931
6932 def testSignMissingMkimage(self):
6933 """Test that FIT signing handles a missing mkimage tool"""
6934 fit, fname, private_key, _ = self._PrepareSignEnv()
6935
6936 # try to sign with a missing mkimage tool
6937 bintool.Bintool.set_missing_list(['mkimage'])
6938 with self.assertRaises(ValueError) as e:
6939 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6940 ['fit'])
6941 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6942
Simon Glass4abf7842023-07-18 07:23:54 -06006943 def testSymbolNoWrite(self):
6944 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006945 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006946 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6947 no_write_symbols=True)
6948
6949 def testSymbolNoWriteExpanded(self):
6950 """Test disabling of symbol writing in expanded entries"""
6951 entry_args = {
6952 'spl-dtb': '1',
6953 }
6954 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6955 U_BOOT_SPL_DTB_DATA, 0x38,
6956 entry_args=entry_args, use_expanded=True,
6957 no_write_symbols=True)
6958
Marek Vasutf7413f02023-07-18 07:23:58 -06006959 def testMkimageSpecial(self):
6960 """Test mkimage ignores special hash-1 node"""
6961 data = self._DoReadFile('283_mkimage_special.dts')
6962
6963 # Just check that the data appears in the file somewhere
6964 self.assertIn(U_BOOT_DATA, data)
6965
Simon Glass2d94c422023-07-18 07:23:59 -06006966 def testFitFdtList(self):
6967 """Test an image with an FIT with the fit,fdt-list-val option"""
6968 entry_args = {
6969 'default-dt': 'test-fdt2',
6970 }
6971 data = self._DoReadFileDtb(
6972 '284_fit_fdt_list.dts',
6973 entry_args=entry_args,
6974 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6975 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6976 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6977
Simon Glass83b8bfe2023-07-18 07:24:01 -06006978 def testSplEmptyBss(self):
6979 """Test an expanded SPL with a zero-size BSS"""
6980 # ELF file with a '__bss_size' symbol
6981 self._SetupSplElf(src_fname='bss_data_zero')
6982
6983 entry_args = {
6984 'spl-bss-pad': 'y',
6985 'spl-dtb': 'y',
6986 }
6987 data = self._DoReadFileDtb('285_spl_expand.dts',
6988 use_expanded=True, entry_args=entry_args)[0]
6989
Simon Glassfc792842023-07-18 07:24:04 -06006990 def testTemplate(self):
6991 """Test using a template"""
6992 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6993 data = self._DoReadFile('286_template.dts')
6994 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6995 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6996 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6997
Simon Glass09490b02023-07-22 21:43:52 -06006998 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6999 self.assertTrue(os.path.exists(dtb_fname1))
7000 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
7001 dtb.Scan()
7002 node1 = dtb.GetNode('/binman/template')
7003 self.assertTrue(node1)
7004 vga = dtb.GetNode('/binman/first/intel-vga')
7005 self.assertTrue(vga)
7006
Simon Glass54825e12023-07-22 21:43:56 -06007007 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
7008 self.assertTrue(os.path.exists(dtb_fname2))
7009 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
7010 dtb2.Scan()
7011 node2 = dtb2.GetNode('/binman/template')
7012 self.assertFalse(node2)
7013
Simon Glass9909c112023-07-18 07:24:05 -06007014 def testTemplateBlobMulti(self):
7015 """Test using a template with 'multiple-images' enabled"""
7016 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
7017 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
7018 retcode = self._DoTestFile('287_template_multi.dts')
7019
7020 self.assertEqual(0, retcode)
7021 image = control.images['image']
7022 image_fname = tools.get_output_filename('my-image.bin')
7023 data = tools.read_file(image_fname)
7024 self.assertEqual(b'blob@@@@other', data)
7025
Simon Glass5dc511b2023-07-18 07:24:06 -06007026 def testTemplateFit(self):
7027 """Test using a template in a FIT"""
7028 fit_data = self._DoReadFile('288_template_fit.dts')
7029 fname = os.path.join(self._indir, 'fit_data.fit')
7030 tools.write_file(fname, fit_data)
7031 out = tools.run('dumpimage', '-l', fname)
7032
Simon Glassaa6e0552023-07-18 07:24:07 -06007033 def testTemplateSection(self):
7034 """Test using a template in a section (not at top level)"""
7035 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
7036 data = self._DoReadFile('289_template_section.dts')
7037 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
7038 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
7039 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
7040
Simon Glassf53a7bc2023-07-18 07:24:08 -06007041 def testMkimageSymbols(self):
7042 """Test using mkimage to build an image with symbols in it"""
7043 self._SetupSplElf('u_boot_binman_syms')
7044 data = self._DoReadFile('290_mkimage_sym.dts')
7045
7046 image = control.images['image']
7047 entries = image.GetEntries()
7048 self.assertIn('u-boot', entries)
7049 u_boot = entries['u-boot']
7050
7051 mkim = entries['mkimage']
7052 mkim_entries = mkim.GetEntries()
7053 self.assertIn('u-boot-spl', mkim_entries)
7054 spl = mkim_entries['u-boot-spl']
7055 self.assertIn('u-boot-spl2', mkim_entries)
7056 spl2 = mkim_entries['u-boot-spl2']
7057
7058 # skip the mkimage header and the area sizes
7059 mk_data = data[mkim.offset + 0x40:]
7060 size, term = struct.unpack('>LL', mk_data[:8])
7061
7062 # There should be only one image, so check that the zero terminator is
7063 # present
7064 self.assertEqual(0, term)
7065
7066 content = mk_data[8:8 + size]
7067
7068 # The image should contain the symbols from u_boot_binman_syms.c
7069 # Note that image_pos is adjusted by the base address of the image,
7070 # which is 0x10 in our test image
7071 spl_data = content[:0x18]
7072 content = content[0x1b:]
7073
7074 # After the header is a table of offsets for each image. There should
7075 # only be one image, then a 0 terminator, so figure out the real start
7076 # of the image data
7077 base = 0x40 + 8
7078
7079 # Check symbols in both u-boot-spl and u-boot-spl2
7080 for i in range(2):
7081 vals = struct.unpack('<LLQLL', spl_data)
7082
7083 # The image should contain the symbols from u_boot_binman_syms.c
7084 # Note that image_pos is adjusted by the base address of the image,
7085 # which is 0x10 in our 'u_boot_binman_syms' test image
7086 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
7087 self.assertEqual(base, vals[1])
7088 self.assertEqual(spl2.offset, vals[2])
7089 # figure out the internal positions of its components
7090 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
7091
7092 # Check that spl and spl2 are actually at the indicated positions
7093 self.assertEqual(
7094 elf.BINMAN_SYM_MAGIC_VALUE,
7095 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
7096 self.assertEqual(
7097 elf.BINMAN_SYM_MAGIC_VALUE,
7098 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
7099
7100 self.assertEqual(len(U_BOOT_DATA), vals[4])
7101
7102 # Move to next
7103 spl_data = content[:0x18]
7104
Simon Glass86b3e472023-07-22 21:43:57 -06007105 def testTemplatePhandle(self):
7106 """Test using a template in a node containing a phandle"""
7107 entry_args = {
7108 'atf-bl31-path': 'bl31.elf',
7109 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06007110 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007111 entry_args=entry_args)
7112 fname = tools.get_output_filename('image.bin')
7113 out = tools.run('dumpimage', '-l', fname)
7114
7115 # We should see the FIT description and one for each of the two images
7116 lines = out.splitlines()
7117 descs = [line.split()[-1] for line in lines if 'escription' in line]
7118 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7119
7120 def testTemplatePhandleDup(self):
7121 """Test using a template in a node containing a phandle"""
7122 entry_args = {
7123 'atf-bl31-path': 'bl31.elf',
7124 }
7125 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007126 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007127 entry_args=entry_args)
7128 self.assertIn(
7129 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7130 str(e.exception))
7131
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307132 def testTIBoardConfig(self):
7133 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007134 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307135 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7136
Neha Malcom Francis8cd04512024-01-05 17:09:17 +05307137 def testTIBoardConfigLint(self):
7138 """Test that an incorrectly linted config file would generate error"""
7139 with self.assertRaises(ValueError) as e:
7140 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7141 self.assertIn("Yamllint error", str(e.exception))
7142
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307143 def testTIBoardConfigCombined(self):
7144 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007145 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307146 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7147 self.assertGreater(data, configlen_noheader)
7148
7149 def testTIBoardConfigNoDataType(self):
7150 """Test that error is thrown when data type is not supported"""
7151 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007152 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307153 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007154
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307155 def testPackTiSecure(self):
7156 """Test that an image with a TI secured binary can be created"""
7157 keyfile = self.TestFile('key.key')
7158 entry_args = {
7159 'keyfile': keyfile,
7160 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007161 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307162 entry_args=entry_args)[0]
7163 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7164
Manorit Chawdhry2e523b02023-12-29 16:16:27 +05307165 def testPackTiSecureFirewall(self):
7166 """Test that an image with a TI secured binary can be created"""
7167 keyfile = self.TestFile('key.key')
7168 entry_args = {
7169 'keyfile': keyfile,
7170 }
7171 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7172 entry_args=entry_args)[0]
7173 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7174 entry_args=entry_args)[0]
7175 self.assertGreater(len(data_firewall),len(data_no_firewall))
7176
7177 def testPackTiSecureFirewallMissingProperty(self):
7178 """Test that an image with a TI secured binary can be created"""
7179 keyfile = self.TestFile('key.key')
7180 entry_args = {
7181 'keyfile': keyfile,
7182 }
7183 with self.assertRaises(ValueError) as e:
7184 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7185 entry_args=entry_args)[0]
7186 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7187
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307188 def testPackTiSecureMissingTool(self):
7189 """Test that an image with a TI secured binary (non-functional) can be created
7190 when openssl is missing"""
7191 keyfile = self.TestFile('key.key')
7192 entry_args = {
7193 'keyfile': keyfile,
7194 }
7195 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007196 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307197 force_missing_bintools='openssl',
7198 entry_args=entry_args)
7199 err = stderr.getvalue()
7200 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7201
7202 def testPackTiSecureROM(self):
7203 """Test that a ROM image with a TI secured binary can be created"""
7204 keyfile = self.TestFile('key.key')
7205 entry_args = {
7206 'keyfile': keyfile,
7207 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007208 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307209 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007210 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307211 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007212 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307213 entry_args=entry_args)[0]
7214 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7215 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7216 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7217
7218 def testPackTiSecureROMCombined(self):
7219 """Test that a ROM image with a TI secured binary can be created"""
7220 keyfile = self.TestFile('key.key')
7221 entry_args = {
7222 'keyfile': keyfile,
7223 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007224 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307225 entry_args=entry_args)[0]
7226 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7227
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007228 def testEncryptedNoAlgo(self):
7229 """Test encrypted node with missing required properties"""
7230 with self.assertRaises(ValueError) as e:
7231 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7232 self.assertIn(
7233 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7234 str(e.exception))
7235
7236 def testEncryptedInvalidIvfile(self):
7237 """Test encrypted node with invalid iv file"""
7238 with self.assertRaises(ValueError) as e:
7239 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7240 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7241 str(e.exception))
7242
7243 def testEncryptedMissingKey(self):
7244 """Test encrypted node with missing key properties"""
7245 with self.assertRaises(ValueError) as e:
7246 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7247 self.assertIn(
7248 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7249 str(e.exception))
7250
7251 def testEncryptedKeySource(self):
7252 """Test encrypted node with key-source property"""
7253 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7254
7255 dtb = fdt.Fdt.FromData(data)
7256 dtb.Scan()
7257
7258 node = dtb.GetNode('/images/u-boot/cipher')
7259 self.assertEqual('algo-name', node.props['algo'].value)
7260 self.assertEqual('key-source-value', node.props['key-source'].value)
7261 self.assertEqual(ENCRYPTED_IV_DATA,
7262 tools.to_bytes(''.join(node.props['iv'].value)))
7263 self.assertNotIn('key', node.props)
7264
7265 def testEncryptedKeyFile(self):
7266 """Test encrypted node with key-filename property"""
7267 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7268
7269 dtb = fdt.Fdt.FromData(data)
7270 dtb.Scan()
7271
7272 node = dtb.GetNode('/images/u-boot/cipher')
7273 self.assertEqual('algo-name', node.props['algo'].value)
7274 self.assertEqual(ENCRYPTED_IV_DATA,
7275 tools.to_bytes(''.join(node.props['iv'].value)))
7276 self.assertEqual(ENCRYPTED_KEY_DATA,
7277 tools.to_bytes(''.join(node.props['key'].value)))
7278 self.assertNotIn('key-source', node.props)
7279
Lukas Funkee901faf2023-07-18 13:53:13 +02007280
7281 def testSplPubkeyDtb(self):
Simon Glass4b861272024-07-20 11:49:41 +01007282 """Test u_boot_spl_pubkey_dtb etype"""
7283 data = tools.read_file(self.TestFile("key.pem"))
7284 self._MakeInputFile("key.crt", data)
7285 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7286 image = control.images['image']
7287 entries = image.GetEntries()
7288 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7289 dtb_data = dtb_entry.GetData()
7290 dtb = fdt.Fdt.FromData(dtb_data)
7291 dtb.Scan()
Lukas Funkee901faf2023-07-18 13:53:13 +02007292
Simon Glass4b861272024-07-20 11:49:41 +01007293 signature_node = dtb.GetNode('/signature')
7294 self.assertIsNotNone(signature_node)
7295 key_node = signature_node.FindNode("key-key")
7296 self.assertIsNotNone(key_node)
7297 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7298 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7299 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007300
Lukas Funke712e1062023-08-03 17:22:14 +02007301 def testXilinxBootgenSigning(self):
7302 """Test xilinx-bootgen etype"""
7303 bootgen = bintool.Bintool.create('bootgen')
7304 self._CheckBintool(bootgen)
7305 data = tools.read_file(self.TestFile("key.key"))
7306 self._MakeInputFile("psk.pem", data)
7307 self._MakeInputFile("ssk.pem", data)
7308 self._SetupPmuFwlElf()
7309 self._SetupSplElf()
7310 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7311 image_fname = tools.get_output_filename('image.bin')
7312
7313 # Read partition header table and check if authentication is enabled
7314 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7315 "-read", image_fname, "pht").splitlines()
7316 attributes = {"authentication": None,
7317 "core": None,
7318 "encryption": None}
7319
7320 for l in bootgen_out:
7321 for a in attributes.keys():
7322 if a in l:
7323 m = re.match(fr".*{a} \[([^]]+)\]", l)
7324 attributes[a] = m.group(1)
7325
7326 self.assertTrue(attributes['authentication'] == "rsa")
7327 self.assertTrue(attributes['core'] == "a53-0")
7328 self.assertTrue(attributes['encryption'] == "no")
7329
7330 def testXilinxBootgenSigningEncryption(self):
7331 """Test xilinx-bootgen etype"""
7332 bootgen = bintool.Bintool.create('bootgen')
7333 self._CheckBintool(bootgen)
7334 data = tools.read_file(self.TestFile("key.key"))
7335 self._MakeInputFile("psk.pem", data)
7336 self._MakeInputFile("ssk.pem", data)
7337 self._SetupPmuFwlElf()
7338 self._SetupSplElf()
7339 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7340 image_fname = tools.get_output_filename('image.bin')
7341
7342 # Read boot header in order to verify encryption source and
7343 # encryption parameter
7344 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7345 "-read", image_fname, "bh").splitlines()
7346 attributes = {"auth_only":
7347 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7348 "encryption_keystore":
7349 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7350 "value": None},
7351 }
7352
7353 for l in bootgen_out:
7354 for a in attributes.keys():
7355 if a in l:
7356 m = re.match(attributes[a]['re'], l)
7357 attributes[a] = m.group(1)
7358
7359 # Check if fsbl-attribute is set correctly
7360 self.assertTrue(attributes['auth_only'] == "true")
7361 # Check if key is stored in efuse
7362 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7363
7364 def testXilinxBootgenMissing(self):
7365 """Test that binman still produces an image if bootgen is missing"""
7366 data = tools.read_file(self.TestFile("key.key"))
7367 self._MakeInputFile("psk.pem", data)
7368 self._MakeInputFile("ssk.pem", data)
7369 self._SetupPmuFwlElf()
7370 self._SetupSplElf()
7371 with test_util.capture_sys_output() as (_, stderr):
7372 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7373 force_missing_bintools='bootgen')
7374 err = stderr.getvalue()
7375 self.assertRegex(err,
7376 "Image 'image'.*missing bintools.*: bootgen")
7377
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307378 def _GetCapsuleHeaders(self, data):
7379 """Get the capsule header contents
7380
7381 Args:
7382 data: Capsule file contents
7383
7384 Returns:
7385 Dict:
7386 key: Capsule Header name (str)
7387 value: Header field value (str)
7388 """
7389 capsule_file = os.path.join(self._indir, 'test.capsule')
7390 tools.write_file(capsule_file, data)
7391
7392 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7393 lines = out.splitlines()
7394
7395 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7396 vals = {}
7397 for line in lines:
7398 mat = re_line.match(line)
7399 if mat:
7400 vals[mat.group(1)] = mat.group(2)
7401
7402 return vals
7403
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307404 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7405 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307406 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7407 fmp_size = "00000010"
7408 fmp_fw_version = "00000002"
7409 capsule_image_index = "00000001"
7410 oemflag = "00018000"
7411 auth_hdr_revision = "00000200"
7412 auth_hdr_cert_type = "00000EF1"
7413
7414 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307415
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307416 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307417
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307418 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307419
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307420 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7421 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7422 self.assertEqual(capsule_image_index,
7423 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307424
7425 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307426 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7427
7428 if signed_capsule:
7429 self.assertEqual(auth_hdr_revision,
7430 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7431 self.assertEqual(auth_hdr_cert_type,
7432 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7433 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7434 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7435
7436 if version_check:
7437 self.assertEqual(fmp_signature,
7438 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7439 self.assertEqual(fmp_size,
7440 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7441 self.assertEqual(fmp_fw_version,
7442 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7443
7444 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307445
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307446 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7447 if accept_capsule:
7448 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7449 else:
7450 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7451
7452 hdr = self._GetCapsuleHeaders(data)
7453
7454 self.assertEqual(capsule_hdr_guid.upper(),
7455 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7456
7457 if accept_capsule:
7458 capsule_size = "0000002C"
7459 else:
7460 capsule_size = "0000001C"
7461 self.assertEqual(capsule_size,
7462 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7463
7464 if accept_capsule:
7465 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7466
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307467 def testCapsuleGen(self):
7468 """Test generation of EFI capsule"""
7469 data = self._DoReadFile('311_capsule.dts')
7470
7471 self._CheckCapsule(data)
7472
7473 def testSignedCapsuleGen(self):
7474 """Test generation of EFI capsule"""
7475 data = tools.read_file(self.TestFile("key.key"))
7476 self._MakeInputFile("key.key", data)
7477 data = tools.read_file(self.TestFile("key.pem"))
7478 self._MakeInputFile("key.crt", data)
7479
7480 data = self._DoReadFile('312_capsule_signed.dts')
7481
7482 self._CheckCapsule(data, signed_capsule=True)
7483
7484 def testCapsuleGenVersionSupport(self):
7485 """Test generation of EFI capsule with version support"""
7486 data = self._DoReadFile('313_capsule_version.dts')
7487
7488 self._CheckCapsule(data, version_check=True)
7489
7490 def testCapsuleGenSignedVer(self):
7491 """Test generation of signed EFI capsule with version information"""
7492 data = tools.read_file(self.TestFile("key.key"))
7493 self._MakeInputFile("key.key", data)
7494 data = tools.read_file(self.TestFile("key.pem"))
7495 self._MakeInputFile("key.crt", data)
7496
7497 data = self._DoReadFile('314_capsule_signed_ver.dts')
7498
7499 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7500
7501 def testCapsuleGenCapOemFlags(self):
7502 """Test generation of EFI capsule with OEM Flags set"""
7503 data = self._DoReadFile('315_capsule_oemflags.dts')
7504
7505 self._CheckCapsule(data, capoemflags=True)
7506
7507 def testCapsuleGenKeyMissing(self):
7508 """Test that binman errors out on missing key"""
7509 with self.assertRaises(ValueError) as e:
7510 self._DoReadFile('316_capsule_missing_key.dts')
7511
7512 self.assertIn("Both private key and public key certificate need to be provided",
7513 str(e.exception))
7514
7515 def testCapsuleGenIndexMissing(self):
7516 """Test that binman errors out on missing image index"""
7517 with self.assertRaises(ValueError) as e:
7518 self._DoReadFile('317_capsule_missing_index.dts')
7519
7520 self.assertIn("entry is missing properties: image-index",
7521 str(e.exception))
7522
7523 def testCapsuleGenGuidMissing(self):
7524 """Test that binman errors out on missing image GUID"""
7525 with self.assertRaises(ValueError) as e:
7526 self._DoReadFile('318_capsule_missing_guid.dts')
7527
7528 self.assertIn("entry is missing properties: image-guid",
7529 str(e.exception))
7530
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307531 def testCapsuleGenAcceptCapsule(self):
7532 """Test generationg of accept EFI capsule"""
7533 data = self._DoReadFile('319_capsule_accept.dts')
7534
7535 self._CheckEmptyCapsule(data, accept_capsule=True)
7536
7537 def testCapsuleGenRevertCapsule(self):
7538 """Test generationg of revert EFI capsule"""
7539 data = self._DoReadFile('320_capsule_revert.dts')
7540
7541 self._CheckEmptyCapsule(data)
7542
7543 def testCapsuleGenAcceptGuidMissing(self):
7544 """Test that binman errors out on missing image GUID for accept capsule"""
7545 with self.assertRaises(ValueError) as e:
7546 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7547
7548 self.assertIn("Image GUID needed for generating accept capsule",
7549 str(e.exception))
7550
7551 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7552 """Test that capsule-type is specified"""
7553 with self.assertRaises(ValueError) as e:
7554 self._DoReadFile('322_empty_capsule_type_missing.dts')
7555
7556 self.assertIn("entry is missing properties: capsule-type",
7557 str(e.exception))
7558
7559 def testCapsuleGenAcceptOrRevertMissing(self):
7560 """Test that both accept and revert capsule are not specified"""
7561 with self.assertRaises(ValueError) as e:
7562 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7563
Simon Glassa360b8f2024-06-23 11:55:06 -06007564 def test_assume_size(self):
7565 """Test handling of the assume-size property for external blob"""
7566 with self.assertRaises(ValueError) as e:
7567 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7568 allow_fake_blobs=True)
7569 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7570 str(e.exception))
7571
7572 def test_assume_size_ok(self):
7573 """Test handling of the assume-size where it fits OK"""
7574 with test_util.capture_sys_output() as (stdout, stderr):
7575 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7576 allow_fake_blobs=True)
7577 err = stderr.getvalue()
7578 self.assertRegex(
7579 err,
7580 "Image '.*' has faked external blobs and is non-functional: .*")
7581
7582 def test_assume_size_no_fake(self):
7583 """Test handling of the assume-size where it fits OK"""
7584 with test_util.capture_sys_output() as (stdout, stderr):
7585 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7586 err = stderr.getvalue()
7587 self.assertRegex(
7588 err,
7589 "Image '.*' is missing external blobs and is non-functional: .*")
7590
Simon Glass5f7aadf2024-07-20 11:49:47 +01007591 def SetupAlternateDts(self):
7592 """Compile the .dts test files for alternative-fdt
7593
7594 Returns:
7595 tuple:
7596 str: Test directory created
7597 list of str: '.bin' files which we expect Binman to create
7598 """
7599 testdir = TestFunctional._MakeInputDir('dtb')
7600 dtb_list = []
7601 for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
7602 tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
7603 base = os.path.splitext(os.path.basename(fname))[0]
7604 dtb_list.append(base + '.bin')
7605 shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
7606
7607 return testdir, dtb_list
7608
Simon Glassf3598922024-07-20 11:49:45 +01007609 def CheckAlternates(self, dts, phase, xpl_data):
7610 """Run the test for the alterative-fdt etype
7611
7612 Args:
7613 dts (str): Devicetree file to process
7614 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7615 xpl_data (bytes): Expected data for the phase's binary
7616
7617 Returns:
7618 dict of .dtb files produced
7619 key: str filename
7620 value: Fdt object
7621 """
Simon Glass5f7aadf2024-07-20 11:49:47 +01007622 dtb_list = self.SetupAlternateDts()[1]
Simon Glassf3598922024-07-20 11:49:45 +01007623
7624 entry_args = {
7625 f'{phase}-dtb': '1',
7626 f'{phase}-bss-pad': 'y',
7627 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7628 }
7629 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7630 use_expanded=True, entry_args=entry_args)[0]
7631 self.assertEqual(xpl_data, data[:len(xpl_data)])
7632 rest = data[len(xpl_data):]
7633 pad_len = 10
7634 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7635
7636 # Check the dtb is using the test file
7637 dtb_data = rest[pad_len:]
7638 dtb = fdt.Fdt.FromData(dtb_data)
7639 dtb.Scan()
7640 fdt_size = dtb.GetFdtObj().totalsize()
7641 self.assertEqual('model-not-set',
7642 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7643
7644 pad_len = 10
7645
7646 # Check the other output files
7647 dtbs = {}
7648 for fname in dtb_list:
7649 pathname = tools.get_output_filename(fname)
7650 self.assertTrue(os.path.exists(pathname))
7651
7652 data = tools.read_file(pathname)
7653 self.assertEqual(xpl_data, data[:len(xpl_data)])
7654 rest = data[len(xpl_data):]
7655
7656 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7657 rest = rest[pad_len:]
7658
7659 dtb = fdt.Fdt.FromData(rest)
7660 dtb.Scan()
7661 dtbs[fname] = dtb
7662
7663 expected = 'one' if '1' in fname else 'two'
7664 self.assertEqual(f'u-boot,model-{expected}',
7665 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7666
7667 # Make sure the FDT is the same size as the 'main' one
7668 rest = rest[fdt_size:]
7669
7670 self.assertEqual(b'', rest)
7671 return dtbs
7672
7673 def testAlternatesFdt(self):
7674 """Test handling of alternates-fdt etype"""
7675 self._SetupTplElf()
7676 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7677 U_BOOT_TPL_NODTB_DATA)
7678 for dtb in dtbs.values():
7679 # Check for the node with the tag
7680 node = dtb.GetNode('/node')
7681 self.assertIsNotNone(node)
7682 self.assertEqual(5, len(node.props.keys()))
7683
7684 # Make sure the other node is still there
7685 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7686
7687 def testAlternatesFdtgrep(self):
7688 """Test handling of alternates-fdt etype using fdtgrep"""
7689 self._SetupTplElf()
7690 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7691 U_BOOT_TPL_NODTB_DATA)
7692 for dtb in dtbs.values():
7693 # Check for the node with the tag
7694 node = dtb.GetNode('/node')
7695 self.assertIsNotNone(node)
7696 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7697 node.props.keys())
7698
7699 # Make sure the other node is gone
7700 self.assertIsNone(dtb.GetNode('/node/other-node'))
7701
7702 def testAlternatesFdtgrepVpl(self):
7703 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7704 self._SetupVplElf()
7705 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7706 U_BOOT_VPL_NODTB_DATA)
7707
7708 def testAlternatesFdtgrepSpl(self):
7709 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7710 self._SetupSplElf()
7711 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7712 U_BOOT_SPL_NODTB_DATA)
7713
7714 def testAlternatesFdtgrepInval(self):
7715 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7716 self._SetupSplElf()
7717 with self.assertRaises(ValueError) as e:
7718 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7719 U_BOOT_SPL_NODTB_DATA)
7720 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7721 str(e.exception))
7722
Simon Glasscd2783e2024-07-20 11:49:46 +01007723 def testFitFdtListDir(self):
7724 """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
Simon Glass1bba8942024-08-26 13:11:34 -06007725 old_dir = os.getcwd()
7726 try:
7727 os.chdir(self._indir)
7728 self.CheckFitFdt('333_fit_fdt_dir.dts', False)
7729 finally:
7730 os.chdir(old_dir)
Simon Glasscd2783e2024-07-20 11:49:46 +01007731
Simon Glassd2a9d6e2024-08-26 13:11:37 -06007732 def testFitFdtListDirDefault(self):
7733 """Test an FIT fit,fdt-list-dir where the default DT in is a subdir"""
7734 old_dir = os.getcwd()
7735 try:
7736 os.chdir(self._indir)
7737 self.CheckFitFdt('333_fit_fdt_dir.dts', False,
7738 default_dt='rockchip/test-fdt2')
7739 finally:
7740 os.chdir(old_dir)
7741
Simon Glass5f7aadf2024-07-20 11:49:47 +01007742 def testFitFdtCompat(self):
7743 """Test an image with an FIT with compatible in the config nodes"""
7744 entry_args = {
7745 'of-list': 'model1 model2',
7746 'default-dt': 'model2',
7747 }
7748 testdir, dtb_list = self.SetupAlternateDts()
7749 data = self._DoReadFileDtb(
7750 '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
7751 entry_args=entry_args, extra_indirs=[testdir])[0]
7752
7753 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7754
7755 fit = fdt.Fdt.FromData(fit_data)
7756 fit.Scan()
7757
7758 cnode = fit.GetNode('/configurations')
7759 self.assertIn('default', cnode.props)
7760 self.assertEqual('config-2', cnode.props['default'].value)
7761
7762 for seq in range(1, 2):
7763 name = f'config-{seq}'
7764 fnode = fit.GetNode('/configurations/%s' % name)
7765 self.assertIsNotNone(fnode)
7766 self.assertIn('compatible', fnode.props.keys())
7767 expected = 'one' if seq == 1 else 'two'
7768 self.assertEqual(f'u-boot,model-{expected}',
7769 fnode.props['compatible'].value)
7770
Simon Glassa04b9942024-07-20 11:49:48 +01007771 def testFitFdtPhase(self):
7772 """Test an image with an FIT with fdt-phase in the fdt nodes"""
7773 phase = 'tpl'
7774 entry_args = {
7775 f'{phase}-dtb': '1',
7776 f'{phase}-bss-pad': 'y',
7777 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7778 'of-list': 'model1 model2',
7779 'default-dt': 'model2',
7780 }
7781 testdir, dtb_list = self.SetupAlternateDts()
7782 data = self._DoReadFileDtb(
7783 '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
7784 entry_args=entry_args, extra_indirs=[testdir])[0]
7785 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7786 fit = fdt.Fdt.FromData(fit_data)
7787 fit.Scan()
7788
7789 # Check that each FDT has only the expected properties for the phase
7790 for seq in range(1, 2):
7791 fnode = fit.GetNode(f'/images/fdt-{seq}')
7792 self.assertIsNotNone(fnode)
7793 dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
7794 dtb.Scan()
7795
7796 # Make sure that the 'bootph-pre-sram' tag in /node protects it from
7797 # removal
7798 node = dtb.GetNode('/node')
7799 self.assertIsNotNone(node)
7800 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7801 node.props.keys())
7802
7803 # Make sure the other node is gone
7804 self.assertIsNone(dtb.GetNode('/node/other-node'))
7805
Simon Glassb553e8a2024-08-26 13:11:29 -06007806 def testMkeficapsuleMissing(self):
7807 """Test that binman complains if mkeficapsule is missing"""
7808 with self.assertRaises(ValueError) as e:
7809 self._DoTestFile('311_capsule.dts',
7810 force_missing_bintools='mkeficapsule')
7811 self.assertIn("Node '/binman/efi-capsule': Missing tool: 'mkeficapsule'",
7812 str(e.exception))
7813
7814 def testMkeficapsuleMissingOk(self):
7815 """Test that binman deals with mkeficapsule being missing"""
7816 with test_util.capture_sys_output() as (stdout, stderr):
7817 ret = self._DoTestFile('311_capsule.dts',
7818 force_missing_bintools='mkeficapsule',
7819 allow_missing=True)
7820 self.assertEqual(103, ret)
7821 err = stderr.getvalue()
7822 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkeficapsule")
7823
Simon Glass4b0f4142024-08-26 13:11:40 -06007824 def testSymbolsBase(self):
7825 """Test handling of symbols-base"""
7826 self.checkSymbols('336_symbols_base.dts', U_BOOT_SPL_DATA, 0x1c,
7827 symbols_base=0)
7828
7829 def testSymbolsBaseExpanded(self):
7830 """Test handling of symbols-base with expanded entries"""
7831 entry_args = {
7832 'spl-dtb': '1',
7833 }
7834 self.checkSymbols('337_symbols_base_expand.dts', U_BOOT_SPL_NODTB_DATA +
7835 U_BOOT_SPL_DTB_DATA, 0x38,
7836 entry_args=entry_args, use_expanded=True,
7837 symbols_base=0)
7838
Simon Glass3eb30a42024-08-26 13:11:42 -06007839 def testSymbolsCompressed(self):
7840 """Test binman complains about symbols from a compressed section"""
7841 with test_util.capture_sys_output() as (stdout, stderr):
7842 self.checkSymbols('338_symbols_comp.dts', U_BOOT_SPL_DATA, None)
7843 out = stdout.getvalue()
7844 self.assertIn('Symbol-writing: no value for /binman/section/u-boot',
7845 out)
7846
Simon Glass9c25ef22024-08-26 13:11:43 -06007847 def testNxpImx8Image(self):
7848 """Test that binman can produce an iMX8 image"""
7849 self._DoTestFile('339_nxp_imx8.dts')
7850
Alexander Kochetkova730a282024-09-16 11:24:46 +03007851 def testFitSignSimple(self):
7852 """Test that image with FIT and signature nodes can be signed"""
7853 if not elf.ELF_TOOLS:
7854 self.skipTest('Python elftools not available')
7855 entry_args = {
7856 'of-list': 'test-fdt1',
7857 'default-dt': 'test-fdt1',
7858 'atf-bl31-path': 'bl31.elf',
7859 }
7860 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7861 self._MakeInputFile("keys/rsa2048.key", data)
7862
7863 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7864 keys_subdir = os.path.join(self._indir, "keys")
7865 data = self._DoReadFileDtb(
7866 '340_fit_signature.dts',
7867 entry_args=entry_args,
7868 extra_indirs=[test_subdir, keys_subdir])[0]
7869
7870 dtb = fdt.Fdt.FromData(data)
7871 dtb.Scan()
7872
7873 conf = dtb.GetNode('/configurations/conf-uboot-1')
7874 self.assertIsNotNone(conf)
7875 signature = conf.FindNode('signature')
7876 self.assertIsNotNone(signature)
7877 self.assertIsNotNone(signature.props.get('value'))
7878
7879 images = dtb.GetNode('/images')
7880 self.assertIsNotNone(images)
7881 for subnode in images.subnodes:
7882 signature = subnode.FindNode('signature')
7883 self.assertIsNotNone(signature)
7884 self.assertIsNotNone(signature.props.get('value'))
7885
7886 def testFitSignKeyNotFound(self):
7887 """Test that missing keys raise an error"""
7888 if not elf.ELF_TOOLS:
7889 self.skipTest('Python elftools not available')
7890 entry_args = {
7891 'of-list': 'test-fdt1',
7892 'default-dt': 'test-fdt1',
7893 'atf-bl31-path': 'bl31.elf',
7894 }
7895 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7896 with self.assertRaises(ValueError) as e:
7897 self._DoReadFileDtb(
7898 '340_fit_signature.dts',
7899 entry_args=entry_args,
7900 extra_indirs=[test_subdir])[0]
7901 self.assertIn(
7902 'Filename \'rsa2048.key\' not found in input path',
7903 str(e.exception))
7904
7905 def testFitSignMultipleKeyPaths(self):
7906 """Test that keys found in multiple paths raise an error"""
7907 if not elf.ELF_TOOLS:
7908 self.skipTest('Python elftools not available')
7909 entry_args = {
7910 'of-list': 'test-fdt1',
7911 'default-dt': 'test-fdt1',
7912 'atf-bl31-path': 'bl31.elf',
7913 }
7914 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7915 self._MakeInputFile("keys1/rsa2048.key", data)
7916 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7917 self._MakeInputFile("keys2/conf-rsa2048.key", data)
7918
7919 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7920 keys_subdir1 = os.path.join(self._indir, "keys1")
7921 keys_subdir2 = os.path.join(self._indir, "keys2")
7922 with self.assertRaises(ValueError) as e:
7923 self._DoReadFileDtb(
7924 '341_fit_signature.dts',
7925 entry_args=entry_args,
7926 extra_indirs=[test_subdir, keys_subdir1, keys_subdir2])[0]
7927 self.assertIn(
7928 'Node \'/binman/fit\': multiple key paths found',
7929 str(e.exception))
7930
7931 def testFitSignNoSingatureNodes(self):
7932 """Test that fit,sign doens't raise error if no signature nodes found"""
7933 if not elf.ELF_TOOLS:
7934 self.skipTest('Python elftools not available')
7935 entry_args = {
7936 'of-list': 'test-fdt1',
7937 'default-dt': 'test-fdt1',
7938 'atf-bl31-path': 'bl31.elf',
7939 }
7940 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7941 self._DoReadFileDtb(
7942 '342_fit_signature.dts',
7943 entry_args=entry_args,
7944 extra_indirs=[test_subdir])[0]
7945
Simon Glassa360b8f2024-06-23 11:55:06 -06007946
Paul HENRYSff318462024-11-25 18:47:17 +01007947 def testSimpleFitEncryptedData(self):
7948 """Test an image with a FIT containing data to be encrypted"""
7949 data = tools.read_file(self.TestFile("aes256.bin"))
7950 self._MakeInputFile("keys/aes256.bin", data)
7951
7952 keys_subdir = os.path.join(self._indir, "keys")
7953 data = self._DoReadFileDtb(
7954 '343_fit_encrypt_data.dts',
7955 extra_indirs=[keys_subdir])[0]
7956
7957 fit = fdt.Fdt.FromData(data)
7958 fit.Scan()
7959
7960 # Extract the encrypted data and the Initialization Vector from the FIT
7961 node = fit.GetNode('/images/u-boot')
7962 subnode = fit.GetNode('/images/u-boot/cipher')
7963 data_size_unciphered = int.from_bytes(fit.GetProps(node)['data-size-unciphered'].bytes,
7964 byteorder='big')
7965 self.assertEqual(data_size_unciphered, len(U_BOOT_NODTB_DATA))
7966
7967 # Retrieve the key name from the FIT removing any null byte
7968 key_name = fit.GetProps(subnode)['key-name-hint'].bytes.replace(b'\x00', b'')
7969 with open(self.TestFile(key_name.decode('ascii') + '.bin'), 'rb') as file:
7970 key = file.read()
7971 iv = fit.GetProps(subnode)['iv'].bytes.hex()
7972 enc_data = fit.GetProps(node)['data'].bytes
7973 outdir = tools.get_output_dir()
7974 enc_data_file = os.path.join(outdir, 'encrypted_data.bin')
7975 tools.write_file(enc_data_file, enc_data)
7976 data_file = os.path.join(outdir, 'data.bin')
7977
7978 # Decrypt the encrypted data from the FIT and compare the data
7979 tools.run('openssl', 'enc', '-aes-256-cbc', '-nosalt', '-d', '-in',
7980 enc_data_file, '-out', data_file, '-K', key.hex(), '-iv', iv)
7981 with open(data_file, 'r') as file:
7982 dec_data = file.read()
7983 self.assertEqual(U_BOOT_NODTB_DATA, dec_data.encode('ascii'))
7984
7985 def testSimpleFitEncryptedDataMissingKey(self):
7986 """Test an image with a FIT containing data to be encrypted but with a missing key"""
7987 with self.assertRaises(ValueError) as e:
7988 self._DoReadFile('344_fit_encrypt_data_no_key.dts')
7989
7990 self.assertIn("Filename 'aes256.bin' not found in input path", str(e.exception))
7991
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01007992 def testFitFdtName(self):
7993 """Test an image with an FIT with multiple FDT images using NAME"""
7994 self.CheckFitFdt('345_fit_fdt_name.dts', use_seq_num=False)
7995
Neha Malcom Francisa25b4832025-03-17 10:24:20 +05307996 def testRemoveTemplate(self):
7997 """Test whether template is removed"""
7998 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
7999 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
8000 self._DoTestFile('346_remove_template.dts',
8001 force_missing_bintools='openssl',)
8002
Simon Glassac599912017-11-12 21:52:22 -07008003if __name__ == "__main__":
8004 unittest.main()