blob: e3f231e4bccbc3caaec8d67294654cbdc191419a [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 Glass57454f42016-11-25 20:15:52 -0700306 command.test_result = None
307
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 Glass840be732022-01-29 14:14:05 -0700348 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700349 capture=True, capture_stderr=True, raise_on_error=False)
350 if result.return_code and kwargs.get('raise_on_error', True):
351 raise Exception("Error running '%s': %s" % (' '.join(args),
352 result.stdout + result.stderr))
353 return result
354
Simon Glassf46732a2019-07-08 14:25:29 -0600355 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700356 """Run binman using directly (in the same process)
357
358 Args:
359 Arguments to pass, as a list of strings
360 Returns:
361 Return value (0 for success)
362 """
Simon Glassf46732a2019-07-08 14:25:29 -0600363 argv = list(argv)
364 args = cmdline.ParseArgs(argv)
365 args.pager = 'binman-invalid-pager'
366 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700367
368 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600369 # args.verbosity = tout.DEBUG
370 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700371
Simon Glass91710b32018-07-17 13:25:32 -0600372 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600373 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300374 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100375 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700376 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis6b463da2023-07-22 00:14:44 +0530377 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass57454f42016-11-25 20:15:52 -0700378 """Run binman with a given test file
379
380 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600381 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600382 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600383 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600384 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600385 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600386 entry_args: Dict of entry args to supply to binman
387 key: arg name
388 value: value of that arg
389 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600390 use_real_dtb: True to use the test file as the contents of
391 the u-boot-dtb entry. Normally this is not needed and the
392 test contents (the U_BOOT_DTB_DATA string) can be used.
393 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300394 use_expanded: True to use expanded entries where available, e.g.
395 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600396 verbosity: Verbosity level to use (0-3, None=don't set it)
397 allow_missing: Set the '--allow-missing' flag so that missing
398 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100399 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600400 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600401 threads: Number of threads to use (None for default, 0 for
402 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600403 test_section_timeout: True to force the first time to timeout, as
404 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600405 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glassb553e8a2024-08-26 13:11:29 -0600406 force_missing_bintools (str): comma-separated list of bintools to
Simon Glass66152ce2022-01-09 20:14:09 -0700407 regard as missing
Simon Glassb553e8a2024-08-26 13:11:29 -0600408 ignore_missing (bool): True to return success even if there are
409 missing blobs or bintools
Andrew Davis6b463da2023-07-22 00:14:44 +0530410 output_dir: Specific output directory to use for image using -O
Simon Glass9a798402021-11-03 21:09:17 -0600411
412 Returns:
413 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700414 """
Simon Glassf46732a2019-07-08 14:25:29 -0600415 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700416 if debug:
417 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600418 if verbosity is not None:
419 args.append('-v%d' % verbosity)
420 elif self.verbosity:
421 args.append('-v%d' % self.verbosity)
422 if self.toolpath:
423 for path in self.toolpath:
424 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600425 if threads is not None:
426 args.append('-T%d' % threads)
427 if test_section_timeout:
428 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600429 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600430 if map:
431 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600432 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600433 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600434 if not use_real_dtb:
435 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300436 if not use_expanded:
437 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600438 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600439 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600440 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600441 if allow_missing:
442 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700443 if ignore_missing:
444 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100445 if allow_fake_blobs:
446 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700447 if force_missing_bintools:
448 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600449 if update_fdt_in_elf:
450 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600451 if images:
452 for image in images:
453 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600454 if extra_indirs:
455 for indir in extra_indirs:
456 args += ['-I', indir]
Andrew Davis6b463da2023-07-22 00:14:44 +0530457 if output_dir:
458 args += ['-O', output_dir]
Simon Glass075a45c2017-11-13 18:55:00 -0700459 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700460
461 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700462 """Set up a new test device-tree file
463
464 The given file is compiled and set up as the device tree to be used
465 for ths test.
466
467 Args:
468 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600469 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700470
471 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600472 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700473 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600474 tmpdir = tempfile.mkdtemp(prefix='binmant.')
475 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600476 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700477 data = fd.read()
478 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600479 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600480 return data
Simon Glass57454f42016-11-25 20:15:52 -0700481
Simon Glass56d05412022-02-28 07:16:54 -0700482 def _GetDtbContentsForSpls(self, dtb_data, name):
483 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600484
485 For testing we don't actually have different versions of the DTB. With
486 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
487 we don't normally have any unwanted nodes.
488
489 We still want the DTBs for SPL and TPL to be different though, since
490 otherwise it is confusing to know which one we are looking at. So add
491 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600492
493 Args:
494 dtb_data: dtb data to modify (this should be a value devicetree)
495 name: Name of a new property to add
496
497 Returns:
498 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600499 """
500 dtb = fdt.Fdt.FromData(dtb_data)
501 dtb.Scan()
502 dtb.GetNode('/binman').AddZeroProp(name)
503 dtb.Sync(auto_resize=True)
504 dtb.Pack()
505 return dtb.GetContents()
506
Simon Glassed930672021-03-18 20:25:05 +1300507 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
Simon Glass3eb30a42024-08-26 13:11:42 -0600508 verbosity=None, map=False, update_dtb=False,
509 entry_args=None, reset_dtbs=True, extra_indirs=None,
510 threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700511 """Run binman and return the resulting image
512
513 This runs binman with a given test file and then reads the resulting
514 output file. It is a shortcut function since most tests need to do
515 these steps.
516
517 Raises an assertion failure if binman returns a non-zero exit code.
518
519 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600520 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700521 use_real_dtb: True to use the test file as the contents of
522 the u-boot-dtb entry. Normally this is not needed and the
523 test contents (the U_BOOT_DTB_DATA string) can be used.
524 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300525 use_expanded: True to use expanded entries where available, e.g.
526 'u-boot-expanded' instead of 'u-boot'
Simon Glass3eb30a42024-08-26 13:11:42 -0600527 verbosity: Verbosity level to use (0-3, None=don't set it)
Simon Glass30732662018-06-01 09:38:20 -0600528 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600529 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600530 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600531 entry_args: Dict of entry args to supply to binman
532 key: arg name
533 value: value of that arg
534 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
535 function. If reset_dtbs is True, then the original test dtb
536 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600537 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600538 threads: Number of threads to use (None for default, 0 for
539 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700540
541 Returns:
542 Tuple:
543 Resulting image contents
544 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600545 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600546 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700547 """
Simon Glass72232452016-11-25 20:15:53 -0700548 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700549 # Use the compiled test file as the u-boot-dtb input
550 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700551 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600552
553 # For testing purposes, make a copy of the DT for SPL and TPL. Add
Simon Glassd9e01d22024-07-20 11:49:40 +0100554 # a node indicating which it is, to aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700555 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600556 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
557 outfile = os.path.join(self._indir, dtb_fname)
558 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700559 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700560
561 try:
Simon Glass91710b32018-07-17 13:25:32 -0600562 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600563 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass3eb30a42024-08-26 13:11:42 -0600564 use_expanded=use_expanded, verbosity=verbosity,
565 extra_indirs=extra_indirs,
Simon Glass76f496d2021-07-06 10:36:37 -0600566 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700567 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700568 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700569
570 # Find the (only) image, read it and return its contents
571 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700572 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600573 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600574 if map:
Simon Glass80025522022-01-29 14:14:04 -0700575 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600576 with open(map_fname) as fd:
577 map_data = fd.read()
578 else:
579 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600580 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600581 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700582 finally:
583 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600584 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600585 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700586
Simon Glass5b4bce32019-07-08 14:25:26 -0600587 def _DoReadFileRealDtb(self, fname):
588 """Run binman with a real .dtb file and return the resulting data
589
590 Args:
591 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
592
593 Returns:
594 Resulting image contents
595 """
596 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
597
Simon Glass72232452016-11-25 20:15:53 -0700598 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600599 """Helper function which discards the device-tree binary
600
601 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600602 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600603 use_real_dtb: True to use the test file as the contents of
604 the u-boot-dtb entry. Normally this is not needed and the
605 test contents (the U_BOOT_DTB_DATA string) can be used.
606 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600607
608 Returns:
609 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600610 """
Simon Glass72232452016-11-25 20:15:53 -0700611 return self._DoReadFileDtb(fname, use_real_dtb)[0]
612
Simon Glass57454f42016-11-25 20:15:52 -0700613 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600614 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700615 """Create a new test input file, creating directories as needed
616
617 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600618 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700619 contents: File contents to write in to the file
620 Returns:
621 Full pathname of file created
622 """
Simon Glass862f8e22019-08-24 07:22:43 -0600623 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700624 dirname = os.path.dirname(pathname)
625 if dirname and not os.path.exists(dirname):
626 os.makedirs(dirname)
627 with open(pathname, 'wb') as fd:
628 fd.write(contents)
629 return pathname
630
631 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600632 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600633 """Create a new test input directory, creating directories as needed
634
635 Args:
636 dirname: Directory name to create
637
638 Returns:
639 Full pathname of directory created
640 """
Simon Glass862f8e22019-08-24 07:22:43 -0600641 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600642 if not os.path.exists(pathname):
643 os.makedirs(pathname)
644 return pathname
645
646 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600647 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600648 """Set up an ELF file with a '_dt_ucode_base_size' symbol
649
650 Args:
651 Filename of ELF file to use as SPL
652 """
Simon Glass93a806f2019-08-24 07:22:59 -0600653 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700654 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600655
656 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600657 def _SetupTplElf(cls, src_fname='bss_data'):
658 """Set up an ELF file with a '_dt_ucode_base_size' symbol
659
660 Args:
661 Filename of ELF file to use as TPL
662 """
663 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700664 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600665
666 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700667 def _SetupVplElf(cls, src_fname='bss_data'):
668 """Set up an ELF file with a '_dt_ucode_base_size' symbol
669
670 Args:
671 Filename of ELF file to use as VPL
672 """
673 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
674 tools.read_file(cls.ElfTestFile(src_fname)))
675
676 @classmethod
Lukas Funkee901faf2023-07-18 13:53:13 +0200677 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
678 """Set up an ELF file with a '_dt_ucode_base_size' symbol
679
680 Args:
681 Filename of ELF file to use as VPL
682 """
683 TestFunctional._MakeInputFile('pmu-firmware.elf',
684 tools.read_file(cls.ElfTestFile(src_fname)))
685
686 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600687 def _SetupDescriptor(cls):
688 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
689 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
690
691 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600692 def TestFile(cls, fname):
693 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700694
Simon Glassf6290892019-08-24 07:22:53 -0600695 @classmethod
696 def ElfTestFile(cls, fname):
697 return os.path.join(cls._elf_testdir, fname)
698
Simon Glassad5cfe12023-01-07 14:07:14 -0700699 @classmethod
700 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
701 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
702 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
703 dummy, paged_sz) + U_BOOT_DATA
704 data += extra_data
705 TestFunctional._MakeInputFile(fname, data)
706
Simon Glass57454f42016-11-25 20:15:52 -0700707 def AssertInList(self, grep_list, target):
708 """Assert that at least one of a list of things is in a target
709
710 Args:
711 grep_list: List of strings to check
712 target: Target string
713 """
714 for grep in grep_list:
715 if grep in target:
716 return
Simon Glass848cdb52019-05-17 22:00:50 -0600717 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700718
719 def CheckNoGaps(self, entries):
720 """Check that all entries fit together without gaps
721
722 Args:
723 entries: List of entries to check
724 """
Simon Glasse8561af2018-08-01 15:22:37 -0600725 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700726 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600727 self.assertEqual(offset, entry.offset)
728 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700729
Simon Glass72232452016-11-25 20:15:53 -0700730 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600731 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700732
733 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600734 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700735
736 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600737 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700738 """
739 return struct.unpack('>L', dtb[4:8])[0]
740
Simon Glass0f621332019-07-08 14:25:27 -0600741 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600742 def AddNode(node, path):
743 if node.name != '/':
744 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600745 for prop in node.props.values():
746 if prop.name in prop_names:
747 prop_path = path + ':' + prop.name
748 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
749 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600750 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600751 AddNode(subnode, path)
752
753 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600754 AddNode(dtb.GetRoot(), '')
755 return tree
756
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000757 def _CheckSign(self, fit, key):
758 try:
759 tools.run('fit_check_sign', '-k', key, '-f', fit)
760 except:
761 self.fail('Expected signed FIT container')
762 return False
763 return True
764
Simon Glass57454f42016-11-25 20:15:52 -0700765 def testRun(self):
766 """Test a basic run with valid args"""
767 result = self._RunBinman('-h')
768
769 def testFullHelp(self):
770 """Test that the full help is displayed with -H"""
771 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300772 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500773 # Remove possible extraneous strings
774 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
775 gothelp = result.stdout.replace(extra, '')
776 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700777 self.assertEqual(0, len(result.stderr))
778 self.assertEqual(0, result.return_code)
779
780 def testFullHelpInternal(self):
781 """Test that the full help is displayed with -H"""
782 try:
783 command.test_result = command.CommandResult()
784 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300785 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700786 finally:
787 command.test_result = None
788
789 def testHelp(self):
790 """Test that the basic help is displayed with -h"""
791 result = self._RunBinman('-h')
792 self.assertTrue(len(result.stdout) > 200)
793 self.assertEqual(0, len(result.stderr))
794 self.assertEqual(0, result.return_code)
795
Simon Glass57454f42016-11-25 20:15:52 -0700796 def testBoard(self):
797 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600798 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700799 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300800 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700801 self.assertEqual(0, result)
802
803 def testNeedBoard(self):
804 """Test that we get an error when no board ius supplied"""
805 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600806 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700807 self.assertIn("Must provide a board to process (use -b <board>)",
808 str(e.exception))
809
810 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600811 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700812 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600813 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700814 # We get one error from libfdt, and a different one from fdtget.
815 self.AssertInList(["Couldn't open blob from 'missing_file'",
816 'No such file or directory'], str(e.exception))
817
818 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600819 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700820
821 Since this is a source file it should be compiled and the error
822 will come from the device-tree compiler (dtc).
823 """
824 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600825 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700826 self.assertIn("FATAL ERROR: Unable to parse input tree",
827 str(e.exception))
828
829 def testMissingNode(self):
830 """Test that a device tree without a 'binman' node generates an error"""
831 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600832 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700833 self.assertIn("does not have a 'binman' node", str(e.exception))
834
835 def testEmpty(self):
836 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600837 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700838 self.assertEqual(0, len(result.stderr))
839 self.assertEqual(0, result.return_code)
840
841 def testInvalidEntry(self):
842 """Test that an invalid entry is flagged"""
843 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600844 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600845 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700846 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
847 "'/binman/not-a-valid-type'", str(e.exception))
848
849 def testSimple(self):
850 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600851 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700852 self.assertEqual(U_BOOT_DATA, data)
853
Simon Glass075a45c2017-11-13 18:55:00 -0700854 def testSimpleDebug(self):
855 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600856 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700857
Simon Glass57454f42016-11-25 20:15:52 -0700858 def testDual(self):
859 """Test that we can handle creating two images
860
861 This also tests image padding.
862 """
Simon Glass511f6582018-10-01 12:22:30 -0600863 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700864 self.assertEqual(0, retcode)
865
866 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600867 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700868 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700869 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600870 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700871 data = fd.read()
872 self.assertEqual(U_BOOT_DATA, data)
873
874 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600875 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700876 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700877 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600878 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700879 data = fd.read()
880 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700881 self.assertEqual(tools.get_bytes(0, 3), data[:3])
882 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700883
884 def testBadAlign(self):
885 """Test that an invalid alignment value is detected"""
886 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600887 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700888 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
889 "of two", str(e.exception))
890
891 def testPackSimple(self):
892 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600893 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700894 self.assertEqual(0, retcode)
895 self.assertIn('image', control.images)
896 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600897 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700898 self.assertEqual(5, len(entries))
899
900 # First u-boot
901 self.assertIn('u-boot', entries)
902 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600903 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700904 self.assertEqual(len(U_BOOT_DATA), entry.size)
905
906 # Second u-boot, aligned to 16-byte boundary
907 self.assertIn('u-boot-align', entries)
908 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600909 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700910 self.assertEqual(len(U_BOOT_DATA), entry.size)
911
912 # Third u-boot, size 23 bytes
913 self.assertIn('u-boot-size', entries)
914 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600915 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700916 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
917 self.assertEqual(23, entry.size)
918
919 # Fourth u-boot, placed immediate after the above
920 self.assertIn('u-boot-next', entries)
921 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600922 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700923 self.assertEqual(len(U_BOOT_DATA), entry.size)
924
Simon Glasse8561af2018-08-01 15:22:37 -0600925 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700926 self.assertIn('u-boot-fixed', entries)
927 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600928 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700929 self.assertEqual(len(U_BOOT_DATA), entry.size)
930
Simon Glass39dd2152019-07-08 14:25:47 -0600931 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700932
933 def testPackExtra(self):
934 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600935 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
936 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700937
Simon Glass57454f42016-11-25 20:15:52 -0700938 self.assertIn('image', control.images)
939 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600940 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600941 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700942
Samuel Hollande2574022023-01-21 17:25:16 -0600943 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700944 self.assertIn('u-boot', entries)
945 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600946 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700947 self.assertEqual(3, entry.pad_before)
948 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600949 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700950 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
951 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600952 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700953
954 # Second u-boot has an aligned size, but it has no effect
955 self.assertIn('u-boot-align-size-nop', entries)
956 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600957 self.assertEqual(pos, entry.offset)
958 self.assertEqual(len(U_BOOT_DATA), entry.size)
959 self.assertEqual(U_BOOT_DATA, entry.data)
960 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
961 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700962
963 # Third u-boot has an aligned size too
964 self.assertIn('u-boot-align-size', entries)
965 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600966 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700967 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600968 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700969 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600970 data[pos:pos + entry.size])
971 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700972
973 # Fourth u-boot has an aligned end
974 self.assertIn('u-boot-align-end', entries)
975 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600976 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700977 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600978 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700979 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600980 data[pos:pos + entry.size])
981 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700982
983 # Fifth u-boot immediately afterwards
984 self.assertIn('u-boot-align-both', entries)
985 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600986 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700987 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600988 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700989 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600990 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700991
Samuel Hollande2574022023-01-21 17:25:16 -0600992 # Sixth u-boot with both minimum size and aligned size
993 self.assertIn('u-boot-min-size', entries)
994 entry = entries['u-boot-min-size']
995 self.assertEqual(128, entry.offset)
996 self.assertEqual(32, entry.size)
997 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
998 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
999 data[pos:pos + entry.size])
1000
Simon Glass57454f42016-11-25 20:15:52 -07001001 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -06001002 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001003
Simon Glassafb9caa2020-10-26 17:40:10 -06001004 dtb = fdt.Fdt(out_dtb_fname)
1005 dtb.Scan()
1006 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
1007 expected = {
1008 'image-pos': 0,
1009 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -06001010 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -06001011
1012 'u-boot:image-pos': 0,
1013 'u-boot:offset': 0,
1014 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1015
1016 'u-boot-align-size-nop:image-pos': 12,
1017 'u-boot-align-size-nop:offset': 12,
1018 'u-boot-align-size-nop:size': 4,
1019
1020 'u-boot-align-size:image-pos': 16,
1021 'u-boot-align-size:offset': 16,
1022 'u-boot-align-size:size': 32,
1023
1024 'u-boot-align-end:image-pos': 48,
1025 'u-boot-align-end:offset': 48,
1026 'u-boot-align-end:size': 16,
1027
1028 'u-boot-align-both:image-pos': 64,
1029 'u-boot-align-both:offset': 64,
1030 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -06001031
1032 'u-boot-min-size:image-pos': 128,
1033 'u-boot-min-size:offset': 128,
1034 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -06001035 }
1036 self.assertEqual(expected, props)
1037
Simon Glass57454f42016-11-25 20:15:52 -07001038 def testPackAlignPowerOf2(self):
1039 """Test that invalid entry alignment is detected"""
1040 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001041 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001042 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1043 "of two", str(e.exception))
1044
1045 def testPackAlignSizePowerOf2(self):
1046 """Test that invalid entry size alignment is detected"""
1047 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001048 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001049 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1050 "power of two", str(e.exception))
1051
1052 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001053 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001054 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001055 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001056 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001057 "align 0x4 (4)", str(e.exception))
1058
1059 def testPackInvalidSizeAlign(self):
1060 """Test that invalid entry size alignment is detected"""
1061 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001062 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001063 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1064 "align-size 0x4 (4)", str(e.exception))
1065
1066 def testPackOverlap(self):
1067 """Test that overlapping regions are detected"""
1068 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001069 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001070 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001071 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1072 str(e.exception))
1073
1074 def testPackEntryOverflow(self):
1075 """Test that entries that overflow their size are detected"""
1076 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001077 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001078 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1079 "but entry size is 0x3 (3)", str(e.exception))
1080
1081 def testPackImageOverflow(self):
1082 """Test that entries which overflow the image size are detected"""
1083 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001084 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001085 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001086 "size 0x3 (3)", str(e.exception))
1087
1088 def testPackImageSize(self):
1089 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001090 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001091 self.assertEqual(0, retcode)
1092 self.assertIn('image', control.images)
1093 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001094 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001095
1096 def testPackImageSizeAlign(self):
1097 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001098 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001099 self.assertEqual(0, retcode)
1100 self.assertIn('image', control.images)
1101 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001102 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001103
1104 def testPackInvalidImageAlign(self):
1105 """Test that invalid image alignment is detected"""
1106 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001107 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001108 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001109 "align-size 0x8 (8)", str(e.exception))
1110
Simon Glass2a0fa982022-02-11 13:23:21 -07001111 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001112 """Test that invalid image alignment is detected"""
1113 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001114 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001115 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001116 "two", str(e.exception))
1117
1118 def testImagePadByte(self):
1119 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001120 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001121 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001122 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001123 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001124
1125 def testImageName(self):
1126 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001127 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001128 self.assertEqual(0, retcode)
1129 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001130 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001131 self.assertTrue(os.path.exists(fname))
1132
1133 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001134 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001135 self.assertTrue(os.path.exists(fname))
1136
1137 def testBlobFilename(self):
1138 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001139 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001140 self.assertEqual(BLOB_DATA, data)
1141
1142 def testPackSorted(self):
1143 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001144 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001145 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001146 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1147 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001148
Simon Glasse8561af2018-08-01 15:22:37 -06001149 def testPackZeroOffset(self):
1150 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001151 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001152 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001153 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001154 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001155 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1156 str(e.exception))
1157
1158 def testPackUbootDtb(self):
1159 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001160 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001161 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001162
1163 def testPackX86RomNoSize(self):
1164 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001165 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001166 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001167 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001168 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001169 "using end-at-4gb", str(e.exception))
1170
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301171 def test4gbAndSkipAtStartTogether(self):
1172 """Test that the end-at-4gb and skip-at-size property can't be used
1173 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001174 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301175 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001176 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001177 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301178 "'skip-at-start'", str(e.exception))
1179
Simon Glass72232452016-11-25 20:15:53 -07001180 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001181 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001182 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001183 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001184 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001185 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1186 "is outside the section '/binman' starting at "
1187 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001188 str(e.exception))
1189
1190 def testPackX86Rom(self):
1191 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001192 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001193 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001194 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1195 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001196
1197 def testPackX86RomMeNoDesc(self):
1198 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001199 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001200 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001201 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001202 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001203 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1204 str(e.exception))
1205 finally:
1206 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001207
1208 def testPackX86RomBadDesc(self):
1209 """Test that the Intel requires a descriptor entry"""
1210 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001211 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001212 self.assertIn("Node '/binman/intel-me': No offset set with "
1213 "offset-unset: should another entry provide this correct "
1214 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001215
1216 def testPackX86RomMe(self):
1217 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001218 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001219 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001220 if data[:0x1000] != expected_desc:
1221 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001222 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1223
1224 def testPackVga(self):
1225 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001226 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001227 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1228
1229 def testPackStart16(self):
1230 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001231 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001232 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1233
Jagdish Gediya311d4842018-09-03 21:35:08 +05301234 def testPackPowerpcMpc85xxBootpgResetvec(self):
1235 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1236 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001237 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301238 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1239
Simon Glass6ba679c2018-07-06 10:27:17 -06001240 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001241 """Handle running a test for insertion of microcode
1242
1243 Args:
1244 dts_fname: Name of test .dts file
1245 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001246 ucode_second: True if the microsecond entry is second instead of
1247 third
Simon Glass820af1d2018-07-06 10:27:16 -06001248
1249 Returns:
1250 Tuple:
1251 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001252 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001253 in the above (two 4-byte words)
1254 """
Simon Glass3d274232017-11-12 21:52:27 -07001255 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001256
1257 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001258 if ucode_second:
1259 ucode_content = data[len(nodtb_data):]
1260 ucode_pos = len(nodtb_data)
1261 dtb_with_ucode = ucode_content[16:]
1262 fdt_len = self.GetFdtLen(dtb_with_ucode)
1263 else:
1264 dtb_with_ucode = data[len(nodtb_data):]
1265 fdt_len = self.GetFdtLen(dtb_with_ucode)
1266 ucode_content = dtb_with_ucode[fdt_len:]
1267 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001268 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001269 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001270 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001271 dtb = fdt.FdtScan(fname)
1272 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001273 self.assertTrue(ucode)
1274 for node in ucode.subnodes:
1275 self.assertFalse(node.props.get('data'))
1276
Simon Glass72232452016-11-25 20:15:53 -07001277 # Check that the microcode appears immediately after the Fdt
1278 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001279 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001280 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1281 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001282 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001283
1284 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001285 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001286 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1287 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001288 u_boot = data[:len(nodtb_data)]
1289 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001290
1291 def testPackUbootMicrocode(self):
1292 """Test that x86 microcode can be handled correctly
1293
1294 We expect to see the following in the image, in order:
1295 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1296 place
1297 u-boot.dtb with the microcode removed
1298 the microcode
1299 """
Simon Glass511f6582018-10-01 12:22:30 -06001300 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001301 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001302 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1303 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001304
Simon Glassbac25c82017-05-27 07:38:26 -06001305 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001306 """Test that x86 microcode can be handled correctly
1307
1308 We expect to see the following in the image, in order:
1309 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1310 place
1311 u-boot.dtb with the microcode
1312 an empty microcode region
1313 """
1314 # We need the libfdt library to run this test since only that allows
1315 # finding the offset of a property. This is required by
1316 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001317 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001318
1319 second = data[len(U_BOOT_NODTB_DATA):]
1320
1321 fdt_len = self.GetFdtLen(second)
1322 third = second[fdt_len:]
1323 second = second[:fdt_len]
1324
Simon Glassbac25c82017-05-27 07:38:26 -06001325 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1326 self.assertIn(ucode_data, second)
1327 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001328
Simon Glassbac25c82017-05-27 07:38:26 -06001329 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001330 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001331 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1332 len(ucode_data))
1333 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001334 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1335 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001336
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001337 def testPackUbootSingleMicrocode(self):
1338 """Test that x86 microcode can be handled correctly with fdt_normal.
1339 """
Simon Glassbac25c82017-05-27 07:38:26 -06001340 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001341
Simon Glass996021e2016-11-25 20:15:54 -07001342 def testUBootImg(self):
1343 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001344 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001345 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001346
1347 def testNoMicrocode(self):
1348 """Test that a missing microcode region is detected"""
1349 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001350 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001351 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1352 "node found in ", str(e.exception))
1353
1354 def testMicrocodeWithoutNode(self):
1355 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1356 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001357 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001358 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1359 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1360
1361 def testMicrocodeWithoutNode2(self):
1362 """Test that a missing u-boot-ucode node is detected"""
1363 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001364 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001365 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1366 "microcode region u-boot-ucode", str(e.exception))
1367
1368 def testMicrocodeWithoutPtrInElf(self):
1369 """Test that a U-Boot binary without the microcode symbol is detected"""
1370 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001371 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001372 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001373 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001374
1375 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001376 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001377 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1378 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1379
1380 finally:
1381 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001382 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001383 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001384
1385 def testMicrocodeNotInImage(self):
1386 """Test that microcode must be placed within the image"""
1387 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001388 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001389 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1390 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001391 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001392
1393 def testWithoutMicrocode(self):
1394 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001395 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001396 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001397 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001398
1399 # Now check the device tree has no microcode
1400 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1401 second = data[len(U_BOOT_NODTB_DATA):]
1402
1403 fdt_len = self.GetFdtLen(second)
1404 self.assertEqual(dtb, second[:fdt_len])
1405
1406 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1407 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001408 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001409
1410 def testUnknownPosSize(self):
1411 """Test that microcode must be placed within the image"""
1412 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001413 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001414 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001415 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001416
1417 def testPackFsp(self):
1418 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001419 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001420 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1421
1422 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001423 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001424 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001425 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001426
1427 def testPackVbt(self):
1428 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001429 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001430 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001431
Simon Glass7f94e832017-11-12 21:52:25 -07001432 def testSplBssPad(self):
1433 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001434 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001435 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001436 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001437 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001438 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001439
Simon Glass04cda032018-10-01 21:12:42 -06001440 def testSplBssPadMissing(self):
1441 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001442 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001443 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001444 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001445 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1446 str(e.exception))
1447
Simon Glasse83679d2017-11-12 21:52:26 -07001448 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001449 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001450 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001451 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1452
Simon Glass6ba679c2018-07-06 10:27:17 -06001453 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1454 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001455
1456 We expect to see the following in the image, in order:
1457 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1458 correct place
1459 u-boot.dtb with the microcode removed
1460 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001461
1462 Args:
1463 dts: Device tree file to use for test
1464 ucode_second: True if the microsecond entry is second instead of
1465 third
Simon Glass3d274232017-11-12 21:52:27 -07001466 """
Simon Glass7057d022018-10-01 21:12:47 -06001467 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001468 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1469 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001470 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1471 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001472
Simon Glass6ba679c2018-07-06 10:27:17 -06001473 def testPackUbootSplMicrocode(self):
1474 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001475 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001476 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001477
1478 def testPackUbootSplMicrocodeReorder(self):
1479 """Test that order doesn't matter for microcode entries
1480
1481 This is the same as testPackUbootSplMicrocode but when we process the
1482 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1483 entry, so we reply on binman to try later.
1484 """
Simon Glass511f6582018-10-01 12:22:30 -06001485 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001486 ucode_second=True)
1487
Simon Glassa409c932017-11-12 21:52:28 -07001488 def testPackMrc(self):
1489 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001490 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001491 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1492
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001493 def testSplDtb(self):
1494 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001495 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001496 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001497 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1498
Simon Glass0a6da312017-11-13 18:54:56 -07001499 def testSplNoDtb(self):
1500 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001501 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001502 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001503 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1504
Simon Glass7098b7f2021-03-21 18:24:30 +13001505 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4b0f4142024-08-26 13:11:40 -06001506 use_expanded=False, no_write_symbols=False,
1507 symbols_base=None):
Simon Glass31e04cb2021-03-18 20:24:56 +13001508 """Check the image contains the expected symbol values
1509
1510 Args:
1511 dts: Device tree file to use for test
1512 base_data: Data before and after 'u-boot' section
Simon Glass3eb30a42024-08-26 13:11:42 -06001513 u_boot_offset (int): Offset of 'u-boot' section in image, or None if
1514 the offset not available due to it being in a compressed section
Simon Glass7098b7f2021-03-21 18:24:30 +13001515 entry_args: Dict of entry args to supply to binman
1516 key: arg name
1517 value: value of that arg
1518 use_expanded: True to use expanded entries where available, e.g.
1519 'u-boot-expanded' instead of 'u-boot'
Simon Glass4b0f4142024-08-26 13:11:40 -06001520 symbols_base (int): Value to expect for symbols-base in u-boot-spl,
1521 None if none
Simon Glass31e04cb2021-03-18 20:24:56 +13001522 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001523 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001524 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1525 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001526 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001527 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001528 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001529
Simon Glass7057d022018-10-01 21:12:47 -06001530 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001531 data = self._DoReadFileDtb(dts, entry_args=entry_args,
Simon Glass3eb30a42024-08-26 13:11:42 -06001532 use_expanded=use_expanded,
1533 verbosity=None if u_boot_offset else 3)[0]
1534
1535 # The lz4-compressed version of the U-Boot data is 19 bytes long
1536 comp_uboot_len = 19
1537
Simon Glass31e04cb2021-03-18 20:24:56 +13001538 # The image should contain the symbols from u_boot_binman_syms.c
1539 # Note that image_pos is adjusted by the base address of the image,
1540 # which is 0x10 in our test image
Simon Glass3eb30a42024-08-26 13:11:42 -06001541 # If u_boot_offset is None, Binman should write -1U into the image
Simon Glass4b0f4142024-08-26 13:11:40 -06001542 vals2 = (elf.BINMAN_SYM_MAGIC_VALUE, 0x00,
Simon Glass3eb30a42024-08-26 13:11:42 -06001543 u_boot_offset + len(U_BOOT_DATA) if u_boot_offset else
1544 len(U_BOOT_SPL_DATA) + 1 + comp_uboot_len,
1545 0x10 + u_boot_offset if u_boot_offset else 0xffffffff, 0x04)
Simon Glass4b0f4142024-08-26 13:11:40 -06001546
1547 # u-boot-spl has a symbols-base property, so take that into account if
1548 # required. The caller must supply the value
1549 vals = list(vals2)
1550 if symbols_base is not None:
1551 vals[3] = symbols_base + u_boot_offset
1552 vals = tuple(vals)
1553
Simon Glass4b4049e2024-08-26 13:11:39 -06001554 sym_values = struct.pack('<LLQLL', *vals)
Simon Glass4b0f4142024-08-26 13:11:40 -06001555 sym_values2 = struct.pack('<LLQLL', *vals2)
Simon Glass4abf7842023-07-18 07:23:54 -06001556 if no_write_symbols:
Simon Glass4b4049e2024-08-26 13:11:39 -06001557 self.assertEqual(
1558 base_data +
1559 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1560 U_BOOT_DATA + base_data, data)
Simon Glass4abf7842023-07-18 07:23:54 -06001561 else:
Simon Glass4b4049e2024-08-26 13:11:39 -06001562 got_vals = struct.unpack('<LLQLL', data[:24])
1563
1564 # For debugging:
1565 #print('expect:', list(f'{v:x}' for v in vals))
1566 #print(' got:', list(f'{v:x}' for v in got_vals))
1567
1568 self.assertEqual(vals, got_vals)
1569 self.assertEqual(sym_values, data[:24])
1570
1571 blen = len(base_data)
1572 self.assertEqual(base_data[24:], data[24:blen])
1573 self.assertEqual(0xff, data[blen])
1574
Simon Glass3eb30a42024-08-26 13:11:42 -06001575 if u_boot_offset:
1576 ofs = blen + 1 + len(U_BOOT_DATA)
1577 self.assertEqual(U_BOOT_DATA, data[blen + 1:ofs])
1578 else:
1579 ofs = blen + 1 + comp_uboot_len
Simon Glass4b4049e2024-08-26 13:11:39 -06001580
Simon Glass4b0f4142024-08-26 13:11:40 -06001581 self.assertEqual(sym_values2, data[ofs:ofs + 24])
Simon Glass4b4049e2024-08-26 13:11:39 -06001582 self.assertEqual(base_data[24:], data[ofs + 24:])
1583
1584 # Just repeating the above asserts all at once, for clarity
Simon Glass3eb30a42024-08-26 13:11:42 -06001585 if u_boot_offset:
1586 expected = (sym_values + base_data[24:] +
1587 tools.get_bytes(0xff, 1) + U_BOOT_DATA +
1588 sym_values2 + base_data[24:])
1589 self.assertEqual(expected, data)
Simon Glass4ca8e042017-11-13 18:55:01 -07001590
Simon Glass31e04cb2021-03-18 20:24:56 +13001591 def testSymbols(self):
1592 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001593 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001594
1595 def testSymbolsNoDtb(self):
1596 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001597 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001598 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1599 0x38)
1600
Simon Glasse76a3e62018-06-01 09:38:11 -06001601 def testPackUnitAddress(self):
1602 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001603 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001604 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1605
Simon Glassa91e1152018-06-01 09:38:16 -06001606 def testSections(self):
1607 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001608 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001609 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1610 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1611 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001612 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001613
Simon Glass30732662018-06-01 09:38:20 -06001614 def testMap(self):
1615 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001616 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001617 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700161800000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600161900000000 00000000 00000010 section@0
162000000000 00000000 00000004 u-boot
162100000010 00000010 00000010 section@1
162200000010 00000000 00000004 u-boot
162300000020 00000020 00000004 section@2
162400000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001625''', map_data)
1626
Simon Glass3b78d532018-06-01 09:38:21 -06001627 def testNamePrefix(self):
1628 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001629 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001630 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700163100000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600163200000000 00000000 00000010 section@0
163300000000 00000000 00000004 ro-u-boot
163400000010 00000010 00000010 section@1
163500000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001636''', map_data)
1637
Simon Glass6ba679c2018-07-06 10:27:17 -06001638 def testUnknownContents(self):
1639 """Test that obtaining the contents works as expected"""
1640 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001641 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001642 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001643 "processing of contents: remaining ["
1644 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001645
Simon Glass2e1169f2018-07-06 10:27:19 -06001646 def testBadChangeSize(self):
1647 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001648 try:
1649 state.SetAllowEntryExpansion(False)
1650 with self.assertRaises(ValueError) as e:
1651 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001652 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001653 str(e.exception))
1654 finally:
1655 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001656
Simon Glassa87014e2018-07-06 10:27:42 -06001657 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001658 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001659 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001660 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001661 dtb = fdt.Fdt(out_dtb_fname)
1662 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001663 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001664 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001665 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001666 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001667 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001668 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001669 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001670 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001671 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001672 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001673 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001674 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001675 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001676
Simon Glasse8561af2018-08-01 15:22:37 -06001677 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001678 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001679 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001680 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001681 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001682 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001683 'size': 40
1684 }, props)
1685
1686 def testUpdateFdtBad(self):
1687 """Test that we detect when ProcessFdt never completes"""
1688 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001689 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001690 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001691 '[<binman.etype._testing.Entry__testing',
1692 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001693
Simon Glass91710b32018-07-17 13:25:32 -06001694 def testEntryArgs(self):
1695 """Test passing arguments to entries from the command line"""
1696 entry_args = {
1697 'test-str-arg': 'test1',
1698 'test-int-arg': '456',
1699 }
Simon Glass511f6582018-10-01 12:22:30 -06001700 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001701 self.assertIn('image', control.images)
1702 entry = control.images['image'].GetEntries()['_testing']
1703 self.assertEqual('test0', entry.test_str_fdt)
1704 self.assertEqual('test1', entry.test_str_arg)
1705 self.assertEqual(123, entry.test_int_fdt)
1706 self.assertEqual(456, entry.test_int_arg)
1707
1708 def testEntryArgsMissing(self):
1709 """Test missing arguments and properties"""
1710 entry_args = {
1711 'test-int-arg': '456',
1712 }
Simon Glass511f6582018-10-01 12:22:30 -06001713 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001714 entry = control.images['image'].GetEntries()['_testing']
1715 self.assertEqual('test0', entry.test_str_fdt)
1716 self.assertEqual(None, entry.test_str_arg)
1717 self.assertEqual(None, entry.test_int_fdt)
1718 self.assertEqual(456, entry.test_int_arg)
1719
1720 def testEntryArgsRequired(self):
1721 """Test missing arguments and properties"""
1722 entry_args = {
1723 'test-int-arg': '456',
1724 }
1725 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001726 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001727 self.assertIn("Node '/binman/_testing': "
1728 'Missing required properties/entry args: test-str-arg, '
1729 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001730 str(e.exception))
1731
1732 def testEntryArgsInvalidFormat(self):
1733 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001734 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1735 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001736 with self.assertRaises(ValueError) as e:
1737 self._DoBinman(*args)
1738 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1739
1740 def testEntryArgsInvalidInteger(self):
1741 """Test that an invalid entry-argument integer is detected"""
1742 entry_args = {
1743 'test-int-arg': 'abc',
1744 }
1745 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001746 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001747 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1748 "'test-int-arg' (value 'abc') to integer",
1749 str(e.exception))
1750
1751 def testEntryArgsInvalidDatatype(self):
1752 """Test that an invalid entry-argument datatype is detected
1753
1754 This test could be written in entry_test.py except that it needs
1755 access to control.entry_args, which seems more than that module should
1756 be able to see.
1757 """
1758 entry_args = {
1759 'test-bad-datatype-arg': '12',
1760 }
1761 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001762 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001763 entry_args=entry_args)
1764 self.assertIn('GetArg() internal error: Unknown data type ',
1765 str(e.exception))
1766
Simon Glass2ca52032018-07-17 13:25:33 -06001767 def testText(self):
1768 """Test for a text entry type"""
1769 entry_args = {
1770 'test-id': TEXT_DATA,
1771 'test-id2': TEXT_DATA2,
1772 'test-id3': TEXT_DATA3,
1773 }
Simon Glass511f6582018-10-01 12:22:30 -06001774 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001775 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001776 expected = (tools.to_bytes(TEXT_DATA) +
1777 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1778 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001779 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001780 self.assertEqual(expected, data)
1781
Simon Glass969616c2018-07-17 13:25:36 -06001782 def testEntryDocs(self):
1783 """Test for creation of entry documentation"""
1784 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001785 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001786 self.assertTrue(len(stdout.getvalue()) > 0)
1787
1788 def testEntryDocsMissing(self):
1789 """Test handling of missing entry documentation"""
1790 with self.assertRaises(ValueError) as e:
1791 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001792 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001793 self.assertIn('Documentation is missing for modules: u_boot',
1794 str(e.exception))
1795
Simon Glass704784b2018-07-17 13:25:38 -06001796 def testFmap(self):
1797 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001798 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001799 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001800 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1801 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001802 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001803 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001804 self.assertEqual(1, fhdr.ver_major)
1805 self.assertEqual(0, fhdr.ver_minor)
1806 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001807 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001808 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001809 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001810 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001811 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001812
Simon Glass82059c22021-04-03 11:05:09 +13001813 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001814 self.assertEqual(b'SECTION0', fentry.name)
1815 self.assertEqual(0, fentry.offset)
1816 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001817 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001818
1819 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001820 self.assertEqual(b'RO_U_BOOT', fentry.name)
1821 self.assertEqual(0, fentry.offset)
1822 self.assertEqual(4, fentry.size)
1823 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001824
Simon Glass82059c22021-04-03 11:05:09 +13001825 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001826 self.assertEqual(b'SECTION1', fentry.name)
1827 self.assertEqual(16, fentry.offset)
1828 self.assertEqual(16, fentry.size)
1829 self.assertEqual(0, fentry.flags)
1830
1831 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001832 self.assertEqual(b'RW_U_BOOT', fentry.name)
1833 self.assertEqual(16, fentry.offset)
1834 self.assertEqual(4, fentry.size)
1835 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001836
Simon Glass82059c22021-04-03 11:05:09 +13001837 fentry = next(fiter)
1838 self.assertEqual(b'FMAP', fentry.name)
1839 self.assertEqual(32, fentry.offset)
1840 self.assertEqual(expect_size, fentry.size)
1841 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001842
Simon Glassdb168d42018-07-17 13:25:39 -06001843 def testBlobNamedByArg(self):
1844 """Test we can add a blob with the filename coming from an entry arg"""
1845 entry_args = {
1846 'cros-ec-rw-path': 'ecrw.bin',
1847 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001848 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001849
Simon Glass53f53992018-07-17 13:25:40 -06001850 def testFill(self):
1851 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001852 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001853 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001854 self.assertEqual(expected, data)
1855
1856 def testFillNoSize(self):
1857 """Test for an fill entry type with no size"""
1858 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001859 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001860 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001861 str(e.exception))
1862
Simon Glassc1ae83c2018-07-17 13:25:44 -06001863 def _HandleGbbCommand(self, pipe_list):
1864 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001865 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001866 fname = pipe_list[0][-1]
1867 # Append our GBB data to the file, which will happen every time the
1868 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001869 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001870 fd.write(GBB_DATA)
1871 return command.CommandResult()
1872
1873 def testGbb(self):
1874 """Test for the Chromium OS Google Binary Block"""
1875 command.test_result = self._HandleGbbCommand
1876 entry_args = {
1877 'keydir': 'devkeys',
1878 'bmpblk': 'bmpblk.bin',
1879 }
Simon Glass511f6582018-10-01 12:22:30 -06001880 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001881
1882 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001883 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1884 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001885 self.assertEqual(expected, data)
1886
1887 def testGbbTooSmall(self):
1888 """Test for the Chromium OS Google Binary Block being large enough"""
1889 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001890 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001891 self.assertIn("Node '/binman/gbb': GBB is too small",
1892 str(e.exception))
1893
1894 def testGbbNoSize(self):
1895 """Test for the Chromium OS Google Binary Block having a size"""
1896 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001897 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001898 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1899 str(e.exception))
1900
Simon Glass66152ce2022-01-09 20:14:09 -07001901 def testGbbMissing(self):
1902 """Test that binman still produces an image if futility is missing"""
1903 entry_args = {
1904 'keydir': 'devkeys',
1905 }
1906 with test_util.capture_sys_output() as (_, stderr):
1907 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1908 entry_args=entry_args)
1909 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001910 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001911
Simon Glass5c350162018-07-17 13:25:47 -06001912 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001913 """Fake calls to the futility utility
1914
1915 The expected pipe is:
1916
1917 [('futility', 'vbutil_firmware', '--vblock',
1918 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1919 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1920 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1921 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1922
1923 This writes to the output file (here, 'vblock.vblock'). If
1924 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1925 of the input data (here, 'input.vblock').
1926 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001927 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001928 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001929 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001930 if self._hash_data:
1931 infile = pipe_list[0][11]
1932 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001933 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001934 m.update(data)
1935 fd.write(m.digest())
1936 else:
1937 fd.write(VBLOCK_DATA)
1938
Simon Glass5c350162018-07-17 13:25:47 -06001939 return command.CommandResult()
1940
1941 def testVblock(self):
1942 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001943 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001944 command.test_result = self._HandleVblockCommand
1945 entry_args = {
1946 'keydir': 'devkeys',
1947 }
Simon Glass511f6582018-10-01 12:22:30 -06001948 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001949 entry_args=entry_args)
1950 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1951 self.assertEqual(expected, data)
1952
1953 def testVblockNoContent(self):
1954 """Test we detect a vblock which has no content to sign"""
1955 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001956 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001957 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001958 'property', str(e.exception))
1959
1960 def testVblockBadPhandle(self):
1961 """Test that we detect a vblock with an invalid phandle in contents"""
1962 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001963 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001964 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1965 '1000', str(e.exception))
1966
1967 def testVblockBadEntry(self):
1968 """Test that we detect an entry that points to a non-entry"""
1969 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001970 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001971 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1972 "'other'", str(e.exception))
1973
Simon Glass220c6222021-01-06 21:35:17 -07001974 def testVblockContent(self):
1975 """Test that the vblock signs the right data"""
1976 self._hash_data = True
1977 command.test_result = self._HandleVblockCommand
1978 entry_args = {
1979 'keydir': 'devkeys',
1980 }
1981 data = self._DoReadFileDtb(
1982 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1983 entry_args=entry_args)[0]
1984 hashlen = 32 # SHA256 hash is 32 bytes
1985 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1986 hashval = data[-hashlen:]
1987 dtb = data[len(U_BOOT_DATA):-hashlen]
1988
1989 expected_data = U_BOOT_DATA + dtb
1990
1991 # The hashval should be a hash of the dtb
1992 m = hashlib.sha256()
1993 m.update(expected_data)
1994 expected_hashval = m.digest()
1995 self.assertEqual(expected_hashval, hashval)
1996
Simon Glass66152ce2022-01-09 20:14:09 -07001997 def testVblockMissing(self):
1998 """Test that binman still produces an image if futility is missing"""
1999 entry_args = {
2000 'keydir': 'devkeys',
2001 }
2002 with test_util.capture_sys_output() as (_, stderr):
2003 self._DoTestFile('074_vblock.dts',
2004 force_missing_bintools='futility',
2005 entry_args=entry_args)
2006 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07002007 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07002008
Simon Glass8425a1f2018-07-17 13:25:48 -06002009 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06002010 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06002011 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06002012 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06002013 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06002014 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
2015
Simon Glass24b97442018-07-17 13:25:51 -06002016 def testUsesPos(self):
2017 """Test that the 'pos' property cannot be used anymore"""
2018 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002019 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06002020 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
2021 "'pos'", str(e.exception))
2022
Simon Glass274bf092018-09-14 04:57:08 -06002023 def testFillZero(self):
2024 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06002025 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07002026 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06002027
Simon Glass267de432018-09-14 04:57:09 -06002028 def testTextMissing(self):
2029 """Test for a text entry type where there is no text"""
2030 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002031 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06002032 self.assertIn("Node '/binman/text': No value provided for text label "
2033 "'test-id'", str(e.exception))
2034
Simon Glassed40e962018-09-14 04:57:10 -06002035 def testPackStart16Tpl(self):
2036 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06002037 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06002038 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
2039
Simon Glass3b376c32018-09-14 04:57:12 -06002040 def testSelectImage(self):
2041 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06002042 expected = 'Skipping images: image1'
2043
2044 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06002045 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06002046 with test_util.capture_sys_output() as (stdout, stderr):
2047 retcode = self._DoTestFile('006_dual_image.dts',
2048 verbosity=verbosity,
2049 images=['image2'])
2050 self.assertEqual(0, retcode)
2051 if verbosity:
2052 self.assertIn(expected, stdout.getvalue())
2053 else:
2054 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06002055
Simon Glass80025522022-01-29 14:14:04 -07002056 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2057 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06002058 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06002059
Simon Glasse219aa42018-09-14 04:57:24 -06002060 def testUpdateFdtAll(self):
2061 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06002062 self._SetupSplElf()
2063 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06002064 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06002065
2066 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06002067 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002068 'image-pos': 0,
2069 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06002070 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002071 'section:image-pos': 0,
2072 'section:size': 565,
2073 'section/u-boot-dtb:offset': 0,
2074 'section/u-boot-dtb:image-pos': 0,
2075 'section/u-boot-dtb:size': 565,
2076 'u-boot-spl-dtb:offset': 565,
2077 'u-boot-spl-dtb:image-pos': 565,
2078 'u-boot-spl-dtb:size': 585,
2079 'u-boot-tpl-dtb:offset': 1150,
2080 'u-boot-tpl-dtb:image-pos': 1150,
2081 'u-boot-tpl-dtb:size': 585,
2082 'u-boot-vpl-dtb:image-pos': 1735,
2083 'u-boot-vpl-dtb:offset': 1735,
2084 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002085 }
2086
2087 # We expect three device-tree files in the output, one after the other.
2088 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2089 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2090 # main U-Boot tree. All three should have the same postions and offset.
2091 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002092 self.maxDiff = None
2093 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002094 dtb = fdt.Fdt.FromData(data[start:])
2095 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002096 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002097 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002098 expected = dict(base_expected)
2099 if item:
2100 expected[item] = 0
2101 self.assertEqual(expected, props)
2102 start += dtb._fdt_obj.totalsize()
2103
2104 def testUpdateFdtOutput(self):
2105 """Test that output DTB files are updated"""
2106 try:
Simon Glass511f6582018-10-01 12:22:30 -06002107 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002108 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2109
2110 # Unfortunately, compiling a source file always results in a file
2111 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002112 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002113 # binman as a file called u-boot.dtb. To fix this, copy the file
2114 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002115 start = 0
2116 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002117 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002118 dtb = fdt.Fdt.FromData(data[start:])
2119 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002120 pathname = tools.get_output_filename(os.path.split(fname)[1])
2121 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002122 name = os.path.split(fname)[0]
2123
2124 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002125 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002126 else:
2127 orig_indata = dtb_data
2128 self.assertNotEqual(outdata, orig_indata,
2129 "Expected output file '%s' be updated" % pathname)
2130 self.assertEqual(outdata, data[start:start + size],
2131 "Expected output file '%s' to match output image" %
2132 pathname)
2133 start += size
2134 finally:
2135 self._ResetDtbs()
2136
Simon Glass7ba33592018-09-14 04:57:26 -06002137 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002138 bintool = self.comp_bintools['lz4']
2139 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002140
2141 def testCompress(self):
2142 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002143 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002144 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002145 use_real_dtb=True, update_dtb=True)
2146 dtb = fdt.Fdt(out_dtb_fname)
2147 dtb.Scan()
2148 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2149 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00002150 self.assertEqual(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002151
2152 # Do a sanity check on various fields
2153 image = control.images['image']
2154 entries = image.GetEntries()
2155 self.assertEqual(1, len(entries))
2156
2157 entry = entries['blob']
2158 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2159 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2160 orig = self._decompress(entry.data)
2161 self.assertEqual(orig, entry.uncomp_data)
2162
Simon Glass72eeff12020-10-26 17:40:16 -06002163 self.assertEqual(image.data, entry.data)
2164
Simon Glass7ba33592018-09-14 04:57:26 -06002165 expected = {
2166 'blob:uncomp-size': len(COMPRESS_DATA),
2167 'blob:size': len(data),
2168 'size': len(data),
2169 }
2170 self.assertEqual(expected, props)
2171
Simon Glassac6328c2018-09-14 04:57:28 -06002172 def testFiles(self):
2173 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002174 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002175 self.assertEqual(FILES_DATA, data)
2176
2177 def testFilesCompress(self):
2178 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002179 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002180 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002181
2182 image = control.images['image']
2183 entries = image.GetEntries()
2184 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002185 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002186
Simon Glass303f62f2019-05-17 22:00:46 -06002187 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002188 for i in range(1, 3):
2189 key = '%d.dat' % i
2190 start = entries[key].image_pos
2191 len = entries[key].size
2192 chunk = data[start:start + len]
2193 orig += self._decompress(chunk)
2194
2195 self.assertEqual(FILES_DATA, orig)
2196
2197 def testFilesMissing(self):
2198 """Test missing files"""
2199 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002200 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002201 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2202 'no files', str(e.exception))
2203
2204 def testFilesNoPattern(self):
2205 """Test missing files"""
2206 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002207 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002208 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2209 str(e.exception))
2210
Simon Glassdd156a42022-03-05 20:18:59 -07002211 def testExtendSize(self):
2212 """Test an extending entry"""
2213 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002214 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002215 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2216 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2217 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2218 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002219 self.assertEqual(expect, data)
2220 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700222100000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600222200000000 00000000 00000008 fill
222300000008 00000008 00000004 u-boot
22240000000c 0000000c 00000004 section
22250000000c 00000000 00000003 intel-mrc
222600000010 00000010 00000004 u-boot2
222700000014 00000014 0000000c section2
222800000014 00000000 00000008 fill
22290000001c 00000008 00000004 u-boot
223000000020 00000020 00000008 fill2
2231''', map_data)
2232
Simon Glassdd156a42022-03-05 20:18:59 -07002233 def testExtendSizeBad(self):
2234 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002235 with test_util.capture_sys_output() as (stdout, stderr):
2236 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002237 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002238 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2239 'expanding entry', str(e.exception))
2240
Simon Glassae7cf032018-09-14 04:57:31 -06002241 def testHash(self):
2242 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002243 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002244 use_real_dtb=True, update_dtb=True)
2245 dtb = fdt.Fdt(out_dtb_fname)
2246 dtb.Scan()
2247 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2248 m = hashlib.sha256()
2249 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002250 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002251
2252 def testHashNoAlgo(self):
2253 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002254 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002255 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2256 'hash node', str(e.exception))
2257
2258 def testHashBadAlgo(self):
2259 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002260 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002261 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002262 str(e.exception))
2263
2264 def testHashSection(self):
2265 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002266 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002267 use_real_dtb=True, update_dtb=True)
2268 dtb = fdt.Fdt(out_dtb_fname)
2269 dtb.Scan()
2270 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2271 m = hashlib.sha256()
2272 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002273 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002274 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002275
Simon Glass3fb4f422018-09-14 04:57:32 -06002276 def testPackUBootTplMicrocode(self):
2277 """Test that x86 microcode can be handled correctly in TPL
2278
2279 We expect to see the following in the image, in order:
2280 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2281 place
2282 u-boot-tpl.dtb with the microcode removed
2283 the microcode
2284 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002285 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002286 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002287 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002288 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2289 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002290
Simon Glassc64aea52018-09-14 04:57:34 -06002291 def testFmapX86(self):
2292 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002293 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002294 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002295 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002296 self.assertEqual(expected, data[:32])
2297 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2298
2299 self.assertEqual(0x100, fhdr.image_size)
2300
2301 self.assertEqual(0, fentries[0].offset)
2302 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002303 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002304
2305 self.assertEqual(4, fentries[1].offset)
2306 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002307 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002308
2309 self.assertEqual(32, fentries[2].offset)
2310 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2311 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002312 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002313
2314 def testFmapX86Section(self):
2315 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002316 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002317 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002318 self.assertEqual(expected, data[:32])
2319 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2320
Simon Glassb1d414c2021-04-03 11:05:10 +13002321 self.assertEqual(0x180, fhdr.image_size)
2322 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002323 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002324
Simon Glass82059c22021-04-03 11:05:09 +13002325 fentry = next(fiter)
2326 self.assertEqual(b'U_BOOT', fentry.name)
2327 self.assertEqual(0, fentry.offset)
2328 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002329
Simon Glass82059c22021-04-03 11:05:09 +13002330 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002331 self.assertEqual(b'SECTION', fentry.name)
2332 self.assertEqual(4, fentry.offset)
2333 self.assertEqual(0x20 + expect_size, fentry.size)
2334
2335 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002336 self.assertEqual(b'INTEL_MRC', fentry.name)
2337 self.assertEqual(4, fentry.offset)
2338 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002339
Simon Glass82059c22021-04-03 11:05:09 +13002340 fentry = next(fiter)
2341 self.assertEqual(b'FMAP', fentry.name)
2342 self.assertEqual(36, fentry.offset)
2343 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002344
Simon Glassb1714232018-09-14 04:57:35 -06002345 def testElf(self):
2346 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002347 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002348 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002349 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002350 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002351 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002352
Simon Glass0d673792019-07-08 13:18:25 -06002353 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002354 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002355 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002356 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002357 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002358 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002359
Simon Glasscd817d52018-09-14 04:57:36 -06002360 def testPackOverlapMap(self):
2361 """Test that overlapping regions are detected"""
2362 with test_util.capture_sys_output() as (stdout, stderr):
2363 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002364 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002365 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002366 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2367 stdout.getvalue())
2368
2369 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002370 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002371 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002372 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002373 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002374<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002375<none> 00000000 00000004 u-boot
2376<none> 00000003 00000004 u-boot-align
2377''', map_data)
2378
Simon Glass0d673792019-07-08 13:18:25 -06002379 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002380 """Test that an image with an Intel Reference code binary works"""
2381 data = self._DoReadFile('100_intel_refcode.dts')
2382 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2383
Simon Glasseb023b32019-04-25 21:58:39 -06002384 def testSectionOffset(self):
2385 """Tests use of a section with an offset"""
2386 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2387 map=True)
2388 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700238900000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600239000000004 00000004 00000010 section@0
239100000004 00000000 00000004 u-boot
239200000018 00000018 00000010 section@1
239300000018 00000000 00000004 u-boot
23940000002c 0000002c 00000004 section@2
23950000002c 00000000 00000004 u-boot
2396''', map_data)
2397 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002398 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2399 tools.get_bytes(0x21, 12) +
2400 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2401 tools.get_bytes(0x61, 12) +
2402 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2403 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002404
Simon Glass1de34482019-07-08 13:18:53 -06002405 def testCbfsRaw(self):
2406 """Test base handling of a Coreboot Filesystem (CBFS)
2407
2408 The exact contents of the CBFS is verified by similar tests in
2409 cbfs_util_test.py. The tests here merely check that the files added to
2410 the CBFS can be found in the final image.
2411 """
2412 data = self._DoReadFile('102_cbfs_raw.dts')
2413 size = 0xb0
2414
2415 cbfs = cbfs_util.CbfsReader(data)
2416 self.assertEqual(size, cbfs.rom_size)
2417
2418 self.assertIn('u-boot-dtb', cbfs.files)
2419 cfile = cbfs.files['u-boot-dtb']
2420 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2421
2422 def testCbfsArch(self):
2423 """Test on non-x86 architecture"""
2424 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2425 size = 0x100
2426
2427 cbfs = cbfs_util.CbfsReader(data)
2428 self.assertEqual(size, cbfs.rom_size)
2429
2430 self.assertIn('u-boot-dtb', cbfs.files)
2431 cfile = cbfs.files['u-boot-dtb']
2432 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2433
2434 def testCbfsStage(self):
2435 """Tests handling of a Coreboot Filesystem (CBFS)"""
2436 if not elf.ELF_TOOLS:
2437 self.skipTest('Python elftools not available')
2438 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2439 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2440 size = 0xb0
2441
2442 data = self._DoReadFile('104_cbfs_stage.dts')
2443 cbfs = cbfs_util.CbfsReader(data)
2444 self.assertEqual(size, cbfs.rom_size)
2445
2446 self.assertIn('u-boot', cbfs.files)
2447 cfile = cbfs.files['u-boot']
2448 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2449
2450 def testCbfsRawCompress(self):
2451 """Test handling of compressing raw files"""
2452 self._CheckLz4()
2453 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2454 size = 0x140
2455
2456 cbfs = cbfs_util.CbfsReader(data)
2457 self.assertIn('u-boot', cbfs.files)
2458 cfile = cbfs.files['u-boot']
2459 self.assertEqual(COMPRESS_DATA, cfile.data)
2460
2461 def testCbfsBadArch(self):
2462 """Test handling of a bad architecture"""
2463 with self.assertRaises(ValueError) as e:
2464 self._DoReadFile('106_cbfs_bad_arch.dts')
2465 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2466
2467 def testCbfsNoSize(self):
2468 """Test handling of a missing size property"""
2469 with self.assertRaises(ValueError) as e:
2470 self._DoReadFile('107_cbfs_no_size.dts')
2471 self.assertIn('entry must have a size property', str(e.exception))
2472
Simon Glass3e28f4f2021-11-23 11:03:54 -07002473 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002474 """Test handling of a CBFS entry which does not provide contentsy"""
2475 with self.assertRaises(ValueError) as e:
2476 self._DoReadFile('108_cbfs_no_contents.dts')
2477 self.assertIn('Could not complete processing of contents',
2478 str(e.exception))
2479
2480 def testCbfsBadCompress(self):
2481 """Test handling of a bad architecture"""
2482 with self.assertRaises(ValueError) as e:
2483 self._DoReadFile('109_cbfs_bad_compress.dts')
2484 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2485 str(e.exception))
2486
2487 def testCbfsNamedEntries(self):
2488 """Test handling of named entries"""
2489 data = self._DoReadFile('110_cbfs_name.dts')
2490
2491 cbfs = cbfs_util.CbfsReader(data)
2492 self.assertIn('FRED', cbfs.files)
2493 cfile1 = cbfs.files['FRED']
2494 self.assertEqual(U_BOOT_DATA, cfile1.data)
2495
2496 self.assertIn('hello', cbfs.files)
2497 cfile2 = cbfs.files['hello']
2498 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2499
Simon Glass759af872019-07-08 13:18:54 -06002500 def _SetupIfwi(self, fname):
2501 """Set up to run an IFWI test
2502
2503 Args:
2504 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2505 """
2506 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002507 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002508
2509 # Intel Integrated Firmware Image (IFWI) file
2510 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2511 data = fd.read()
2512 TestFunctional._MakeInputFile(fname,data)
2513
2514 def _CheckIfwi(self, data):
2515 """Check that an image with an IFWI contains the correct output
2516
2517 Args:
2518 data: Conents of output file
2519 """
Simon Glass80025522022-01-29 14:14:04 -07002520 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002521 if data[:0x1000] != expected_desc:
2522 self.fail('Expected descriptor binary at start of image')
2523
2524 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002525 image_fname = tools.get_output_filename('image.bin')
2526 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002527 ifwitool = bintool.Bintool.create('ifwitool')
2528 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002529
Simon Glass80025522022-01-29 14:14:04 -07002530 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002531 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002532
2533 def testPackX86RomIfwi(self):
2534 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2535 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002536 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002537 self._CheckIfwi(data)
2538
2539 def testPackX86RomIfwiNoDesc(self):
2540 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2541 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002542 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002543 self._CheckIfwi(data)
2544
2545 def testPackX86RomIfwiNoData(self):
2546 """Test that an x86 ROM with IFWI handles missing data"""
2547 self._SetupIfwi('ifwi.bin')
2548 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002549 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002550 self.assertIn('Could not complete processing of contents',
2551 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002552
Simon Glass66152ce2022-01-09 20:14:09 -07002553 def testIfwiMissing(self):
2554 """Test that binman still produces an image if ifwitool is missing"""
2555 self._SetupIfwi('fitimage.bin')
2556 with test_util.capture_sys_output() as (_, stderr):
2557 self._DoTestFile('111_x86_rom_ifwi.dts',
2558 force_missing_bintools='ifwitool')
2559 err = stderr.getvalue()
2560 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002561 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002562
Simon Glassc2f1aed2019-07-08 13:18:56 -06002563 def testCbfsOffset(self):
2564 """Test a CBFS with files at particular offsets
2565
2566 Like all CFBS tests, this is just checking the logic that calls
2567 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2568 """
2569 data = self._DoReadFile('114_cbfs_offset.dts')
2570 size = 0x200
2571
2572 cbfs = cbfs_util.CbfsReader(data)
2573 self.assertEqual(size, cbfs.rom_size)
2574
2575 self.assertIn('u-boot', cbfs.files)
2576 cfile = cbfs.files['u-boot']
2577 self.assertEqual(U_BOOT_DATA, cfile.data)
2578 self.assertEqual(0x40, cfile.cbfs_offset)
2579
2580 self.assertIn('u-boot-dtb', cbfs.files)
2581 cfile2 = cbfs.files['u-boot-dtb']
2582 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2583 self.assertEqual(0x140, cfile2.cbfs_offset)
2584
Simon Glass0f621332019-07-08 14:25:27 -06002585 def testFdtmap(self):
2586 """Test an FDT map can be inserted in the image"""
2587 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2588 fdtmap_data = data[len(U_BOOT_DATA):]
2589 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002590 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002591 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002592
2593 fdt_data = fdtmap_data[16:]
2594 dtb = fdt.Fdt.FromData(fdt_data)
2595 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002596 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002597 self.assertEqual({
2598 'image-pos': 0,
2599 'offset': 0,
2600 'u-boot:offset': 0,
2601 'u-boot:size': len(U_BOOT_DATA),
2602 'u-boot:image-pos': 0,
2603 'fdtmap:image-pos': 4,
2604 'fdtmap:offset': 4,
2605 'fdtmap:size': len(fdtmap_data),
2606 'size': len(data),
2607 }, props)
2608
2609 def testFdtmapNoMatch(self):
2610 """Check handling of an FDT map when the section cannot be found"""
2611 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2612
2613 # Mangle the section name, which should cause a mismatch between the
2614 # correct FDT path and the one expected by the section
2615 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002616 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002617 entries = image.GetEntries()
2618 fdtmap = entries['fdtmap']
2619 with self.assertRaises(ValueError) as e:
2620 fdtmap._GetFdtmap()
2621 self.assertIn("Cannot locate node for path '/binman-suffix'",
2622 str(e.exception))
2623
Simon Glasscec34ba2019-07-08 14:25:28 -06002624 def testFdtmapHeader(self):
2625 """Test an FDT map and image header can be inserted in the image"""
2626 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2627 fdtmap_pos = len(U_BOOT_DATA)
2628 fdtmap_data = data[fdtmap_pos:]
2629 fdt_data = fdtmap_data[16:]
2630 dtb = fdt.Fdt.FromData(fdt_data)
2631 fdt_size = dtb.GetFdtObj().totalsize()
2632 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002633 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002634 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2635 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2636
2637 def testFdtmapHeaderStart(self):
2638 """Test an image header can be inserted at the image start"""
2639 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2640 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2641 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002642 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002643 offset = struct.unpack('<I', hdr_data[4:])[0]
2644 self.assertEqual(fdtmap_pos, offset)
2645
2646 def testFdtmapHeaderPos(self):
2647 """Test an image header can be inserted at a chosen position"""
2648 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2649 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2650 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002651 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002652 offset = struct.unpack('<I', hdr_data[4:])[0]
2653 self.assertEqual(fdtmap_pos, offset)
2654
2655 def testHeaderMissingFdtmap(self):
2656 """Test an image header requires an fdtmap"""
2657 with self.assertRaises(ValueError) as e:
2658 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2659 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2660 str(e.exception))
2661
2662 def testHeaderNoLocation(self):
2663 """Test an image header with a no specified location is detected"""
2664 with self.assertRaises(ValueError) as e:
2665 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2666 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2667 str(e.exception))
2668
Simon Glasse61b6f62019-07-08 14:25:37 -06002669 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002670 """Test extending an entry after it is packed"""
2671 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002672 self.assertEqual(b'aaa', data[:3])
2673 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2674 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002675
Simon Glassdd156a42022-03-05 20:18:59 -07002676 def testEntryExtendBad(self):
2677 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002678 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002679 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002680 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002681 str(e.exception))
2682
Simon Glassdd156a42022-03-05 20:18:59 -07002683 def testEntryExtendSection(self):
2684 """Test extending an entry within a section after it is packed"""
2685 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002686 self.assertEqual(b'aaa', data[:3])
2687 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2688 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002689
Simon Glass90d29682019-07-08 14:25:38 -06002690 def testCompressDtb(self):
2691 """Test that compress of device-tree files is supported"""
2692 self._CheckLz4()
2693 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2694 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2695 comp_data = data[len(U_BOOT_DATA):]
2696 orig = self._decompress(comp_data)
2697 dtb = fdt.Fdt.FromData(orig)
2698 dtb.Scan()
2699 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2700 expected = {
2701 'u-boot:size': len(U_BOOT_DATA),
2702 'u-boot-dtb:uncomp-size': len(orig),
2703 'u-boot-dtb:size': len(comp_data),
2704 'size': len(data),
2705 }
2706 self.assertEqual(expected, props)
2707
Simon Glass151bbbf2019-07-08 14:25:41 -06002708 def testCbfsUpdateFdt(self):
2709 """Test that we can update the device tree with CBFS offset/size info"""
2710 self._CheckLz4()
2711 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2712 update_dtb=True)
2713 dtb = fdt.Fdt(out_dtb_fname)
2714 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002715 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002716 del props['cbfs/u-boot:size']
2717 self.assertEqual({
2718 'offset': 0,
2719 'size': len(data),
2720 'image-pos': 0,
2721 'cbfs:offset': 0,
2722 'cbfs:size': len(data),
2723 'cbfs:image-pos': 0,
Simon Glassfa144222023-10-14 14:40:28 -06002724 'cbfs/u-boot:offset': 0x30,
Simon Glass151bbbf2019-07-08 14:25:41 -06002725 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002726 'cbfs/u-boot:image-pos': 0x30,
2727 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002728 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002729 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002730 }, props)
2731
Simon Glass3c9b4f22019-07-08 14:25:42 -06002732 def testCbfsBadType(self):
2733 """Test an image header with a no specified location is detected"""
2734 with self.assertRaises(ValueError) as e:
2735 self._DoReadFile('126_cbfs_bad_type.dts')
2736 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2737
Simon Glass6b156f82019-07-08 14:25:43 -06002738 def testList(self):
2739 """Test listing the files in an image"""
2740 self._CheckLz4()
2741 data = self._DoReadFile('127_list.dts')
2742 image = control.images['image']
2743 entries = image.BuildEntryList()
2744 self.assertEqual(7, len(entries))
2745
2746 ent = entries[0]
2747 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002748 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002749 self.assertEqual('section', ent.etype)
2750 self.assertEqual(len(data), ent.size)
2751 self.assertEqual(0, ent.image_pos)
2752 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002753 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002754
2755 ent = entries[1]
2756 self.assertEqual(1, ent.indent)
2757 self.assertEqual('u-boot', ent.name)
2758 self.assertEqual('u-boot', ent.etype)
2759 self.assertEqual(len(U_BOOT_DATA), ent.size)
2760 self.assertEqual(0, ent.image_pos)
2761 self.assertEqual(None, ent.uncomp_size)
2762 self.assertEqual(0, ent.offset)
2763
2764 ent = entries[2]
2765 self.assertEqual(1, ent.indent)
2766 self.assertEqual('section', ent.name)
2767 self.assertEqual('section', ent.etype)
2768 section_size = ent.size
2769 self.assertEqual(0x100, ent.image_pos)
2770 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002771 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002772
2773 ent = entries[3]
2774 self.assertEqual(2, ent.indent)
2775 self.assertEqual('cbfs', ent.name)
2776 self.assertEqual('cbfs', ent.etype)
2777 self.assertEqual(0x400, ent.size)
2778 self.assertEqual(0x100, ent.image_pos)
2779 self.assertEqual(None, ent.uncomp_size)
2780 self.assertEqual(0, ent.offset)
2781
2782 ent = entries[4]
2783 self.assertEqual(3, ent.indent)
2784 self.assertEqual('u-boot', ent.name)
2785 self.assertEqual('u-boot', ent.etype)
2786 self.assertEqual(len(U_BOOT_DATA), ent.size)
2787 self.assertEqual(0x138, ent.image_pos)
2788 self.assertEqual(None, ent.uncomp_size)
2789 self.assertEqual(0x38, ent.offset)
2790
2791 ent = entries[5]
2792 self.assertEqual(3, ent.indent)
2793 self.assertEqual('u-boot-dtb', ent.name)
2794 self.assertEqual('text', ent.etype)
2795 self.assertGreater(len(COMPRESS_DATA), ent.size)
2796 self.assertEqual(0x178, ent.image_pos)
2797 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2798 self.assertEqual(0x78, ent.offset)
2799
2800 ent = entries[6]
2801 self.assertEqual(2, ent.indent)
2802 self.assertEqual('u-boot-dtb', ent.name)
2803 self.assertEqual('u-boot-dtb', ent.etype)
2804 self.assertEqual(0x500, ent.image_pos)
2805 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2806 dtb_size = ent.size
2807 # Compressing this data expands it since headers are added
2808 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2809 self.assertEqual(0x400, ent.offset)
2810
2811 self.assertEqual(len(data), 0x100 + section_size)
2812 self.assertEqual(section_size, 0x400 + dtb_size)
2813
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002814 def testFindFdtmap(self):
2815 """Test locating an FDT map in an image"""
2816 self._CheckLz4()
2817 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2818 image = control.images['image']
2819 entries = image.GetEntries()
2820 entry = entries['fdtmap']
2821 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2822
2823 def testFindFdtmapMissing(self):
2824 """Test failing to locate an FDP map"""
2825 data = self._DoReadFile('005_simple.dts')
2826 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2827
Simon Glassed39a3c2019-07-08 14:25:45 -06002828 def testFindImageHeader(self):
2829 """Test locating a image header"""
2830 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002831 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002832 image = control.images['image']
2833 entries = image.GetEntries()
2834 entry = entries['fdtmap']
2835 # The header should point to the FDT map
2836 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2837
2838 def testFindImageHeaderStart(self):
2839 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002840 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002841 image = control.images['image']
2842 entries = image.GetEntries()
2843 entry = entries['fdtmap']
2844 # The header should point to the FDT map
2845 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2846
2847 def testFindImageHeaderMissing(self):
2848 """Test failing to locate an image header"""
2849 data = self._DoReadFile('005_simple.dts')
2850 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2851
Simon Glassb8424fa2019-07-08 14:25:46 -06002852 def testReadImage(self):
2853 """Test reading an image and accessing its FDT map"""
2854 self._CheckLz4()
2855 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002856 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002857 orig_image = control.images['image']
2858 image = Image.FromFile(image_fname)
2859 self.assertEqual(orig_image.GetEntries().keys(),
2860 image.GetEntries().keys())
2861
2862 orig_entry = orig_image.GetEntries()['fdtmap']
2863 entry = image.GetEntries()['fdtmap']
Brandon Maiera657bc62024-06-04 16:16:05 +00002864 self.assertEqual(orig_entry.offset, entry.offset)
2865 self.assertEqual(orig_entry.size, entry.size)
2866 self.assertEqual(orig_entry.image_pos, entry.image_pos)
Simon Glassb8424fa2019-07-08 14:25:46 -06002867
2868 def testReadImageNoHeader(self):
2869 """Test accessing an image's FDT map without an image header"""
2870 self._CheckLz4()
2871 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002872 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002873 image = Image.FromFile(image_fname)
2874 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002875 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002876
2877 def testReadImageFail(self):
2878 """Test failing to read an image image's FDT map"""
2879 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002880 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002881 with self.assertRaises(ValueError) as e:
2882 image = Image.FromFile(image_fname)
2883 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002884
Simon Glassb2fd11d2019-07-08 14:25:48 -06002885 def testListCmd(self):
2886 """Test listing the files in an image using an Fdtmap"""
2887 self._CheckLz4()
2888 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2889
2890 # lz4 compression size differs depending on the version
2891 image = control.images['image']
2892 entries = image.GetEntries()
2893 section_size = entries['section'].size
2894 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2895 fdtmap_offset = entries['fdtmap'].offset
2896
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002897 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002898 try:
2899 tmpdir, updated_fname = self._SetupImageInTmpdir()
2900 with test_util.capture_sys_output() as (stdout, stderr):
2901 self._DoBinman('ls', '-i', updated_fname)
2902 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002903 if tmpdir:
2904 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002905 lines = stdout.getvalue().splitlines()
2906 expected = [
2907'Name Image-pos Size Entry-type Offset Uncomp-size',
2908'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002909'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002910' u-boot 0 4 u-boot 0',
2911' section 100 %x section 100' % section_size,
2912' cbfs 100 400 cbfs 0',
Simon Glassfa144222023-10-14 14:40:28 -06002913' u-boot 120 4 u-boot 20',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002914' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002915' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002916' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002917 (fdtmap_offset, fdtmap_offset),
2918' image-header bf8 8 image-header bf8',
2919 ]
2920 self.assertEqual(expected, lines)
2921
2922 def testListCmdFail(self):
2923 """Test failing to list an image"""
2924 self._DoReadFile('005_simple.dts')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002925 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002926 try:
2927 tmpdir, updated_fname = self._SetupImageInTmpdir()
2928 with self.assertRaises(ValueError) as e:
2929 self._DoBinman('ls', '-i', updated_fname)
2930 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002931 if tmpdir:
2932 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002933 self.assertIn("Cannot find FDT map in image", str(e.exception))
2934
2935 def _RunListCmd(self, paths, expected):
2936 """List out entries and check the result
2937
2938 Args:
2939 paths: List of paths to pass to the list command
2940 expected: Expected list of filenames to be returned, in order
2941 """
2942 self._CheckLz4()
2943 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002944 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002945 image = Image.FromFile(image_fname)
2946 lines = image.GetListEntries(paths)[1]
2947 files = [line[0].strip() for line in lines[1:]]
2948 self.assertEqual(expected, files)
2949
2950 def testListCmdSection(self):
2951 """Test listing the files in a section"""
2952 self._RunListCmd(['section'],
2953 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2954
2955 def testListCmdFile(self):
2956 """Test listing a particular file"""
2957 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2958
2959 def testListCmdWildcard(self):
2960 """Test listing a wildcarded file"""
2961 self._RunListCmd(['*boot*'],
2962 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2963
2964 def testListCmdWildcardMulti(self):
2965 """Test listing a wildcarded file"""
2966 self._RunListCmd(['*cb*', '*head*'],
2967 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2968
2969 def testListCmdEmpty(self):
2970 """Test listing a wildcarded file"""
2971 self._RunListCmd(['nothing'], [])
2972
2973 def testListCmdPath(self):
2974 """Test listing the files in a sub-entry of a section"""
2975 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2976
Simon Glass4c613bf2019-07-08 14:25:50 -06002977 def _RunExtractCmd(self, entry_name, decomp=True):
2978 """Extract an entry from an image
2979
2980 Args:
2981 entry_name: Entry name to extract
2982 decomp: True to decompress the data if compressed, False to leave
2983 it in its raw uncompressed format
2984
2985 Returns:
2986 data from entry
2987 """
2988 self._CheckLz4()
2989 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002990 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002991 return control.ReadEntry(image_fname, entry_name, decomp)
2992
2993 def testExtractSimple(self):
2994 """Test extracting a single file"""
2995 data = self._RunExtractCmd('u-boot')
2996 self.assertEqual(U_BOOT_DATA, data)
2997
Simon Glass980a2842019-07-08 14:25:52 -06002998 def testExtractSection(self):
2999 """Test extracting the files in a section"""
3000 data = self._RunExtractCmd('section')
3001 cbfs_data = data[:0x400]
3002 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06003003 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06003004 dtb_data = data[0x400:]
3005 dtb = self._decompress(dtb_data)
3006 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3007
3008 def testExtractCompressed(self):
3009 """Test extracting compressed data"""
3010 data = self._RunExtractCmd('section/u-boot-dtb')
3011 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3012
3013 def testExtractRaw(self):
3014 """Test extracting compressed data without decompressing it"""
3015 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
3016 dtb = self._decompress(data)
3017 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3018
3019 def testExtractCbfs(self):
3020 """Test extracting CBFS data"""
3021 data = self._RunExtractCmd('section/cbfs/u-boot')
3022 self.assertEqual(U_BOOT_DATA, data)
3023
3024 def testExtractCbfsCompressed(self):
3025 """Test extracting CBFS compressed data"""
3026 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
3027 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3028
3029 def testExtractCbfsRaw(self):
3030 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003031 bintool = self.comp_bintools['lzma_alone']
3032 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06003033 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003034 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06003035 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3036
Simon Glass4c613bf2019-07-08 14:25:50 -06003037 def testExtractBadEntry(self):
3038 """Test extracting a bad section path"""
3039 with self.assertRaises(ValueError) as e:
3040 self._RunExtractCmd('section/does-not-exist')
3041 self.assertIn("Entry 'does-not-exist' not found in '/section'",
3042 str(e.exception))
3043
3044 def testExtractMissingFile(self):
3045 """Test extracting file that does not exist"""
3046 with self.assertRaises(IOError) as e:
3047 control.ReadEntry('missing-file', 'name')
3048
3049 def testExtractBadFile(self):
3050 """Test extracting an invalid file"""
3051 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07003052 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06003053 with self.assertRaises(ValueError) as e:
3054 control.ReadEntry(fname, 'name')
3055
Simon Glass980a2842019-07-08 14:25:52 -06003056 def testExtractCmd(self):
3057 """Test extracting a file fron an image on the command line"""
3058 self._CheckLz4()
3059 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06003060 fname = os.path.join(self._indir, 'output.extact')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003061 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06003062 try:
3063 tmpdir, updated_fname = self._SetupImageInTmpdir()
3064 with test_util.capture_sys_output() as (stdout, stderr):
3065 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3066 '-f', fname)
3067 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003068 if tmpdir:
3069 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07003070 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003071 self.assertEqual(U_BOOT_DATA, data)
3072
3073 def testExtractOneEntry(self):
3074 """Test extracting a single entry fron an image """
3075 self._CheckLz4()
3076 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003077 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003078 fname = os.path.join(self._indir, 'output.extact')
3079 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003080 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003081 self.assertEqual(U_BOOT_DATA, data)
3082
3083 def _CheckExtractOutput(self, decomp):
3084 """Helper to test file output with and without decompression
3085
3086 Args:
3087 decomp: True to decompress entry data, False to output it raw
3088 """
3089 def _CheckPresent(entry_path, expect_data, expect_size=None):
3090 """Check and remove expected file
3091
3092 This checks the data/size of a file and removes the file both from
3093 the outfiles set and from the output directory. Once all files are
3094 processed, both the set and directory should be empty.
3095
3096 Args:
3097 entry_path: Entry path
3098 expect_data: Data to expect in file, or None to skip check
3099 expect_size: Size of data to expect in file, or None to skip
3100 """
3101 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003102 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003103 os.remove(path)
3104 if expect_data:
3105 self.assertEqual(expect_data, data)
3106 elif expect_size:
3107 self.assertEqual(expect_size, len(data))
3108 outfiles.remove(path)
3109
3110 def _CheckDirPresent(name):
3111 """Remove expected directory
3112
3113 This gives an error if the directory does not exist as expected
3114
3115 Args:
3116 name: Name of directory to remove
3117 """
3118 path = os.path.join(outdir, name)
3119 os.rmdir(path)
3120
3121 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003122 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003123 outdir = os.path.join(self._indir, 'extract')
3124 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3125
3126 # Create a set of all file that were output (should be 9)
3127 outfiles = set()
3128 for root, dirs, files in os.walk(outdir):
3129 outfiles |= set([os.path.join(root, fname) for fname in files])
3130 self.assertEqual(9, len(outfiles))
3131 self.assertEqual(9, len(einfos))
3132
3133 image = control.images['image']
3134 entries = image.GetEntries()
3135
3136 # Check the 9 files in various ways
3137 section = entries['section']
3138 section_entries = section.GetEntries()
3139 cbfs_entries = section_entries['cbfs'].GetEntries()
3140 _CheckPresent('u-boot', U_BOOT_DATA)
3141 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3142 dtb_len = EXTRACT_DTB_SIZE
3143 if not decomp:
3144 dtb_len = cbfs_entries['u-boot-dtb'].size
3145 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3146 if not decomp:
3147 dtb_len = section_entries['u-boot-dtb'].size
3148 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3149
3150 fdtmap = entries['fdtmap']
3151 _CheckPresent('fdtmap', fdtmap.data)
3152 hdr = entries['image-header']
3153 _CheckPresent('image-header', hdr.data)
3154
3155 _CheckPresent('section/root', section.data)
3156 cbfs = section_entries['cbfs']
3157 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003158 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003159 _CheckPresent('root', data)
3160
3161 # There should be no files left. Remove all the directories to check.
3162 # If there are any files/dirs remaining, one of these checks will fail.
3163 self.assertEqual(0, len(outfiles))
3164 _CheckDirPresent('section/cbfs')
3165 _CheckDirPresent('section')
3166 _CheckDirPresent('')
3167 self.assertFalse(os.path.exists(outdir))
3168
3169 def testExtractAllEntries(self):
3170 """Test extracting all entries"""
3171 self._CheckLz4()
3172 self._CheckExtractOutput(decomp=True)
3173
3174 def testExtractAllEntriesRaw(self):
3175 """Test extracting all entries without decompressing them"""
3176 self._CheckLz4()
3177 self._CheckExtractOutput(decomp=False)
3178
3179 def testExtractSelectedEntries(self):
3180 """Test extracting some entries"""
3181 self._CheckLz4()
3182 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003183 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003184 outdir = os.path.join(self._indir, 'extract')
3185 einfos = control.ExtractEntries(image_fname, None, outdir,
3186 ['*cb*', '*head*'])
3187
3188 # File output is tested by testExtractAllEntries(), so just check that
3189 # the expected entries are selected
3190 names = [einfo.name for einfo in einfos]
3191 self.assertEqual(names,
3192 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3193
3194 def testExtractNoEntryPaths(self):
3195 """Test extracting some entries"""
3196 self._CheckLz4()
3197 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003198 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003199 with self.assertRaises(ValueError) as e:
3200 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003201 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003202 str(e.exception))
3203
3204 def testExtractTooManyEntryPaths(self):
3205 """Test extracting some entries"""
3206 self._CheckLz4()
3207 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003208 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003209 with self.assertRaises(ValueError) as e:
3210 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003211 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003212 str(e.exception))
3213
Simon Glass52d06212019-07-08 14:25:53 -06003214 def testPackAlignSection(self):
3215 """Test that sections can have alignment"""
3216 self._DoReadFile('131_pack_align_section.dts')
3217
3218 self.assertIn('image', control.images)
3219 image = control.images['image']
3220 entries = image.GetEntries()
3221 self.assertEqual(3, len(entries))
3222
3223 # First u-boot
3224 self.assertIn('u-boot', entries)
3225 entry = entries['u-boot']
3226 self.assertEqual(0, entry.offset)
3227 self.assertEqual(0, entry.image_pos)
3228 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3229 self.assertEqual(len(U_BOOT_DATA), entry.size)
3230
3231 # Section0
3232 self.assertIn('section0', entries)
3233 section0 = entries['section0']
3234 self.assertEqual(0x10, section0.offset)
3235 self.assertEqual(0x10, section0.image_pos)
3236 self.assertEqual(len(U_BOOT_DATA), section0.size)
3237
3238 # Second u-boot
3239 section_entries = section0.GetEntries()
3240 self.assertIn('u-boot', section_entries)
3241 entry = section_entries['u-boot']
3242 self.assertEqual(0, entry.offset)
3243 self.assertEqual(0x10, entry.image_pos)
3244 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3245 self.assertEqual(len(U_BOOT_DATA), entry.size)
3246
3247 # Section1
3248 self.assertIn('section1', entries)
3249 section1 = entries['section1']
3250 self.assertEqual(0x14, section1.offset)
3251 self.assertEqual(0x14, section1.image_pos)
3252 self.assertEqual(0x20, section1.size)
3253
3254 # Second u-boot
3255 section_entries = section1.GetEntries()
3256 self.assertIn('u-boot', section_entries)
3257 entry = section_entries['u-boot']
3258 self.assertEqual(0, entry.offset)
3259 self.assertEqual(0x14, entry.image_pos)
3260 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3261 self.assertEqual(len(U_BOOT_DATA), entry.size)
3262
3263 # Section2
3264 self.assertIn('section2', section_entries)
3265 section2 = section_entries['section2']
3266 self.assertEqual(0x4, section2.offset)
3267 self.assertEqual(0x18, section2.image_pos)
3268 self.assertEqual(4, section2.size)
3269
3270 # Third u-boot
3271 section_entries = section2.GetEntries()
3272 self.assertIn('u-boot', section_entries)
3273 entry = section_entries['u-boot']
3274 self.assertEqual(0, entry.offset)
3275 self.assertEqual(0x18, entry.image_pos)
3276 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3277 self.assertEqual(len(U_BOOT_DATA), entry.size)
3278
Simon Glassf8a54bc2019-07-20 12:23:56 -06003279 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3280 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003281 """Replace an entry in an image
3282
3283 This writes the entry data to update it, then opens the updated file and
3284 returns the value that it now finds there.
3285
3286 Args:
3287 entry_name: Entry name to replace
3288 data: Data to replace it with
3289 decomp: True to compress the data if needed, False if data is
3290 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003291 allow_resize: True to allow entries to change size, False to raise
3292 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003293
3294 Returns:
3295 Tuple:
3296 data from entry
3297 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003298 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003299 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003300 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003301 update_dtb=True)[1]
3302
3303 self.assertIn('image', control.images)
3304 image = control.images['image']
3305 entries = image.GetEntries()
3306 orig_dtb_data = entries['u-boot-dtb'].data
3307 orig_fdtmap_data = entries['fdtmap'].data
3308
Simon Glass80025522022-01-29 14:14:04 -07003309 image_fname = tools.get_output_filename('image.bin')
3310 updated_fname = tools.get_output_filename('image-updated.bin')
3311 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003312 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3313 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003314 data = control.ReadEntry(updated_fname, entry_name, decomp)
3315
Simon Glassf8a54bc2019-07-20 12:23:56 -06003316 # The DT data should not change unless resized:
3317 if not allow_resize:
3318 new_dtb_data = entries['u-boot-dtb'].data
3319 self.assertEqual(new_dtb_data, orig_dtb_data)
3320 new_fdtmap_data = entries['fdtmap'].data
3321 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003322
Simon Glassf8a54bc2019-07-20 12:23:56 -06003323 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003324
3325 def testReplaceSimple(self):
3326 """Test replacing a single file"""
3327 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003328 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3329 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003330 self.assertEqual(expected, data)
3331
3332 # Test that the state looks right. There should be an FDT for the fdtmap
3333 # that we jsut read back in, and it should match what we find in the
3334 # 'control' tables. Checking for an FDT that does not exist should
3335 # return None.
3336 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003337 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003338 self.assertEqual(expected_fdtmap, fdtmap)
3339
3340 dtb = state.GetFdtForEtype('fdtmap')
3341 self.assertEqual(dtb.GetContents(), fdtmap)
3342
3343 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3344 self.assertIsNone(missing_path)
3345 self.assertIsNone(missing_fdtmap)
3346
3347 missing_dtb = state.GetFdtForEtype('missing')
3348 self.assertIsNone(missing_dtb)
3349
3350 self.assertEqual('/binman', state.fdt_path_prefix)
3351
3352 def testReplaceResizeFail(self):
3353 """Test replacing a file by something larger"""
3354 expected = U_BOOT_DATA + b'x'
3355 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003356 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3357 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003358 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3359 str(e.exception))
3360
3361 def testReplaceMulti(self):
3362 """Test replacing entry data where multiple images are generated"""
3363 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3364 update_dtb=True)[0]
3365 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003366 updated_fname = tools.get_output_filename('image-updated.bin')
3367 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003368 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003369 control.WriteEntry(updated_fname, entry_name, expected,
3370 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003371 data = control.ReadEntry(updated_fname, entry_name)
3372 self.assertEqual(expected, data)
3373
3374 # Check the state looks right.
3375 self.assertEqual('/binman/image', state.fdt_path_prefix)
3376
3377 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003378 image_fname = tools.get_output_filename('first-image.bin')
3379 updated_fname = tools.get_output_filename('first-updated.bin')
3380 tools.write_file(updated_fname, tools.read_file(image_fname))
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/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003389
Simon Glassfb30e292019-07-20 12:23:51 -06003390 def testUpdateFdtAllRepack(self):
3391 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003392 self._SetupSplElf()
3393 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003394 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3395 SECTION_SIZE = 0x300
3396 DTB_SIZE = 602
3397 FDTMAP_SIZE = 608
3398 base_expected = {
3399 'offset': 0,
3400 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3401 'image-pos': 0,
3402 'section:offset': 0,
3403 'section:size': SECTION_SIZE,
3404 'section:image-pos': 0,
3405 'section/u-boot-dtb:offset': 4,
3406 'section/u-boot-dtb:size': 636,
3407 'section/u-boot-dtb:image-pos': 4,
3408 'u-boot-spl-dtb:offset': SECTION_SIZE,
3409 'u-boot-spl-dtb:size': DTB_SIZE,
3410 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3411 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3412 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3413 'u-boot-tpl-dtb:size': DTB_SIZE,
3414 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3415 'fdtmap:size': FDTMAP_SIZE,
3416 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3417 }
3418 main_expected = {
3419 'section:orig-size': SECTION_SIZE,
3420 'section/u-boot-dtb:orig-offset': 4,
3421 }
3422
3423 # We expect three device-tree files in the output, with the first one
3424 # within a fixed-size section.
3425 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3426 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3427 # main U-Boot tree. All three should have the same positions and offset
3428 # except that the main tree should include the main_expected properties
3429 start = 4
3430 for item in ['', 'spl', 'tpl', None]:
3431 if item is None:
3432 start += 16 # Move past fdtmap header
3433 dtb = fdt.Fdt.FromData(data[start:])
3434 dtb.Scan()
3435 props = self._GetPropTree(dtb,
3436 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3437 prefix='/' if item is None else '/binman/')
3438 expected = dict(base_expected)
3439 if item:
3440 expected[item] = 0
3441 else:
3442 # Main DTB and fdtdec should include the 'orig-' properties
3443 expected.update(main_expected)
3444 # Helpful for debugging:
3445 #for prop in sorted(props):
3446 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3447 self.assertEqual(expected, props)
3448 if item == '':
3449 start = SECTION_SIZE
3450 else:
3451 start += dtb._fdt_obj.totalsize()
3452
Simon Glass11453762019-07-20 12:23:55 -06003453 def testFdtmapHeaderMiddle(self):
3454 """Test an FDT map in the middle of an image when it should be at end"""
3455 with self.assertRaises(ValueError) as e:
3456 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3457 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3458 str(e.exception))
3459
3460 def testFdtmapHeaderStartBad(self):
3461 """Test an FDT map in middle of an image when it should be at start"""
3462 with self.assertRaises(ValueError) as e:
3463 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3464 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3465 str(e.exception))
3466
3467 def testFdtmapHeaderEndBad(self):
3468 """Test an FDT map at the start of an image when it should be at end"""
3469 with self.assertRaises(ValueError) as e:
3470 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3471 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3472 str(e.exception))
3473
3474 def testFdtmapHeaderNoSize(self):
3475 """Test an image header at the end of an image with undefined size"""
3476 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3477
Simon Glassf8a54bc2019-07-20 12:23:56 -06003478 def testReplaceResize(self):
3479 """Test replacing a single file in an entry with a larger file"""
3480 expected = U_BOOT_DATA + b'x'
3481 data, _, image = self._RunReplaceCmd('u-boot', expected,
3482 dts='139_replace_repack.dts')
3483 self.assertEqual(expected, data)
3484
3485 entries = image.GetEntries()
3486 dtb_data = entries['u-boot-dtb'].data
3487 dtb = fdt.Fdt.FromData(dtb_data)
3488 dtb.Scan()
3489
3490 # The u-boot section should now be larger in the dtb
3491 node = dtb.GetNode('/binman/u-boot')
3492 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3493
3494 # Same for the fdtmap
3495 fdata = entries['fdtmap'].data
3496 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3497 fdtb.Scan()
3498 fnode = fdtb.GetNode('/u-boot')
3499 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3500
3501 def testReplaceResizeNoRepack(self):
3502 """Test replacing an entry with a larger file when not allowed"""
3503 expected = U_BOOT_DATA + b'x'
3504 with self.assertRaises(ValueError) as e:
3505 self._RunReplaceCmd('u-boot', expected)
3506 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3507 str(e.exception))
3508
Simon Glass9d8ee322019-07-20 12:23:58 -06003509 def testEntryShrink(self):
3510 """Test contracting an entry after it is packed"""
3511 try:
3512 state.SetAllowEntryContraction(True)
3513 data = self._DoReadFileDtb('140_entry_shrink.dts',
3514 update_dtb=True)[0]
3515 finally:
3516 state.SetAllowEntryContraction(False)
3517 self.assertEqual(b'a', data[:1])
3518 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3519 self.assertEqual(b'a', data[-1:])
3520
3521 def testEntryShrinkFail(self):
3522 """Test not being allowed to contract an entry after it is packed"""
3523 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3524
3525 # In this case there is a spare byte at the end of the data. The size of
3526 # the contents is only 1 byte but we still have the size before it
3527 # shrunk.
3528 self.assertEqual(b'a\0', data[:2])
3529 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3530 self.assertEqual(b'a\0', data[-2:])
3531
Simon Glass70e32982019-07-20 12:24:01 -06003532 def testDescriptorOffset(self):
3533 """Test that the Intel descriptor is always placed at at the start"""
3534 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3535 image = control.images['image']
3536 entries = image.GetEntries()
3537 desc = entries['intel-descriptor']
3538 self.assertEqual(0xff800000, desc.offset);
3539 self.assertEqual(0xff800000, desc.image_pos);
3540
Simon Glass37fdd142019-07-20 12:24:06 -06003541 def testReplaceCbfs(self):
3542 """Test replacing a single file in CBFS without changing the size"""
3543 self._CheckLz4()
3544 expected = b'x' * len(U_BOOT_DATA)
3545 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003546 updated_fname = tools.get_output_filename('image-updated.bin')
3547 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003548 entry_name = 'section/cbfs/u-boot'
3549 control.WriteEntry(updated_fname, entry_name, expected,
3550 allow_resize=True)
3551 data = control.ReadEntry(updated_fname, entry_name)
3552 self.assertEqual(expected, data)
3553
3554 def testReplaceResizeCbfs(self):
3555 """Test replacing a single file in CBFS with one of a different size"""
3556 self._CheckLz4()
3557 expected = U_BOOT_DATA + b'x'
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
Simon Glass30033c22019-07-20 12:24:15 -06003567 def _SetupForReplace(self):
3568 """Set up some files to use to replace entries
3569
3570 This generates an image, copies it to a new file, extracts all the files
3571 in it and updates some of them
3572
3573 Returns:
3574 List
3575 Image filename
3576 Output directory
3577 Expected values for updated entries, each a string
3578 """
3579 data = self._DoReadFileRealDtb('143_replace_all.dts')
3580
Simon Glass80025522022-01-29 14:14:04 -07003581 updated_fname = tools.get_output_filename('image-updated.bin')
3582 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003583
3584 outdir = os.path.join(self._indir, 'extract')
3585 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3586
3587 expected1 = b'x' + U_BOOT_DATA + b'y'
3588 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003589 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003590
3591 expected2 = b'a' + U_BOOT_DATA + b'b'
3592 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003593 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003594
3595 expected_text = b'not the same text'
3596 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003597 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003598
3599 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3600 dtb = fdt.FdtScan(dtb_fname)
3601 node = dtb.GetNode('/binman/text')
3602 node.AddString('my-property', 'the value')
3603 dtb.Sync(auto_resize=True)
3604 dtb.Flush()
3605
3606 return updated_fname, outdir, expected1, expected2, expected_text
3607
3608 def _CheckReplaceMultiple(self, entry_paths):
3609 """Handle replacing the contents of multiple entries
3610
3611 Args:
3612 entry_paths: List of entry paths to replace
3613
3614 Returns:
3615 List
3616 Dict of entries in the image:
3617 key: Entry name
3618 Value: Entry object
3619 Expected values for updated entries, each a string
3620 """
3621 updated_fname, outdir, expected1, expected2, expected_text = (
3622 self._SetupForReplace())
3623 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3624
3625 image = Image.FromFile(updated_fname)
3626 image.LoadData()
3627 return image.GetEntries(), expected1, expected2, expected_text
3628
3629 def testReplaceAll(self):
3630 """Test replacing the contents of all entries"""
3631 entries, expected1, expected2, expected_text = (
3632 self._CheckReplaceMultiple([]))
3633 data = entries['u-boot'].data
3634 self.assertEqual(expected1, data)
3635
3636 data = entries['u-boot2'].data
3637 self.assertEqual(expected2, data)
3638
3639 data = entries['text'].data
3640 self.assertEqual(expected_text, data)
3641
3642 # Check that the device tree is updated
3643 data = entries['u-boot-dtb'].data
3644 dtb = fdt.Fdt.FromData(data)
3645 dtb.Scan()
3646 node = dtb.GetNode('/binman/text')
3647 self.assertEqual('the value', node.props['my-property'].value)
3648
3649 def testReplaceSome(self):
3650 """Test replacing the contents of a few entries"""
3651 entries, expected1, expected2, expected_text = (
3652 self._CheckReplaceMultiple(['u-boot2', 'text']))
3653
3654 # This one should not change
3655 data = entries['u-boot'].data
3656 self.assertEqual(U_BOOT_DATA, data)
3657
3658 data = entries['u-boot2'].data
3659 self.assertEqual(expected2, data)
3660
3661 data = entries['text'].data
3662 self.assertEqual(expected_text, data)
3663
3664 def testReplaceCmd(self):
3665 """Test replacing a file fron an image on the command line"""
3666 self._DoReadFileRealDtb('143_replace_all.dts')
3667
3668 try:
3669 tmpdir, updated_fname = self._SetupImageInTmpdir()
3670
3671 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3672 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003673 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003674
3675 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003676 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003677 self.assertEqual(expected, data[:len(expected)])
3678 map_fname = os.path.join(tmpdir, 'image-updated.map')
3679 self.assertFalse(os.path.exists(map_fname))
3680 finally:
3681 shutil.rmtree(tmpdir)
3682
3683 def testReplaceCmdSome(self):
3684 """Test replacing some files fron an image on the command line"""
3685 updated_fname, outdir, expected1, expected2, expected_text = (
3686 self._SetupForReplace())
3687
3688 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3689 'u-boot2', 'text')
3690
Simon Glass80025522022-01-29 14:14:04 -07003691 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003692 image = Image.FromFile(updated_fname)
3693 image.LoadData()
3694 entries = image.GetEntries()
3695
3696 # This one should not change
3697 data = entries['u-boot'].data
3698 self.assertEqual(U_BOOT_DATA, data)
3699
3700 data = entries['u-boot2'].data
3701 self.assertEqual(expected2, data)
3702
3703 data = entries['text'].data
3704 self.assertEqual(expected_text, data)
3705
3706 def testReplaceMissing(self):
3707 """Test replacing entries where the file is missing"""
3708 updated_fname, outdir, expected1, expected2, expected_text = (
3709 self._SetupForReplace())
3710
3711 # Remove one of the files, to generate a warning
3712 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3713 os.remove(u_boot_fname1)
3714
3715 with test_util.capture_sys_output() as (stdout, stderr):
3716 control.ReplaceEntries(updated_fname, None, outdir, [])
3717 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003718 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003719
3720 def testReplaceCmdMap(self):
3721 """Test replacing a file fron an image on the command line"""
3722 self._DoReadFileRealDtb('143_replace_all.dts')
3723
3724 try:
3725 tmpdir, updated_fname = self._SetupImageInTmpdir()
3726
3727 fname = os.path.join(self._indir, 'update-u-boot.bin')
3728 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003729 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003730
3731 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3732 '-f', fname, '-m')
3733 map_fname = os.path.join(tmpdir, 'image-updated.map')
3734 self.assertTrue(os.path.exists(map_fname))
3735 finally:
3736 shutil.rmtree(tmpdir)
3737
3738 def testReplaceNoEntryPaths(self):
3739 """Test replacing an entry without an entry path"""
3740 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003741 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003742 with self.assertRaises(ValueError) as e:
3743 control.ReplaceEntries(image_fname, 'fname', None, [])
3744 self.assertIn('Must specify an entry path to read with -f',
3745 str(e.exception))
3746
3747 def testReplaceTooManyEntryPaths(self):
3748 """Test extracting some entries"""
3749 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003750 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003751 with self.assertRaises(ValueError) as e:
3752 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3753 self.assertIn('Must specify exactly one entry path to write with -f',
3754 str(e.exception))
3755
Simon Glass0b074d62019-08-24 07:22:48 -06003756 def testPackReset16(self):
3757 """Test that an image with an x86 reset16 region can be created"""
3758 data = self._DoReadFile('144_x86_reset16.dts')
3759 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3760
3761 def testPackReset16Spl(self):
3762 """Test that an image with an x86 reset16-spl region can be created"""
3763 data = self._DoReadFile('145_x86_reset16_spl.dts')
3764 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3765
3766 def testPackReset16Tpl(self):
3767 """Test that an image with an x86 reset16-tpl region can be created"""
3768 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3769 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3770
Simon Glass232f90c2019-08-24 07:22:50 -06003771 def testPackIntelFit(self):
3772 """Test that an image with an Intel FIT and pointer can be created"""
3773 data = self._DoReadFile('147_intel_fit.dts')
3774 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3775 fit = data[16:32];
3776 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3777 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3778
3779 image = control.images['image']
3780 entries = image.GetEntries()
3781 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3782 self.assertEqual(expected_ptr, ptr)
3783
3784 def testPackIntelFitMissing(self):
3785 """Test detection of a FIT pointer with not FIT region"""
3786 with self.assertRaises(ValueError) as e:
3787 self._DoReadFile('148_intel_fit_missing.dts')
3788 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3789 str(e.exception))
3790
Simon Glass72555fa2019-11-06 17:22:44 -07003791 def _CheckSymbolsTplSection(self, dts, expected_vals):
3792 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003793 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003794 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003795 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003796 self.assertEqual(expected1, data[:upto1])
3797
3798 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003799 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003800 self.assertEqual(expected2, data[upto1:upto2])
3801
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003802 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003803 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003804 self.assertEqual(expected3, data[upto2:upto3])
3805
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003806 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003807 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3808
3809 def testSymbolsTplSection(self):
3810 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3811 self._SetupSplElf('u_boot_binman_syms')
3812 self._SetupTplElf('u_boot_binman_syms')
3813 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003814 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003815
3816 def testSymbolsTplSectionX86(self):
3817 """Test binman can assign symbols in a section with end-at-4gb"""
3818 self._SetupSplElf('u_boot_binman_syms_x86')
3819 self._SetupTplElf('u_boot_binman_syms_x86')
3820 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003821 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003822 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003823
Simon Glass98c59572019-08-24 07:23:03 -06003824 def testPackX86RomIfwiSectiom(self):
3825 """Test that a section can be placed in an IFWI region"""
3826 self._SetupIfwi('fitimage.bin')
3827 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3828 self._CheckIfwi(data)
3829
Simon Glassba7985d2019-08-24 07:23:07 -06003830 def testPackFspM(self):
3831 """Test that an image with a FSP memory-init binary can be created"""
3832 data = self._DoReadFile('152_intel_fsp_m.dts')
3833 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3834
Simon Glass4d9086d2019-10-20 21:31:35 -06003835 def testPackFspS(self):
3836 """Test that an image with a FSP silicon-init binary can be created"""
3837 data = self._DoReadFile('153_intel_fsp_s.dts')
3838 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003839
Simon Glass9ea87b22019-10-20 21:31:36 -06003840 def testPackFspT(self):
3841 """Test that an image with a FSP temp-ram-init binary can be created"""
3842 data = self._DoReadFile('154_intel_fsp_t.dts')
3843 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3844
Simon Glass48f3aad2020-07-09 18:39:31 -06003845 def testMkimage(self):
3846 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003847 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003848 data = self._DoReadFile('156_mkimage.dts')
3849
3850 # Just check that the data appears in the file somewhere
3851 self.assertIn(U_BOOT_SPL_DATA, data)
3852
Simon Glass66152ce2022-01-09 20:14:09 -07003853 def testMkimageMissing(self):
3854 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003855 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003856 with test_util.capture_sys_output() as (_, stderr):
3857 self._DoTestFile('156_mkimage.dts',
3858 force_missing_bintools='mkimage')
3859 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003860 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003861
Simon Glass5e560182020-07-09 18:39:36 -06003862 def testExtblob(self):
3863 """Test an image with an external blob"""
3864 data = self._DoReadFile('157_blob_ext.dts')
3865 self.assertEqual(REFCODE_DATA, data)
3866
3867 def testExtblobMissing(self):
3868 """Test an image with a missing external blob"""
3869 with self.assertRaises(ValueError) as e:
3870 self._DoReadFile('158_blob_ext_missing.dts')
3871 self.assertIn("Filename 'missing-file' not found in input path",
3872 str(e.exception))
3873
Simon Glass5d94cc62020-07-09 18:39:38 -06003874 def testExtblobMissingOk(self):
3875 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003876 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003877 ret = self._DoTestFile('158_blob_ext_missing.dts',
3878 allow_missing=True)
3879 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003880 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003881 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003882 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003883 self.assertIn('Some images are invalid', err)
3884
3885 def testExtblobMissingOkFlag(self):
3886 """Test an image with an missing external blob allowed with -W"""
3887 with test_util.capture_sys_output() as (stdout, stderr):
3888 ret = self._DoTestFile('158_blob_ext_missing.dts',
3889 allow_missing=True, ignore_missing=True)
3890 self.assertEqual(0, ret)
3891 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003892 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003893 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003894 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003895
3896 def testExtblobMissingOkSect(self):
3897 """Test an image with an missing external blob that is allowed"""
3898 with test_util.capture_sys_output() as (stdout, stderr):
3899 self._DoTestFile('159_blob_ext_missing_sect.dts',
3900 allow_missing=True)
3901 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003902 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003903
Simon Glasse88cef92020-07-09 18:39:41 -06003904 def testPackX86RomMeMissingDesc(self):
3905 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003906 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003907 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003908 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003909 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003910
3911 def testPackX86RomMissingIfwi(self):
3912 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3913 self._SetupIfwi('fitimage.bin')
3914 pathname = os.path.join(self._indir, 'fitimage.bin')
3915 os.remove(pathname)
3916 with test_util.capture_sys_output() as (stdout, stderr):
3917 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3918 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003919 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003920
Simon Glass2a0fa982022-02-11 13:23:21 -07003921 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003922 """Test that zero-size overlapping regions are ignored"""
3923 self._DoTestFile('160_pack_overlap_zero.dts')
3924
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003925 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003926 # The data should be inside the FIT
3927 dtb = fdt.Fdt.FromData(fit_data)
3928 dtb.Scan()
3929 fnode = dtb.GetNode('/images/kernel')
3930 self.assertIn('data', fnode.props)
3931
3932 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003933 tools.write_file(fname, fit_data)
3934 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003935
3936 # Check a few features to make sure the plumbing works. We don't need
3937 # to test the operation of mkimage or dumpimage here. First convert the
3938 # output into a dict where the keys are the fields printed by dumpimage
3939 # and the values are a list of values for each field
3940 lines = out.splitlines()
3941
3942 # Converts "Compression: gzip compressed" into two groups:
3943 # 'Compression' and 'gzip compressed'
3944 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3945 vals = collections.defaultdict(list)
3946 for line in lines:
3947 mat = re_line.match(line)
3948 vals[mat.group(1)].append(mat.group(2))
3949
Brandon Maiera657bc62024-06-04 16:16:05 +00003950 self.assertEqual('FIT description: test-desc', lines[0])
Simon Glass45d556d2020-07-09 18:39:45 -06003951 self.assertIn('Created:', lines[1])
3952 self.assertIn('Image 0 (kernel)', vals)
3953 self.assertIn('Hash value', vals)
3954 data_sizes = vals.get('Data Size')
3955 self.assertIsNotNone(data_sizes)
3956 self.assertEqual(2, len(data_sizes))
3957 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003958 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3959 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3960
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003961 # Check if entry listing correctly omits /images/
3962 image = control.images['image']
3963 fit_entry = image.GetEntries()['fit']
3964 subentries = list(fit_entry.GetEntries().keys())
3965 expected = ['kernel', 'fdt-1']
3966 self.assertEqual(expected, subentries)
3967
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003968 def testSimpleFit(self):
3969 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003970 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003971 data = self._DoReadFile('161_fit.dts')
3972 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3973 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3974 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3975
3976 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3977
3978 def testSimpleFitExpandsSubentries(self):
3979 """Test that FIT images expand their subentries"""
3980 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3981 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3982 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3983 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3984
3985 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003986
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003987 def testSimpleFitImagePos(self):
3988 """Test that we have correct image-pos for FIT subentries"""
3989 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3990 update_dtb=True)
3991 dtb = fdt.Fdt(out_dtb_fname)
3992 dtb.Scan()
3993 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3994
Simon Glassb7bad182022-03-05 20:19:01 -07003995 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003996 self.assertEqual({
3997 'image-pos': 0,
3998 'offset': 0,
3999 'size': 1890,
4000
4001 'u-boot:image-pos': 0,
4002 'u-boot:offset': 0,
4003 'u-boot:size': 4,
4004
4005 'fit:image-pos': 4,
4006 'fit:offset': 4,
4007 'fit:size': 1840,
4008
Simon Glassb7bad182022-03-05 20:19:01 -07004009 'fit/images/kernel:image-pos': 304,
4010 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004011 'fit/images/kernel:size': 4,
4012
Simon Glassb7bad182022-03-05 20:19:01 -07004013 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004014 'fit/images/kernel/u-boot:offset': 0,
4015 'fit/images/kernel/u-boot:size': 4,
4016
Simon Glassb7bad182022-03-05 20:19:01 -07004017 'fit/images/fdt-1:image-pos': 552,
4018 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004019 'fit/images/fdt-1:size': 6,
4020
Simon Glassb7bad182022-03-05 20:19:01 -07004021 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004022 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
4023 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
4024
4025 'u-boot-nodtb:image-pos': 1844,
4026 'u-boot-nodtb:offset': 1844,
4027 'u-boot-nodtb:size': 46,
4028 }, props)
4029
4030 # Actually check the data is where we think it is
4031 for node, expected in [
4032 ("u-boot", U_BOOT_DATA),
4033 ("fit/images/kernel", U_BOOT_DATA),
4034 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4035 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
4036 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
4037 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4038 ]:
4039 image_pos = props[f"{node}:image-pos"]
4040 size = props[f"{node}:size"]
4041 self.assertEqual(len(expected), size)
4042 self.assertEqual(expected, data[image_pos:image_pos+size])
4043
Simon Glass45d556d2020-07-09 18:39:45 -06004044 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06004045 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06004046 data = self._DoReadFile('162_fit_external.dts')
4047 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
4048
Simon Glass7932c882022-01-09 20:13:39 -07004049 # Size of the external-data region as set up by mkimage
4050 external_data_size = len(U_BOOT_DATA) + 2
4051 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07004052 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07004053 len(U_BOOT_NODTB_DATA))
4054
Simon Glass45d556d2020-07-09 18:39:45 -06004055 # The data should be outside the FIT
4056 dtb = fdt.Fdt.FromData(fit_data)
4057 dtb.Scan()
4058 fnode = dtb.GetNode('/images/kernel')
4059 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07004060 self.assertEqual(len(U_BOOT_DATA),
4061 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4062 fit_pos = 0x400;
4063 self.assertEqual(
4064 fit_pos,
4065 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4066
Brandon Maiera657bc62024-06-04 16:16:05 +00004067 self.assertEqual(expected_size, len(data))
Simon Glass7932c882022-01-09 20:13:39 -07004068 actual_pos = len(U_BOOT_DATA) + fit_pos
4069 self.assertEqual(U_BOOT_DATA + b'aa',
4070 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004071
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004072 def testFitExternalImagePos(self):
4073 """Test that we have correct image-pos for external FIT subentries"""
4074 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4075 update_dtb=True)
4076 dtb = fdt.Fdt(out_dtb_fname)
4077 dtb.Scan()
4078 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4079
4080 self.assertEqual({
4081 'image-pos': 0,
4082 'offset': 0,
4083 'size': 1082,
4084
4085 'u-boot:image-pos': 0,
4086 'u-boot:offset': 0,
4087 'u-boot:size': 4,
4088
4089 'fit:size': 1032,
4090 'fit:offset': 4,
4091 'fit:image-pos': 4,
4092
4093 'fit/images/kernel:size': 4,
4094 'fit/images/kernel:offset': 1024,
4095 'fit/images/kernel:image-pos': 1028,
4096
4097 'fit/images/kernel/u-boot:size': 4,
4098 'fit/images/kernel/u-boot:offset': 0,
4099 'fit/images/kernel/u-boot:image-pos': 1028,
4100
4101 'fit/images/fdt-1:size': 2,
4102 'fit/images/fdt-1:offset': 1028,
4103 'fit/images/fdt-1:image-pos': 1032,
4104
4105 'fit/images/fdt-1/_testing:size': 2,
4106 'fit/images/fdt-1/_testing:offset': 0,
4107 'fit/images/fdt-1/_testing:image-pos': 1032,
4108
4109 'u-boot-nodtb:image-pos': 1036,
4110 'u-boot-nodtb:offset': 1036,
4111 'u-boot-nodtb:size': 46,
4112 }, props)
4113
4114 # Actually check the data is where we think it is
4115 for node, expected in [
4116 ("u-boot", U_BOOT_DATA),
4117 ("fit/images/kernel", U_BOOT_DATA),
4118 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4119 ("fit/images/fdt-1", b'aa'),
4120 ("fit/images/fdt-1/_testing", b'aa'),
4121 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4122 ]:
4123 image_pos = props[f"{node}:image-pos"]
4124 size = props[f"{node}:size"]
4125 self.assertEqual(len(expected), size)
4126 self.assertEqual(expected, data[image_pos:image_pos+size])
4127
Simon Glass66152ce2022-01-09 20:14:09 -07004128 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004129 """Test that binman complains if mkimage is missing"""
4130 with self.assertRaises(ValueError) as e:
4131 self._DoTestFile('162_fit_external.dts',
4132 force_missing_bintools='mkimage')
4133 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4134 str(e.exception))
4135
4136 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004137 """Test that binman still produces a FIT image if mkimage is missing"""
4138 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004139 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004140 force_missing_bintools='mkimage')
4141 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004142 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004143
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004144 def testSectionIgnoreHashSignature(self):
4145 """Test that sections ignore hash, signature nodes for its data"""
4146 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4147 expected = (U_BOOT_DATA + U_BOOT_DATA)
4148 self.assertEqual(expected, data)
4149
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004150 def testPadInSections(self):
4151 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004152 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4153 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004154 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4155 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004156 U_BOOT_DATA)
4157 self.assertEqual(expected, data)
4158
Simon Glassd12599d2020-10-26 17:40:09 -06004159 dtb = fdt.Fdt(out_dtb_fname)
4160 dtb.Scan()
4161 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4162 expected = {
4163 'image-pos': 0,
4164 'offset': 0,
4165 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4166
4167 'section:image-pos': 0,
4168 'section:offset': 0,
4169 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4170
4171 'section/before:image-pos': 0,
4172 'section/before:offset': 0,
4173 'section/before:size': len(U_BOOT_DATA),
4174
4175 'section/u-boot:image-pos': 4,
4176 'section/u-boot:offset': 4,
4177 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4178
4179 'section/after:image-pos': 26,
4180 'section/after:offset': 26,
4181 'section/after:size': len(U_BOOT_DATA),
4182 }
4183 self.assertEqual(expected, props)
4184
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004185 def testFitImageSubentryAlignment(self):
4186 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004187 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004188 entry_args = {
4189 'test-id': TEXT_DATA,
4190 }
4191 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4192 entry_args=entry_args)
4193 dtb = fdt.Fdt.FromData(data)
4194 dtb.Scan()
4195
4196 node = dtb.GetNode('/images/kernel')
4197 data = dtb.GetProps(node)["data"].bytes
4198 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004199 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4200 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004201 self.assertEqual(expected, data)
4202
4203 node = dtb.GetNode('/images/fdt-1')
4204 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004205 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4206 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004207 U_BOOT_DTB_DATA)
4208 self.assertEqual(expected, data)
4209
4210 def testFitExtblobMissingOk(self):
4211 """Test a FIT with a missing external blob that is allowed"""
4212 with test_util.capture_sys_output() as (stdout, stderr):
4213 self._DoTestFile('168_fit_missing_blob.dts',
4214 allow_missing=True)
4215 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004216 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004217
Simon Glass21db0ff2020-09-01 05:13:54 -06004218 def testBlobNamedByArgMissing(self):
4219 """Test handling of a missing entry arg"""
4220 with self.assertRaises(ValueError) as e:
4221 self._DoReadFile('068_blob_named_by_arg.dts')
4222 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4223 str(e.exception))
4224
Simon Glass559c4de2020-09-01 05:13:58 -06004225 def testPackBl31(self):
4226 """Test that an image with an ATF BL31 binary can be created"""
4227 data = self._DoReadFile('169_atf_bl31.dts')
4228 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4229
Samuel Holland9d8cc632020-10-21 21:12:15 -05004230 def testPackScp(self):
4231 """Test that an image with an SCP binary can be created"""
4232 data = self._DoReadFile('172_scp.dts')
4233 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4234
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004235 def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True,
4236 default_dt=None):
Simon Glasscd2783e2024-07-20 11:49:46 +01004237 """Check an image with an FIT with multiple FDT images"""
Simon Glassa435cd12020-09-01 05:13:59 -06004238 def _CheckFdt(seq, expected_data):
4239 """Check the FDT nodes
4240
4241 Args:
4242 seq: Sequence number to check (0 or 1)
4243 expected_data: Expected contents of 'data' property
4244 """
4245 name = 'fdt-%d' % seq
4246 fnode = dtb.GetNode('/images/%s' % name)
4247 self.assertIsNotNone(fnode)
4248 self.assertEqual({'description','type', 'compression', 'data'},
4249 set(fnode.props.keys()))
4250 self.assertEqual(expected_data, fnode.props['data'].bytes)
4251 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4252 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004253 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004254
4255 def _CheckConfig(seq, expected_data):
4256 """Check the configuration nodes
4257
4258 Args:
4259 seq: Sequence number to check (0 or 1)
4260 expected_data: Expected contents of 'data' property
4261 """
4262 cnode = dtb.GetNode('/configurations')
4263 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004264 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004265
4266 name = 'config-%d' % seq
4267 fnode = dtb.GetNode('/configurations/%s' % name)
4268 self.assertIsNotNone(fnode)
4269 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4270 set(fnode.props.keys()))
4271 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4272 fnode.props['description'].value)
4273 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4274
4275 entry_args = {
Simon Glass1032acc2020-09-06 10:39:08 -06004276 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004277 }
Simon Glasscd2783e2024-07-20 11:49:46 +01004278 if use_fdt_list:
4279 entry_args['of-list'] = 'test-fdt1 test-fdt2'
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004280 if default_dt:
4281 entry_args['default-dt'] = default_dt
Simon Glassa435cd12020-09-01 05:13:59 -06004282 data = self._DoReadFileDtb(
Simon Glasscd2783e2024-07-20 11:49:46 +01004283 dts,
Simon Glassa435cd12020-09-01 05:13:59 -06004284 entry_args=entry_args,
4285 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4286 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4287 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4288
4289 dtb = fdt.Fdt.FromData(fit_data)
4290 dtb.Scan()
4291 fnode = dtb.GetNode('/images/kernel')
4292 self.assertIn('data', fnode.props)
4293
4294 # Check all the properties in fdt-1 and fdt-2
4295 _CheckFdt(1, TEST_FDT1_DATA)
4296 _CheckFdt(2, TEST_FDT2_DATA)
4297
4298 # Check configurations
4299 _CheckConfig(1, TEST_FDT1_DATA)
4300 _CheckConfig(2, TEST_FDT2_DATA)
4301
Simon Glasscd2783e2024-07-20 11:49:46 +01004302 def testFitFdt(self):
4303 """Test an image with an FIT with multiple FDT images"""
4304 self.CheckFitFdt()
4305
Simon Glassa435cd12020-09-01 05:13:59 -06004306 def testFitFdtMissingList(self):
4307 """Test handling of a missing 'of-list' entry arg"""
4308 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004309 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004310 self.assertIn("Generator node requires 'of-list' entry argument",
4311 str(e.exception))
4312
4313 def testFitFdtEmptyList(self):
4314 """Test handling of an empty 'of-list' entry arg"""
4315 entry_args = {
4316 'of-list': '',
4317 }
4318 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4319
4320 def testFitFdtMissingProp(self):
4321 """Test handling of a missing 'fit,fdt-list' property"""
4322 with self.assertRaises(ValueError) as e:
4323 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4324 self.assertIn("Generator node requires 'fit,fdt-list' property",
4325 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004326
Simon Glass1032acc2020-09-06 10:39:08 -06004327 def testFitFdtMissing(self):
4328 """Test handling of a missing 'default-dt' entry arg"""
4329 entry_args = {
4330 'of-list': 'test-fdt1 test-fdt2',
4331 }
4332 with self.assertRaises(ValueError) as e:
4333 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004334 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004335 entry_args=entry_args,
4336 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4337 self.assertIn("Generated 'default' node requires default-dt entry argument",
4338 str(e.exception))
4339
4340 def testFitFdtNotInList(self):
4341 """Test handling of a default-dt that is not in the of-list"""
4342 entry_args = {
4343 'of-list': 'test-fdt1 test-fdt2',
4344 'default-dt': 'test-fdt3',
4345 }
4346 with self.assertRaises(ValueError) as e:
4347 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004348 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004349 entry_args=entry_args,
4350 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4351 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4352 str(e.exception))
4353
Simon Glassa820af72020-09-06 10:39:09 -06004354 def testFitExtblobMissingHelp(self):
4355 """Test display of help messages when an external blob is missing"""
4356 control.missing_blob_help = control._ReadMissingBlobHelp()
4357 control.missing_blob_help['wibble'] = 'Wibble test'
4358 control.missing_blob_help['another'] = 'Another test'
4359 with test_util.capture_sys_output() as (stdout, stderr):
4360 self._DoTestFile('168_fit_missing_blob.dts',
4361 allow_missing=True)
4362 err = stderr.getvalue()
4363
4364 # We can get the tag from the name, the type or the missing-msg
4365 # property. Check all three.
4366 self.assertIn('You may need to build ARM Trusted', err)
4367 self.assertIn('Wibble test', err)
4368 self.assertIn('Another test', err)
4369
Simon Glass6f1f4d42020-09-06 10:35:32 -06004370 def testMissingBlob(self):
4371 """Test handling of a blob containing a missing file"""
4372 with self.assertRaises(ValueError) as e:
4373 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4374 self.assertIn("Filename 'missing' not found in input path",
4375 str(e.exception))
4376
Simon Glassa0729502020-09-06 10:35:33 -06004377 def testEnvironment(self):
4378 """Test adding a U-Boot environment"""
4379 data = self._DoReadFile('174_env.dts')
4380 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4381 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4382 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4383 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4384 env)
4385
4386 def testEnvironmentNoSize(self):
4387 """Test that a missing 'size' property is detected"""
4388 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004389 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004390 self.assertIn("'u-boot-env' entry must have a size property",
4391 str(e.exception))
4392
4393 def testEnvironmentTooSmall(self):
4394 """Test handling of an environment that does not fit"""
4395 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004396 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004397
4398 # checksum, start byte, environment with \0 terminator, final \0
4399 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4400 short = need - 0x8
4401 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4402 str(e.exception))
4403
Simon Glassd1fdf752020-10-26 17:40:01 -06004404 def testSkipAtStart(self):
4405 """Test handling of skip-at-start section"""
4406 data = self._DoReadFile('177_skip_at_start.dts')
4407 self.assertEqual(U_BOOT_DATA, data)
4408
4409 image = control.images['image']
4410 entries = image.GetEntries()
4411 section = entries['section']
4412 self.assertEqual(0, section.offset)
4413 self.assertEqual(len(U_BOOT_DATA), section.size)
4414 self.assertEqual(U_BOOT_DATA, section.GetData())
4415
4416 entry = section.GetEntries()['u-boot']
4417 self.assertEqual(16, entry.offset)
4418 self.assertEqual(len(U_BOOT_DATA), entry.size)
4419 self.assertEqual(U_BOOT_DATA, entry.data)
4420
4421 def testSkipAtStartPad(self):
4422 """Test handling of skip-at-start section with padded entry"""
4423 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004424 before = tools.get_bytes(0, 8)
4425 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004426 all = before + U_BOOT_DATA + after
4427 self.assertEqual(all, data)
4428
4429 image = control.images['image']
4430 entries = image.GetEntries()
4431 section = entries['section']
4432 self.assertEqual(0, section.offset)
4433 self.assertEqual(len(all), section.size)
4434 self.assertEqual(all, section.GetData())
4435
4436 entry = section.GetEntries()['u-boot']
4437 self.assertEqual(16, entry.offset)
4438 self.assertEqual(len(all), entry.size)
4439 self.assertEqual(U_BOOT_DATA, entry.data)
4440
4441 def testSkipAtStartSectionPad(self):
4442 """Test handling of skip-at-start section with padding"""
4443 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004444 before = tools.get_bytes(0, 8)
4445 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004446 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004447 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004448
4449 image = control.images['image']
4450 entries = image.GetEntries()
4451 section = entries['section']
4452 self.assertEqual(0, section.offset)
4453 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004454 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004455 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004456
4457 entry = section.GetEntries()['u-boot']
4458 self.assertEqual(16, entry.offset)
4459 self.assertEqual(len(U_BOOT_DATA), entry.size)
4460 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004461
Simon Glassbb395742020-10-26 17:40:14 -06004462 def testSectionPad(self):
4463 """Testing padding with sections"""
4464 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004465 expected = (tools.get_bytes(ord('&'), 3) +
4466 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004467 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004468 tools.get_bytes(ord('!'), 1) +
4469 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004470 self.assertEqual(expected, data)
4471
4472 def testSectionAlign(self):
4473 """Testing alignment with sections"""
4474 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4475 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004476 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004477 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004478 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004479 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004480 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4481 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004482 self.assertEqual(expected, data)
4483
Simon Glassd92c8362020-10-26 17:40:25 -06004484 def testCompressImage(self):
4485 """Test compression of the entire image"""
4486 self._CheckLz4()
4487 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4488 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4489 dtb = fdt.Fdt(out_dtb_fname)
4490 dtb.Scan()
4491 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4492 'uncomp-size'])
4493 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004494 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004495
4496 # Do a sanity check on various fields
4497 image = control.images['image']
4498 entries = image.GetEntries()
4499 self.assertEqual(2, len(entries))
4500
4501 entry = entries['blob']
4502 self.assertEqual(COMPRESS_DATA, entry.data)
4503 self.assertEqual(len(COMPRESS_DATA), entry.size)
4504
4505 entry = entries['u-boot']
4506 self.assertEqual(U_BOOT_DATA, entry.data)
4507 self.assertEqual(len(U_BOOT_DATA), entry.size)
4508
4509 self.assertEqual(len(data), image.size)
4510 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4511 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4512 orig = self._decompress(image.data)
4513 self.assertEqual(orig, image.uncomp_data)
4514
4515 expected = {
4516 'blob:offset': 0,
4517 'blob:size': len(COMPRESS_DATA),
4518 'u-boot:offset': len(COMPRESS_DATA),
4519 'u-boot:size': len(U_BOOT_DATA),
4520 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4521 'offset': 0,
4522 'image-pos': 0,
4523 'size': len(data),
4524 }
4525 self.assertEqual(expected, props)
4526
4527 def testCompressImageLess(self):
4528 """Test compression where compression reduces the image size"""
4529 self._CheckLz4()
4530 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4531 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4532 dtb = fdt.Fdt(out_dtb_fname)
4533 dtb.Scan()
4534 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4535 'uncomp-size'])
4536 orig = self._decompress(data)
4537
Brandon Maiera657bc62024-06-04 16:16:05 +00004538 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004539
4540 # Do a sanity check on various fields
4541 image = control.images['image']
4542 entries = image.GetEntries()
4543 self.assertEqual(2, len(entries))
4544
4545 entry = entries['blob']
4546 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4547 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4548
4549 entry = entries['u-boot']
4550 self.assertEqual(U_BOOT_DATA, entry.data)
4551 self.assertEqual(len(U_BOOT_DATA), entry.size)
4552
4553 self.assertEqual(len(data), image.size)
4554 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4555 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4556 image.uncomp_size)
4557 orig = self._decompress(image.data)
4558 self.assertEqual(orig, image.uncomp_data)
4559
4560 expected = {
4561 'blob:offset': 0,
4562 'blob:size': len(COMPRESS_DATA_BIG),
4563 'u-boot:offset': len(COMPRESS_DATA_BIG),
4564 'u-boot:size': len(U_BOOT_DATA),
4565 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4566 'offset': 0,
4567 'image-pos': 0,
4568 'size': len(data),
4569 }
4570 self.assertEqual(expected, props)
4571
4572 def testCompressSectionSize(self):
4573 """Test compression of a section with a fixed size"""
4574 self._CheckLz4()
4575 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4576 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4577 dtb = fdt.Fdt(out_dtb_fname)
4578 dtb.Scan()
4579 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4580 'uncomp-size'])
4581 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004582 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004583 expected = {
4584 'section/blob:offset': 0,
4585 'section/blob:size': len(COMPRESS_DATA),
4586 'section/u-boot:offset': len(COMPRESS_DATA),
4587 'section/u-boot:size': len(U_BOOT_DATA),
4588 'section:offset': 0,
4589 'section:image-pos': 0,
4590 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4591 'section:size': 0x30,
4592 'offset': 0,
4593 'image-pos': 0,
4594 'size': 0x30,
4595 }
4596 self.assertEqual(expected, props)
4597
4598 def testCompressSection(self):
4599 """Test compression of a section with no fixed size"""
4600 self._CheckLz4()
4601 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4602 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4603 dtb = fdt.Fdt(out_dtb_fname)
4604 dtb.Scan()
4605 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4606 'uncomp-size'])
4607 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004608 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004609 expected = {
4610 'section/blob:offset': 0,
4611 'section/blob:size': len(COMPRESS_DATA),
4612 'section/u-boot:offset': len(COMPRESS_DATA),
4613 'section/u-boot:size': len(U_BOOT_DATA),
4614 'section:offset': 0,
4615 'section:image-pos': 0,
4616 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4617 'section:size': len(data),
4618 'offset': 0,
4619 'image-pos': 0,
4620 'size': len(data),
4621 }
4622 self.assertEqual(expected, props)
4623
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004624 def testLz4Missing(self):
4625 """Test that binman still produces an image if lz4 is missing"""
4626 with test_util.capture_sys_output() as (_, stderr):
4627 self._DoTestFile('185_compress_section.dts',
4628 force_missing_bintools='lz4')
4629 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004630 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004631
Simon Glassd92c8362020-10-26 17:40:25 -06004632 def testCompressExtra(self):
4633 """Test compression of a section with no fixed size"""
4634 self._CheckLz4()
4635 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4636 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4637 dtb = fdt.Fdt(out_dtb_fname)
4638 dtb.Scan()
4639 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4640 'uncomp-size'])
4641
4642 base = data[len(U_BOOT_DATA):]
Brandon Maiera657bc62024-06-04 16:16:05 +00004643 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glassd92c8362020-10-26 17:40:25 -06004644 rest = base[len(U_BOOT_DATA):]
4645
4646 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004647 bintool = self.comp_bintools['lz4']
4648 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004649 data1 = rest[:len(expect1)]
4650 section1 = self._decompress(data1)
Brandon Maiera657bc62024-06-04 16:16:05 +00004651 self.assertEqual(expect1, data1)
4652 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glassd92c8362020-10-26 17:40:25 -06004653 rest1 = rest[len(expect1):]
4654
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004655 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004656 data2 = rest1[:len(expect2)]
4657 section2 = self._decompress(data2)
Brandon Maiera657bc62024-06-04 16:16:05 +00004658 self.assertEqual(expect2, data2)
4659 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glassd92c8362020-10-26 17:40:25 -06004660 rest2 = rest1[len(expect2):]
4661
4662 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4663 len(expect2) + len(U_BOOT_DATA))
Brandon Maiera657bc62024-06-04 16:16:05 +00004664 #self.assertEqual(expect_size, len(data))
Simon Glassd92c8362020-10-26 17:40:25 -06004665
Brandon Maiera657bc62024-06-04 16:16:05 +00004666 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glassd92c8362020-10-26 17:40:25 -06004667
4668 self.maxDiff = None
4669 expected = {
4670 'u-boot:offset': 0,
4671 'u-boot:image-pos': 0,
4672 'u-boot:size': len(U_BOOT_DATA),
4673
4674 'base:offset': len(U_BOOT_DATA),
4675 'base:image-pos': len(U_BOOT_DATA),
4676 'base:size': len(data) - len(U_BOOT_DATA),
4677 'base/u-boot:offset': 0,
4678 'base/u-boot:image-pos': len(U_BOOT_DATA),
4679 'base/u-boot:size': len(U_BOOT_DATA),
4680 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4681 len(expect2),
4682 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4683 len(expect2),
4684 'base/u-boot2:size': len(U_BOOT_DATA),
4685
4686 'base/section:offset': len(U_BOOT_DATA),
4687 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4688 'base/section:size': len(expect1),
4689 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4690 'base/section/blob:offset': 0,
4691 'base/section/blob:size': len(COMPRESS_DATA),
4692 'base/section/u-boot:offset': len(COMPRESS_DATA),
4693 'base/section/u-boot:size': len(U_BOOT_DATA),
4694
4695 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4696 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4697 'base/section2:size': len(expect2),
4698 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4699 'base/section2/blob:offset': 0,
4700 'base/section2/blob:size': len(COMPRESS_DATA),
4701 'base/section2/blob2:offset': len(COMPRESS_DATA),
4702 'base/section2/blob2:size': len(COMPRESS_DATA),
4703
4704 'offset': 0,
4705 'image-pos': 0,
4706 'size': len(data),
4707 }
4708 self.assertEqual(expected, props)
4709
Simon Glassecbe4732021-01-06 21:35:15 -07004710 def testSymbolsSubsection(self):
4711 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004712 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004713
Simon Glass3fb25402021-01-06 21:35:16 -07004714 def testReadImageEntryArg(self):
4715 """Test reading an image that would need an entry arg to generate"""
4716 entry_args = {
4717 'cros-ec-rw-path': 'ecrw.bin',
4718 }
4719 data = self.data = self._DoReadFileDtb(
4720 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4721 entry_args=entry_args)
4722
Simon Glass80025522022-01-29 14:14:04 -07004723 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004724 orig_image = control.images['image']
4725
4726 # This should not generate an error about the missing 'cros-ec-rw-path'
4727 # since we are reading the image from a file. Compare with
4728 # testEntryArgsRequired()
4729 image = Image.FromFile(image_fname)
4730 self.assertEqual(orig_image.GetEntries().keys(),
4731 image.GetEntries().keys())
4732
Simon Glassa2af7302021-01-06 21:35:18 -07004733 def testFilesAlign(self):
4734 """Test alignment with files"""
4735 data = self._DoReadFile('190_files_align.dts')
4736
4737 # The first string is 15 bytes so will align to 16
4738 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4739 self.assertEqual(expect, data)
4740
Simon Glassdb84b562021-01-06 21:35:19 -07004741 def testReadImageSkip(self):
4742 """Test reading an image and accessing its FDT map"""
4743 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004744 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004745 orig_image = control.images['image']
4746 image = Image.FromFile(image_fname)
4747 self.assertEqual(orig_image.GetEntries().keys(),
4748 image.GetEntries().keys())
4749
4750 orig_entry = orig_image.GetEntries()['fdtmap']
4751 entry = image.GetEntries()['fdtmap']
4752 self.assertEqual(orig_entry.offset, entry.offset)
4753 self.assertEqual(orig_entry.size, entry.size)
4754 self.assertEqual(16, entry.image_pos)
4755
4756 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4757
Brandon Maiera657bc62024-06-04 16:16:05 +00004758 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glassdb84b562021-01-06 21:35:19 -07004759
Simon Glassc98de972021-03-18 20:24:57 +13004760 def testTplNoDtb(self):
4761 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004762 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004763 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4764 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4765 data[:len(U_BOOT_TPL_NODTB_DATA)])
4766
Simon Glass63f41d42021-03-18 20:24:58 +13004767 def testTplBssPad(self):
4768 """Test that we can pad TPL's BSS with zeros"""
4769 # ELF file with a '__bss_size' symbol
4770 self._SetupTplElf()
4771 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004772 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004773 data)
4774
4775 def testTplBssPadMissing(self):
4776 """Test that a missing symbol is detected"""
4777 self._SetupTplElf('u_boot_ucode_ptr')
4778 with self.assertRaises(ValueError) as e:
4779 self._DoReadFile('193_tpl_bss_pad.dts')
4780 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4781 str(e.exception))
4782
Simon Glass718b5292021-03-18 20:25:07 +13004783 def checkDtbSizes(self, data, pad_len, start):
4784 """Check the size arguments in a dtb embedded in an image
4785
4786 Args:
4787 data: The image data
4788 pad_len: Length of the pad section in the image, in bytes
4789 start: Start offset of the devicetree to examine, within the image
4790
4791 Returns:
4792 Size of the devicetree in bytes
4793 """
4794 dtb_data = data[start:]
4795 dtb = fdt.Fdt.FromData(dtb_data)
4796 fdt_size = dtb.GetFdtObj().totalsize()
4797 dtb.Scan()
4798 props = self._GetPropTree(dtb, 'size')
4799 self.assertEqual({
4800 'size': len(data),
4801 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4802 'u-boot-spl/u-boot-spl-dtb:size': 801,
4803 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4804 'u-boot-spl:size': 860,
4805 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4806 'u-boot/u-boot-dtb:size': 781,
4807 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4808 'u-boot:size': 827,
4809 }, props)
4810 return fdt_size
4811
4812 def testExpanded(self):
4813 """Test that an expanded entry type is selected when needed"""
4814 self._SetupSplElf()
4815 self._SetupTplElf()
4816
4817 # SPL has a devicetree, TPL does not
4818 entry_args = {
4819 'spl-dtb': '1',
4820 'spl-bss-pad': 'y',
4821 'tpl-dtb': '',
4822 }
4823 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4824 entry_args=entry_args)
4825 image = control.images['image']
4826 entries = image.GetEntries()
4827 self.assertEqual(3, len(entries))
4828
4829 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4830 self.assertIn('u-boot', entries)
4831 entry = entries['u-boot']
4832 self.assertEqual('u-boot-expanded', entry.etype)
4833 subent = entry.GetEntries()
4834 self.assertEqual(2, len(subent))
4835 self.assertIn('u-boot-nodtb', subent)
4836 self.assertIn('u-boot-dtb', subent)
4837
4838 # Second, u-boot-spl, which should be expanded into three parts
4839 self.assertIn('u-boot-spl', entries)
4840 entry = entries['u-boot-spl']
4841 self.assertEqual('u-boot-spl-expanded', entry.etype)
4842 subent = entry.GetEntries()
4843 self.assertEqual(3, len(subent))
4844 self.assertIn('u-boot-spl-nodtb', subent)
4845 self.assertIn('u-boot-spl-bss-pad', subent)
4846 self.assertIn('u-boot-spl-dtb', subent)
4847
4848 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4849 # devicetree
4850 self.assertIn('u-boot-tpl', entries)
4851 entry = entries['u-boot-tpl']
4852 self.assertEqual('u-boot-tpl', entry.etype)
4853 self.assertEqual(None, entry.GetEntries())
4854
4855 def testExpandedTpl(self):
4856 """Test that an expanded entry type is selected for TPL when needed"""
4857 self._SetupTplElf()
4858
4859 entry_args = {
4860 'tpl-bss-pad': 'y',
4861 'tpl-dtb': 'y',
4862 }
4863 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4864 entry_args=entry_args)
4865 image = control.images['image']
4866 entries = image.GetEntries()
4867 self.assertEqual(1, len(entries))
4868
4869 # We only have u-boot-tpl, which be expanded
4870 self.assertIn('u-boot-tpl', entries)
4871 entry = entries['u-boot-tpl']
4872 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4873 subent = entry.GetEntries()
4874 self.assertEqual(3, len(subent))
4875 self.assertIn('u-boot-tpl-nodtb', subent)
4876 self.assertIn('u-boot-tpl-bss-pad', subent)
4877 self.assertIn('u-boot-tpl-dtb', subent)
4878
4879 def testExpandedNoPad(self):
4880 """Test an expanded entry without BSS pad enabled"""
4881 self._SetupSplElf()
4882 self._SetupTplElf()
4883
4884 # SPL has a devicetree, TPL does not
4885 entry_args = {
4886 'spl-dtb': 'something',
4887 'spl-bss-pad': 'n',
4888 'tpl-dtb': '',
4889 }
4890 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4891 entry_args=entry_args)
4892 image = control.images['image']
4893 entries = image.GetEntries()
4894
4895 # Just check u-boot-spl, which should be expanded into two parts
4896 self.assertIn('u-boot-spl', entries)
4897 entry = entries['u-boot-spl']
4898 self.assertEqual('u-boot-spl-expanded', entry.etype)
4899 subent = entry.GetEntries()
4900 self.assertEqual(2, len(subent))
4901 self.assertIn('u-boot-spl-nodtb', subent)
4902 self.assertIn('u-boot-spl-dtb', subent)
4903
4904 def testExpandedTplNoPad(self):
4905 """Test that an expanded entry type with padding disabled in TPL"""
4906 self._SetupTplElf()
4907
4908 entry_args = {
4909 'tpl-bss-pad': '',
4910 'tpl-dtb': 'y',
4911 }
4912 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4913 entry_args=entry_args)
4914 image = control.images['image']
4915 entries = image.GetEntries()
4916 self.assertEqual(1, len(entries))
4917
4918 # We only have u-boot-tpl, which be expanded
4919 self.assertIn('u-boot-tpl', entries)
4920 entry = entries['u-boot-tpl']
4921 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4922 subent = entry.GetEntries()
4923 self.assertEqual(2, len(subent))
4924 self.assertIn('u-boot-tpl-nodtb', subent)
4925 self.assertIn('u-boot-tpl-dtb', subent)
4926
4927 def testFdtInclude(self):
4928 """Test that an Fdt is update within all binaries"""
4929 self._SetupSplElf()
4930 self._SetupTplElf()
4931
4932 # SPL has a devicetree, TPL does not
4933 self.maxDiff = None
4934 entry_args = {
4935 'spl-dtb': '1',
4936 'spl-bss-pad': 'y',
4937 'tpl-dtb': '',
4938 }
4939 # Build the image. It includes two separate devicetree binaries, each
4940 # with their own contents, but all contain the binman definition.
4941 data = self._DoReadFileDtb(
4942 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4943 update_dtb=True, entry_args=entry_args)[0]
4944 pad_len = 10
4945
4946 # Check the U-Boot dtb
4947 start = len(U_BOOT_NODTB_DATA)
4948 fdt_size = self.checkDtbSizes(data, pad_len, start)
4949
4950 # Now check SPL
4951 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4952 fdt_size = self.checkDtbSizes(data, pad_len, start)
4953
4954 # TPL has no devicetree
4955 start += fdt_size + len(U_BOOT_TPL_DATA)
4956 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004957
Simon Glass7098b7f2021-03-21 18:24:30 +13004958 def testSymbolsExpanded(self):
4959 """Test binman can assign symbols in expanded entries"""
4960 entry_args = {
4961 'spl-dtb': '1',
4962 }
4963 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4964 U_BOOT_SPL_DTB_DATA, 0x38,
4965 entry_args=entry_args, use_expanded=True)
4966
Simon Glasse1915782021-03-21 18:24:31 +13004967 def testCollection(self):
4968 """Test a collection"""
4969 data = self._DoReadFile('198_collection.dts')
4970 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004971 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4972 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004973 data)
4974
Simon Glass27a7f772021-03-21 18:24:32 +13004975 def testCollectionSection(self):
4976 """Test a collection where a section must be built first"""
4977 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004978 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004979 # building the contents, producing an error is anything is still
4980 # missing.
4981 data = self._DoReadFile('199_collection_section.dts')
4982 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004983 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4984 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004985 data)
4986
Simon Glassf427c5f2021-03-21 18:24:33 +13004987 def testAlignDefault(self):
4988 """Test that default alignment works on sections"""
4989 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004990 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004991 U_BOOT_DATA)
4992 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004993 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004994 # No alignment within the nested section
4995 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4996 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004997 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004998 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004999
Bin Mengc0b15742021-05-10 20:23:33 +08005000 def testPackOpenSBI(self):
5001 """Test that an image with an OpenSBI binary can be created"""
5002 data = self._DoReadFile('201_opensbi.dts')
5003 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
5004
Simon Glass76f496d2021-07-06 10:36:37 -06005005 def testSectionsSingleThread(self):
5006 """Test sections without multithreading"""
5007 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07005008 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
5009 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
5010 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06005011 self.assertEqual(expected, data)
5012
5013 def testThreadTimeout(self):
5014 """Test handling a thread that takes too long"""
5015 with self.assertRaises(ValueError) as e:
5016 self._DoTestFile('202_section_timeout.dts',
5017 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06005018 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06005019
Simon Glass748a1d42021-07-06 10:36:41 -06005020 def testTiming(self):
5021 """Test output of timing information"""
5022 data = self._DoReadFile('055_sections.dts')
5023 with test_util.capture_sys_output() as (stdout, stderr):
5024 state.TimingShow()
5025 self.assertIn('read:', stdout.getvalue())
5026 self.assertIn('compress:', stdout.getvalue())
5027
Simon Glassadfb8492021-11-03 21:09:18 -06005028 def testUpdateFdtInElf(self):
5029 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005030 if not elf.ELF_TOOLS:
5031 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005032 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5033 outfile = os.path.join(self._indir, 'u-boot.out')
5034 begin_sym = 'dtb_embed_begin'
5035 end_sym = 'dtb_embed_end'
5036 retcode = self._DoTestFile(
5037 '060_fdt_update.dts', update_dtb=True,
5038 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5039 self.assertEqual(0, retcode)
5040
5041 # Check that the output file does in fact contact a dtb with the binman
5042 # definition in the correct place
5043 syms = elf.GetSymbolFileOffset(infile,
5044 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07005045 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06005046 dtb_data = data[syms['dtb_embed_begin'].offset:
5047 syms['dtb_embed_end'].offset]
5048
5049 dtb = fdt.Fdt.FromData(dtb_data)
5050 dtb.Scan()
5051 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
5052 self.assertEqual({
5053 'image-pos': 0,
5054 'offset': 0,
5055 '_testing:offset': 32,
5056 '_testing:size': 2,
5057 '_testing:image-pos': 32,
5058 'section@0/u-boot:offset': 0,
5059 'section@0/u-boot:size': len(U_BOOT_DATA),
5060 'section@0/u-boot:image-pos': 0,
5061 'section@0:offset': 0,
5062 'section@0:size': 16,
5063 'section@0:image-pos': 0,
5064
5065 'section@1/u-boot:offset': 0,
5066 'section@1/u-boot:size': len(U_BOOT_DATA),
5067 'section@1/u-boot:image-pos': 16,
5068 'section@1:offset': 16,
5069 'section@1:size': 16,
5070 'section@1:image-pos': 16,
5071 'size': 40
5072 }, props)
5073
5074 def testUpdateFdtInElfInvalid(self):
5075 """Test that invalid args are detected with --update-fdt-in-elf"""
5076 with self.assertRaises(ValueError) as e:
5077 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5078 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5079 str(e.exception))
5080
5081 def testUpdateFdtInElfNoSyms(self):
5082 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005083 if not elf.ELF_TOOLS:
5084 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005085 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5086 outfile = ''
5087 begin_sym = 'wrong_begin'
5088 end_sym = 'wrong_end'
5089 with self.assertRaises(ValueError) as e:
5090 self._DoTestFile(
5091 '060_fdt_update.dts',
5092 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5093 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5094 str(e.exception))
5095
5096 def testUpdateFdtInElfTooSmall(self):
5097 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005098 if not elf.ELF_TOOLS:
5099 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005100 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5101 outfile = os.path.join(self._indir, 'u-boot.out')
5102 begin_sym = 'dtb_embed_begin'
5103 end_sym = 'dtb_embed_end'
5104 with self.assertRaises(ValueError) as e:
5105 self._DoTestFile(
5106 '060_fdt_update.dts', update_dtb=True,
5107 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5108 self.assertRegex(
5109 str(e.exception),
5110 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5111
Simon Glass88e04da2021-11-23 11:03:42 -07005112 def testVersion(self):
5113 """Test we can get the binman version"""
5114 version = '(unreleased)'
5115 self.assertEqual(version, state.GetVersion(self._indir))
5116
5117 with self.assertRaises(SystemExit):
5118 with test_util.capture_sys_output() as (_, stderr):
5119 self._DoBinman('-V')
5120 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5121
5122 # Try running the tool too, just to be safe
5123 result = self._RunBinman('-V')
5124 self.assertEqual('Binman %s\n' % version, result.stderr)
5125
5126 # Set up a version file to make sure that works
5127 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005128 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005129 binary=False)
5130 self.assertEqual(version, state.GetVersion(self._indir))
5131
Simon Glass637958f2021-11-23 21:09:50 -07005132 def testAltFormat(self):
5133 """Test that alternative formats can be used to extract"""
5134 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5135
5136 try:
5137 tmpdir, updated_fname = self._SetupImageInTmpdir()
5138 with test_util.capture_sys_output() as (stdout, _):
5139 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5140 self.assertEqual(
5141 '''Flag (-F) Entry type Description
5142fdt fdtmap Extract the devicetree blob from the fdtmap
5143''',
5144 stdout.getvalue())
5145
5146 dtb = os.path.join(tmpdir, 'fdt.dtb')
5147 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5148 dtb, 'fdtmap')
5149
5150 # Check that we can read it and it can be scanning, meaning it does
5151 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005152 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005153 dtb = fdt.Fdt.FromData(data)
5154 dtb.Scan()
5155
5156 # Now check u-boot which has no alt_format
5157 fname = os.path.join(tmpdir, 'fdt.dtb')
5158 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5159 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005160 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005161 self.assertEqual(U_BOOT_DATA, data)
5162
5163 finally:
5164 shutil.rmtree(tmpdir)
5165
Simon Glass0b00ae62021-11-23 21:09:52 -07005166 def testExtblobList(self):
5167 """Test an image with an external blob list"""
5168 data = self._DoReadFile('215_blob_ext_list.dts')
5169 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5170
5171 def testExtblobListMissing(self):
5172 """Test an image with a missing external blob"""
5173 with self.assertRaises(ValueError) as e:
5174 self._DoReadFile('216_blob_ext_list_missing.dts')
5175 self.assertIn("Filename 'missing-file' not found in input path",
5176 str(e.exception))
5177
5178 def testExtblobListMissingOk(self):
5179 """Test an image with an missing external blob that is allowed"""
5180 with test_util.capture_sys_output() as (stdout, stderr):
5181 self._DoTestFile('216_blob_ext_list_missing.dts',
5182 allow_missing=True)
5183 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005184 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005185
Simon Glass3efb2972021-11-23 21:08:59 -07005186 def testFip(self):
5187 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5188 data = self._DoReadFile('203_fip.dts')
5189 hdr, fents = fip_util.decode_fip(data)
5190 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5191 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5192 self.assertEqual(0x123, hdr.flags)
5193
5194 self.assertEqual(2, len(fents))
5195
5196 fent = fents[0]
5197 self.assertEqual(
5198 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5199 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5200 self.assertEqual('soc-fw', fent.fip_type)
5201 self.assertEqual(0x88, fent.offset)
5202 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5203 self.assertEqual(0x123456789abcdef, fent.flags)
5204 self.assertEqual(ATF_BL31_DATA, fent.data)
5205 self.assertEqual(True, fent.valid)
5206
5207 fent = fents[1]
5208 self.assertEqual(
5209 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5210 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5211 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5212 self.assertEqual(0x8c, fent.offset)
5213 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5214 self.assertEqual(0, fent.flags)
5215 self.assertEqual(ATF_BL2U_DATA, fent.data)
5216 self.assertEqual(True, fent.valid)
5217
5218 def testFipOther(self):
5219 """Basic FIP with something that isn't a external blob"""
5220 data = self._DoReadFile('204_fip_other.dts')
5221 hdr, fents = fip_util.decode_fip(data)
5222
5223 self.assertEqual(2, len(fents))
5224 fent = fents[1]
5225 self.assertEqual('rot-cert', fent.fip_type)
5226 self.assertEqual(b'aa', fent.data)
5227
Simon Glass3efb2972021-11-23 21:08:59 -07005228 def testFipNoType(self):
5229 """FIP with an entry of an unknown type"""
5230 with self.assertRaises(ValueError) as e:
5231 self._DoReadFile('205_fip_no_type.dts')
5232 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5233 str(e.exception))
5234
5235 def testFipUuid(self):
5236 """Basic FIP with a manual uuid"""
5237 data = self._DoReadFile('206_fip_uuid.dts')
5238 hdr, fents = fip_util.decode_fip(data)
5239
5240 self.assertEqual(2, len(fents))
5241 fent = fents[1]
5242 self.assertEqual(None, fent.fip_type)
5243 self.assertEqual(
5244 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5245 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5246 fent.uuid)
5247 self.assertEqual(U_BOOT_DATA, fent.data)
5248
5249 def testFipLs(self):
5250 """Test listing a FIP"""
5251 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5252 hdr, fents = fip_util.decode_fip(data)
5253
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005254 tmpdir = None
Simon Glass3efb2972021-11-23 21:08:59 -07005255 try:
5256 tmpdir, updated_fname = self._SetupImageInTmpdir()
5257 with test_util.capture_sys_output() as (stdout, stderr):
5258 self._DoBinman('ls', '-i', updated_fname)
5259 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005260 if tmpdir:
5261 shutil.rmtree(tmpdir)
Simon Glass3efb2972021-11-23 21:08:59 -07005262 lines = stdout.getvalue().splitlines()
5263 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005264'Name Image-pos Size Entry-type Offset Uncomp-size',
5265'--------------------------------------------------------------',
5266'image 0 2d3 section 0',
5267' atf-fip 0 90 atf-fip 0',
5268' soc-fw 88 4 blob-ext 88',
5269' u-boot 8c 4 u-boot 8c',
5270' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005271]
5272 self.assertEqual(expected, lines)
5273
5274 image = control.images['image']
5275 entries = image.GetEntries()
5276 fdtmap = entries['fdtmap']
5277
5278 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5279 magic = fdtmap_data[:8]
5280 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005281 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005282
5283 fdt_data = fdtmap_data[16:]
5284 dtb = fdt.Fdt.FromData(fdt_data)
5285 dtb.Scan()
5286 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5287 self.assertEqual({
5288 'atf-fip/soc-fw:image-pos': 136,
5289 'atf-fip/soc-fw:offset': 136,
5290 'atf-fip/soc-fw:size': 4,
5291 'atf-fip/u-boot:image-pos': 140,
5292 'atf-fip/u-boot:offset': 140,
5293 'atf-fip/u-boot:size': 4,
5294 'atf-fip:image-pos': 0,
5295 'atf-fip:offset': 0,
5296 'atf-fip:size': 144,
5297 'image-pos': 0,
5298 'offset': 0,
5299 'fdtmap:image-pos': fdtmap.image_pos,
5300 'fdtmap:offset': fdtmap.offset,
5301 'fdtmap:size': len(fdtmap_data),
5302 'size': len(data),
5303 }, props)
5304
5305 def testFipExtractOneEntry(self):
5306 """Test extracting a single entry fron an FIP"""
5307 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005308 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005309 fname = os.path.join(self._indir, 'output.extact')
5310 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005311 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005312 self.assertEqual(U_BOOT_DATA, data)
5313
5314 def testFipReplace(self):
5315 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005316 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005317 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005318 updated_fname = tools.get_output_filename('image-updated.bin')
5319 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005320 entry_name = 'atf-fip/u-boot'
5321 control.WriteEntry(updated_fname, entry_name, expected,
5322 allow_resize=True)
5323 actual = control.ReadEntry(updated_fname, entry_name)
5324 self.assertEqual(expected, actual)
5325
Simon Glass80025522022-01-29 14:14:04 -07005326 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005327 hdr, fents = fip_util.decode_fip(new_data)
5328
5329 self.assertEqual(2, len(fents))
5330
5331 # Check that the FIP entry is updated
5332 fent = fents[1]
5333 self.assertEqual(0x8c, fent.offset)
5334 self.assertEqual(len(expected), fent.size)
5335 self.assertEqual(0, fent.flags)
5336 self.assertEqual(expected, fent.data)
5337 self.assertEqual(True, fent.valid)
5338
5339 def testFipMissing(self):
5340 with test_util.capture_sys_output() as (stdout, stderr):
5341 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5342 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005343 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005344
5345 def testFipSize(self):
5346 """Test a FIP with a size property"""
5347 data = self._DoReadFile('210_fip_size.dts')
5348 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5349 hdr, fents = fip_util.decode_fip(data)
5350 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5351 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5352
5353 self.assertEqual(1, len(fents))
5354
5355 fent = fents[0]
5356 self.assertEqual('soc-fw', fent.fip_type)
5357 self.assertEqual(0x60, fent.offset)
5358 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5359 self.assertEqual(ATF_BL31_DATA, fent.data)
5360 self.assertEqual(True, fent.valid)
5361
5362 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005363 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005364
5365 def testFipBadAlign(self):
5366 """Test that an invalid alignment value in a FIP is detected"""
5367 with self.assertRaises(ValueError) as e:
5368 self._DoTestFile('211_fip_bad_align.dts')
5369 self.assertIn(
5370 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5371 str(e.exception))
5372
5373 def testFipCollection(self):
5374 """Test using a FIP in a collection"""
5375 data = self._DoReadFile('212_fip_collection.dts')
5376 entry1 = control.images['image'].GetEntries()['collection']
5377 data1 = data[:entry1.size]
5378 hdr1, fents2 = fip_util.decode_fip(data1)
5379
5380 entry2 = control.images['image'].GetEntries()['atf-fip']
5381 data2 = data[entry2.offset:entry2.offset + entry2.size]
5382 hdr1, fents2 = fip_util.decode_fip(data2)
5383
5384 # The 'collection' entry should have U-Boot included at the end
5385 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5386 self.assertEqual(data1, data2 + U_BOOT_DATA)
5387 self.assertEqual(U_BOOT_DATA, data1[-4:])
5388
5389 # There should be a U-Boot after the final FIP
5390 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005391
Simon Glassccae6862022-01-12 13:10:35 -07005392 def testFakeBlob(self):
5393 """Test handling of faking an external blob"""
5394 with test_util.capture_sys_output() as (stdout, stderr):
5395 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5396 allow_fake_blobs=True)
5397 err = stderr.getvalue()
5398 self.assertRegex(
5399 err,
5400 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005401
Simon Glassceb5f912022-01-09 20:13:46 -07005402 def testExtblobListFaked(self):
5403 """Test an extblob with missing external blob that are faked"""
5404 with test_util.capture_sys_output() as (stdout, stderr):
5405 self._DoTestFile('216_blob_ext_list_missing.dts',
5406 allow_fake_blobs=True)
5407 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005408 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005409
Simon Glass162017b2022-01-09 20:13:57 -07005410 def testListBintools(self):
5411 args = ['tool', '--list']
5412 with test_util.capture_sys_output() as (stdout, _):
5413 self._DoBinman(*args)
5414 out = stdout.getvalue().splitlines()
5415 self.assertTrue(len(out) >= 2)
5416
5417 def testFetchBintools(self):
5418 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005419 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005420 raise urllib.error.URLError('my error')
5421
5422 args = ['tool']
5423 with self.assertRaises(ValueError) as e:
5424 self._DoBinman(*args)
5425 self.assertIn("Invalid arguments to 'tool' subcommand",
5426 str(e.exception))
5427
5428 args = ['tool', '--fetch']
5429 with self.assertRaises(ValueError) as e:
5430 self._DoBinman(*args)
5431 self.assertIn('Please specify bintools to fetch', str(e.exception))
5432
5433 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005434 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005435 side_effect=fail_download):
5436 with test_util.capture_sys_output() as (stdout, _):
5437 self._DoBinman(*args)
5438 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5439
Simon Glass620c4462022-01-09 20:14:11 -07005440 def testBintoolDocs(self):
5441 """Test for creation of bintool documentation"""
5442 with test_util.capture_sys_output() as (stdout, stderr):
5443 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5444 self.assertTrue(len(stdout.getvalue()) > 0)
5445
5446 def testBintoolDocsMissing(self):
5447 """Test handling of missing bintool documentation"""
5448 with self.assertRaises(ValueError) as e:
5449 with test_util.capture_sys_output() as (stdout, stderr):
5450 control.write_bintool_docs(
5451 control.bintool.Bintool.get_tool_list(), 'mkimage')
5452 self.assertIn('Documentation is missing for modules: mkimage',
5453 str(e.exception))
5454
Jan Kiszka58c407f2022-01-28 20:37:53 +01005455 def testListWithGenNode(self):
5456 """Check handling of an FDT map when the section cannot be found"""
5457 entry_args = {
5458 'of-list': 'test-fdt1 test-fdt2',
5459 }
5460 data = self._DoReadFileDtb(
5461 '219_fit_gennode.dts',
5462 entry_args=entry_args,
5463 use_real_dtb=True,
5464 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5465
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005466 tmpdir = None
Jan Kiszka58c407f2022-01-28 20:37:53 +01005467 try:
5468 tmpdir, updated_fname = self._SetupImageInTmpdir()
5469 with test_util.capture_sys_output() as (stdout, stderr):
5470 self._RunBinman('ls', '-i', updated_fname)
5471 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005472 if tmpdir:
5473 shutil.rmtree(tmpdir)
Jan Kiszka58c407f2022-01-28 20:37:53 +01005474
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005475 def testFitSubentryUsesBintool(self):
5476 """Test that binman FIT subentries can use bintools"""
5477 command.test_result = self._HandleGbbCommand
5478 entry_args = {
5479 'keydir': 'devkeys',
5480 'bmpblk': 'bmpblk.bin',
5481 }
5482 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5483 entry_args=entry_args)
5484
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005485 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5486 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005487 self.assertIn(expected, data)
5488
5489 def testFitSubentryMissingBintool(self):
5490 """Test that binman reports missing bintools for FIT subentries"""
5491 entry_args = {
5492 'keydir': 'devkeys',
5493 }
5494 with test_util.capture_sys_output() as (_, stderr):
5495 self._DoTestFile('220_fit_subentry_bintool.dts',
5496 force_missing_bintools='futility', entry_args=entry_args)
5497 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005498 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005499
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005500 def testFitSubentryHashSubnode(self):
5501 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005502 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005503 data, _, _, out_dtb_name = self._DoReadFileDtb(
5504 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5505
5506 mkimage_dtb = fdt.Fdt.FromData(data)
5507 mkimage_dtb.Scan()
5508 binman_dtb = fdt.Fdt(out_dtb_name)
5509 binman_dtb.Scan()
5510
5511 # Check that binman didn't add hash values
5512 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5513 self.assertNotIn('value', fnode.props)
5514
5515 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5516 self.assertNotIn('value', fnode.props)
5517
5518 # Check that mkimage added hash values
5519 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5520 self.assertIn('value', fnode.props)
5521
5522 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5523 self.assertIn('value', fnode.props)
5524
Roger Quadros5cdcea02022-02-19 20:50:04 +02005525 def testPackTeeOs(self):
5526 """Test that an image with an TEE binary can be created"""
5527 data = self._DoReadFile('222_tee_os.dts')
5528 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5529
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305530 def testPackTiDm(self):
5531 """Test that an image with a TI DM binary can be created"""
5532 data = self._DoReadFile('225_ti_dm.dts')
5533 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5534
Simon Glass912339f2022-02-08 11:50:03 -07005535 def testFitFdtOper(self):
5536 """Check handling of a specified FIT operation"""
5537 entry_args = {
5538 'of-list': 'test-fdt1 test-fdt2',
5539 'default-dt': 'test-fdt2',
5540 }
5541 self._DoReadFileDtb(
5542 '223_fit_fdt_oper.dts',
5543 entry_args=entry_args,
5544 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5545
5546 def testFitFdtBadOper(self):
5547 """Check handling of an FDT map when the section cannot be found"""
5548 with self.assertRaises(ValueError) as exc:
5549 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005550 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005551 str(exc.exception))
5552
Simon Glassdd156a42022-03-05 20:18:59 -07005553 def test_uses_expand_size(self):
5554 """Test that the 'expand-size' property cannot be used anymore"""
5555 with self.assertRaises(ValueError) as e:
5556 data = self._DoReadFile('225_expand_size_bad.dts')
5557 self.assertIn(
5558 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5559 str(e.exception))
5560
Simon Glass5f423422022-03-05 20:19:12 -07005561 def testFitSplitElf(self):
5562 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005563 if not elf.ELF_TOOLS:
5564 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005565 entry_args = {
5566 'of-list': 'test-fdt1 test-fdt2',
5567 'default-dt': 'test-fdt2',
5568 'atf-bl31-path': 'bl31.elf',
5569 'tee-os-path': 'tee.elf',
5570 }
5571 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5572 data = self._DoReadFileDtb(
5573 '226_fit_split_elf.dts',
5574 entry_args=entry_args,
5575 extra_indirs=[test_subdir])[0]
5576
5577 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5578 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5579
5580 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5581 'data', 'load'}
5582 dtb = fdt.Fdt.FromData(fit_data)
5583 dtb.Scan()
5584
5585 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5586 segments, entry = elf.read_loadable_segments(elf_data)
5587
5588 # We assume there are two segments
Brandon Maiera657bc62024-06-04 16:16:05 +00005589 self.assertEqual(2, len(segments))
Simon Glass5f423422022-03-05 20:19:12 -07005590
5591 atf1 = dtb.GetNode('/images/atf-1')
5592 _, start, data = segments[0]
5593 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5594 self.assertEqual(entry,
5595 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5596 self.assertEqual(start,
5597 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5598 self.assertEqual(data, atf1.props['data'].bytes)
5599
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005600 hash_node = atf1.FindNode('hash')
5601 self.assertIsNotNone(hash_node)
5602 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5603
Simon Glass5f423422022-03-05 20:19:12 -07005604 atf2 = dtb.GetNode('/images/atf-2')
5605 self.assertEqual(base_keys, atf2.props.keys())
5606 _, start, data = segments[1]
5607 self.assertEqual(start,
5608 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5609 self.assertEqual(data, atf2.props['data'].bytes)
5610
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005611 hash_node = atf2.FindNode('hash')
5612 self.assertIsNotNone(hash_node)
5613 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5614
5615 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5616 self.assertIsNotNone(hash_node)
5617 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5618
Simon Glass5f423422022-03-05 20:19:12 -07005619 conf = dtb.GetNode('/configurations')
5620 self.assertEqual({'default'}, conf.props.keys())
5621
5622 for subnode in conf.subnodes:
5623 self.assertEqual({'description', 'fdt', 'loadables'},
5624 subnode.props.keys())
5625 self.assertEqual(
5626 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5627 fdt_util.GetStringList(subnode, 'loadables'))
5628
5629 def _check_bad_fit(self, dts):
5630 """Check a bad FIT
5631
5632 This runs with the given dts and returns the assertion raised
5633
5634 Args:
5635 dts (str): dts filename to use
5636
5637 Returns:
5638 str: Assertion string raised
5639 """
5640 entry_args = {
5641 'of-list': 'test-fdt1 test-fdt2',
5642 'default-dt': 'test-fdt2',
5643 'atf-bl31-path': 'bl31.elf',
5644 'tee-os-path': 'tee.elf',
5645 }
5646 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5647 with self.assertRaises(ValueError) as exc:
5648 self._DoReadFileDtb(dts, entry_args=entry_args,
5649 extra_indirs=[test_subdir])[0]
5650 return str(exc.exception)
5651
5652 def testFitSplitElfBadElf(self):
5653 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005654 if not elf.ELF_TOOLS:
5655 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005656 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5657 entry_args = {
5658 'of-list': 'test-fdt1 test-fdt2',
5659 'default-dt': 'test-fdt2',
5660 'atf-bl31-path': 'bad.elf',
5661 'tee-os-path': 'tee.elf',
5662 }
5663 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5664 with self.assertRaises(ValueError) as exc:
5665 self._DoReadFileDtb(
5666 '226_fit_split_elf.dts',
5667 entry_args=entry_args,
5668 extra_indirs=[test_subdir])[0]
5669 self.assertIn(
5670 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5671 str(exc.exception))
5672
Simon Glass5f423422022-03-05 20:19:12 -07005673 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005674 """Test an split-elf FIT with a missing ELF file
5675
5676 Args:
5677 kwargs (dict of str): Arguments to pass to _DoTestFile()
5678
5679 Returns:
5680 tuple:
5681 str: stdout result
5682 str: stderr result
5683 """
Simon Glass5f423422022-03-05 20:19:12 -07005684 entry_args = {
5685 'of-list': 'test-fdt1 test-fdt2',
5686 'default-dt': 'test-fdt2',
5687 'atf-bl31-path': 'bl31.elf',
5688 'tee-os-path': 'missing.elf',
5689 }
5690 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5691 with test_util.capture_sys_output() as (stdout, stderr):
5692 self._DoTestFile(
5693 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005694 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5695 out = stdout.getvalue()
5696 err = stderr.getvalue()
5697 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005698
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005699 def testFitSplitElfBadDirective(self):
5700 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5701 if not elf.ELF_TOOLS:
5702 self.skipTest('Python elftools not available')
5703 err = self._check_bad_fit('227_fit_bad_dir.dts')
5704 self.assertIn(
5705 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5706 err)
5707
5708 def testFitSplitElfBadDirectiveConfig(self):
5709 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5710 if not elf.ELF_TOOLS:
5711 self.skipTest('Python elftools not available')
5712 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5713 self.assertEqual(
5714 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5715 err)
5716
5717
Simon Glass5f423422022-03-05 20:19:12 -07005718 def testFitSplitElfMissing(self):
5719 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005720 if not elf.ELF_TOOLS:
5721 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005722 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005723 self.assertRegex(
5724 err,
5725 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005726 self.assertNotRegex(out, '.*Faked blob.*')
5727 fname = tools.get_output_filename('binman-fake/missing.elf')
5728 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005729
5730 def testFitSplitElfFaked(self):
5731 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005732 if not elf.ELF_TOOLS:
5733 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005734 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005735 self.assertRegex(
5736 err,
5737 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005738 self.assertRegex(
5739 out,
5740 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5741 fname = tools.get_output_filename('binman-fake/missing.elf')
5742 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005743
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005744 def testMkimageMissingBlob(self):
5745 """Test using mkimage to build an image"""
5746 with test_util.capture_sys_output() as (stdout, stderr):
5747 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5748 allow_fake_blobs=True)
5749 err = stderr.getvalue()
5750 self.assertRegex(
5751 err,
5752 "Image '.*' has faked external blobs and is non-functional: .*")
5753
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005754 def testPreLoad(self):
5755 """Test an image with a pre-load header"""
5756 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005757 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005758 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005759 data = self._DoReadFileDtb(
5760 '230_pre_load.dts', entry_args=entry_args,
5761 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005762 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5763 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5764 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Simon Glasse2dfb962023-07-24 09:19:57 -06005765
5766 def testPreLoadNoKey(self):
5767 """Test an image with a pre-load heade0r with missing key"""
5768 with self.assertRaises(FileNotFoundError) as exc:
5769 self._DoReadFile('230_pre_load.dts')
5770 self.assertIn("No such file or directory: 'dev.key'",
5771 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005772
5773 def testPreLoadPkcs(self):
5774 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005775 entry_args = {
5776 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5777 }
5778 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5779 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005780 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5781 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5782 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5783
5784 def testPreLoadPss(self):
5785 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005786 entry_args = {
5787 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5788 }
5789 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5790 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005791 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5792 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5793 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5794
5795 def testPreLoadInvalidPadding(self):
5796 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005797 entry_args = {
5798 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5799 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005800 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005801 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5802 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005803
5804 def testPreLoadInvalidSha(self):
5805 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005806 entry_args = {
5807 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5808 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005809 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005810 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5811 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005812
5813 def testPreLoadInvalidAlgo(self):
5814 """Test an image with a pre-load header with an invalid algo"""
5815 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005816 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005817
5818 def testPreLoadInvalidKey(self):
5819 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005820 entry_args = {
5821 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5822 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005823 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005824 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5825 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005826
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005827 def _CheckSafeUniqueNames(self, *images):
5828 """Check all entries of given images for unsafe unique names"""
5829 for image in images:
5830 entries = {}
5831 image._CollectEntries(entries, {}, image)
5832 for entry in entries.values():
5833 uniq = entry.GetUniqueName()
5834
5835 # Used as part of a filename, so must not be absolute paths.
5836 self.assertFalse(os.path.isabs(uniq))
5837
5838 def testSafeUniqueNames(self):
5839 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005840 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005841
5842 orig_image = control.images['image']
5843 image_fname = tools.get_output_filename('image.bin')
5844 image = Image.FromFile(image_fname)
5845
5846 self._CheckSafeUniqueNames(orig_image, image)
5847
5848 def testSafeUniqueNamesMulti(self):
5849 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005850 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005851
5852 orig_image = control.images['image']
5853 image_fname = tools.get_output_filename('image.bin')
5854 image = Image.FromFile(image_fname)
5855
5856 self._CheckSafeUniqueNames(orig_image, image)
5857
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005858 def testReplaceCmdWithBintool(self):
5859 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005860 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005861 expected = U_BOOT_DATA + b'aa'
5862 self.assertEqual(expected, data[:len(expected)])
5863
5864 try:
5865 tmpdir, updated_fname = self._SetupImageInTmpdir()
5866 fname = os.path.join(tmpdir, 'update-testing.bin')
5867 tools.write_file(fname, b'zz')
5868 self._DoBinman('replace', '-i', updated_fname,
5869 '_testing', '-f', fname)
5870
5871 data = tools.read_file(updated_fname)
5872 expected = U_BOOT_DATA + b'zz'
5873 self.assertEqual(expected, data[:len(expected)])
5874 finally:
5875 shutil.rmtree(tmpdir)
5876
5877 def testReplaceCmdOtherWithBintool(self):
5878 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005879 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005880 expected = U_BOOT_DATA + b'aa'
5881 self.assertEqual(expected, data[:len(expected)])
5882
5883 try:
5884 tmpdir, updated_fname = self._SetupImageInTmpdir()
5885 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5886 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5887 self._DoBinman('replace', '-i', updated_fname,
5888 'u-boot', '-f', fname)
5889
5890 data = tools.read_file(updated_fname)
5891 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5892 self.assertEqual(expected, data[:len(expected)])
5893 finally:
5894 shutil.rmtree(tmpdir)
5895
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005896 def testReplaceResizeNoRepackSameSize(self):
5897 """Test replacing entries with same-size data without repacking"""
5898 expected = b'x' * len(U_BOOT_DATA)
5899 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5900 self.assertEqual(expected, data)
5901
5902 path, fdtmap = state.GetFdtContents('fdtmap')
5903 self.assertIsNotNone(path)
5904 self.assertEqual(expected_fdtmap, fdtmap)
5905
5906 def testReplaceResizeNoRepackSmallerSize(self):
5907 """Test replacing entries with smaller-size data without repacking"""
5908 new_data = b'x'
5909 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5910 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5911 self.assertEqual(expected, data)
5912
5913 path, fdtmap = state.GetFdtContents('fdtmap')
5914 self.assertIsNotNone(path)
5915 self.assertEqual(expected_fdtmap, fdtmap)
5916
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005917 def testExtractFit(self):
5918 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005919 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005920 image_fname = tools.get_output_filename('image.bin')
5921
5922 fit_data = control.ReadEntry(image_fname, 'fit')
5923 fit = fdt.Fdt.FromData(fit_data)
5924 fit.Scan()
5925
5926 # Check subentry data inside the extracted fit
5927 for node_path, expected in [
5928 ('/images/kernel', U_BOOT_DATA),
5929 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5930 ('/images/scr-1', COMPRESS_DATA),
5931 ]:
5932 node = fit.GetNode(node_path)
5933 data = fit.GetProps(node)['data'].bytes
5934 self.assertEqual(expected, data)
5935
5936 def testExtractFitSubentries(self):
5937 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005938 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005939 image_fname = tools.get_output_filename('image.bin')
5940
5941 for entry_path, expected in [
5942 ('fit/kernel', U_BOOT_DATA),
5943 ('fit/kernel/u-boot', U_BOOT_DATA),
5944 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5945 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5946 ('fit/scr-1', COMPRESS_DATA),
5947 ('fit/scr-1/blob', COMPRESS_DATA),
5948 ]:
5949 data = control.ReadEntry(image_fname, entry_path)
5950 self.assertEqual(expected, data)
5951
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005952 def testReplaceFitSubentryLeafSameSize(self):
5953 """Test replacing a FIT leaf subentry with same-size data"""
5954 new_data = b'x' * len(U_BOOT_DATA)
5955 data, expected_fdtmap, _ = self._RunReplaceCmd(
5956 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005957 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005958 self.assertEqual(new_data, data)
5959
5960 path, fdtmap = state.GetFdtContents('fdtmap')
5961 self.assertIsNotNone(path)
5962 self.assertEqual(expected_fdtmap, fdtmap)
5963
5964 def testReplaceFitSubentryLeafBiggerSize(self):
5965 """Test replacing a FIT leaf subentry with bigger-size data"""
5966 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5967 data, expected_fdtmap, _ = self._RunReplaceCmd(
5968 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005969 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005970 self.assertEqual(new_data, data)
5971
5972 # Will be repacked, so fdtmap must change
5973 path, fdtmap = state.GetFdtContents('fdtmap')
5974 self.assertIsNotNone(path)
5975 self.assertNotEqual(expected_fdtmap, fdtmap)
5976
5977 def testReplaceFitSubentryLeafSmallerSize(self):
5978 """Test replacing a FIT leaf subentry with smaller-size data"""
5979 new_data = b'x'
5980 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5981 data, expected_fdtmap, _ = self._RunReplaceCmd(
5982 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005983 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005984 self.assertEqual(expected, data)
5985
5986 path, fdtmap = state.GetFdtContents('fdtmap')
5987 self.assertIsNotNone(path)
5988 self.assertEqual(expected_fdtmap, fdtmap)
5989
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005990 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005991 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005992 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005993 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5994 new_data, dts='241_replace_section_simple.dts')
5995 self.assertEqual(new_data, data)
5996
5997 entries = image.GetEntries()
5998 self.assertIn('section', entries)
5999 entry = entries['section']
6000 self.assertEqual(len(new_data), entry.size)
6001
6002 def testReplaceSectionLarger(self):
6003 """Test replacing a simple section with larger data"""
6004 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6005 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6006 new_data, dts='241_replace_section_simple.dts')
6007 self.assertEqual(new_data, data)
6008
6009 entries = image.GetEntries()
6010 self.assertIn('section', entries)
6011 entry = entries['section']
6012 self.assertEqual(len(new_data), entry.size)
6013 fentry = entries['fdtmap']
6014 self.assertEqual(entry.offset + entry.size, fentry.offset)
6015
6016 def testReplaceSectionSmaller(self):
6017 """Test replacing a simple section with smaller data"""
6018 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
6019 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6020 new_data, dts='241_replace_section_simple.dts')
6021 self.assertEqual(new_data, data)
6022
6023 # The new size is the same as the old, just with a pad byte at the end
6024 entries = image.GetEntries()
6025 self.assertIn('section', entries)
6026 entry = entries['section']
6027 self.assertEqual(len(new_data), entry.size)
6028
6029 def testReplaceSectionSmallerAllow(self):
6030 """Test failing to replace a simple section with smaller data"""
6031 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
6032 try:
6033 state.SetAllowEntryContraction(True)
6034 with self.assertRaises(ValueError) as exc:
6035 self._RunReplaceCmd('section', new_data,
6036 dts='241_replace_section_simple.dts')
6037 finally:
6038 state.SetAllowEntryContraction(False)
6039
6040 # Since we have no information about the position of things within the
6041 # section, we cannot adjust the position of /section-u-boot so it ends
6042 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06006043 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07006044 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
6045 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06006046 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006047
Simon Glass8fbca772022-08-13 11:40:48 -06006048 def testMkimageImagename(self):
6049 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006050 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006051 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06006052
6053 # Check that the data appears in the file somewhere
6054 self.assertIn(U_BOOT_SPL_DATA, data)
6055
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006056 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06006057 name = data[0x20:0x40]
6058
6059 # Build the filename that we expect to be placed in there, by virtue of
6060 # the -n paraameter
6061 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6062
6063 # Check that the image name is set to the temporary filename used
6064 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6065
Simon Glassb1669752022-08-13 11:40:49 -06006066 def testMkimageImage(self):
6067 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006068 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006069 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006070
6071 # Check that the data appears in the file somewhere
6072 self.assertIn(U_BOOT_SPL_DATA, data)
6073
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006074 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006075 name = data[0x20:0x40]
6076
6077 # Build the filename that we expect to be placed in there, by virtue of
6078 # the -n paraameter
6079 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6080
6081 # Check that the image name is set to the temporary filename used
6082 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6083
6084 # Check the corect data is in the imagename file
6085 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6086
6087 def testMkimageImageNoContent(self):
6088 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006089 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006090 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006091 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006092 self.assertIn('Could not complete processing of contents',
6093 str(exc.exception))
6094
6095 def testMkimageImageBad(self):
6096 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006097 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006098 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006099 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006100 self.assertIn('Cannot use both imagename node and data-to-imagename',
6101 str(exc.exception))
6102
Simon Glassbd5cd882022-08-13 11:40:50 -06006103 def testCollectionOther(self):
6104 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006105 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006106 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6107 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6108 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6109 data)
6110
6111 def testMkimageCollection(self):
6112 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006113 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006114 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006115 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6116 self.assertEqual(expect, data[:len(expect)])
6117
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006118 def testCompressDtbPrependInvalid(self):
6119 """Test that invalid header is detected"""
6120 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006121 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006122 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6123 "'u-boot-dtb': 'invalid'", str(e.exception))
6124
6125 def testCompressDtbPrependLength(self):
6126 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006127 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006128 image = control.images['image']
6129 entries = image.GetEntries()
6130 self.assertIn('u-boot-dtb', entries)
6131 u_boot_dtb = entries['u-boot-dtb']
6132 self.assertIn('fdtmap', entries)
6133 fdtmap = entries['fdtmap']
6134
6135 image_fname = tools.get_output_filename('image.bin')
6136 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6137 dtb = fdt.Fdt.FromData(orig)
6138 dtb.Scan()
6139 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6140 expected = {
6141 'u-boot:size': len(U_BOOT_DATA),
6142 'u-boot-dtb:uncomp-size': len(orig),
6143 'u-boot-dtb:size': u_boot_dtb.size,
6144 'fdtmap:size': fdtmap.size,
6145 'size': len(data),
6146 }
6147 self.assertEqual(expected, props)
6148
6149 # Check implementation
6150 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6151 rest = data[len(U_BOOT_DATA):]
6152 comp_data_len = struct.unpack('<I', rest[:4])[0]
6153 comp_data = rest[4:4 + comp_data_len]
6154 orig2 = self._decompress(comp_data)
6155 self.assertEqual(orig, orig2)
6156
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006157 def testInvalidCompress(self):
6158 """Test that invalid compress algorithm is detected"""
6159 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006160 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006161 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6162
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006163 def testCompUtilCompressions(self):
6164 """Test compression algorithms"""
6165 for bintool in self.comp_bintools.values():
6166 self._CheckBintool(bintool)
6167 data = bintool.compress(COMPRESS_DATA)
6168 self.assertNotEqual(COMPRESS_DATA, data)
6169 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006170 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006171
6172 def testCompUtilVersions(self):
6173 """Test tool version of compression algorithms"""
6174 for bintool in self.comp_bintools.values():
6175 self._CheckBintool(bintool)
6176 version = bintool.version()
6177 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6178
6179 def testCompUtilPadding(self):
6180 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006181 # Skip zstd because it doesn't support padding
6182 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006183 self._CheckBintool(bintool)
6184 data = bintool.compress(COMPRESS_DATA)
6185 self.assertNotEqual(COMPRESS_DATA, data)
6186 data += tools.get_bytes(0, 64)
6187 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006188 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006189
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006190 def testCompressDtbZstd(self):
6191 """Test that zstd compress of device-tree files failed"""
6192 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006193 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006194 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6195 "requires a length header", str(e.exception))
6196
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006197 def testMkimageMultipleDataFiles(self):
6198 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006199 self._SetupSplElf()
6200 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006201 data = self._DoReadFile('252_mkimage_mult_data.dts')
6202 # Size of files are packed in their 4B big-endian format
6203 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6204 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6205 # Size info is always followed by a 4B zero value.
6206 expect += tools.get_bytes(0, 4)
6207 expect += U_BOOT_TPL_DATA
6208 # All but last files are 4B-aligned
6209 align_pad = len(U_BOOT_TPL_DATA) % 4
6210 if align_pad:
6211 expect += tools.get_bytes(0, align_pad)
6212 expect += U_BOOT_SPL_DATA
6213 self.assertEqual(expect, data[-len(expect):])
6214
Marek Vasutf7413f02023-07-18 07:23:58 -06006215 def testMkimageMultipleExpanded(self):
6216 """Test passing multiple files to mkimage in a mkimage entry"""
6217 self._SetupSplElf()
6218 self._SetupTplElf()
6219 entry_args = {
6220 'spl-bss-pad': 'y',
6221 'spl-dtb': 'y',
6222 }
6223 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6224 use_expanded=True, entry_args=entry_args)[0]
6225 pad_len = 10
6226 tpl_expect = U_BOOT_TPL_DATA
6227 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6228 spl_expect += U_BOOT_SPL_DTB_DATA
6229
6230 content = data[0x40:]
6231 lens = struct.unpack('>III', content[:12])
6232
6233 # Size of files are packed in their 4B big-endian format
6234 # Size info is always followed by a 4B zero value.
6235 self.assertEqual(len(tpl_expect), lens[0])
6236 self.assertEqual(len(spl_expect), lens[1])
6237 self.assertEqual(0, lens[2])
6238
6239 rest = content[12:]
6240 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6241
6242 rest = rest[len(tpl_expect):]
6243 align_pad = len(tpl_expect) % 4
6244 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6245 rest = rest[align_pad:]
6246 self.assertEqual(spl_expect, rest)
6247
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006248 def testMkimageMultipleNoContent(self):
6249 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006250 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006251 with self.assertRaises(ValueError) as exc:
6252 self._DoReadFile('253_mkimage_mult_no_content.dts')
6253 self.assertIn('Could not complete processing of contents',
6254 str(exc.exception))
6255
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006256 def testMkimageFilename(self):
6257 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006258 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006259 retcode = self._DoTestFile('254_mkimage_filename.dts')
6260 self.assertEqual(0, retcode)
6261 fname = tools.get_output_filename('mkimage-test.bin')
6262 self.assertTrue(os.path.exists(fname))
6263
Simon Glass56d05412022-02-28 07:16:54 -07006264 def testVpl(self):
6265 """Test that an image with VPL and its device tree can be created"""
6266 # ELF file with a '__bss_size' symbol
6267 self._SetupVplElf()
6268 data = self._DoReadFile('255_u_boot_vpl.dts')
6269 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6270
6271 def testVplNoDtb(self):
6272 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6273 self._SetupVplElf()
6274 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6275 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6276 data[:len(U_BOOT_VPL_NODTB_DATA)])
6277
6278 def testExpandedVpl(self):
6279 """Test that an expanded entry type is selected for TPL when needed"""
6280 self._SetupVplElf()
6281
6282 entry_args = {
6283 'vpl-bss-pad': 'y',
6284 'vpl-dtb': 'y',
6285 }
6286 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6287 entry_args=entry_args)
6288 image = control.images['image']
6289 entries = image.GetEntries()
6290 self.assertEqual(1, len(entries))
6291
6292 # We only have u-boot-vpl, which be expanded
6293 self.assertIn('u-boot-vpl', entries)
6294 entry = entries['u-boot-vpl']
6295 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6296 subent = entry.GetEntries()
6297 self.assertEqual(3, len(subent))
6298 self.assertIn('u-boot-vpl-nodtb', subent)
6299 self.assertIn('u-boot-vpl-bss-pad', subent)
6300 self.assertIn('u-boot-vpl-dtb', subent)
6301
6302 def testVplBssPadMissing(self):
6303 """Test that a missing symbol is detected"""
6304 self._SetupVplElf('u_boot_ucode_ptr')
6305 with self.assertRaises(ValueError) as e:
6306 self._DoReadFile('258_vpl_bss_pad.dts')
6307 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6308 str(e.exception))
6309
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306310 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306311 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306312 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6313 self.assertEqual(0, retcode)
6314 image = control.images['test_image']
6315 fname = tools.get_output_filename('test_image.bin')
6316 sname = tools.get_output_filename('symlink_to_test.bin')
6317 self.assertTrue(os.path.islink(sname))
6318 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006319
Andrew Davis6b463da2023-07-22 00:14:44 +05306320 def testSymlinkOverwrite(self):
6321 """Test that symlinked images can be overwritten"""
6322 testdir = TestFunctional._MakeInputDir('symlinktest')
6323 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6324 # build the same image again in the same directory so that existing symlink is present
6325 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6326 fname = tools.get_output_filename('test_image.bin')
6327 sname = tools.get_output_filename('symlink_to_test.bin')
6328 self.assertTrue(os.path.islink(sname))
6329 self.assertEqual(os.readlink(sname), fname)
6330
Simon Glass37f85de2022-10-20 18:22:47 -06006331 def testSymbolsElf(self):
6332 """Test binman can assign symbols embedded in an ELF file"""
6333 if not elf.ELF_TOOLS:
6334 self.skipTest('Python elftools not available')
6335 self._SetupTplElf('u_boot_binman_syms')
6336 self._SetupVplElf('u_boot_binman_syms')
6337 self._SetupSplElf('u_boot_binman_syms')
6338 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6339 image_fname = tools.get_output_filename('image.bin')
6340
6341 image = control.images['image']
6342 entries = image.GetEntries()
6343
6344 for entry in entries.values():
6345 # No symbols in u-boot and it has faked contents anyway
6346 if entry.name == 'u-boot':
6347 continue
6348 edata = data[entry.image_pos:entry.image_pos + entry.size]
6349 efname = tools.get_output_filename(f'edata-{entry.name}')
6350 tools.write_file(efname, edata)
6351
6352 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6353 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6354 for name, sym in syms.items():
6355 msg = 'test'
6356 val = elf.GetSymbolValue(sym, edata, msg)
6357 entry_m = re_name.match(name)
6358 if entry_m:
6359 ename, prop = entry_m.group(1), entry_m.group(3)
6360 entry, entry_name, prop_name = image.LookupEntry(entries,
6361 name, msg)
6362 if prop_name == 'offset':
6363 expect_val = entry.offset
6364 elif prop_name == 'image_pos':
6365 expect_val = entry.image_pos
6366 elif prop_name == 'size':
6367 expect_val = entry.size
6368 self.assertEqual(expect_val, val)
6369
6370 def testSymbolsElfBad(self):
6371 """Check error when trying to write symbols without the elftools lib"""
6372 if not elf.ELF_TOOLS:
6373 self.skipTest('Python elftools not available')
6374 self._SetupTplElf('u_boot_binman_syms')
6375 self._SetupVplElf('u_boot_binman_syms')
6376 self._SetupSplElf('u_boot_binman_syms')
6377 try:
6378 elf.ELF_TOOLS = False
6379 with self.assertRaises(ValueError) as exc:
6380 self._DoReadFileDtb('260_symbols_elf.dts')
6381 finally:
6382 elf.ELF_TOOLS = True
6383 self.assertIn(
6384 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6385 'Cannot write symbols to an ELF file without Python elftools',
6386 str(exc.exception))
6387
Simon Glassde244162023-01-07 14:07:08 -07006388 def testSectionFilename(self):
6389 """Check writing of section contents to a file"""
6390 data = self._DoReadFile('261_section_fname.dts')
6391 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6392 tools.get_bytes(ord('!'), 7) +
6393 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6394 self.assertEqual(expected, data)
6395
6396 sect_fname = tools.get_output_filename('outfile.bin')
6397 self.assertTrue(os.path.exists(sect_fname))
6398 sect_data = tools.read_file(sect_fname)
6399 self.assertEqual(U_BOOT_DATA, sect_data)
6400
Simon Glass1e9e61c2023-01-07 14:07:12 -07006401 def testAbsent(self):
6402 """Check handling of absent entries"""
6403 data = self._DoReadFile('262_absent.dts')
6404 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6405
Simon Glassad5cfe12023-01-07 14:07:14 -07006406 def testPackTeeOsOptional(self):
6407 """Test that an image with an optional TEE binary can be created"""
6408 entry_args = {
6409 'tee-os-path': 'tee.elf',
6410 }
6411 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6412 entry_args=entry_args)[0]
6413 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6414
6415 def checkFitTee(self, dts, tee_fname):
6416 """Check that a tee-os entry works and returns data
6417
6418 Args:
6419 dts (str): Device tree filename to use
6420 tee_fname (str): filename containing tee-os
6421
6422 Returns:
6423 bytes: Image contents
6424 """
6425 if not elf.ELF_TOOLS:
6426 self.skipTest('Python elftools not available')
6427 entry_args = {
6428 'of-list': 'test-fdt1 test-fdt2',
6429 'default-dt': 'test-fdt2',
6430 'tee-os-path': tee_fname,
6431 }
6432 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6433 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6434 extra_indirs=[test_subdir])[0]
6435 return data
6436
6437 def testFitTeeOsOptionalFit(self):
6438 """Test an image with a FIT with an optional OP-TEE binary"""
6439 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6440
6441 # There should be only one node, holding the data set up in SetUpClass()
6442 # for tee.bin
6443 dtb = fdt.Fdt.FromData(data)
6444 dtb.Scan()
6445 node = dtb.GetNode('/images/tee-1')
6446 self.assertEqual(TEE_ADDR,
6447 fdt_util.fdt32_to_cpu(node.props['load'].value))
6448 self.assertEqual(TEE_ADDR,
6449 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6450 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6451
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006452 with test_util.capture_sys_output() as (stdout, stderr):
6453 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6454 err = stderr.getvalue()
6455 self.assertRegex(
6456 err,
6457 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6458
Simon Glassad5cfe12023-01-07 14:07:14 -07006459 def testFitTeeOsOptionalFitBad(self):
6460 """Test an image with a FIT with an optional OP-TEE binary"""
6461 with self.assertRaises(ValueError) as exc:
6462 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6463 self.assertIn(
6464 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6465 str(exc.exception))
6466
6467 def testFitTeeOsBad(self):
6468 """Test an OP-TEE binary with wrong formats"""
6469 self.make_tee_bin('tee.bad1', 123)
6470 with self.assertRaises(ValueError) as exc:
6471 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6472 self.assertIn(
6473 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6474 str(exc.exception))
6475
6476 self.make_tee_bin('tee.bad2', 0, b'extra data')
6477 with self.assertRaises(ValueError) as exc:
6478 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6479 self.assertIn(
6480 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6481 str(exc.exception))
6482
Simon Glass63328f12023-01-07 14:07:15 -07006483 def testExtblobOptional(self):
6484 """Test an image with an external blob that is optional"""
6485 with test_util.capture_sys_output() as (stdout, stderr):
6486 data = self._DoReadFile('266_blob_ext_opt.dts')
6487 self.assertEqual(REFCODE_DATA, data)
6488 err = stderr.getvalue()
6489 self.assertRegex(
6490 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006491 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006492
Simon Glass7447a9d2023-01-11 16:10:12 -07006493 def testSectionInner(self):
6494 """Test an inner section with a size"""
6495 data = self._DoReadFile('267_section_inner.dts')
6496 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6497 self.assertEqual(expected, data)
6498
Simon Glassa4948b22023-01-11 16:10:14 -07006499 def testNull(self):
6500 """Test an image with a null entry"""
6501 data = self._DoReadFile('268_null.dts')
6502 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6503
Simon Glassf1ee03b2023-01-11 16:10:16 -07006504 def testOverlap(self):
6505 """Test an image with a overlapping entry"""
6506 data = self._DoReadFile('269_overlap.dts')
6507 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6508
6509 image = control.images['image']
6510 entries = image.GetEntries()
6511
6512 self.assertIn('inset', entries)
6513 inset = entries['inset']
6514 self.assertEqual(1, inset.offset);
6515 self.assertEqual(1, inset.image_pos);
6516 self.assertEqual(2, inset.size);
6517
6518 def testOverlapNull(self):
6519 """Test an image with a null overlap"""
6520 data = self._DoReadFile('270_overlap_null.dts')
6521 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6522
6523 # Check the FMAP
6524 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6525 self.assertEqual(4, fhdr.nareas)
6526 fiter = iter(fentries)
6527
6528 fentry = next(fiter)
6529 self.assertEqual(b'SECTION', fentry.name)
6530 self.assertEqual(0, fentry.offset)
6531 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6532 self.assertEqual(0, fentry.flags)
6533
6534 fentry = next(fiter)
6535 self.assertEqual(b'U_BOOT', fentry.name)
6536 self.assertEqual(0, fentry.offset)
6537 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6538 self.assertEqual(0, fentry.flags)
6539
6540 # Make sure that the NULL entry appears in the FMAP
6541 fentry = next(fiter)
6542 self.assertEqual(b'NULL', fentry.name)
6543 self.assertEqual(1, fentry.offset)
6544 self.assertEqual(2, fentry.size)
6545 self.assertEqual(0, fentry.flags)
6546
6547 fentry = next(fiter)
6548 self.assertEqual(b'FMAP', fentry.name)
6549 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6550
6551 def testOverlapBad(self):
6552 """Test an image with a bad overlapping entry"""
6553 with self.assertRaises(ValueError) as exc:
6554 self._DoReadFile('271_overlap_bad.dts')
6555 self.assertIn(
6556 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6557 str(exc.exception))
6558
6559 def testOverlapNoOffset(self):
6560 """Test an image with a bad overlapping entry"""
6561 with self.assertRaises(ValueError) as exc:
6562 self._DoReadFile('272_overlap_no_size.dts')
6563 self.assertIn(
6564 "Node '/binman/inset': 'fill' entry is missing properties: size",
6565 str(exc.exception))
6566
Simon Glasse0035c92023-01-11 16:10:17 -07006567 def testBlobSymbol(self):
6568 """Test a blob with symbols read from an ELF file"""
6569 elf_fname = self.ElfTestFile('blob_syms')
6570 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6571 TestFunctional._MakeInputFile('blob_syms.bin',
6572 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6573
6574 data = self._DoReadFile('273_blob_symbol.dts')
6575
6576 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6577 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6578 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6579 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6580 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6581
6582 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6583 expected = sym_values
6584 self.assertEqual(expected, data[:len(expected)])
6585
Simon Glass49e9c002023-01-11 16:10:19 -07006586 def testOffsetFromElf(self):
6587 """Test a blob with symbols read from an ELF file"""
6588 elf_fname = self.ElfTestFile('blob_syms')
6589 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6590 TestFunctional._MakeInputFile('blob_syms.bin',
6591 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6592
6593 data = self._DoReadFile('274_offset_from_elf.dts')
6594
6595 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6596 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6597
6598 image = control.images['image']
6599 entries = image.GetEntries()
6600
6601 self.assertIn('inset', entries)
6602 inset = entries['inset']
6603
6604 self.assertEqual(base + 4, inset.offset);
6605 self.assertEqual(base + 4, inset.image_pos);
6606 self.assertEqual(4, inset.size);
6607
6608 self.assertIn('inset2', entries)
6609 inset = entries['inset2']
6610 self.assertEqual(base + 8, inset.offset);
6611 self.assertEqual(base + 8, inset.image_pos);
6612 self.assertEqual(4, inset.size);
6613
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006614 def testFitAlign(self):
6615 """Test an image with an FIT with aligned external data"""
6616 data = self._DoReadFile('275_fit_align.dts')
6617 self.assertEqual(4096, len(data))
6618
6619 dtb = fdt.Fdt.FromData(data)
6620 dtb.Scan()
6621
6622 props = self._GetPropTree(dtb, ['data-position'])
6623 expected = {
6624 'u-boot:data-position': 1024,
6625 'fdt-1:data-position': 2048,
6626 'fdt-2:data-position': 3072,
6627 }
6628 self.assertEqual(expected, props)
6629
Jonas Karlman490f73c2023-01-21 19:02:12 +00006630 def testFitFirmwareLoadables(self):
6631 """Test an image with an FIT that use fit,firmware"""
6632 if not elf.ELF_TOOLS:
6633 self.skipTest('Python elftools not available')
6634 entry_args = {
6635 'of-list': 'test-fdt1',
6636 'default-dt': 'test-fdt1',
6637 'atf-bl31-path': 'bl31.elf',
6638 'tee-os-path': 'missing.bin',
6639 }
6640 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006641 with test_util.capture_sys_output() as (stdout, stderr):
6642 data = self._DoReadFileDtb(
6643 '276_fit_firmware_loadables.dts',
6644 entry_args=entry_args,
6645 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006646
6647 dtb = fdt.Fdt.FromData(data)
6648 dtb.Scan()
6649
6650 node = dtb.GetNode('/configurations/conf-uboot-1')
6651 self.assertEqual('u-boot', node.props['firmware'].value)
6652 self.assertEqual(['atf-1', 'atf-2'],
6653 fdt_util.GetStringList(node, 'loadables'))
6654
6655 node = dtb.GetNode('/configurations/conf-atf-1')
6656 self.assertEqual('atf-1', node.props['firmware'].value)
6657 self.assertEqual(['u-boot', 'atf-2'],
6658 fdt_util.GetStringList(node, 'loadables'))
6659
6660 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6661 self.assertEqual('u-boot', node.props['firmware'].value)
6662 self.assertEqual(['atf-1', 'atf-2'],
6663 fdt_util.GetStringList(node, 'loadables'))
6664
6665 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6666 self.assertEqual('atf-1', node.props['firmware'].value)
6667 self.assertEqual(['u-boot', 'atf-2'],
6668 fdt_util.GetStringList(node, 'loadables'))
6669
6670 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6671 self.assertEqual('atf-1', node.props['firmware'].value)
6672 self.assertEqual(['u-boot', 'atf-2'],
6673 fdt_util.GetStringList(node, 'loadables'))
6674
Simon Glass9a1c7262023-02-22 12:14:49 -07006675 def testTooldir(self):
6676 """Test that we can specify the tooldir"""
6677 with test_util.capture_sys_output() as (stdout, stderr):
6678 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6679 'tool', '-l'))
6680 self.assertEqual('fred', bintool.Bintool.tooldir)
6681
6682 # Check that the toolpath is updated correctly
6683 self.assertEqual(['fred'], tools.tool_search_paths)
6684
6685 # Try with a few toolpaths; the tooldir should be at the end
6686 with test_util.capture_sys_output() as (stdout, stderr):
6687 self.assertEqual(0, self._DoBinman(
6688 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6689 'tool', '-l'))
6690 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6691
Simon Glass49b77e82023-03-02 17:02:44 -07006692 def testReplaceSectionEntry(self):
6693 """Test replacing an entry in a section"""
6694 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6695 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6696 expect_data, dts='241_replace_section_simple.dts')
6697 self.assertEqual(expect_data, entry_data)
6698
6699 entries = image.GetEntries()
6700 self.assertIn('section', entries)
6701 section = entries['section']
6702
6703 sect_entries = section.GetEntries()
6704 self.assertIn('blob', sect_entries)
6705 entry = sect_entries['blob']
6706 self.assertEqual(len(expect_data), entry.size)
6707
6708 fname = tools.get_output_filename('image-updated.bin')
6709 data = tools.read_file(fname)
6710
6711 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6712 self.assertEqual(expect_data, new_blob_data)
6713
6714 self.assertEqual(U_BOOT_DATA,
6715 data[entry.image_pos + len(expect_data):]
6716 [:len(U_BOOT_DATA)])
6717
6718 def testReplaceSectionDeep(self):
6719 """Test replacing an entry in two levels of sections"""
6720 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6721 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6722 'section/section/blob', expect_data,
6723 dts='278_replace_section_deep.dts')
6724 self.assertEqual(expect_data, entry_data)
6725
6726 entries = image.GetEntries()
6727 self.assertIn('section', entries)
6728 section = entries['section']
6729
6730 subentries = section.GetEntries()
6731 self.assertIn('section', subentries)
6732 section = subentries['section']
6733
6734 sect_entries = section.GetEntries()
6735 self.assertIn('blob', sect_entries)
6736 entry = sect_entries['blob']
6737 self.assertEqual(len(expect_data), entry.size)
6738
6739 fname = tools.get_output_filename('image-updated.bin')
6740 data = tools.read_file(fname)
6741
6742 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6743 self.assertEqual(expect_data, new_blob_data)
6744
6745 self.assertEqual(U_BOOT_DATA,
6746 data[entry.image_pos + len(expect_data):]
6747 [:len(U_BOOT_DATA)])
6748
6749 def testReplaceFitSibling(self):
6750 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006751 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006752 fname = TestFunctional._MakeInputFile('once', b'available once')
6753 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6754 os.remove(fname)
6755
6756 try:
6757 tmpdir, updated_fname = self._SetupImageInTmpdir()
6758
6759 fname = os.path.join(tmpdir, 'update-blob')
6760 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6761 tools.write_file(fname, expected)
6762
6763 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6764 data = tools.read_file(updated_fname)
6765 start = len(U_BOOT_DTB_DATA)
6766 self.assertEqual(expected, data[start:start + len(expected)])
6767 map_fname = os.path.join(tmpdir, 'image-updated.map')
6768 self.assertFalse(os.path.exists(map_fname))
6769 finally:
6770 shutil.rmtree(tmpdir)
6771
Simon Glassc3fe97f2023-03-02 17:02:45 -07006772 def testX509Cert(self):
6773 """Test creating an X509 certificate"""
6774 keyfile = self.TestFile('key.key')
6775 entry_args = {
6776 'keyfile': keyfile,
6777 }
6778 data = self._DoReadFileDtb('279_x509_cert.dts',
6779 entry_args=entry_args)[0]
6780 cert = data[:-4]
6781 self.assertEqual(U_BOOT_DATA, data[-4:])
6782
6783 # TODO: verify the signature
6784
6785 def testX509CertMissing(self):
6786 """Test that binman still produces an image if openssl is missing"""
6787 keyfile = self.TestFile('key.key')
6788 entry_args = {
6789 'keyfile': 'keyfile',
6790 }
6791 with test_util.capture_sys_output() as (_, stderr):
6792 self._DoTestFile('279_x509_cert.dts',
6793 force_missing_bintools='openssl',
6794 entry_args=entry_args)
6795 err = stderr.getvalue()
6796 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6797
Jonas Karlman35305492023-02-25 19:01:33 +00006798 def testPackRockchipTpl(self):
6799 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006800 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006801 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6802
Jonas Karlman1016ec72023-02-25 19:01:35 +00006803 def testMkimageMissingBlobMultiple(self):
6804 """Test missing blob with mkimage entry and multiple-data-files"""
6805 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006806 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006807 err = stderr.getvalue()
6808 self.assertIn("is missing external blobs and is non-functional", err)
6809
6810 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006811 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006812 self.assertIn("not found in input path", str(e.exception))
6813
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006814 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6815 """Prepare sign environment
6816
6817 Create private and public keys, add pubkey into dtb.
6818
6819 Returns:
6820 Tuple:
6821 FIT container
6822 Image name
6823 Private key
6824 DTB
6825 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006826 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006827 data = self._DoReadFileRealDtb(dts)
6828 updated_fname = tools.get_output_filename('image-updated.bin')
6829 tools.write_file(updated_fname, data)
6830 dtb = tools.get_output_filename('source.dtb')
6831 private_key = tools.get_output_filename('test_key.key')
6832 public_key = tools.get_output_filename('test_key.crt')
6833 fit = tools.get_output_filename('fit.fit')
6834 key_dir = tools.get_output_dir()
6835
6836 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6837 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6838 private_key, '-out', public_key)
6839 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6840 '-n', 'test_key', '-r', 'conf', dtb)
6841
6842 return fit, updated_fname, private_key, dtb
6843
6844 def testSignSimple(self):
6845 """Test that a FIT container can be signed in image"""
6846 is_signed = False
6847 fit, fname, private_key, dtb = self._PrepareSignEnv()
6848
6849 # do sign with private key
6850 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6851 ['fit'])
6852 is_signed = self._CheckSign(fit, dtb)
6853
6854 self.assertEqual(is_signed, True)
6855
6856 def testSignExactFIT(self):
6857 """Test that a FIT container can be signed and replaced in image"""
6858 is_signed = False
6859 fit, fname, private_key, dtb = self._PrepareSignEnv()
6860
6861 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6862 args = []
6863 if self.toolpath:
6864 for path in self.toolpath:
6865 args += ['--toolpath', path]
6866
6867 # do sign with private key
6868 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6869 'sha256,rsa4096', '-f', fit, 'fit')
6870 is_signed = self._CheckSign(fit, dtb)
6871
6872 self.assertEqual(is_signed, True)
6873
6874 def testSignNonFit(self):
6875 """Test a non-FIT entry cannot be signed"""
6876 is_signed = False
6877 fit, fname, private_key, _ = self._PrepareSignEnv(
6878 '281_sign_non_fit.dts')
6879
6880 # do sign with private key
6881 with self.assertRaises(ValueError) as e:
6882 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6883 'sha256,rsa4096', '-f', fit, 'u-boot')
6884 self.assertIn(
6885 "Node '/u-boot': Updating signatures is not supported with this entry type",
6886 str(e.exception))
6887
6888 def testSignMissingMkimage(self):
6889 """Test that FIT signing handles a missing mkimage tool"""
6890 fit, fname, private_key, _ = self._PrepareSignEnv()
6891
6892 # try to sign with a missing mkimage tool
6893 bintool.Bintool.set_missing_list(['mkimage'])
6894 with self.assertRaises(ValueError) as e:
6895 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6896 ['fit'])
6897 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6898
Simon Glass4abf7842023-07-18 07:23:54 -06006899 def testSymbolNoWrite(self):
6900 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006901 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006902 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6903 no_write_symbols=True)
6904
6905 def testSymbolNoWriteExpanded(self):
6906 """Test disabling of symbol writing in expanded entries"""
6907 entry_args = {
6908 'spl-dtb': '1',
6909 }
6910 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6911 U_BOOT_SPL_DTB_DATA, 0x38,
6912 entry_args=entry_args, use_expanded=True,
6913 no_write_symbols=True)
6914
Marek Vasutf7413f02023-07-18 07:23:58 -06006915 def testMkimageSpecial(self):
6916 """Test mkimage ignores special hash-1 node"""
6917 data = self._DoReadFile('283_mkimage_special.dts')
6918
6919 # Just check that the data appears in the file somewhere
6920 self.assertIn(U_BOOT_DATA, data)
6921
Simon Glass2d94c422023-07-18 07:23:59 -06006922 def testFitFdtList(self):
6923 """Test an image with an FIT with the fit,fdt-list-val option"""
6924 entry_args = {
6925 'default-dt': 'test-fdt2',
6926 }
6927 data = self._DoReadFileDtb(
6928 '284_fit_fdt_list.dts',
6929 entry_args=entry_args,
6930 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6931 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6932 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6933
Simon Glass83b8bfe2023-07-18 07:24:01 -06006934 def testSplEmptyBss(self):
6935 """Test an expanded SPL with a zero-size BSS"""
6936 # ELF file with a '__bss_size' symbol
6937 self._SetupSplElf(src_fname='bss_data_zero')
6938
6939 entry_args = {
6940 'spl-bss-pad': 'y',
6941 'spl-dtb': 'y',
6942 }
6943 data = self._DoReadFileDtb('285_spl_expand.dts',
6944 use_expanded=True, entry_args=entry_args)[0]
6945
Simon Glassfc792842023-07-18 07:24:04 -06006946 def testTemplate(self):
6947 """Test using a template"""
6948 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6949 data = self._DoReadFile('286_template.dts')
6950 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6951 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6952 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6953
Simon Glass09490b02023-07-22 21:43:52 -06006954 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6955 self.assertTrue(os.path.exists(dtb_fname1))
6956 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6957 dtb.Scan()
6958 node1 = dtb.GetNode('/binman/template')
6959 self.assertTrue(node1)
6960 vga = dtb.GetNode('/binman/first/intel-vga')
6961 self.assertTrue(vga)
6962
Simon Glass54825e12023-07-22 21:43:56 -06006963 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6964 self.assertTrue(os.path.exists(dtb_fname2))
6965 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6966 dtb2.Scan()
6967 node2 = dtb2.GetNode('/binman/template')
6968 self.assertFalse(node2)
6969
Simon Glass9909c112023-07-18 07:24:05 -06006970 def testTemplateBlobMulti(self):
6971 """Test using a template with 'multiple-images' enabled"""
6972 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6973 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6974 retcode = self._DoTestFile('287_template_multi.dts')
6975
6976 self.assertEqual(0, retcode)
6977 image = control.images['image']
6978 image_fname = tools.get_output_filename('my-image.bin')
6979 data = tools.read_file(image_fname)
6980 self.assertEqual(b'blob@@@@other', data)
6981
Simon Glass5dc511b2023-07-18 07:24:06 -06006982 def testTemplateFit(self):
6983 """Test using a template in a FIT"""
6984 fit_data = self._DoReadFile('288_template_fit.dts')
6985 fname = os.path.join(self._indir, 'fit_data.fit')
6986 tools.write_file(fname, fit_data)
6987 out = tools.run('dumpimage', '-l', fname)
6988
Simon Glassaa6e0552023-07-18 07:24:07 -06006989 def testTemplateSection(self):
6990 """Test using a template in a section (not at top level)"""
6991 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6992 data = self._DoReadFile('289_template_section.dts')
6993 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6994 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6995 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6996
Simon Glassf53a7bc2023-07-18 07:24:08 -06006997 def testMkimageSymbols(self):
6998 """Test using mkimage to build an image with symbols in it"""
6999 self._SetupSplElf('u_boot_binman_syms')
7000 data = self._DoReadFile('290_mkimage_sym.dts')
7001
7002 image = control.images['image']
7003 entries = image.GetEntries()
7004 self.assertIn('u-boot', entries)
7005 u_boot = entries['u-boot']
7006
7007 mkim = entries['mkimage']
7008 mkim_entries = mkim.GetEntries()
7009 self.assertIn('u-boot-spl', mkim_entries)
7010 spl = mkim_entries['u-boot-spl']
7011 self.assertIn('u-boot-spl2', mkim_entries)
7012 spl2 = mkim_entries['u-boot-spl2']
7013
7014 # skip the mkimage header and the area sizes
7015 mk_data = data[mkim.offset + 0x40:]
7016 size, term = struct.unpack('>LL', mk_data[:8])
7017
7018 # There should be only one image, so check that the zero terminator is
7019 # present
7020 self.assertEqual(0, term)
7021
7022 content = mk_data[8:8 + size]
7023
7024 # The image should contain the symbols from u_boot_binman_syms.c
7025 # Note that image_pos is adjusted by the base address of the image,
7026 # which is 0x10 in our test image
7027 spl_data = content[:0x18]
7028 content = content[0x1b:]
7029
7030 # After the header is a table of offsets for each image. There should
7031 # only be one image, then a 0 terminator, so figure out the real start
7032 # of the image data
7033 base = 0x40 + 8
7034
7035 # Check symbols in both u-boot-spl and u-boot-spl2
7036 for i in range(2):
7037 vals = struct.unpack('<LLQLL', spl_data)
7038
7039 # The image should contain the symbols from u_boot_binman_syms.c
7040 # Note that image_pos is adjusted by the base address of the image,
7041 # which is 0x10 in our 'u_boot_binman_syms' test image
7042 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
7043 self.assertEqual(base, vals[1])
7044 self.assertEqual(spl2.offset, vals[2])
7045 # figure out the internal positions of its components
7046 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
7047
7048 # Check that spl and spl2 are actually at the indicated positions
7049 self.assertEqual(
7050 elf.BINMAN_SYM_MAGIC_VALUE,
7051 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
7052 self.assertEqual(
7053 elf.BINMAN_SYM_MAGIC_VALUE,
7054 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
7055
7056 self.assertEqual(len(U_BOOT_DATA), vals[4])
7057
7058 # Move to next
7059 spl_data = content[:0x18]
7060
Simon Glass86b3e472023-07-22 21:43:57 -06007061 def testTemplatePhandle(self):
7062 """Test using a template in a node containing a phandle"""
7063 entry_args = {
7064 'atf-bl31-path': 'bl31.elf',
7065 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06007066 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007067 entry_args=entry_args)
7068 fname = tools.get_output_filename('image.bin')
7069 out = tools.run('dumpimage', '-l', fname)
7070
7071 # We should see the FIT description and one for each of the two images
7072 lines = out.splitlines()
7073 descs = [line.split()[-1] for line in lines if 'escription' in line]
7074 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7075
7076 def testTemplatePhandleDup(self):
7077 """Test using a template in a node containing a phandle"""
7078 entry_args = {
7079 'atf-bl31-path': 'bl31.elf',
7080 }
7081 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007082 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007083 entry_args=entry_args)
7084 self.assertIn(
7085 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7086 str(e.exception))
7087
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307088 def testTIBoardConfig(self):
7089 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007090 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307091 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7092
Neha Malcom Francis8cd04512024-01-05 17:09:17 +05307093 def testTIBoardConfigLint(self):
7094 """Test that an incorrectly linted config file would generate error"""
7095 with self.assertRaises(ValueError) as e:
7096 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7097 self.assertIn("Yamllint error", str(e.exception))
7098
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307099 def testTIBoardConfigCombined(self):
7100 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007101 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307102 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7103 self.assertGreater(data, configlen_noheader)
7104
7105 def testTIBoardConfigNoDataType(self):
7106 """Test that error is thrown when data type is not supported"""
7107 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007108 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307109 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007110
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307111 def testPackTiSecure(self):
7112 """Test that an image with a TI secured binary can be created"""
7113 keyfile = self.TestFile('key.key')
7114 entry_args = {
7115 'keyfile': keyfile,
7116 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007117 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307118 entry_args=entry_args)[0]
7119 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7120
Manorit Chawdhry2e523b02023-12-29 16:16:27 +05307121 def testPackTiSecureFirewall(self):
7122 """Test that an image with a TI secured binary can be created"""
7123 keyfile = self.TestFile('key.key')
7124 entry_args = {
7125 'keyfile': keyfile,
7126 }
7127 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7128 entry_args=entry_args)[0]
7129 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7130 entry_args=entry_args)[0]
7131 self.assertGreater(len(data_firewall),len(data_no_firewall))
7132
7133 def testPackTiSecureFirewallMissingProperty(self):
7134 """Test that an image with a TI secured binary can be created"""
7135 keyfile = self.TestFile('key.key')
7136 entry_args = {
7137 'keyfile': keyfile,
7138 }
7139 with self.assertRaises(ValueError) as e:
7140 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7141 entry_args=entry_args)[0]
7142 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7143
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307144 def testPackTiSecureMissingTool(self):
7145 """Test that an image with a TI secured binary (non-functional) can be created
7146 when openssl is missing"""
7147 keyfile = self.TestFile('key.key')
7148 entry_args = {
7149 'keyfile': keyfile,
7150 }
7151 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007152 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307153 force_missing_bintools='openssl',
7154 entry_args=entry_args)
7155 err = stderr.getvalue()
7156 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7157
7158 def testPackTiSecureROM(self):
7159 """Test that a ROM image with a TI secured binary can be created"""
7160 keyfile = self.TestFile('key.key')
7161 entry_args = {
7162 'keyfile': keyfile,
7163 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007164 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307165 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007166 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307167 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007168 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307169 entry_args=entry_args)[0]
7170 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7171 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7172 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7173
7174 def testPackTiSecureROMCombined(self):
7175 """Test that a ROM image with a TI secured binary can be created"""
7176 keyfile = self.TestFile('key.key')
7177 entry_args = {
7178 'keyfile': keyfile,
7179 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007180 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307181 entry_args=entry_args)[0]
7182 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7183
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007184 def testEncryptedNoAlgo(self):
7185 """Test encrypted node with missing required properties"""
7186 with self.assertRaises(ValueError) as e:
7187 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7188 self.assertIn(
7189 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7190 str(e.exception))
7191
7192 def testEncryptedInvalidIvfile(self):
7193 """Test encrypted node with invalid iv file"""
7194 with self.assertRaises(ValueError) as e:
7195 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7196 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7197 str(e.exception))
7198
7199 def testEncryptedMissingKey(self):
7200 """Test encrypted node with missing key properties"""
7201 with self.assertRaises(ValueError) as e:
7202 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7203 self.assertIn(
7204 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7205 str(e.exception))
7206
7207 def testEncryptedKeySource(self):
7208 """Test encrypted node with key-source property"""
7209 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7210
7211 dtb = fdt.Fdt.FromData(data)
7212 dtb.Scan()
7213
7214 node = dtb.GetNode('/images/u-boot/cipher')
7215 self.assertEqual('algo-name', node.props['algo'].value)
7216 self.assertEqual('key-source-value', node.props['key-source'].value)
7217 self.assertEqual(ENCRYPTED_IV_DATA,
7218 tools.to_bytes(''.join(node.props['iv'].value)))
7219 self.assertNotIn('key', node.props)
7220
7221 def testEncryptedKeyFile(self):
7222 """Test encrypted node with key-filename property"""
7223 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7224
7225 dtb = fdt.Fdt.FromData(data)
7226 dtb.Scan()
7227
7228 node = dtb.GetNode('/images/u-boot/cipher')
7229 self.assertEqual('algo-name', node.props['algo'].value)
7230 self.assertEqual(ENCRYPTED_IV_DATA,
7231 tools.to_bytes(''.join(node.props['iv'].value)))
7232 self.assertEqual(ENCRYPTED_KEY_DATA,
7233 tools.to_bytes(''.join(node.props['key'].value)))
7234 self.assertNotIn('key-source', node.props)
7235
Lukas Funkee901faf2023-07-18 13:53:13 +02007236
7237 def testSplPubkeyDtb(self):
Simon Glass4b861272024-07-20 11:49:41 +01007238 """Test u_boot_spl_pubkey_dtb etype"""
7239 data = tools.read_file(self.TestFile("key.pem"))
7240 self._MakeInputFile("key.crt", data)
7241 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7242 image = control.images['image']
7243 entries = image.GetEntries()
7244 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7245 dtb_data = dtb_entry.GetData()
7246 dtb = fdt.Fdt.FromData(dtb_data)
7247 dtb.Scan()
Lukas Funkee901faf2023-07-18 13:53:13 +02007248
Simon Glass4b861272024-07-20 11:49:41 +01007249 signature_node = dtb.GetNode('/signature')
7250 self.assertIsNotNone(signature_node)
7251 key_node = signature_node.FindNode("key-key")
7252 self.assertIsNotNone(key_node)
7253 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7254 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7255 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007256
Lukas Funke712e1062023-08-03 17:22:14 +02007257 def testXilinxBootgenSigning(self):
7258 """Test xilinx-bootgen etype"""
7259 bootgen = bintool.Bintool.create('bootgen')
7260 self._CheckBintool(bootgen)
7261 data = tools.read_file(self.TestFile("key.key"))
7262 self._MakeInputFile("psk.pem", data)
7263 self._MakeInputFile("ssk.pem", data)
7264 self._SetupPmuFwlElf()
7265 self._SetupSplElf()
7266 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7267 image_fname = tools.get_output_filename('image.bin')
7268
7269 # Read partition header table and check if authentication is enabled
7270 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7271 "-read", image_fname, "pht").splitlines()
7272 attributes = {"authentication": None,
7273 "core": None,
7274 "encryption": None}
7275
7276 for l in bootgen_out:
7277 for a in attributes.keys():
7278 if a in l:
7279 m = re.match(fr".*{a} \[([^]]+)\]", l)
7280 attributes[a] = m.group(1)
7281
7282 self.assertTrue(attributes['authentication'] == "rsa")
7283 self.assertTrue(attributes['core'] == "a53-0")
7284 self.assertTrue(attributes['encryption'] == "no")
7285
7286 def testXilinxBootgenSigningEncryption(self):
7287 """Test xilinx-bootgen etype"""
7288 bootgen = bintool.Bintool.create('bootgen')
7289 self._CheckBintool(bootgen)
7290 data = tools.read_file(self.TestFile("key.key"))
7291 self._MakeInputFile("psk.pem", data)
7292 self._MakeInputFile("ssk.pem", data)
7293 self._SetupPmuFwlElf()
7294 self._SetupSplElf()
7295 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7296 image_fname = tools.get_output_filename('image.bin')
7297
7298 # Read boot header in order to verify encryption source and
7299 # encryption parameter
7300 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7301 "-read", image_fname, "bh").splitlines()
7302 attributes = {"auth_only":
7303 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7304 "encryption_keystore":
7305 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7306 "value": None},
7307 }
7308
7309 for l in bootgen_out:
7310 for a in attributes.keys():
7311 if a in l:
7312 m = re.match(attributes[a]['re'], l)
7313 attributes[a] = m.group(1)
7314
7315 # Check if fsbl-attribute is set correctly
7316 self.assertTrue(attributes['auth_only'] == "true")
7317 # Check if key is stored in efuse
7318 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7319
7320 def testXilinxBootgenMissing(self):
7321 """Test that binman still produces an image if bootgen is missing"""
7322 data = tools.read_file(self.TestFile("key.key"))
7323 self._MakeInputFile("psk.pem", data)
7324 self._MakeInputFile("ssk.pem", data)
7325 self._SetupPmuFwlElf()
7326 self._SetupSplElf()
7327 with test_util.capture_sys_output() as (_, stderr):
7328 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7329 force_missing_bintools='bootgen')
7330 err = stderr.getvalue()
7331 self.assertRegex(err,
7332 "Image 'image'.*missing bintools.*: bootgen")
7333
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307334 def _GetCapsuleHeaders(self, data):
7335 """Get the capsule header contents
7336
7337 Args:
7338 data: Capsule file contents
7339
7340 Returns:
7341 Dict:
7342 key: Capsule Header name (str)
7343 value: Header field value (str)
7344 """
7345 capsule_file = os.path.join(self._indir, 'test.capsule')
7346 tools.write_file(capsule_file, data)
7347
7348 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7349 lines = out.splitlines()
7350
7351 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7352 vals = {}
7353 for line in lines:
7354 mat = re_line.match(line)
7355 if mat:
7356 vals[mat.group(1)] = mat.group(2)
7357
7358 return vals
7359
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307360 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7361 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307362 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7363 fmp_size = "00000010"
7364 fmp_fw_version = "00000002"
7365 capsule_image_index = "00000001"
7366 oemflag = "00018000"
7367 auth_hdr_revision = "00000200"
7368 auth_hdr_cert_type = "00000EF1"
7369
7370 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307371
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307372 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307373
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307374 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307375
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307376 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7377 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7378 self.assertEqual(capsule_image_index,
7379 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307380
7381 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307382 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7383
7384 if signed_capsule:
7385 self.assertEqual(auth_hdr_revision,
7386 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7387 self.assertEqual(auth_hdr_cert_type,
7388 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7389 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7390 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7391
7392 if version_check:
7393 self.assertEqual(fmp_signature,
7394 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7395 self.assertEqual(fmp_size,
7396 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7397 self.assertEqual(fmp_fw_version,
7398 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7399
7400 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307401
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307402 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7403 if accept_capsule:
7404 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7405 else:
7406 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7407
7408 hdr = self._GetCapsuleHeaders(data)
7409
7410 self.assertEqual(capsule_hdr_guid.upper(),
7411 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7412
7413 if accept_capsule:
7414 capsule_size = "0000002C"
7415 else:
7416 capsule_size = "0000001C"
7417 self.assertEqual(capsule_size,
7418 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7419
7420 if accept_capsule:
7421 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7422
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307423 def testCapsuleGen(self):
7424 """Test generation of EFI capsule"""
7425 data = self._DoReadFile('311_capsule.dts')
7426
7427 self._CheckCapsule(data)
7428
7429 def testSignedCapsuleGen(self):
7430 """Test generation of EFI capsule"""
7431 data = tools.read_file(self.TestFile("key.key"))
7432 self._MakeInputFile("key.key", data)
7433 data = tools.read_file(self.TestFile("key.pem"))
7434 self._MakeInputFile("key.crt", data)
7435
7436 data = self._DoReadFile('312_capsule_signed.dts')
7437
7438 self._CheckCapsule(data, signed_capsule=True)
7439
7440 def testCapsuleGenVersionSupport(self):
7441 """Test generation of EFI capsule with version support"""
7442 data = self._DoReadFile('313_capsule_version.dts')
7443
7444 self._CheckCapsule(data, version_check=True)
7445
7446 def testCapsuleGenSignedVer(self):
7447 """Test generation of signed EFI capsule with version information"""
7448 data = tools.read_file(self.TestFile("key.key"))
7449 self._MakeInputFile("key.key", data)
7450 data = tools.read_file(self.TestFile("key.pem"))
7451 self._MakeInputFile("key.crt", data)
7452
7453 data = self._DoReadFile('314_capsule_signed_ver.dts')
7454
7455 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7456
7457 def testCapsuleGenCapOemFlags(self):
7458 """Test generation of EFI capsule with OEM Flags set"""
7459 data = self._DoReadFile('315_capsule_oemflags.dts')
7460
7461 self._CheckCapsule(data, capoemflags=True)
7462
7463 def testCapsuleGenKeyMissing(self):
7464 """Test that binman errors out on missing key"""
7465 with self.assertRaises(ValueError) as e:
7466 self._DoReadFile('316_capsule_missing_key.dts')
7467
7468 self.assertIn("Both private key and public key certificate need to be provided",
7469 str(e.exception))
7470
7471 def testCapsuleGenIndexMissing(self):
7472 """Test that binman errors out on missing image index"""
7473 with self.assertRaises(ValueError) as e:
7474 self._DoReadFile('317_capsule_missing_index.dts')
7475
7476 self.assertIn("entry is missing properties: image-index",
7477 str(e.exception))
7478
7479 def testCapsuleGenGuidMissing(self):
7480 """Test that binman errors out on missing image GUID"""
7481 with self.assertRaises(ValueError) as e:
7482 self._DoReadFile('318_capsule_missing_guid.dts')
7483
7484 self.assertIn("entry is missing properties: image-guid",
7485 str(e.exception))
7486
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307487 def testCapsuleGenAcceptCapsule(self):
7488 """Test generationg of accept EFI capsule"""
7489 data = self._DoReadFile('319_capsule_accept.dts')
7490
7491 self._CheckEmptyCapsule(data, accept_capsule=True)
7492
7493 def testCapsuleGenRevertCapsule(self):
7494 """Test generationg of revert EFI capsule"""
7495 data = self._DoReadFile('320_capsule_revert.dts')
7496
7497 self._CheckEmptyCapsule(data)
7498
7499 def testCapsuleGenAcceptGuidMissing(self):
7500 """Test that binman errors out on missing image GUID for accept capsule"""
7501 with self.assertRaises(ValueError) as e:
7502 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7503
7504 self.assertIn("Image GUID needed for generating accept capsule",
7505 str(e.exception))
7506
7507 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7508 """Test that capsule-type is specified"""
7509 with self.assertRaises(ValueError) as e:
7510 self._DoReadFile('322_empty_capsule_type_missing.dts')
7511
7512 self.assertIn("entry is missing properties: capsule-type",
7513 str(e.exception))
7514
7515 def testCapsuleGenAcceptOrRevertMissing(self):
7516 """Test that both accept and revert capsule are not specified"""
7517 with self.assertRaises(ValueError) as e:
7518 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7519
Simon Glassa360b8f2024-06-23 11:55:06 -06007520 def test_assume_size(self):
7521 """Test handling of the assume-size property for external blob"""
7522 with self.assertRaises(ValueError) as e:
7523 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7524 allow_fake_blobs=True)
7525 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7526 str(e.exception))
7527
7528 def test_assume_size_ok(self):
7529 """Test handling of the assume-size where it fits OK"""
7530 with test_util.capture_sys_output() as (stdout, stderr):
7531 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7532 allow_fake_blobs=True)
7533 err = stderr.getvalue()
7534 self.assertRegex(
7535 err,
7536 "Image '.*' has faked external blobs and is non-functional: .*")
7537
7538 def test_assume_size_no_fake(self):
7539 """Test handling of the assume-size where it fits OK"""
7540 with test_util.capture_sys_output() as (stdout, stderr):
7541 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7542 err = stderr.getvalue()
7543 self.assertRegex(
7544 err,
7545 "Image '.*' is missing external blobs and is non-functional: .*")
7546
Simon Glass5f7aadf2024-07-20 11:49:47 +01007547 def SetupAlternateDts(self):
7548 """Compile the .dts test files for alternative-fdt
7549
7550 Returns:
7551 tuple:
7552 str: Test directory created
7553 list of str: '.bin' files which we expect Binman to create
7554 """
7555 testdir = TestFunctional._MakeInputDir('dtb')
7556 dtb_list = []
7557 for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
7558 tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
7559 base = os.path.splitext(os.path.basename(fname))[0]
7560 dtb_list.append(base + '.bin')
7561 shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
7562
7563 return testdir, dtb_list
7564
Simon Glassf3598922024-07-20 11:49:45 +01007565 def CheckAlternates(self, dts, phase, xpl_data):
7566 """Run the test for the alterative-fdt etype
7567
7568 Args:
7569 dts (str): Devicetree file to process
7570 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7571 xpl_data (bytes): Expected data for the phase's binary
7572
7573 Returns:
7574 dict of .dtb files produced
7575 key: str filename
7576 value: Fdt object
7577 """
Simon Glass5f7aadf2024-07-20 11:49:47 +01007578 dtb_list = self.SetupAlternateDts()[1]
Simon Glassf3598922024-07-20 11:49:45 +01007579
7580 entry_args = {
7581 f'{phase}-dtb': '1',
7582 f'{phase}-bss-pad': 'y',
7583 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7584 }
7585 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7586 use_expanded=True, entry_args=entry_args)[0]
7587 self.assertEqual(xpl_data, data[:len(xpl_data)])
7588 rest = data[len(xpl_data):]
7589 pad_len = 10
7590 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7591
7592 # Check the dtb is using the test file
7593 dtb_data = rest[pad_len:]
7594 dtb = fdt.Fdt.FromData(dtb_data)
7595 dtb.Scan()
7596 fdt_size = dtb.GetFdtObj().totalsize()
7597 self.assertEqual('model-not-set',
7598 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7599
7600 pad_len = 10
7601
7602 # Check the other output files
7603 dtbs = {}
7604 for fname in dtb_list:
7605 pathname = tools.get_output_filename(fname)
7606 self.assertTrue(os.path.exists(pathname))
7607
7608 data = tools.read_file(pathname)
7609 self.assertEqual(xpl_data, data[:len(xpl_data)])
7610 rest = data[len(xpl_data):]
7611
7612 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7613 rest = rest[pad_len:]
7614
7615 dtb = fdt.Fdt.FromData(rest)
7616 dtb.Scan()
7617 dtbs[fname] = dtb
7618
7619 expected = 'one' if '1' in fname else 'two'
7620 self.assertEqual(f'u-boot,model-{expected}',
7621 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7622
7623 # Make sure the FDT is the same size as the 'main' one
7624 rest = rest[fdt_size:]
7625
7626 self.assertEqual(b'', rest)
7627 return dtbs
7628
7629 def testAlternatesFdt(self):
7630 """Test handling of alternates-fdt etype"""
7631 self._SetupTplElf()
7632 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7633 U_BOOT_TPL_NODTB_DATA)
7634 for dtb in dtbs.values():
7635 # Check for the node with the tag
7636 node = dtb.GetNode('/node')
7637 self.assertIsNotNone(node)
7638 self.assertEqual(5, len(node.props.keys()))
7639
7640 # Make sure the other node is still there
7641 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7642
7643 def testAlternatesFdtgrep(self):
7644 """Test handling of alternates-fdt etype using fdtgrep"""
7645 self._SetupTplElf()
7646 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7647 U_BOOT_TPL_NODTB_DATA)
7648 for dtb in dtbs.values():
7649 # Check for the node with the tag
7650 node = dtb.GetNode('/node')
7651 self.assertIsNotNone(node)
7652 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7653 node.props.keys())
7654
7655 # Make sure the other node is gone
7656 self.assertIsNone(dtb.GetNode('/node/other-node'))
7657
7658 def testAlternatesFdtgrepVpl(self):
7659 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7660 self._SetupVplElf()
7661 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7662 U_BOOT_VPL_NODTB_DATA)
7663
7664 def testAlternatesFdtgrepSpl(self):
7665 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7666 self._SetupSplElf()
7667 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7668 U_BOOT_SPL_NODTB_DATA)
7669
7670 def testAlternatesFdtgrepInval(self):
7671 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7672 self._SetupSplElf()
7673 with self.assertRaises(ValueError) as e:
7674 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7675 U_BOOT_SPL_NODTB_DATA)
7676 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7677 str(e.exception))
7678
Simon Glasscd2783e2024-07-20 11:49:46 +01007679 def testFitFdtListDir(self):
7680 """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
Simon Glass1bba8942024-08-26 13:11:34 -06007681 old_dir = os.getcwd()
7682 try:
7683 os.chdir(self._indir)
7684 self.CheckFitFdt('333_fit_fdt_dir.dts', False)
7685 finally:
7686 os.chdir(old_dir)
Simon Glasscd2783e2024-07-20 11:49:46 +01007687
Simon Glassd2a9d6e2024-08-26 13:11:37 -06007688 def testFitFdtListDirDefault(self):
7689 """Test an FIT fit,fdt-list-dir where the default DT in is a subdir"""
7690 old_dir = os.getcwd()
7691 try:
7692 os.chdir(self._indir)
7693 self.CheckFitFdt('333_fit_fdt_dir.dts', False,
7694 default_dt='rockchip/test-fdt2')
7695 finally:
7696 os.chdir(old_dir)
7697
Simon Glass5f7aadf2024-07-20 11:49:47 +01007698 def testFitFdtCompat(self):
7699 """Test an image with an FIT with compatible in the config nodes"""
7700 entry_args = {
7701 'of-list': 'model1 model2',
7702 'default-dt': 'model2',
7703 }
7704 testdir, dtb_list = self.SetupAlternateDts()
7705 data = self._DoReadFileDtb(
7706 '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
7707 entry_args=entry_args, extra_indirs=[testdir])[0]
7708
7709 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7710
7711 fit = fdt.Fdt.FromData(fit_data)
7712 fit.Scan()
7713
7714 cnode = fit.GetNode('/configurations')
7715 self.assertIn('default', cnode.props)
7716 self.assertEqual('config-2', cnode.props['default'].value)
7717
7718 for seq in range(1, 2):
7719 name = f'config-{seq}'
7720 fnode = fit.GetNode('/configurations/%s' % name)
7721 self.assertIsNotNone(fnode)
7722 self.assertIn('compatible', fnode.props.keys())
7723 expected = 'one' if seq == 1 else 'two'
7724 self.assertEqual(f'u-boot,model-{expected}',
7725 fnode.props['compatible'].value)
7726
Simon Glassa04b9942024-07-20 11:49:48 +01007727 def testFitFdtPhase(self):
7728 """Test an image with an FIT with fdt-phase in the fdt nodes"""
7729 phase = 'tpl'
7730 entry_args = {
7731 f'{phase}-dtb': '1',
7732 f'{phase}-bss-pad': 'y',
7733 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7734 'of-list': 'model1 model2',
7735 'default-dt': 'model2',
7736 }
7737 testdir, dtb_list = self.SetupAlternateDts()
7738 data = self._DoReadFileDtb(
7739 '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
7740 entry_args=entry_args, extra_indirs=[testdir])[0]
7741 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7742 fit = fdt.Fdt.FromData(fit_data)
7743 fit.Scan()
7744
7745 # Check that each FDT has only the expected properties for the phase
7746 for seq in range(1, 2):
7747 fnode = fit.GetNode(f'/images/fdt-{seq}')
7748 self.assertIsNotNone(fnode)
7749 dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
7750 dtb.Scan()
7751
7752 # Make sure that the 'bootph-pre-sram' tag in /node protects it from
7753 # removal
7754 node = dtb.GetNode('/node')
7755 self.assertIsNotNone(node)
7756 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7757 node.props.keys())
7758
7759 # Make sure the other node is gone
7760 self.assertIsNone(dtb.GetNode('/node/other-node'))
7761
Simon Glassb553e8a2024-08-26 13:11:29 -06007762 def testMkeficapsuleMissing(self):
7763 """Test that binman complains if mkeficapsule is missing"""
7764 with self.assertRaises(ValueError) as e:
7765 self._DoTestFile('311_capsule.dts',
7766 force_missing_bintools='mkeficapsule')
7767 self.assertIn("Node '/binman/efi-capsule': Missing tool: 'mkeficapsule'",
7768 str(e.exception))
7769
7770 def testMkeficapsuleMissingOk(self):
7771 """Test that binman deals with mkeficapsule being missing"""
7772 with test_util.capture_sys_output() as (stdout, stderr):
7773 ret = self._DoTestFile('311_capsule.dts',
7774 force_missing_bintools='mkeficapsule',
7775 allow_missing=True)
7776 self.assertEqual(103, ret)
7777 err = stderr.getvalue()
7778 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkeficapsule")
7779
Simon Glass4b0f4142024-08-26 13:11:40 -06007780 def testSymbolsBase(self):
7781 """Test handling of symbols-base"""
7782 self.checkSymbols('336_symbols_base.dts', U_BOOT_SPL_DATA, 0x1c,
7783 symbols_base=0)
7784
7785 def testSymbolsBaseExpanded(self):
7786 """Test handling of symbols-base with expanded entries"""
7787 entry_args = {
7788 'spl-dtb': '1',
7789 }
7790 self.checkSymbols('337_symbols_base_expand.dts', U_BOOT_SPL_NODTB_DATA +
7791 U_BOOT_SPL_DTB_DATA, 0x38,
7792 entry_args=entry_args, use_expanded=True,
7793 symbols_base=0)
7794
Simon Glass3eb30a42024-08-26 13:11:42 -06007795 def testSymbolsCompressed(self):
7796 """Test binman complains about symbols from a compressed section"""
7797 with test_util.capture_sys_output() as (stdout, stderr):
7798 self.checkSymbols('338_symbols_comp.dts', U_BOOT_SPL_DATA, None)
7799 out = stdout.getvalue()
7800 self.assertIn('Symbol-writing: no value for /binman/section/u-boot',
7801 out)
7802
Simon Glass9c25ef22024-08-26 13:11:43 -06007803 def testNxpImx8Image(self):
7804 """Test that binman can produce an iMX8 image"""
7805 self._DoTestFile('339_nxp_imx8.dts')
7806
Simon Glassa360b8f2024-06-23 11:55:06 -06007807
Simon Glassac599912017-11-12 21:52:22 -07007808if __name__ == "__main__":
7809 unittest.main()