blob: 733169b99f6b1755142ce9e0d8474309da18826f [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)
Simon Glassed836ac2025-02-26 09:26:17 -07002300 base = (1 << 32) - 0x100
Simon Glassc64aea52018-09-14 04:57:34 -06002301
Simon Glassed836ac2025-02-26 09:26:17 -07002302 self.assertEqual(base, fentries[0].offset)
Simon Glassc64aea52018-09-14 04:57:34 -06002303 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002304 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002305
Simon Glassed836ac2025-02-26 09:26:17 -07002306 self.assertEqual(base + 4, fentries[1].offset)
Simon Glassc64aea52018-09-14 04:57:34 -06002307 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002308 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002309
Simon Glassed836ac2025-02-26 09:26:17 -07002310 self.assertEqual(base + 32, fentries[2].offset)
Simon Glassc64aea52018-09-14 04:57:34 -06002311 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2312 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002313 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002314
2315 def testFmapX86Section(self):
2316 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002317 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002318 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002319 self.assertEqual(expected, data[:32])
2320 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2321
Simon Glassb1d414c2021-04-03 11:05:10 +13002322 self.assertEqual(0x180, fhdr.image_size)
Simon Glassed836ac2025-02-26 09:26:17 -07002323 base = (1 << 32) - 0x180
Simon Glassb1d414c2021-04-03 11:05:10 +13002324 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002325 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002326
Simon Glass82059c22021-04-03 11:05:09 +13002327 fentry = next(fiter)
2328 self.assertEqual(b'U_BOOT', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002329 self.assertEqual(base, fentry.offset)
Simon Glass82059c22021-04-03 11:05:09 +13002330 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002331
Simon Glass82059c22021-04-03 11:05:09 +13002332 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002333 self.assertEqual(b'SECTION', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002334 self.assertEqual(base + 4, fentry.offset)
Simon Glassb1d414c2021-04-03 11:05:10 +13002335 self.assertEqual(0x20 + expect_size, fentry.size)
2336
2337 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002338 self.assertEqual(b'INTEL_MRC', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002339 self.assertEqual(base + 4, fentry.offset)
Simon Glass82059c22021-04-03 11:05:09 +13002340 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002341
Simon Glass82059c22021-04-03 11:05:09 +13002342 fentry = next(fiter)
2343 self.assertEqual(b'FMAP', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002344 self.assertEqual(base + 36, fentry.offset)
Simon Glass82059c22021-04-03 11:05:09 +13002345 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002346
Simon Glassb1714232018-09-14 04:57:35 -06002347 def testElf(self):
2348 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002349 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002350 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002351 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002352 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002353 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002354
Simon Glass0d673792019-07-08 13:18:25 -06002355 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002356 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002357 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002358 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002359 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002360 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002361
Simon Glasscd817d52018-09-14 04:57:36 -06002362 def testPackOverlapMap(self):
2363 """Test that overlapping regions are detected"""
2364 with test_util.capture_sys_output() as (stdout, stderr):
2365 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002366 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002367 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002368 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2369 stdout.getvalue())
2370
2371 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002372 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002373 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002374 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002375 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002376<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002377<none> 00000000 00000004 u-boot
2378<none> 00000003 00000004 u-boot-align
2379''', map_data)
2380
Simon Glass0d673792019-07-08 13:18:25 -06002381 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002382 """Test that an image with an Intel Reference code binary works"""
2383 data = self._DoReadFile('100_intel_refcode.dts')
2384 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2385
Simon Glasseb023b32019-04-25 21:58:39 -06002386 def testSectionOffset(self):
2387 """Tests use of a section with an offset"""
2388 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2389 map=True)
2390 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700239100000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600239200000004 00000004 00000010 section@0
239300000004 00000000 00000004 u-boot
239400000018 00000018 00000010 section@1
239500000018 00000000 00000004 u-boot
23960000002c 0000002c 00000004 section@2
23970000002c 00000000 00000004 u-boot
2398''', map_data)
2399 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002400 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2401 tools.get_bytes(0x21, 12) +
2402 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2403 tools.get_bytes(0x61, 12) +
2404 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2405 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002406
Simon Glass1de34482019-07-08 13:18:53 -06002407 def testCbfsRaw(self):
2408 """Test base handling of a Coreboot Filesystem (CBFS)
2409
2410 The exact contents of the CBFS is verified by similar tests in
2411 cbfs_util_test.py. The tests here merely check that the files added to
2412 the CBFS can be found in the final image.
2413 """
2414 data = self._DoReadFile('102_cbfs_raw.dts')
2415 size = 0xb0
2416
2417 cbfs = cbfs_util.CbfsReader(data)
2418 self.assertEqual(size, cbfs.rom_size)
2419
2420 self.assertIn('u-boot-dtb', cbfs.files)
2421 cfile = cbfs.files['u-boot-dtb']
2422 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2423
2424 def testCbfsArch(self):
2425 """Test on non-x86 architecture"""
2426 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2427 size = 0x100
2428
2429 cbfs = cbfs_util.CbfsReader(data)
2430 self.assertEqual(size, cbfs.rom_size)
2431
2432 self.assertIn('u-boot-dtb', cbfs.files)
2433 cfile = cbfs.files['u-boot-dtb']
2434 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2435
2436 def testCbfsStage(self):
2437 """Tests handling of a Coreboot Filesystem (CBFS)"""
2438 if not elf.ELF_TOOLS:
2439 self.skipTest('Python elftools not available')
2440 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2441 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2442 size = 0xb0
2443
2444 data = self._DoReadFile('104_cbfs_stage.dts')
2445 cbfs = cbfs_util.CbfsReader(data)
2446 self.assertEqual(size, cbfs.rom_size)
2447
2448 self.assertIn('u-boot', cbfs.files)
2449 cfile = cbfs.files['u-boot']
2450 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2451
2452 def testCbfsRawCompress(self):
2453 """Test handling of compressing raw files"""
2454 self._CheckLz4()
2455 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2456 size = 0x140
2457
2458 cbfs = cbfs_util.CbfsReader(data)
2459 self.assertIn('u-boot', cbfs.files)
2460 cfile = cbfs.files['u-boot']
2461 self.assertEqual(COMPRESS_DATA, cfile.data)
2462
2463 def testCbfsBadArch(self):
2464 """Test handling of a bad architecture"""
2465 with self.assertRaises(ValueError) as e:
2466 self._DoReadFile('106_cbfs_bad_arch.dts')
2467 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2468
2469 def testCbfsNoSize(self):
2470 """Test handling of a missing size property"""
2471 with self.assertRaises(ValueError) as e:
2472 self._DoReadFile('107_cbfs_no_size.dts')
2473 self.assertIn('entry must have a size property', str(e.exception))
2474
Simon Glass3e28f4f2021-11-23 11:03:54 -07002475 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002476 """Test handling of a CBFS entry which does not provide contentsy"""
2477 with self.assertRaises(ValueError) as e:
2478 self._DoReadFile('108_cbfs_no_contents.dts')
2479 self.assertIn('Could not complete processing of contents',
2480 str(e.exception))
2481
2482 def testCbfsBadCompress(self):
2483 """Test handling of a bad architecture"""
2484 with self.assertRaises(ValueError) as e:
2485 self._DoReadFile('109_cbfs_bad_compress.dts')
2486 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2487 str(e.exception))
2488
2489 def testCbfsNamedEntries(self):
2490 """Test handling of named entries"""
2491 data = self._DoReadFile('110_cbfs_name.dts')
2492
2493 cbfs = cbfs_util.CbfsReader(data)
2494 self.assertIn('FRED', cbfs.files)
2495 cfile1 = cbfs.files['FRED']
2496 self.assertEqual(U_BOOT_DATA, cfile1.data)
2497
2498 self.assertIn('hello', cbfs.files)
2499 cfile2 = cbfs.files['hello']
2500 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2501
Simon Glass759af872019-07-08 13:18:54 -06002502 def _SetupIfwi(self, fname):
2503 """Set up to run an IFWI test
2504
2505 Args:
2506 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2507 """
2508 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002509 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002510
2511 # Intel Integrated Firmware Image (IFWI) file
2512 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2513 data = fd.read()
2514 TestFunctional._MakeInputFile(fname,data)
2515
2516 def _CheckIfwi(self, data):
2517 """Check that an image with an IFWI contains the correct output
2518
2519 Args:
2520 data: Conents of output file
2521 """
Simon Glass80025522022-01-29 14:14:04 -07002522 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002523 if data[:0x1000] != expected_desc:
2524 self.fail('Expected descriptor binary at start of image')
2525
2526 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002527 image_fname = tools.get_output_filename('image.bin')
2528 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002529 ifwitool = bintool.Bintool.create('ifwitool')
2530 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002531
Simon Glass80025522022-01-29 14:14:04 -07002532 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002533 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002534
2535 def testPackX86RomIfwi(self):
2536 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2537 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002538 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002539 self._CheckIfwi(data)
2540
2541 def testPackX86RomIfwiNoDesc(self):
2542 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2543 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002544 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002545 self._CheckIfwi(data)
2546
2547 def testPackX86RomIfwiNoData(self):
2548 """Test that an x86 ROM with IFWI handles missing data"""
2549 self._SetupIfwi('ifwi.bin')
2550 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002551 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002552 self.assertIn('Could not complete processing of contents',
2553 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002554
Simon Glass66152ce2022-01-09 20:14:09 -07002555 def testIfwiMissing(self):
2556 """Test that binman still produces an image if ifwitool is missing"""
2557 self._SetupIfwi('fitimage.bin')
2558 with test_util.capture_sys_output() as (_, stderr):
2559 self._DoTestFile('111_x86_rom_ifwi.dts',
2560 force_missing_bintools='ifwitool')
2561 err = stderr.getvalue()
2562 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002563 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002564
Simon Glassc2f1aed2019-07-08 13:18:56 -06002565 def testCbfsOffset(self):
2566 """Test a CBFS with files at particular offsets
2567
2568 Like all CFBS tests, this is just checking the logic that calls
2569 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2570 """
2571 data = self._DoReadFile('114_cbfs_offset.dts')
2572 size = 0x200
2573
2574 cbfs = cbfs_util.CbfsReader(data)
2575 self.assertEqual(size, cbfs.rom_size)
2576
2577 self.assertIn('u-boot', cbfs.files)
2578 cfile = cbfs.files['u-boot']
2579 self.assertEqual(U_BOOT_DATA, cfile.data)
2580 self.assertEqual(0x40, cfile.cbfs_offset)
2581
2582 self.assertIn('u-boot-dtb', cbfs.files)
2583 cfile2 = cbfs.files['u-boot-dtb']
2584 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2585 self.assertEqual(0x140, cfile2.cbfs_offset)
2586
Simon Glass0f621332019-07-08 14:25:27 -06002587 def testFdtmap(self):
2588 """Test an FDT map can be inserted in the image"""
2589 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2590 fdtmap_data = data[len(U_BOOT_DATA):]
2591 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002592 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002593 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002594
2595 fdt_data = fdtmap_data[16:]
2596 dtb = fdt.Fdt.FromData(fdt_data)
2597 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002598 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002599 self.assertEqual({
2600 'image-pos': 0,
2601 'offset': 0,
2602 'u-boot:offset': 0,
2603 'u-boot:size': len(U_BOOT_DATA),
2604 'u-boot:image-pos': 0,
2605 'fdtmap:image-pos': 4,
2606 'fdtmap:offset': 4,
2607 'fdtmap:size': len(fdtmap_data),
2608 'size': len(data),
2609 }, props)
2610
2611 def testFdtmapNoMatch(self):
2612 """Check handling of an FDT map when the section cannot be found"""
2613 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2614
2615 # Mangle the section name, which should cause a mismatch between the
2616 # correct FDT path and the one expected by the section
2617 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002618 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002619 entries = image.GetEntries()
2620 fdtmap = entries['fdtmap']
2621 with self.assertRaises(ValueError) as e:
2622 fdtmap._GetFdtmap()
2623 self.assertIn("Cannot locate node for path '/binman-suffix'",
2624 str(e.exception))
2625
Simon Glasscec34ba2019-07-08 14:25:28 -06002626 def testFdtmapHeader(self):
2627 """Test an FDT map and image header can be inserted in the image"""
2628 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2629 fdtmap_pos = len(U_BOOT_DATA)
2630 fdtmap_data = data[fdtmap_pos:]
2631 fdt_data = fdtmap_data[16:]
2632 dtb = fdt.Fdt.FromData(fdt_data)
2633 fdt_size = dtb.GetFdtObj().totalsize()
2634 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002635 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002636 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2637 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2638
2639 def testFdtmapHeaderStart(self):
2640 """Test an image header can be inserted at the image start"""
2641 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2642 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2643 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002644 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002645 offset = struct.unpack('<I', hdr_data[4:])[0]
2646 self.assertEqual(fdtmap_pos, offset)
2647
2648 def testFdtmapHeaderPos(self):
2649 """Test an image header can be inserted at a chosen position"""
2650 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2651 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2652 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002653 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002654 offset = struct.unpack('<I', hdr_data[4:])[0]
2655 self.assertEqual(fdtmap_pos, offset)
2656
2657 def testHeaderMissingFdtmap(self):
2658 """Test an image header requires an fdtmap"""
2659 with self.assertRaises(ValueError) as e:
2660 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2661 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2662 str(e.exception))
2663
2664 def testHeaderNoLocation(self):
2665 """Test an image header with a no specified location is detected"""
2666 with self.assertRaises(ValueError) as e:
2667 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2668 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2669 str(e.exception))
2670
Simon Glasse61b6f62019-07-08 14:25:37 -06002671 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002672 """Test extending an entry after it is packed"""
2673 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002674 self.assertEqual(b'aaa', data[:3])
2675 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2676 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002677
Simon Glassdd156a42022-03-05 20:18:59 -07002678 def testEntryExtendBad(self):
2679 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002680 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002681 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002682 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002683 str(e.exception))
2684
Simon Glassdd156a42022-03-05 20:18:59 -07002685 def testEntryExtendSection(self):
2686 """Test extending an entry within a section after it is packed"""
2687 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002688 self.assertEqual(b'aaa', data[:3])
2689 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2690 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002691
Simon Glass90d29682019-07-08 14:25:38 -06002692 def testCompressDtb(self):
2693 """Test that compress of device-tree files is supported"""
2694 self._CheckLz4()
2695 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2696 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2697 comp_data = data[len(U_BOOT_DATA):]
2698 orig = self._decompress(comp_data)
2699 dtb = fdt.Fdt.FromData(orig)
2700 dtb.Scan()
2701 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2702 expected = {
2703 'u-boot:size': len(U_BOOT_DATA),
2704 'u-boot-dtb:uncomp-size': len(orig),
2705 'u-boot-dtb:size': len(comp_data),
2706 'size': len(data),
2707 }
2708 self.assertEqual(expected, props)
2709
Simon Glass151bbbf2019-07-08 14:25:41 -06002710 def testCbfsUpdateFdt(self):
2711 """Test that we can update the device tree with CBFS offset/size info"""
2712 self._CheckLz4()
2713 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2714 update_dtb=True)
2715 dtb = fdt.Fdt(out_dtb_fname)
2716 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002717 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002718 del props['cbfs/u-boot:size']
2719 self.assertEqual({
2720 'offset': 0,
2721 'size': len(data),
2722 'image-pos': 0,
2723 'cbfs:offset': 0,
2724 'cbfs:size': len(data),
2725 'cbfs:image-pos': 0,
Simon Glassfa144222023-10-14 14:40:28 -06002726 'cbfs/u-boot:offset': 0x30,
Simon Glass151bbbf2019-07-08 14:25:41 -06002727 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002728 'cbfs/u-boot:image-pos': 0x30,
2729 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002730 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002731 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002732 }, props)
2733
Simon Glass3c9b4f22019-07-08 14:25:42 -06002734 def testCbfsBadType(self):
2735 """Test an image header with a no specified location is detected"""
2736 with self.assertRaises(ValueError) as e:
2737 self._DoReadFile('126_cbfs_bad_type.dts')
2738 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2739
Simon Glass6b156f82019-07-08 14:25:43 -06002740 def testList(self):
2741 """Test listing the files in an image"""
2742 self._CheckLz4()
2743 data = self._DoReadFile('127_list.dts')
2744 image = control.images['image']
2745 entries = image.BuildEntryList()
2746 self.assertEqual(7, len(entries))
2747
2748 ent = entries[0]
2749 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002750 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002751 self.assertEqual('section', ent.etype)
2752 self.assertEqual(len(data), ent.size)
2753 self.assertEqual(0, ent.image_pos)
2754 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002755 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002756
2757 ent = entries[1]
2758 self.assertEqual(1, ent.indent)
2759 self.assertEqual('u-boot', ent.name)
2760 self.assertEqual('u-boot', ent.etype)
2761 self.assertEqual(len(U_BOOT_DATA), ent.size)
2762 self.assertEqual(0, ent.image_pos)
2763 self.assertEqual(None, ent.uncomp_size)
2764 self.assertEqual(0, ent.offset)
2765
2766 ent = entries[2]
2767 self.assertEqual(1, ent.indent)
2768 self.assertEqual('section', ent.name)
2769 self.assertEqual('section', ent.etype)
2770 section_size = ent.size
2771 self.assertEqual(0x100, ent.image_pos)
2772 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002773 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002774
2775 ent = entries[3]
2776 self.assertEqual(2, ent.indent)
2777 self.assertEqual('cbfs', ent.name)
2778 self.assertEqual('cbfs', ent.etype)
2779 self.assertEqual(0x400, ent.size)
2780 self.assertEqual(0x100, ent.image_pos)
2781 self.assertEqual(None, ent.uncomp_size)
2782 self.assertEqual(0, ent.offset)
2783
2784 ent = entries[4]
2785 self.assertEqual(3, ent.indent)
2786 self.assertEqual('u-boot', ent.name)
2787 self.assertEqual('u-boot', ent.etype)
2788 self.assertEqual(len(U_BOOT_DATA), ent.size)
2789 self.assertEqual(0x138, ent.image_pos)
2790 self.assertEqual(None, ent.uncomp_size)
2791 self.assertEqual(0x38, ent.offset)
2792
2793 ent = entries[5]
2794 self.assertEqual(3, ent.indent)
2795 self.assertEqual('u-boot-dtb', ent.name)
2796 self.assertEqual('text', ent.etype)
2797 self.assertGreater(len(COMPRESS_DATA), ent.size)
2798 self.assertEqual(0x178, ent.image_pos)
2799 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2800 self.assertEqual(0x78, ent.offset)
2801
2802 ent = entries[6]
2803 self.assertEqual(2, ent.indent)
2804 self.assertEqual('u-boot-dtb', ent.name)
2805 self.assertEqual('u-boot-dtb', ent.etype)
2806 self.assertEqual(0x500, ent.image_pos)
2807 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2808 dtb_size = ent.size
2809 # Compressing this data expands it since headers are added
2810 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2811 self.assertEqual(0x400, ent.offset)
2812
2813 self.assertEqual(len(data), 0x100 + section_size)
2814 self.assertEqual(section_size, 0x400 + dtb_size)
2815
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002816 def testFindFdtmap(self):
2817 """Test locating an FDT map in an image"""
2818 self._CheckLz4()
2819 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2820 image = control.images['image']
2821 entries = image.GetEntries()
2822 entry = entries['fdtmap']
2823 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2824
2825 def testFindFdtmapMissing(self):
2826 """Test failing to locate an FDP map"""
2827 data = self._DoReadFile('005_simple.dts')
2828 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2829
Simon Glassed39a3c2019-07-08 14:25:45 -06002830 def testFindImageHeader(self):
2831 """Test locating a image header"""
2832 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002833 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002834 image = control.images['image']
2835 entries = image.GetEntries()
2836 entry = entries['fdtmap']
2837 # The header should point to the FDT map
2838 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2839
2840 def testFindImageHeaderStart(self):
2841 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002842 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002843 image = control.images['image']
2844 entries = image.GetEntries()
2845 entry = entries['fdtmap']
2846 # The header should point to the FDT map
2847 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2848
2849 def testFindImageHeaderMissing(self):
2850 """Test failing to locate an image header"""
2851 data = self._DoReadFile('005_simple.dts')
2852 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2853
Simon Glassb8424fa2019-07-08 14:25:46 -06002854 def testReadImage(self):
2855 """Test reading an image and accessing its FDT map"""
2856 self._CheckLz4()
2857 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002858 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002859 orig_image = control.images['image']
2860 image = Image.FromFile(image_fname)
2861 self.assertEqual(orig_image.GetEntries().keys(),
2862 image.GetEntries().keys())
2863
2864 orig_entry = orig_image.GetEntries()['fdtmap']
2865 entry = image.GetEntries()['fdtmap']
Brandon Maiera657bc62024-06-04 16:16:05 +00002866 self.assertEqual(orig_entry.offset, entry.offset)
2867 self.assertEqual(orig_entry.size, entry.size)
2868 self.assertEqual(orig_entry.image_pos, entry.image_pos)
Simon Glassb8424fa2019-07-08 14:25:46 -06002869
2870 def testReadImageNoHeader(self):
2871 """Test accessing an image's FDT map without an image header"""
2872 self._CheckLz4()
2873 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002874 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002875 image = Image.FromFile(image_fname)
2876 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002877 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002878
2879 def testReadImageFail(self):
2880 """Test failing to read an image image's FDT map"""
2881 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002882 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002883 with self.assertRaises(ValueError) as e:
2884 image = Image.FromFile(image_fname)
2885 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002886
Simon Glassb2fd11d2019-07-08 14:25:48 -06002887 def testListCmd(self):
2888 """Test listing the files in an image using an Fdtmap"""
2889 self._CheckLz4()
2890 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2891
2892 # lz4 compression size differs depending on the version
2893 image = control.images['image']
2894 entries = image.GetEntries()
2895 section_size = entries['section'].size
2896 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2897 fdtmap_offset = entries['fdtmap'].offset
2898
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002899 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002900 try:
2901 tmpdir, updated_fname = self._SetupImageInTmpdir()
2902 with test_util.capture_sys_output() as (stdout, stderr):
2903 self._DoBinman('ls', '-i', updated_fname)
2904 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002905 if tmpdir:
2906 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002907 lines = stdout.getvalue().splitlines()
2908 expected = [
2909'Name Image-pos Size Entry-type Offset Uncomp-size',
2910'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002911'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002912' u-boot 0 4 u-boot 0',
2913' section 100 %x section 100' % section_size,
2914' cbfs 100 400 cbfs 0',
Simon Glassfa144222023-10-14 14:40:28 -06002915' u-boot 120 4 u-boot 20',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002916' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002917' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002918' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002919 (fdtmap_offset, fdtmap_offset),
2920' image-header bf8 8 image-header bf8',
2921 ]
2922 self.assertEqual(expected, lines)
2923
2924 def testListCmdFail(self):
2925 """Test failing to list an image"""
2926 self._DoReadFile('005_simple.dts')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002927 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002928 try:
2929 tmpdir, updated_fname = self._SetupImageInTmpdir()
2930 with self.assertRaises(ValueError) as e:
2931 self._DoBinman('ls', '-i', updated_fname)
2932 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002933 if tmpdir:
2934 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002935 self.assertIn("Cannot find FDT map in image", str(e.exception))
2936
2937 def _RunListCmd(self, paths, expected):
2938 """List out entries and check the result
2939
2940 Args:
2941 paths: List of paths to pass to the list command
2942 expected: Expected list of filenames to be returned, in order
2943 """
2944 self._CheckLz4()
2945 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002946 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002947 image = Image.FromFile(image_fname)
2948 lines = image.GetListEntries(paths)[1]
2949 files = [line[0].strip() for line in lines[1:]]
2950 self.assertEqual(expected, files)
2951
2952 def testListCmdSection(self):
2953 """Test listing the files in a section"""
2954 self._RunListCmd(['section'],
2955 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2956
2957 def testListCmdFile(self):
2958 """Test listing a particular file"""
2959 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2960
2961 def testListCmdWildcard(self):
2962 """Test listing a wildcarded file"""
2963 self._RunListCmd(['*boot*'],
2964 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2965
2966 def testListCmdWildcardMulti(self):
2967 """Test listing a wildcarded file"""
2968 self._RunListCmd(['*cb*', '*head*'],
2969 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2970
2971 def testListCmdEmpty(self):
2972 """Test listing a wildcarded file"""
2973 self._RunListCmd(['nothing'], [])
2974
2975 def testListCmdPath(self):
2976 """Test listing the files in a sub-entry of a section"""
2977 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2978
Simon Glass4c613bf2019-07-08 14:25:50 -06002979 def _RunExtractCmd(self, entry_name, decomp=True):
2980 """Extract an entry from an image
2981
2982 Args:
2983 entry_name: Entry name to extract
2984 decomp: True to decompress the data if compressed, False to leave
2985 it in its raw uncompressed format
2986
2987 Returns:
2988 data from entry
2989 """
2990 self._CheckLz4()
2991 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002992 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002993 return control.ReadEntry(image_fname, entry_name, decomp)
2994
2995 def testExtractSimple(self):
2996 """Test extracting a single file"""
2997 data = self._RunExtractCmd('u-boot')
2998 self.assertEqual(U_BOOT_DATA, data)
2999
Simon Glass980a2842019-07-08 14:25:52 -06003000 def testExtractSection(self):
3001 """Test extracting the files in a section"""
3002 data = self._RunExtractCmd('section')
3003 cbfs_data = data[:0x400]
3004 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06003005 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06003006 dtb_data = data[0x400:]
3007 dtb = self._decompress(dtb_data)
3008 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3009
3010 def testExtractCompressed(self):
3011 """Test extracting compressed data"""
3012 data = self._RunExtractCmd('section/u-boot-dtb')
3013 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3014
3015 def testExtractRaw(self):
3016 """Test extracting compressed data without decompressing it"""
3017 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
3018 dtb = self._decompress(data)
3019 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3020
3021 def testExtractCbfs(self):
3022 """Test extracting CBFS data"""
3023 data = self._RunExtractCmd('section/cbfs/u-boot')
3024 self.assertEqual(U_BOOT_DATA, data)
3025
3026 def testExtractCbfsCompressed(self):
3027 """Test extracting CBFS compressed data"""
3028 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
3029 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3030
3031 def testExtractCbfsRaw(self):
3032 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003033 bintool = self.comp_bintools['lzma_alone']
3034 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06003035 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003036 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06003037 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3038
Simon Glass4c613bf2019-07-08 14:25:50 -06003039 def testExtractBadEntry(self):
3040 """Test extracting a bad section path"""
3041 with self.assertRaises(ValueError) as e:
3042 self._RunExtractCmd('section/does-not-exist')
3043 self.assertIn("Entry 'does-not-exist' not found in '/section'",
3044 str(e.exception))
3045
3046 def testExtractMissingFile(self):
3047 """Test extracting file that does not exist"""
3048 with self.assertRaises(IOError) as e:
3049 control.ReadEntry('missing-file', 'name')
3050
3051 def testExtractBadFile(self):
3052 """Test extracting an invalid file"""
3053 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07003054 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06003055 with self.assertRaises(ValueError) as e:
3056 control.ReadEntry(fname, 'name')
3057
Simon Glass980a2842019-07-08 14:25:52 -06003058 def testExtractCmd(self):
3059 """Test extracting a file fron an image on the command line"""
3060 self._CheckLz4()
3061 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06003062 fname = os.path.join(self._indir, 'output.extact')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003063 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06003064 try:
3065 tmpdir, updated_fname = self._SetupImageInTmpdir()
3066 with test_util.capture_sys_output() as (stdout, stderr):
3067 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3068 '-f', fname)
3069 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003070 if tmpdir:
3071 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07003072 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003073 self.assertEqual(U_BOOT_DATA, data)
3074
3075 def testExtractOneEntry(self):
3076 """Test extracting a single entry fron an image """
3077 self._CheckLz4()
3078 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003079 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003080 fname = os.path.join(self._indir, 'output.extact')
3081 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003082 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003083 self.assertEqual(U_BOOT_DATA, data)
3084
3085 def _CheckExtractOutput(self, decomp):
3086 """Helper to test file output with and without decompression
3087
3088 Args:
3089 decomp: True to decompress entry data, False to output it raw
3090 """
3091 def _CheckPresent(entry_path, expect_data, expect_size=None):
3092 """Check and remove expected file
3093
3094 This checks the data/size of a file and removes the file both from
3095 the outfiles set and from the output directory. Once all files are
3096 processed, both the set and directory should be empty.
3097
3098 Args:
3099 entry_path: Entry path
3100 expect_data: Data to expect in file, or None to skip check
3101 expect_size: Size of data to expect in file, or None to skip
3102 """
3103 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003104 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003105 os.remove(path)
3106 if expect_data:
3107 self.assertEqual(expect_data, data)
3108 elif expect_size:
3109 self.assertEqual(expect_size, len(data))
3110 outfiles.remove(path)
3111
3112 def _CheckDirPresent(name):
3113 """Remove expected directory
3114
3115 This gives an error if the directory does not exist as expected
3116
3117 Args:
3118 name: Name of directory to remove
3119 """
3120 path = os.path.join(outdir, name)
3121 os.rmdir(path)
3122
3123 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003124 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003125 outdir = os.path.join(self._indir, 'extract')
3126 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3127
3128 # Create a set of all file that were output (should be 9)
3129 outfiles = set()
3130 for root, dirs, files in os.walk(outdir):
3131 outfiles |= set([os.path.join(root, fname) for fname in files])
3132 self.assertEqual(9, len(outfiles))
3133 self.assertEqual(9, len(einfos))
3134
3135 image = control.images['image']
3136 entries = image.GetEntries()
3137
3138 # Check the 9 files in various ways
3139 section = entries['section']
3140 section_entries = section.GetEntries()
3141 cbfs_entries = section_entries['cbfs'].GetEntries()
3142 _CheckPresent('u-boot', U_BOOT_DATA)
3143 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3144 dtb_len = EXTRACT_DTB_SIZE
3145 if not decomp:
3146 dtb_len = cbfs_entries['u-boot-dtb'].size
3147 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3148 if not decomp:
3149 dtb_len = section_entries['u-boot-dtb'].size
3150 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3151
3152 fdtmap = entries['fdtmap']
3153 _CheckPresent('fdtmap', fdtmap.data)
3154 hdr = entries['image-header']
3155 _CheckPresent('image-header', hdr.data)
3156
3157 _CheckPresent('section/root', section.data)
3158 cbfs = section_entries['cbfs']
3159 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003160 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003161 _CheckPresent('root', data)
3162
3163 # There should be no files left. Remove all the directories to check.
3164 # If there are any files/dirs remaining, one of these checks will fail.
3165 self.assertEqual(0, len(outfiles))
3166 _CheckDirPresent('section/cbfs')
3167 _CheckDirPresent('section')
3168 _CheckDirPresent('')
3169 self.assertFalse(os.path.exists(outdir))
3170
3171 def testExtractAllEntries(self):
3172 """Test extracting all entries"""
3173 self._CheckLz4()
3174 self._CheckExtractOutput(decomp=True)
3175
3176 def testExtractAllEntriesRaw(self):
3177 """Test extracting all entries without decompressing them"""
3178 self._CheckLz4()
3179 self._CheckExtractOutput(decomp=False)
3180
3181 def testExtractSelectedEntries(self):
3182 """Test extracting some entries"""
3183 self._CheckLz4()
3184 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003185 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003186 outdir = os.path.join(self._indir, 'extract')
3187 einfos = control.ExtractEntries(image_fname, None, outdir,
3188 ['*cb*', '*head*'])
3189
3190 # File output is tested by testExtractAllEntries(), so just check that
3191 # the expected entries are selected
3192 names = [einfo.name for einfo in einfos]
3193 self.assertEqual(names,
3194 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3195
3196 def testExtractNoEntryPaths(self):
3197 """Test extracting some entries"""
3198 self._CheckLz4()
3199 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003200 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003201 with self.assertRaises(ValueError) as e:
3202 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003203 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003204 str(e.exception))
3205
3206 def testExtractTooManyEntryPaths(self):
3207 """Test extracting some entries"""
3208 self._CheckLz4()
3209 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003210 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003211 with self.assertRaises(ValueError) as e:
3212 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003213 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003214 str(e.exception))
3215
Simon Glass52d06212019-07-08 14:25:53 -06003216 def testPackAlignSection(self):
3217 """Test that sections can have alignment"""
3218 self._DoReadFile('131_pack_align_section.dts')
3219
3220 self.assertIn('image', control.images)
3221 image = control.images['image']
3222 entries = image.GetEntries()
3223 self.assertEqual(3, len(entries))
3224
3225 # First u-boot
3226 self.assertIn('u-boot', entries)
3227 entry = entries['u-boot']
3228 self.assertEqual(0, entry.offset)
3229 self.assertEqual(0, entry.image_pos)
3230 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3231 self.assertEqual(len(U_BOOT_DATA), entry.size)
3232
3233 # Section0
3234 self.assertIn('section0', entries)
3235 section0 = entries['section0']
3236 self.assertEqual(0x10, section0.offset)
3237 self.assertEqual(0x10, section0.image_pos)
3238 self.assertEqual(len(U_BOOT_DATA), section0.size)
3239
3240 # Second u-boot
3241 section_entries = section0.GetEntries()
3242 self.assertIn('u-boot', section_entries)
3243 entry = section_entries['u-boot']
3244 self.assertEqual(0, entry.offset)
3245 self.assertEqual(0x10, entry.image_pos)
3246 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3247 self.assertEqual(len(U_BOOT_DATA), entry.size)
3248
3249 # Section1
3250 self.assertIn('section1', entries)
3251 section1 = entries['section1']
3252 self.assertEqual(0x14, section1.offset)
3253 self.assertEqual(0x14, section1.image_pos)
3254 self.assertEqual(0x20, section1.size)
3255
3256 # Second u-boot
3257 section_entries = section1.GetEntries()
3258 self.assertIn('u-boot', section_entries)
3259 entry = section_entries['u-boot']
3260 self.assertEqual(0, entry.offset)
3261 self.assertEqual(0x14, entry.image_pos)
3262 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3263 self.assertEqual(len(U_BOOT_DATA), entry.size)
3264
3265 # Section2
3266 self.assertIn('section2', section_entries)
3267 section2 = section_entries['section2']
3268 self.assertEqual(0x4, section2.offset)
3269 self.assertEqual(0x18, section2.image_pos)
3270 self.assertEqual(4, section2.size)
3271
3272 # Third u-boot
3273 section_entries = section2.GetEntries()
3274 self.assertIn('u-boot', section_entries)
3275 entry = section_entries['u-boot']
3276 self.assertEqual(0, entry.offset)
3277 self.assertEqual(0x18, entry.image_pos)
3278 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3279 self.assertEqual(len(U_BOOT_DATA), entry.size)
3280
Simon Glassf8a54bc2019-07-20 12:23:56 -06003281 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3282 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003283 """Replace an entry in an image
3284
3285 This writes the entry data to update it, then opens the updated file and
3286 returns the value that it now finds there.
3287
3288 Args:
3289 entry_name: Entry name to replace
3290 data: Data to replace it with
3291 decomp: True to compress the data if needed, False if data is
3292 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003293 allow_resize: True to allow entries to change size, False to raise
3294 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003295
3296 Returns:
3297 Tuple:
3298 data from entry
3299 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003300 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003301 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003302 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003303 update_dtb=True)[1]
3304
3305 self.assertIn('image', control.images)
3306 image = control.images['image']
3307 entries = image.GetEntries()
3308 orig_dtb_data = entries['u-boot-dtb'].data
3309 orig_fdtmap_data = entries['fdtmap'].data
3310
Simon Glass80025522022-01-29 14:14:04 -07003311 image_fname = tools.get_output_filename('image.bin')
3312 updated_fname = tools.get_output_filename('image-updated.bin')
3313 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003314 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3315 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003316 data = control.ReadEntry(updated_fname, entry_name, decomp)
3317
Simon Glassf8a54bc2019-07-20 12:23:56 -06003318 # The DT data should not change unless resized:
3319 if not allow_resize:
3320 new_dtb_data = entries['u-boot-dtb'].data
3321 self.assertEqual(new_dtb_data, orig_dtb_data)
3322 new_fdtmap_data = entries['fdtmap'].data
3323 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003324
Simon Glassf8a54bc2019-07-20 12:23:56 -06003325 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003326
3327 def testReplaceSimple(self):
3328 """Test replacing a single file"""
3329 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003330 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3331 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003332 self.assertEqual(expected, data)
3333
3334 # Test that the state looks right. There should be an FDT for the fdtmap
3335 # that we jsut read back in, and it should match what we find in the
3336 # 'control' tables. Checking for an FDT that does not exist should
3337 # return None.
3338 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003339 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003340 self.assertEqual(expected_fdtmap, fdtmap)
3341
3342 dtb = state.GetFdtForEtype('fdtmap')
3343 self.assertEqual(dtb.GetContents(), fdtmap)
3344
3345 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3346 self.assertIsNone(missing_path)
3347 self.assertIsNone(missing_fdtmap)
3348
3349 missing_dtb = state.GetFdtForEtype('missing')
3350 self.assertIsNone(missing_dtb)
3351
3352 self.assertEqual('/binman', state.fdt_path_prefix)
3353
3354 def testReplaceResizeFail(self):
3355 """Test replacing a file by something larger"""
3356 expected = U_BOOT_DATA + b'x'
3357 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003358 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3359 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003360 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3361 str(e.exception))
3362
3363 def testReplaceMulti(self):
3364 """Test replacing entry data where multiple images are generated"""
3365 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3366 update_dtb=True)[0]
3367 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003368 updated_fname = tools.get_output_filename('image-updated.bin')
3369 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003370 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003371 control.WriteEntry(updated_fname, entry_name, expected,
3372 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003373 data = control.ReadEntry(updated_fname, entry_name)
3374 self.assertEqual(expected, data)
3375
3376 # Check the state looks right.
3377 self.assertEqual('/binman/image', state.fdt_path_prefix)
3378
3379 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003380 image_fname = tools.get_output_filename('first-image.bin')
3381 updated_fname = tools.get_output_filename('first-updated.bin')
3382 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003383 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003384 control.WriteEntry(updated_fname, entry_name, expected,
3385 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003386 data = control.ReadEntry(updated_fname, entry_name)
3387 self.assertEqual(expected, data)
3388
3389 # Check the state looks right.
3390 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003391
Simon Glassfb30e292019-07-20 12:23:51 -06003392 def testUpdateFdtAllRepack(self):
3393 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003394 self._SetupSplElf()
3395 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003396 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3397 SECTION_SIZE = 0x300
3398 DTB_SIZE = 602
3399 FDTMAP_SIZE = 608
3400 base_expected = {
3401 'offset': 0,
3402 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3403 'image-pos': 0,
3404 'section:offset': 0,
3405 'section:size': SECTION_SIZE,
3406 'section:image-pos': 0,
3407 'section/u-boot-dtb:offset': 4,
3408 'section/u-boot-dtb:size': 636,
3409 'section/u-boot-dtb:image-pos': 4,
3410 'u-boot-spl-dtb:offset': SECTION_SIZE,
3411 'u-boot-spl-dtb:size': DTB_SIZE,
3412 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3413 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3414 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3415 'u-boot-tpl-dtb:size': DTB_SIZE,
3416 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3417 'fdtmap:size': FDTMAP_SIZE,
3418 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3419 }
3420 main_expected = {
3421 'section:orig-size': SECTION_SIZE,
3422 'section/u-boot-dtb:orig-offset': 4,
3423 }
3424
3425 # We expect three device-tree files in the output, with the first one
3426 # within a fixed-size section.
3427 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3428 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3429 # main U-Boot tree. All three should have the same positions and offset
3430 # except that the main tree should include the main_expected properties
3431 start = 4
3432 for item in ['', 'spl', 'tpl', None]:
3433 if item is None:
3434 start += 16 # Move past fdtmap header
3435 dtb = fdt.Fdt.FromData(data[start:])
3436 dtb.Scan()
3437 props = self._GetPropTree(dtb,
3438 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3439 prefix='/' if item is None else '/binman/')
3440 expected = dict(base_expected)
3441 if item:
3442 expected[item] = 0
3443 else:
3444 # Main DTB and fdtdec should include the 'orig-' properties
3445 expected.update(main_expected)
3446 # Helpful for debugging:
3447 #for prop in sorted(props):
3448 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3449 self.assertEqual(expected, props)
3450 if item == '':
3451 start = SECTION_SIZE
3452 else:
3453 start += dtb._fdt_obj.totalsize()
3454
Simon Glass11453762019-07-20 12:23:55 -06003455 def testFdtmapHeaderMiddle(self):
3456 """Test an FDT map in the middle of an image when it should be at end"""
3457 with self.assertRaises(ValueError) as e:
3458 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3459 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3460 str(e.exception))
3461
3462 def testFdtmapHeaderStartBad(self):
3463 """Test an FDT map in middle of an image when it should be at start"""
3464 with self.assertRaises(ValueError) as e:
3465 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3466 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3467 str(e.exception))
3468
3469 def testFdtmapHeaderEndBad(self):
3470 """Test an FDT map at the start of an image when it should be at end"""
3471 with self.assertRaises(ValueError) as e:
3472 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3473 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3474 str(e.exception))
3475
3476 def testFdtmapHeaderNoSize(self):
3477 """Test an image header at the end of an image with undefined size"""
3478 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3479
Simon Glassf8a54bc2019-07-20 12:23:56 -06003480 def testReplaceResize(self):
3481 """Test replacing a single file in an entry with a larger file"""
3482 expected = U_BOOT_DATA + b'x'
3483 data, _, image = self._RunReplaceCmd('u-boot', expected,
3484 dts='139_replace_repack.dts')
3485 self.assertEqual(expected, data)
3486
3487 entries = image.GetEntries()
3488 dtb_data = entries['u-boot-dtb'].data
3489 dtb = fdt.Fdt.FromData(dtb_data)
3490 dtb.Scan()
3491
3492 # The u-boot section should now be larger in the dtb
3493 node = dtb.GetNode('/binman/u-boot')
3494 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3495
3496 # Same for the fdtmap
3497 fdata = entries['fdtmap'].data
3498 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3499 fdtb.Scan()
3500 fnode = fdtb.GetNode('/u-boot')
3501 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3502
3503 def testReplaceResizeNoRepack(self):
3504 """Test replacing an entry with a larger file when not allowed"""
3505 expected = U_BOOT_DATA + b'x'
3506 with self.assertRaises(ValueError) as e:
3507 self._RunReplaceCmd('u-boot', expected)
3508 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3509 str(e.exception))
3510
Simon Glass9d8ee322019-07-20 12:23:58 -06003511 def testEntryShrink(self):
3512 """Test contracting an entry after it is packed"""
3513 try:
3514 state.SetAllowEntryContraction(True)
3515 data = self._DoReadFileDtb('140_entry_shrink.dts',
3516 update_dtb=True)[0]
3517 finally:
3518 state.SetAllowEntryContraction(False)
3519 self.assertEqual(b'a', data[:1])
3520 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3521 self.assertEqual(b'a', data[-1:])
3522
3523 def testEntryShrinkFail(self):
3524 """Test not being allowed to contract an entry after it is packed"""
3525 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3526
3527 # In this case there is a spare byte at the end of the data. The size of
3528 # the contents is only 1 byte but we still have the size before it
3529 # shrunk.
3530 self.assertEqual(b'a\0', data[:2])
3531 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3532 self.assertEqual(b'a\0', data[-2:])
3533
Simon Glass70e32982019-07-20 12:24:01 -06003534 def testDescriptorOffset(self):
3535 """Test that the Intel descriptor is always placed at at the start"""
3536 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3537 image = control.images['image']
3538 entries = image.GetEntries()
3539 desc = entries['intel-descriptor']
Simon Glassed836ac2025-02-26 09:26:17 -07003540 self.assertEqual(0xff800000, desc.offset)
3541 self.assertEqual(0xff800000, desc.image_pos)
Simon Glass70e32982019-07-20 12:24:01 -06003542
Simon Glass37fdd142019-07-20 12:24:06 -06003543 def testReplaceCbfs(self):
3544 """Test replacing a single file in CBFS without changing the size"""
3545 self._CheckLz4()
3546 expected = b'x' * len(U_BOOT_DATA)
3547 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003548 updated_fname = tools.get_output_filename('image-updated.bin')
3549 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003550 entry_name = 'section/cbfs/u-boot'
3551 control.WriteEntry(updated_fname, entry_name, expected,
3552 allow_resize=True)
3553 data = control.ReadEntry(updated_fname, entry_name)
3554 self.assertEqual(expected, data)
3555
3556 def testReplaceResizeCbfs(self):
3557 """Test replacing a single file in CBFS with one of a different size"""
3558 self._CheckLz4()
3559 expected = U_BOOT_DATA + b'x'
3560 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003561 updated_fname = tools.get_output_filename('image-updated.bin')
3562 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003563 entry_name = 'section/cbfs/u-boot'
3564 control.WriteEntry(updated_fname, entry_name, expected,
3565 allow_resize=True)
3566 data = control.ReadEntry(updated_fname, entry_name)
3567 self.assertEqual(expected, data)
3568
Simon Glass30033c22019-07-20 12:24:15 -06003569 def _SetupForReplace(self):
3570 """Set up some files to use to replace entries
3571
3572 This generates an image, copies it to a new file, extracts all the files
3573 in it and updates some of them
3574
3575 Returns:
3576 List
3577 Image filename
3578 Output directory
3579 Expected values for updated entries, each a string
3580 """
3581 data = self._DoReadFileRealDtb('143_replace_all.dts')
3582
Simon Glass80025522022-01-29 14:14:04 -07003583 updated_fname = tools.get_output_filename('image-updated.bin')
3584 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003585
3586 outdir = os.path.join(self._indir, 'extract')
3587 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3588
3589 expected1 = b'x' + U_BOOT_DATA + b'y'
3590 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003591 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003592
3593 expected2 = b'a' + U_BOOT_DATA + b'b'
3594 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003595 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003596
3597 expected_text = b'not the same text'
3598 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003599 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003600
3601 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3602 dtb = fdt.FdtScan(dtb_fname)
3603 node = dtb.GetNode('/binman/text')
3604 node.AddString('my-property', 'the value')
3605 dtb.Sync(auto_resize=True)
3606 dtb.Flush()
3607
3608 return updated_fname, outdir, expected1, expected2, expected_text
3609
3610 def _CheckReplaceMultiple(self, entry_paths):
3611 """Handle replacing the contents of multiple entries
3612
3613 Args:
3614 entry_paths: List of entry paths to replace
3615
3616 Returns:
3617 List
3618 Dict of entries in the image:
3619 key: Entry name
3620 Value: Entry object
3621 Expected values for updated entries, each a string
3622 """
3623 updated_fname, outdir, expected1, expected2, expected_text = (
3624 self._SetupForReplace())
3625 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3626
3627 image = Image.FromFile(updated_fname)
3628 image.LoadData()
3629 return image.GetEntries(), expected1, expected2, expected_text
3630
3631 def testReplaceAll(self):
3632 """Test replacing the contents of all entries"""
3633 entries, expected1, expected2, expected_text = (
3634 self._CheckReplaceMultiple([]))
3635 data = entries['u-boot'].data
3636 self.assertEqual(expected1, data)
3637
3638 data = entries['u-boot2'].data
3639 self.assertEqual(expected2, data)
3640
3641 data = entries['text'].data
3642 self.assertEqual(expected_text, data)
3643
3644 # Check that the device tree is updated
3645 data = entries['u-boot-dtb'].data
3646 dtb = fdt.Fdt.FromData(data)
3647 dtb.Scan()
3648 node = dtb.GetNode('/binman/text')
3649 self.assertEqual('the value', node.props['my-property'].value)
3650
3651 def testReplaceSome(self):
3652 """Test replacing the contents of a few entries"""
3653 entries, expected1, expected2, expected_text = (
3654 self._CheckReplaceMultiple(['u-boot2', 'text']))
3655
3656 # This one should not change
3657 data = entries['u-boot'].data
3658 self.assertEqual(U_BOOT_DATA, data)
3659
3660 data = entries['u-boot2'].data
3661 self.assertEqual(expected2, data)
3662
3663 data = entries['text'].data
3664 self.assertEqual(expected_text, data)
3665
3666 def testReplaceCmd(self):
3667 """Test replacing a file fron an image on the command line"""
3668 self._DoReadFileRealDtb('143_replace_all.dts')
3669
3670 try:
3671 tmpdir, updated_fname = self._SetupImageInTmpdir()
3672
3673 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3674 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003675 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003676
3677 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003678 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003679 self.assertEqual(expected, data[:len(expected)])
3680 map_fname = os.path.join(tmpdir, 'image-updated.map')
3681 self.assertFalse(os.path.exists(map_fname))
3682 finally:
3683 shutil.rmtree(tmpdir)
3684
3685 def testReplaceCmdSome(self):
3686 """Test replacing some files fron an image on the command line"""
3687 updated_fname, outdir, expected1, expected2, expected_text = (
3688 self._SetupForReplace())
3689
3690 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3691 'u-boot2', 'text')
3692
Simon Glass80025522022-01-29 14:14:04 -07003693 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003694 image = Image.FromFile(updated_fname)
3695 image.LoadData()
3696 entries = image.GetEntries()
3697
3698 # This one should not change
3699 data = entries['u-boot'].data
3700 self.assertEqual(U_BOOT_DATA, data)
3701
3702 data = entries['u-boot2'].data
3703 self.assertEqual(expected2, data)
3704
3705 data = entries['text'].data
3706 self.assertEqual(expected_text, data)
3707
3708 def testReplaceMissing(self):
3709 """Test replacing entries where the file is missing"""
3710 updated_fname, outdir, expected1, expected2, expected_text = (
3711 self._SetupForReplace())
3712
3713 # Remove one of the files, to generate a warning
3714 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3715 os.remove(u_boot_fname1)
3716
3717 with test_util.capture_sys_output() as (stdout, stderr):
3718 control.ReplaceEntries(updated_fname, None, outdir, [])
3719 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003720 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003721
3722 def testReplaceCmdMap(self):
3723 """Test replacing a file fron an image on the command line"""
3724 self._DoReadFileRealDtb('143_replace_all.dts')
3725
3726 try:
3727 tmpdir, updated_fname = self._SetupImageInTmpdir()
3728
3729 fname = os.path.join(self._indir, 'update-u-boot.bin')
3730 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003731 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003732
3733 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3734 '-f', fname, '-m')
3735 map_fname = os.path.join(tmpdir, 'image-updated.map')
3736 self.assertTrue(os.path.exists(map_fname))
3737 finally:
3738 shutil.rmtree(tmpdir)
3739
3740 def testReplaceNoEntryPaths(self):
3741 """Test replacing an entry without an entry path"""
3742 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003743 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003744 with self.assertRaises(ValueError) as e:
3745 control.ReplaceEntries(image_fname, 'fname', None, [])
3746 self.assertIn('Must specify an entry path to read with -f',
3747 str(e.exception))
3748
3749 def testReplaceTooManyEntryPaths(self):
3750 """Test extracting some entries"""
3751 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003752 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003753 with self.assertRaises(ValueError) as e:
3754 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3755 self.assertIn('Must specify exactly one entry path to write with -f',
3756 str(e.exception))
3757
Simon Glass0b074d62019-08-24 07:22:48 -06003758 def testPackReset16(self):
3759 """Test that an image with an x86 reset16 region can be created"""
3760 data = self._DoReadFile('144_x86_reset16.dts')
3761 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3762
3763 def testPackReset16Spl(self):
3764 """Test that an image with an x86 reset16-spl region can be created"""
3765 data = self._DoReadFile('145_x86_reset16_spl.dts')
3766 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3767
3768 def testPackReset16Tpl(self):
3769 """Test that an image with an x86 reset16-tpl region can be created"""
3770 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3771 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3772
Simon Glass232f90c2019-08-24 07:22:50 -06003773 def testPackIntelFit(self):
3774 """Test that an image with an Intel FIT and pointer can be created"""
3775 data = self._DoReadFile('147_intel_fit.dts')
3776 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3777 fit = data[16:32];
3778 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3779 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3780
3781 image = control.images['image']
3782 entries = image.GetEntries()
Simon Glassed836ac2025-02-26 09:26:17 -07003783 expected_ptr = entries['intel-fit'].image_pos #- (1 << 32)
3784 self.assertEqual(expected_ptr, ptr + (1 << 32))
Simon Glass232f90c2019-08-24 07:22:50 -06003785
3786 def testPackIntelFitMissing(self):
3787 """Test detection of a FIT pointer with not FIT region"""
3788 with self.assertRaises(ValueError) as e:
3789 self._DoReadFile('148_intel_fit_missing.dts')
3790 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3791 str(e.exception))
3792
Simon Glass72555fa2019-11-06 17:22:44 -07003793 def _CheckSymbolsTplSection(self, dts, expected_vals):
3794 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003795 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003796 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003797 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003798 self.assertEqual(expected1, data[:upto1])
3799
3800 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003801 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003802 self.assertEqual(expected2, data[upto1:upto2])
3803
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003804 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003805 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003806 self.assertEqual(expected3, data[upto2:upto3])
3807
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003808 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003809 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3810
3811 def testSymbolsTplSection(self):
3812 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3813 self._SetupSplElf('u_boot_binman_syms')
3814 self._SetupTplElf('u_boot_binman_syms')
3815 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003816 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003817
3818 def testSymbolsTplSectionX86(self):
3819 """Test binman can assign symbols in a section with end-at-4gb"""
3820 self._SetupSplElf('u_boot_binman_syms_x86')
3821 self._SetupTplElf('u_boot_binman_syms_x86')
3822 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003823 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003824 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003825
Simon Glass98c59572019-08-24 07:23:03 -06003826 def testPackX86RomIfwiSectiom(self):
3827 """Test that a section can be placed in an IFWI region"""
3828 self._SetupIfwi('fitimage.bin')
3829 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3830 self._CheckIfwi(data)
3831
Simon Glassba7985d2019-08-24 07:23:07 -06003832 def testPackFspM(self):
3833 """Test that an image with a FSP memory-init binary can be created"""
3834 data = self._DoReadFile('152_intel_fsp_m.dts')
3835 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3836
Simon Glass4d9086d2019-10-20 21:31:35 -06003837 def testPackFspS(self):
3838 """Test that an image with a FSP silicon-init binary can be created"""
3839 data = self._DoReadFile('153_intel_fsp_s.dts')
3840 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003841
Simon Glass9ea87b22019-10-20 21:31:36 -06003842 def testPackFspT(self):
3843 """Test that an image with a FSP temp-ram-init binary can be created"""
3844 data = self._DoReadFile('154_intel_fsp_t.dts')
3845 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3846
Simon Glass48f3aad2020-07-09 18:39:31 -06003847 def testMkimage(self):
3848 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003849 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003850 data = self._DoReadFile('156_mkimage.dts')
3851
3852 # Just check that the data appears in the file somewhere
3853 self.assertIn(U_BOOT_SPL_DATA, data)
3854
Simon Glass66152ce2022-01-09 20:14:09 -07003855 def testMkimageMissing(self):
3856 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003857 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003858 with test_util.capture_sys_output() as (_, stderr):
3859 self._DoTestFile('156_mkimage.dts',
3860 force_missing_bintools='mkimage')
3861 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003862 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003863
Simon Glass5e560182020-07-09 18:39:36 -06003864 def testExtblob(self):
3865 """Test an image with an external blob"""
3866 data = self._DoReadFile('157_blob_ext.dts')
3867 self.assertEqual(REFCODE_DATA, data)
3868
3869 def testExtblobMissing(self):
3870 """Test an image with a missing external blob"""
3871 with self.assertRaises(ValueError) as e:
3872 self._DoReadFile('158_blob_ext_missing.dts')
3873 self.assertIn("Filename 'missing-file' not found in input path",
3874 str(e.exception))
3875
Simon Glass5d94cc62020-07-09 18:39:38 -06003876 def testExtblobMissingOk(self):
3877 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003878 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003879 ret = self._DoTestFile('158_blob_ext_missing.dts',
3880 allow_missing=True)
3881 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003882 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003883 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003884 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003885 self.assertIn('Some images are invalid', err)
3886
3887 def testExtblobMissingOkFlag(self):
3888 """Test an image with an missing external blob allowed with -W"""
3889 with test_util.capture_sys_output() as (stdout, stderr):
3890 ret = self._DoTestFile('158_blob_ext_missing.dts',
3891 allow_missing=True, ignore_missing=True)
3892 self.assertEqual(0, ret)
3893 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003894 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003895 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003896 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003897
3898 def testExtblobMissingOkSect(self):
3899 """Test an image with an missing external blob that is allowed"""
3900 with test_util.capture_sys_output() as (stdout, stderr):
3901 self._DoTestFile('159_blob_ext_missing_sect.dts',
3902 allow_missing=True)
3903 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003904 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003905
Simon Glasse88cef92020-07-09 18:39:41 -06003906 def testPackX86RomMeMissingDesc(self):
3907 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003908 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003909 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003910 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003911 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003912
3913 def testPackX86RomMissingIfwi(self):
3914 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3915 self._SetupIfwi('fitimage.bin')
3916 pathname = os.path.join(self._indir, 'fitimage.bin')
3917 os.remove(pathname)
3918 with test_util.capture_sys_output() as (stdout, stderr):
3919 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3920 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003921 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003922
Simon Glass2a0fa982022-02-11 13:23:21 -07003923 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003924 """Test that zero-size overlapping regions are ignored"""
3925 self._DoTestFile('160_pack_overlap_zero.dts')
3926
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003927 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003928 # The data should be inside the FIT
3929 dtb = fdt.Fdt.FromData(fit_data)
3930 dtb.Scan()
3931 fnode = dtb.GetNode('/images/kernel')
3932 self.assertIn('data', fnode.props)
3933
3934 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003935 tools.write_file(fname, fit_data)
3936 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003937
3938 # Check a few features to make sure the plumbing works. We don't need
3939 # to test the operation of mkimage or dumpimage here. First convert the
3940 # output into a dict where the keys are the fields printed by dumpimage
3941 # and the values are a list of values for each field
3942 lines = out.splitlines()
3943
3944 # Converts "Compression: gzip compressed" into two groups:
3945 # 'Compression' and 'gzip compressed'
3946 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3947 vals = collections.defaultdict(list)
3948 for line in lines:
3949 mat = re_line.match(line)
3950 vals[mat.group(1)].append(mat.group(2))
3951
Brandon Maiera657bc62024-06-04 16:16:05 +00003952 self.assertEqual('FIT description: test-desc', lines[0])
Simon Glass45d556d2020-07-09 18:39:45 -06003953 self.assertIn('Created:', lines[1])
3954 self.assertIn('Image 0 (kernel)', vals)
3955 self.assertIn('Hash value', vals)
3956 data_sizes = vals.get('Data Size')
3957 self.assertIsNotNone(data_sizes)
3958 self.assertEqual(2, len(data_sizes))
3959 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003960 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3961 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3962
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003963 # Check if entry listing correctly omits /images/
3964 image = control.images['image']
3965 fit_entry = image.GetEntries()['fit']
3966 subentries = list(fit_entry.GetEntries().keys())
3967 expected = ['kernel', 'fdt-1']
3968 self.assertEqual(expected, subentries)
3969
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003970 def testSimpleFit(self):
3971 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003972 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003973 data = self._DoReadFile('161_fit.dts')
3974 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3975 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3976 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3977
3978 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3979
3980 def testSimpleFitExpandsSubentries(self):
3981 """Test that FIT images expand their subentries"""
3982 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3983 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3984 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3985 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3986
3987 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003988
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003989 def testSimpleFitImagePos(self):
3990 """Test that we have correct image-pos for FIT subentries"""
3991 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3992 update_dtb=True)
3993 dtb = fdt.Fdt(out_dtb_fname)
3994 dtb.Scan()
3995 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3996
Simon Glassb7bad182022-03-05 20:19:01 -07003997 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003998 self.assertEqual({
3999 'image-pos': 0,
4000 'offset': 0,
4001 'size': 1890,
4002
4003 'u-boot:image-pos': 0,
4004 'u-boot:offset': 0,
4005 'u-boot:size': 4,
4006
4007 'fit:image-pos': 4,
4008 'fit:offset': 4,
4009 'fit:size': 1840,
4010
Simon Glassb7bad182022-03-05 20:19:01 -07004011 'fit/images/kernel:image-pos': 304,
4012 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004013 'fit/images/kernel:size': 4,
4014
Simon Glassb7bad182022-03-05 20:19:01 -07004015 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004016 'fit/images/kernel/u-boot:offset': 0,
4017 'fit/images/kernel/u-boot:size': 4,
4018
Simon Glassb7bad182022-03-05 20:19:01 -07004019 'fit/images/fdt-1:image-pos': 552,
4020 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004021 'fit/images/fdt-1:size': 6,
4022
Simon Glassb7bad182022-03-05 20:19:01 -07004023 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004024 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
4025 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
4026
4027 'u-boot-nodtb:image-pos': 1844,
4028 'u-boot-nodtb:offset': 1844,
4029 'u-boot-nodtb:size': 46,
4030 }, props)
4031
4032 # Actually check the data is where we think it is
4033 for node, expected in [
4034 ("u-boot", U_BOOT_DATA),
4035 ("fit/images/kernel", U_BOOT_DATA),
4036 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4037 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
4038 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
4039 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4040 ]:
4041 image_pos = props[f"{node}:image-pos"]
4042 size = props[f"{node}:size"]
4043 self.assertEqual(len(expected), size)
4044 self.assertEqual(expected, data[image_pos:image_pos+size])
4045
Simon Glass45d556d2020-07-09 18:39:45 -06004046 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06004047 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06004048 data = self._DoReadFile('162_fit_external.dts')
4049 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
4050
Simon Glass7932c882022-01-09 20:13:39 -07004051 # Size of the external-data region as set up by mkimage
4052 external_data_size = len(U_BOOT_DATA) + 2
4053 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07004054 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07004055 len(U_BOOT_NODTB_DATA))
4056
Simon Glass45d556d2020-07-09 18:39:45 -06004057 # The data should be outside the FIT
4058 dtb = fdt.Fdt.FromData(fit_data)
4059 dtb.Scan()
4060 fnode = dtb.GetNode('/images/kernel')
4061 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07004062 self.assertEqual(len(U_BOOT_DATA),
4063 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4064 fit_pos = 0x400;
4065 self.assertEqual(
4066 fit_pos,
4067 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4068
Brandon Maiera657bc62024-06-04 16:16:05 +00004069 self.assertEqual(expected_size, len(data))
Simon Glass7932c882022-01-09 20:13:39 -07004070 actual_pos = len(U_BOOT_DATA) + fit_pos
4071 self.assertEqual(U_BOOT_DATA + b'aa',
4072 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004073
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004074 def testFitExternalImagePos(self):
4075 """Test that we have correct image-pos for external FIT subentries"""
4076 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4077 update_dtb=True)
4078 dtb = fdt.Fdt(out_dtb_fname)
4079 dtb.Scan()
4080 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4081
4082 self.assertEqual({
4083 'image-pos': 0,
4084 'offset': 0,
4085 'size': 1082,
4086
4087 'u-boot:image-pos': 0,
4088 'u-boot:offset': 0,
4089 'u-boot:size': 4,
4090
4091 'fit:size': 1032,
4092 'fit:offset': 4,
4093 'fit:image-pos': 4,
4094
4095 'fit/images/kernel:size': 4,
4096 'fit/images/kernel:offset': 1024,
4097 'fit/images/kernel:image-pos': 1028,
4098
4099 'fit/images/kernel/u-boot:size': 4,
4100 'fit/images/kernel/u-boot:offset': 0,
4101 'fit/images/kernel/u-boot:image-pos': 1028,
4102
4103 'fit/images/fdt-1:size': 2,
4104 'fit/images/fdt-1:offset': 1028,
4105 'fit/images/fdt-1:image-pos': 1032,
4106
4107 'fit/images/fdt-1/_testing:size': 2,
4108 'fit/images/fdt-1/_testing:offset': 0,
4109 'fit/images/fdt-1/_testing:image-pos': 1032,
4110
4111 'u-boot-nodtb:image-pos': 1036,
4112 'u-boot-nodtb:offset': 1036,
4113 'u-boot-nodtb:size': 46,
4114 }, props)
4115
4116 # Actually check the data is where we think it is
4117 for node, expected in [
4118 ("u-boot", U_BOOT_DATA),
4119 ("fit/images/kernel", U_BOOT_DATA),
4120 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4121 ("fit/images/fdt-1", b'aa'),
4122 ("fit/images/fdt-1/_testing", b'aa'),
4123 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4124 ]:
4125 image_pos = props[f"{node}:image-pos"]
4126 size = props[f"{node}:size"]
4127 self.assertEqual(len(expected), size)
4128 self.assertEqual(expected, data[image_pos:image_pos+size])
4129
Simon Glass66152ce2022-01-09 20:14:09 -07004130 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004131 """Test that binman complains if mkimage is missing"""
4132 with self.assertRaises(ValueError) as e:
4133 self._DoTestFile('162_fit_external.dts',
4134 force_missing_bintools='mkimage')
4135 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4136 str(e.exception))
4137
4138 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004139 """Test that binman still produces a FIT image if mkimage is missing"""
4140 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004141 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004142 force_missing_bintools='mkimage')
4143 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004144 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004145
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004146 def testSectionIgnoreHashSignature(self):
4147 """Test that sections ignore hash, signature nodes for its data"""
4148 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4149 expected = (U_BOOT_DATA + U_BOOT_DATA)
4150 self.assertEqual(expected, data)
4151
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004152 def testPadInSections(self):
4153 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004154 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4155 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004156 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4157 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004158 U_BOOT_DATA)
4159 self.assertEqual(expected, data)
4160
Simon Glassd12599d2020-10-26 17:40:09 -06004161 dtb = fdt.Fdt(out_dtb_fname)
4162 dtb.Scan()
4163 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4164 expected = {
4165 'image-pos': 0,
4166 'offset': 0,
4167 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4168
4169 'section:image-pos': 0,
4170 'section:offset': 0,
4171 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4172
4173 'section/before:image-pos': 0,
4174 'section/before:offset': 0,
4175 'section/before:size': len(U_BOOT_DATA),
4176
4177 'section/u-boot:image-pos': 4,
4178 'section/u-boot:offset': 4,
4179 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4180
4181 'section/after:image-pos': 26,
4182 'section/after:offset': 26,
4183 'section/after:size': len(U_BOOT_DATA),
4184 }
4185 self.assertEqual(expected, props)
4186
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004187 def testFitImageSubentryAlignment(self):
4188 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004189 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004190 entry_args = {
4191 'test-id': TEXT_DATA,
4192 }
4193 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4194 entry_args=entry_args)
4195 dtb = fdt.Fdt.FromData(data)
4196 dtb.Scan()
4197
4198 node = dtb.GetNode('/images/kernel')
4199 data = dtb.GetProps(node)["data"].bytes
4200 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004201 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4202 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004203 self.assertEqual(expected, data)
4204
4205 node = dtb.GetNode('/images/fdt-1')
4206 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004207 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4208 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004209 U_BOOT_DTB_DATA)
4210 self.assertEqual(expected, data)
4211
4212 def testFitExtblobMissingOk(self):
4213 """Test a FIT with a missing external blob that is allowed"""
4214 with test_util.capture_sys_output() as (stdout, stderr):
4215 self._DoTestFile('168_fit_missing_blob.dts',
4216 allow_missing=True)
4217 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004218 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004219
Simon Glass21db0ff2020-09-01 05:13:54 -06004220 def testBlobNamedByArgMissing(self):
4221 """Test handling of a missing entry arg"""
4222 with self.assertRaises(ValueError) as e:
4223 self._DoReadFile('068_blob_named_by_arg.dts')
4224 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4225 str(e.exception))
4226
Simon Glass559c4de2020-09-01 05:13:58 -06004227 def testPackBl31(self):
4228 """Test that an image with an ATF BL31 binary can be created"""
4229 data = self._DoReadFile('169_atf_bl31.dts')
4230 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4231
Samuel Holland9d8cc632020-10-21 21:12:15 -05004232 def testPackScp(self):
4233 """Test that an image with an SCP binary can be created"""
4234 data = self._DoReadFile('172_scp.dts')
4235 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4236
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004237 def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True,
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004238 default_dt=None, use_seq_num=True):
Simon Glasscd2783e2024-07-20 11:49:46 +01004239 """Check an image with an FIT with multiple FDT images"""
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004240 def _CheckFdt(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004241 """Check the FDT nodes
4242
4243 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004244 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004245 expected_data: Expected contents of 'data' property
4246 """
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004247 name = 'fdt-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004248 fnode = dtb.GetNode('/images/%s' % name)
4249 self.assertIsNotNone(fnode)
4250 self.assertEqual({'description','type', 'compression', 'data'},
4251 set(fnode.props.keys()))
4252 self.assertEqual(expected_data, fnode.props['data'].bytes)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004253 description = (
4254 'fdt-test-fdt%s.dtb' % val if len(val) == 1 else
4255 'fdt-%s.dtb' % val
4256 )
4257 self.assertEqual(description, fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004258 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004259
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004260 def _CheckConfig(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004261 """Check the configuration nodes
4262
4263 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004264 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004265 expected_data: Expected contents of 'data' property
4266 """
4267 cnode = dtb.GetNode('/configurations')
4268 self.assertIn('default', cnode.props)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004269 default = (
4270 'config-2' if len(val) == 1 else
4271 'config-test-fdt2'
4272 )
4273 self.assertEqual(default, cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004274
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004275 name = 'config-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004276 fnode = dtb.GetNode('/configurations/%s' % name)
4277 self.assertIsNotNone(fnode)
4278 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4279 set(fnode.props.keys()))
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004280 description = (
4281 'conf-test-fdt%s.dtb' % val if len(val) == 1 else
4282 'conf-%s.dtb' % val
4283 )
4284 self.assertEqual(description, fnode.props['description'].value)
4285 self.assertEqual('fdt-%s' % val, fnode.props['fdt'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004286
4287 entry_args = {
Simon Glass1032acc2020-09-06 10:39:08 -06004288 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004289 }
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004290 extra_indirs = None
Simon Glasscd2783e2024-07-20 11:49:46 +01004291 if use_fdt_list:
4292 entry_args['of-list'] = 'test-fdt1 test-fdt2'
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004293 if default_dt:
4294 entry_args['default-dt'] = default_dt
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004295 if use_fdt_list:
4296 extra_indirs = [os.path.join(self._indir, TEST_FDT_SUBDIR)]
Simon Glassa435cd12020-09-01 05:13:59 -06004297 data = self._DoReadFileDtb(
Simon Glasscd2783e2024-07-20 11:49:46 +01004298 dts,
Simon Glassa435cd12020-09-01 05:13:59 -06004299 entry_args=entry_args,
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004300 extra_indirs=extra_indirs)[0]
Simon Glassa435cd12020-09-01 05:13:59 -06004301 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4302 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4303
4304 dtb = fdt.Fdt.FromData(fit_data)
4305 dtb.Scan()
4306 fnode = dtb.GetNode('/images/kernel')
4307 self.assertIn('data', fnode.props)
4308
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004309 if use_seq_num == True:
4310 # Check all the properties in fdt-1 and fdt-2
4311 _CheckFdt('1', TEST_FDT1_DATA)
4312 _CheckFdt('2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004313
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004314 # Check configurations
4315 _CheckConfig('1', TEST_FDT1_DATA)
4316 _CheckConfig('2', TEST_FDT2_DATA)
4317 else:
4318 # Check all the properties in fdt-1 and fdt-2
4319 _CheckFdt('test-fdt1', TEST_FDT1_DATA)
4320 _CheckFdt('test-fdt2', TEST_FDT2_DATA)
4321
4322 # Check configurations
4323 _CheckConfig('test-fdt1', TEST_FDT1_DATA)
4324 _CheckConfig('test-fdt2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004325
Simon Glasscd2783e2024-07-20 11:49:46 +01004326 def testFitFdt(self):
4327 """Test an image with an FIT with multiple FDT images"""
4328 self.CheckFitFdt()
4329
Simon Glassa435cd12020-09-01 05:13:59 -06004330 def testFitFdtMissingList(self):
4331 """Test handling of a missing 'of-list' entry arg"""
4332 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004333 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004334 self.assertIn("Generator node requires 'of-list' entry argument",
4335 str(e.exception))
4336
4337 def testFitFdtEmptyList(self):
4338 """Test handling of an empty 'of-list' entry arg"""
4339 entry_args = {
4340 'of-list': '',
4341 }
4342 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4343
4344 def testFitFdtMissingProp(self):
4345 """Test handling of a missing 'fit,fdt-list' property"""
4346 with self.assertRaises(ValueError) as e:
4347 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4348 self.assertIn("Generator node requires 'fit,fdt-list' property",
4349 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004350
Simon Glass1032acc2020-09-06 10:39:08 -06004351 def testFitFdtMissing(self):
4352 """Test handling of a missing 'default-dt' entry arg"""
4353 entry_args = {
4354 'of-list': 'test-fdt1 test-fdt2',
4355 }
4356 with self.assertRaises(ValueError) as e:
4357 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004358 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004359 entry_args=entry_args,
4360 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4361 self.assertIn("Generated 'default' node requires default-dt entry argument",
4362 str(e.exception))
4363
4364 def testFitFdtNotInList(self):
4365 """Test handling of a default-dt that is not in the of-list"""
4366 entry_args = {
4367 'of-list': 'test-fdt1 test-fdt2',
4368 'default-dt': 'test-fdt3',
4369 }
4370 with self.assertRaises(ValueError) as e:
4371 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004372 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004373 entry_args=entry_args,
4374 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4375 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4376 str(e.exception))
4377
Simon Glassa820af72020-09-06 10:39:09 -06004378 def testFitExtblobMissingHelp(self):
4379 """Test display of help messages when an external blob is missing"""
4380 control.missing_blob_help = control._ReadMissingBlobHelp()
4381 control.missing_blob_help['wibble'] = 'Wibble test'
4382 control.missing_blob_help['another'] = 'Another test'
4383 with test_util.capture_sys_output() as (stdout, stderr):
4384 self._DoTestFile('168_fit_missing_blob.dts',
4385 allow_missing=True)
4386 err = stderr.getvalue()
4387
4388 # We can get the tag from the name, the type or the missing-msg
4389 # property. Check all three.
4390 self.assertIn('You may need to build ARM Trusted', err)
4391 self.assertIn('Wibble test', err)
4392 self.assertIn('Another test', err)
4393
Simon Glass6f1f4d42020-09-06 10:35:32 -06004394 def testMissingBlob(self):
4395 """Test handling of a blob containing a missing file"""
4396 with self.assertRaises(ValueError) as e:
4397 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4398 self.assertIn("Filename 'missing' not found in input path",
4399 str(e.exception))
4400
Simon Glassa0729502020-09-06 10:35:33 -06004401 def testEnvironment(self):
4402 """Test adding a U-Boot environment"""
4403 data = self._DoReadFile('174_env.dts')
4404 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4405 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4406 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4407 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4408 env)
4409
4410 def testEnvironmentNoSize(self):
4411 """Test that a missing 'size' property is detected"""
4412 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004413 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004414 self.assertIn("'u-boot-env' entry must have a size property",
4415 str(e.exception))
4416
4417 def testEnvironmentTooSmall(self):
4418 """Test handling of an environment that does not fit"""
4419 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004420 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004421
4422 # checksum, start byte, environment with \0 terminator, final \0
4423 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4424 short = need - 0x8
4425 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4426 str(e.exception))
4427
Simon Glassd1fdf752020-10-26 17:40:01 -06004428 def testSkipAtStart(self):
4429 """Test handling of skip-at-start section"""
4430 data = self._DoReadFile('177_skip_at_start.dts')
4431 self.assertEqual(U_BOOT_DATA, data)
4432
4433 image = control.images['image']
4434 entries = image.GetEntries()
4435 section = entries['section']
4436 self.assertEqual(0, section.offset)
4437 self.assertEqual(len(U_BOOT_DATA), section.size)
4438 self.assertEqual(U_BOOT_DATA, section.GetData())
4439
4440 entry = section.GetEntries()['u-boot']
4441 self.assertEqual(16, entry.offset)
4442 self.assertEqual(len(U_BOOT_DATA), entry.size)
4443 self.assertEqual(U_BOOT_DATA, entry.data)
4444
4445 def testSkipAtStartPad(self):
4446 """Test handling of skip-at-start section with padded entry"""
4447 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004448 before = tools.get_bytes(0, 8)
4449 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004450 all = before + U_BOOT_DATA + after
4451 self.assertEqual(all, data)
4452
4453 image = control.images['image']
4454 entries = image.GetEntries()
4455 section = entries['section']
4456 self.assertEqual(0, section.offset)
4457 self.assertEqual(len(all), section.size)
4458 self.assertEqual(all, section.GetData())
4459
4460 entry = section.GetEntries()['u-boot']
4461 self.assertEqual(16, entry.offset)
4462 self.assertEqual(len(all), entry.size)
4463 self.assertEqual(U_BOOT_DATA, entry.data)
4464
4465 def testSkipAtStartSectionPad(self):
4466 """Test handling of skip-at-start section with padding"""
4467 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004468 before = tools.get_bytes(0, 8)
4469 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004470 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004471 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004472
4473 image = control.images['image']
4474 entries = image.GetEntries()
4475 section = entries['section']
4476 self.assertEqual(0, section.offset)
4477 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004478 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004479 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004480
4481 entry = section.GetEntries()['u-boot']
4482 self.assertEqual(16, entry.offset)
4483 self.assertEqual(len(U_BOOT_DATA), entry.size)
4484 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004485
Simon Glassbb395742020-10-26 17:40:14 -06004486 def testSectionPad(self):
4487 """Testing padding with sections"""
4488 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004489 expected = (tools.get_bytes(ord('&'), 3) +
4490 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004491 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004492 tools.get_bytes(ord('!'), 1) +
4493 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004494 self.assertEqual(expected, data)
4495
4496 def testSectionAlign(self):
4497 """Testing alignment with sections"""
4498 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4499 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004500 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004501 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004502 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004503 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004504 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4505 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004506 self.assertEqual(expected, data)
4507
Simon Glassd92c8362020-10-26 17:40:25 -06004508 def testCompressImage(self):
4509 """Test compression of the entire image"""
4510 self._CheckLz4()
4511 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4512 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4513 dtb = fdt.Fdt(out_dtb_fname)
4514 dtb.Scan()
4515 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4516 'uncomp-size'])
4517 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004518 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004519
4520 # Do a sanity check on various fields
4521 image = control.images['image']
4522 entries = image.GetEntries()
4523 self.assertEqual(2, len(entries))
4524
4525 entry = entries['blob']
4526 self.assertEqual(COMPRESS_DATA, entry.data)
4527 self.assertEqual(len(COMPRESS_DATA), entry.size)
4528
4529 entry = entries['u-boot']
4530 self.assertEqual(U_BOOT_DATA, entry.data)
4531 self.assertEqual(len(U_BOOT_DATA), entry.size)
4532
4533 self.assertEqual(len(data), image.size)
4534 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4535 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4536 orig = self._decompress(image.data)
4537 self.assertEqual(orig, image.uncomp_data)
4538
4539 expected = {
4540 'blob:offset': 0,
4541 'blob:size': len(COMPRESS_DATA),
4542 'u-boot:offset': len(COMPRESS_DATA),
4543 'u-boot:size': len(U_BOOT_DATA),
4544 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4545 'offset': 0,
4546 'image-pos': 0,
4547 'size': len(data),
4548 }
4549 self.assertEqual(expected, props)
4550
4551 def testCompressImageLess(self):
4552 """Test compression where compression reduces the image size"""
4553 self._CheckLz4()
4554 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4555 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4556 dtb = fdt.Fdt(out_dtb_fname)
4557 dtb.Scan()
4558 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4559 'uncomp-size'])
4560 orig = self._decompress(data)
4561
Brandon Maiera657bc62024-06-04 16:16:05 +00004562 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004563
4564 # Do a sanity check on various fields
4565 image = control.images['image']
4566 entries = image.GetEntries()
4567 self.assertEqual(2, len(entries))
4568
4569 entry = entries['blob']
4570 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4571 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4572
4573 entry = entries['u-boot']
4574 self.assertEqual(U_BOOT_DATA, entry.data)
4575 self.assertEqual(len(U_BOOT_DATA), entry.size)
4576
4577 self.assertEqual(len(data), image.size)
4578 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4579 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4580 image.uncomp_size)
4581 orig = self._decompress(image.data)
4582 self.assertEqual(orig, image.uncomp_data)
4583
4584 expected = {
4585 'blob:offset': 0,
4586 'blob:size': len(COMPRESS_DATA_BIG),
4587 'u-boot:offset': len(COMPRESS_DATA_BIG),
4588 'u-boot:size': len(U_BOOT_DATA),
4589 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4590 'offset': 0,
4591 'image-pos': 0,
4592 'size': len(data),
4593 }
4594 self.assertEqual(expected, props)
4595
4596 def testCompressSectionSize(self):
4597 """Test compression of a section with a fixed size"""
4598 self._CheckLz4()
4599 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4600 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4601 dtb = fdt.Fdt(out_dtb_fname)
4602 dtb.Scan()
4603 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4604 'uncomp-size'])
4605 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004606 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004607 expected = {
4608 'section/blob:offset': 0,
4609 'section/blob:size': len(COMPRESS_DATA),
4610 'section/u-boot:offset': len(COMPRESS_DATA),
4611 'section/u-boot:size': len(U_BOOT_DATA),
4612 'section:offset': 0,
4613 'section:image-pos': 0,
4614 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4615 'section:size': 0x30,
4616 'offset': 0,
4617 'image-pos': 0,
4618 'size': 0x30,
4619 }
4620 self.assertEqual(expected, props)
4621
4622 def testCompressSection(self):
4623 """Test compression of a section with no fixed size"""
4624 self._CheckLz4()
4625 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4626 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4627 dtb = fdt.Fdt(out_dtb_fname)
4628 dtb.Scan()
4629 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4630 'uncomp-size'])
4631 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004632 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004633 expected = {
4634 'section/blob:offset': 0,
4635 'section/blob:size': len(COMPRESS_DATA),
4636 'section/u-boot:offset': len(COMPRESS_DATA),
4637 'section/u-boot:size': len(U_BOOT_DATA),
4638 'section:offset': 0,
4639 'section:image-pos': 0,
4640 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4641 'section:size': len(data),
4642 'offset': 0,
4643 'image-pos': 0,
4644 'size': len(data),
4645 }
4646 self.assertEqual(expected, props)
4647
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004648 def testLz4Missing(self):
4649 """Test that binman still produces an image if lz4 is missing"""
4650 with test_util.capture_sys_output() as (_, stderr):
4651 self._DoTestFile('185_compress_section.dts',
4652 force_missing_bintools='lz4')
4653 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004654 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004655
Simon Glassd92c8362020-10-26 17:40:25 -06004656 def testCompressExtra(self):
4657 """Test compression of a section with no fixed size"""
4658 self._CheckLz4()
4659 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4660 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4661 dtb = fdt.Fdt(out_dtb_fname)
4662 dtb.Scan()
4663 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4664 'uncomp-size'])
4665
4666 base = data[len(U_BOOT_DATA):]
Brandon Maiera657bc62024-06-04 16:16:05 +00004667 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glassd92c8362020-10-26 17:40:25 -06004668 rest = base[len(U_BOOT_DATA):]
4669
4670 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004671 bintool = self.comp_bintools['lz4']
4672 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004673 data1 = rest[:len(expect1)]
4674 section1 = self._decompress(data1)
Brandon Maiera657bc62024-06-04 16:16:05 +00004675 self.assertEqual(expect1, data1)
4676 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glassd92c8362020-10-26 17:40:25 -06004677 rest1 = rest[len(expect1):]
4678
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004679 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004680 data2 = rest1[:len(expect2)]
4681 section2 = self._decompress(data2)
Brandon Maiera657bc62024-06-04 16:16:05 +00004682 self.assertEqual(expect2, data2)
4683 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glassd92c8362020-10-26 17:40:25 -06004684 rest2 = rest1[len(expect2):]
4685
4686 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4687 len(expect2) + len(U_BOOT_DATA))
Brandon Maiera657bc62024-06-04 16:16:05 +00004688 #self.assertEqual(expect_size, len(data))
Simon Glassd92c8362020-10-26 17:40:25 -06004689
Brandon Maiera657bc62024-06-04 16:16:05 +00004690 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glassd92c8362020-10-26 17:40:25 -06004691
4692 self.maxDiff = None
4693 expected = {
4694 'u-boot:offset': 0,
4695 'u-boot:image-pos': 0,
4696 'u-boot:size': len(U_BOOT_DATA),
4697
4698 'base:offset': len(U_BOOT_DATA),
4699 'base:image-pos': len(U_BOOT_DATA),
4700 'base:size': len(data) - len(U_BOOT_DATA),
4701 'base/u-boot:offset': 0,
4702 'base/u-boot:image-pos': len(U_BOOT_DATA),
4703 'base/u-boot:size': len(U_BOOT_DATA),
4704 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4705 len(expect2),
4706 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4707 len(expect2),
4708 'base/u-boot2:size': len(U_BOOT_DATA),
4709
4710 'base/section:offset': len(U_BOOT_DATA),
4711 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4712 'base/section:size': len(expect1),
4713 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4714 'base/section/blob:offset': 0,
4715 'base/section/blob:size': len(COMPRESS_DATA),
4716 'base/section/u-boot:offset': len(COMPRESS_DATA),
4717 'base/section/u-boot:size': len(U_BOOT_DATA),
4718
4719 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4720 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4721 'base/section2:size': len(expect2),
4722 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4723 'base/section2/blob:offset': 0,
4724 'base/section2/blob:size': len(COMPRESS_DATA),
4725 'base/section2/blob2:offset': len(COMPRESS_DATA),
4726 'base/section2/blob2:size': len(COMPRESS_DATA),
4727
4728 'offset': 0,
4729 'image-pos': 0,
4730 'size': len(data),
4731 }
4732 self.assertEqual(expected, props)
4733
Simon Glassecbe4732021-01-06 21:35:15 -07004734 def testSymbolsSubsection(self):
4735 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004736 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004737
Simon Glass3fb25402021-01-06 21:35:16 -07004738 def testReadImageEntryArg(self):
4739 """Test reading an image that would need an entry arg to generate"""
4740 entry_args = {
4741 'cros-ec-rw-path': 'ecrw.bin',
4742 }
4743 data = self.data = self._DoReadFileDtb(
4744 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4745 entry_args=entry_args)
4746
Simon Glass80025522022-01-29 14:14:04 -07004747 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004748 orig_image = control.images['image']
4749
4750 # This should not generate an error about the missing 'cros-ec-rw-path'
4751 # since we are reading the image from a file. Compare with
4752 # testEntryArgsRequired()
4753 image = Image.FromFile(image_fname)
4754 self.assertEqual(orig_image.GetEntries().keys(),
4755 image.GetEntries().keys())
4756
Simon Glassa2af7302021-01-06 21:35:18 -07004757 def testFilesAlign(self):
4758 """Test alignment with files"""
4759 data = self._DoReadFile('190_files_align.dts')
4760
4761 # The first string is 15 bytes so will align to 16
4762 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4763 self.assertEqual(expect, data)
4764
Simon Glassdb84b562021-01-06 21:35:19 -07004765 def testReadImageSkip(self):
4766 """Test reading an image and accessing its FDT map"""
4767 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004768 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004769 orig_image = control.images['image']
4770 image = Image.FromFile(image_fname)
4771 self.assertEqual(orig_image.GetEntries().keys(),
4772 image.GetEntries().keys())
4773
4774 orig_entry = orig_image.GetEntries()['fdtmap']
4775 entry = image.GetEntries()['fdtmap']
4776 self.assertEqual(orig_entry.offset, entry.offset)
4777 self.assertEqual(orig_entry.size, entry.size)
Simon Glassed836ac2025-02-26 09:26:17 -07004778 self.assertEqual((1 << 32) - 0x400 + 16, entry.image_pos)
Simon Glassdb84b562021-01-06 21:35:19 -07004779
4780 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4781
Brandon Maiera657bc62024-06-04 16:16:05 +00004782 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glassdb84b562021-01-06 21:35:19 -07004783
Simon Glassc98de972021-03-18 20:24:57 +13004784 def testTplNoDtb(self):
4785 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004786 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004787 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4788 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4789 data[:len(U_BOOT_TPL_NODTB_DATA)])
4790
Simon Glass63f41d42021-03-18 20:24:58 +13004791 def testTplBssPad(self):
4792 """Test that we can pad TPL's BSS with zeros"""
4793 # ELF file with a '__bss_size' symbol
4794 self._SetupTplElf()
4795 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004796 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004797 data)
4798
4799 def testTplBssPadMissing(self):
4800 """Test that a missing symbol is detected"""
4801 self._SetupTplElf('u_boot_ucode_ptr')
4802 with self.assertRaises(ValueError) as e:
4803 self._DoReadFile('193_tpl_bss_pad.dts')
4804 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4805 str(e.exception))
4806
Simon Glass718b5292021-03-18 20:25:07 +13004807 def checkDtbSizes(self, data, pad_len, start):
4808 """Check the size arguments in a dtb embedded in an image
4809
4810 Args:
4811 data: The image data
4812 pad_len: Length of the pad section in the image, in bytes
4813 start: Start offset of the devicetree to examine, within the image
4814
4815 Returns:
4816 Size of the devicetree in bytes
4817 """
4818 dtb_data = data[start:]
4819 dtb = fdt.Fdt.FromData(dtb_data)
4820 fdt_size = dtb.GetFdtObj().totalsize()
4821 dtb.Scan()
4822 props = self._GetPropTree(dtb, 'size')
4823 self.assertEqual({
4824 'size': len(data),
4825 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4826 'u-boot-spl/u-boot-spl-dtb:size': 801,
4827 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4828 'u-boot-spl:size': 860,
4829 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4830 'u-boot/u-boot-dtb:size': 781,
4831 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4832 'u-boot:size': 827,
4833 }, props)
4834 return fdt_size
4835
4836 def testExpanded(self):
4837 """Test that an expanded entry type is selected when needed"""
4838 self._SetupSplElf()
4839 self._SetupTplElf()
4840
4841 # SPL has a devicetree, TPL does not
4842 entry_args = {
4843 'spl-dtb': '1',
4844 'spl-bss-pad': 'y',
4845 'tpl-dtb': '',
4846 }
4847 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4848 entry_args=entry_args)
4849 image = control.images['image']
4850 entries = image.GetEntries()
4851 self.assertEqual(3, len(entries))
4852
4853 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4854 self.assertIn('u-boot', entries)
4855 entry = entries['u-boot']
4856 self.assertEqual('u-boot-expanded', entry.etype)
4857 subent = entry.GetEntries()
4858 self.assertEqual(2, len(subent))
4859 self.assertIn('u-boot-nodtb', subent)
4860 self.assertIn('u-boot-dtb', subent)
4861
4862 # Second, u-boot-spl, which should be expanded into three parts
4863 self.assertIn('u-boot-spl', entries)
4864 entry = entries['u-boot-spl']
4865 self.assertEqual('u-boot-spl-expanded', entry.etype)
4866 subent = entry.GetEntries()
4867 self.assertEqual(3, len(subent))
4868 self.assertIn('u-boot-spl-nodtb', subent)
4869 self.assertIn('u-boot-spl-bss-pad', subent)
4870 self.assertIn('u-boot-spl-dtb', subent)
4871
4872 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4873 # devicetree
4874 self.assertIn('u-boot-tpl', entries)
4875 entry = entries['u-boot-tpl']
4876 self.assertEqual('u-boot-tpl', entry.etype)
4877 self.assertEqual(None, entry.GetEntries())
4878
4879 def testExpandedTpl(self):
4880 """Test that an expanded entry type is selected for TPL when needed"""
4881 self._SetupTplElf()
4882
4883 entry_args = {
4884 'tpl-bss-pad': 'y',
4885 'tpl-dtb': 'y',
4886 }
4887 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4888 entry_args=entry_args)
4889 image = control.images['image']
4890 entries = image.GetEntries()
4891 self.assertEqual(1, len(entries))
4892
4893 # We only have u-boot-tpl, which be expanded
4894 self.assertIn('u-boot-tpl', entries)
4895 entry = entries['u-boot-tpl']
4896 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4897 subent = entry.GetEntries()
4898 self.assertEqual(3, len(subent))
4899 self.assertIn('u-boot-tpl-nodtb', subent)
4900 self.assertIn('u-boot-tpl-bss-pad', subent)
4901 self.assertIn('u-boot-tpl-dtb', subent)
4902
4903 def testExpandedNoPad(self):
4904 """Test an expanded entry without BSS pad enabled"""
4905 self._SetupSplElf()
4906 self._SetupTplElf()
4907
4908 # SPL has a devicetree, TPL does not
4909 entry_args = {
4910 'spl-dtb': 'something',
4911 'spl-bss-pad': 'n',
4912 'tpl-dtb': '',
4913 }
4914 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4915 entry_args=entry_args)
4916 image = control.images['image']
4917 entries = image.GetEntries()
4918
4919 # Just check u-boot-spl, which should be expanded into two parts
4920 self.assertIn('u-boot-spl', entries)
4921 entry = entries['u-boot-spl']
4922 self.assertEqual('u-boot-spl-expanded', entry.etype)
4923 subent = entry.GetEntries()
4924 self.assertEqual(2, len(subent))
4925 self.assertIn('u-boot-spl-nodtb', subent)
4926 self.assertIn('u-boot-spl-dtb', subent)
4927
4928 def testExpandedTplNoPad(self):
4929 """Test that an expanded entry type with padding disabled in TPL"""
4930 self._SetupTplElf()
4931
4932 entry_args = {
4933 'tpl-bss-pad': '',
4934 'tpl-dtb': 'y',
4935 }
4936 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4937 entry_args=entry_args)
4938 image = control.images['image']
4939 entries = image.GetEntries()
4940 self.assertEqual(1, len(entries))
4941
4942 # We only have u-boot-tpl, which be expanded
4943 self.assertIn('u-boot-tpl', entries)
4944 entry = entries['u-boot-tpl']
4945 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4946 subent = entry.GetEntries()
4947 self.assertEqual(2, len(subent))
4948 self.assertIn('u-boot-tpl-nodtb', subent)
4949 self.assertIn('u-boot-tpl-dtb', subent)
4950
4951 def testFdtInclude(self):
4952 """Test that an Fdt is update within all binaries"""
4953 self._SetupSplElf()
4954 self._SetupTplElf()
4955
4956 # SPL has a devicetree, TPL does not
4957 self.maxDiff = None
4958 entry_args = {
4959 'spl-dtb': '1',
4960 'spl-bss-pad': 'y',
4961 'tpl-dtb': '',
4962 }
4963 # Build the image. It includes two separate devicetree binaries, each
4964 # with their own contents, but all contain the binman definition.
4965 data = self._DoReadFileDtb(
4966 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4967 update_dtb=True, entry_args=entry_args)[0]
4968 pad_len = 10
4969
4970 # Check the U-Boot dtb
4971 start = len(U_BOOT_NODTB_DATA)
4972 fdt_size = self.checkDtbSizes(data, pad_len, start)
4973
4974 # Now check SPL
4975 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4976 fdt_size = self.checkDtbSizes(data, pad_len, start)
4977
4978 # TPL has no devicetree
4979 start += fdt_size + len(U_BOOT_TPL_DATA)
4980 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004981
Simon Glass7098b7f2021-03-21 18:24:30 +13004982 def testSymbolsExpanded(self):
4983 """Test binman can assign symbols in expanded entries"""
4984 entry_args = {
4985 'spl-dtb': '1',
4986 }
4987 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4988 U_BOOT_SPL_DTB_DATA, 0x38,
4989 entry_args=entry_args, use_expanded=True)
4990
Simon Glasse1915782021-03-21 18:24:31 +13004991 def testCollection(self):
4992 """Test a collection"""
4993 data = self._DoReadFile('198_collection.dts')
4994 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004995 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4996 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004997 data)
4998
Simon Glass27a7f772021-03-21 18:24:32 +13004999 def testCollectionSection(self):
5000 """Test a collection where a section must be built first"""
5001 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07005002 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13005003 # building the contents, producing an error is anything is still
5004 # missing.
5005 data = self._DoReadFile('199_collection_section.dts')
5006 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07005007 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
5008 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13005009 data)
5010
Simon Glassf427c5f2021-03-21 18:24:33 +13005011 def testAlignDefault(self):
5012 """Test that default alignment works on sections"""
5013 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07005014 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13005015 U_BOOT_DATA)
5016 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07005017 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13005018 # No alignment within the nested section
5019 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
5020 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07005021 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13005022 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13005023
Bin Mengc0b15742021-05-10 20:23:33 +08005024 def testPackOpenSBI(self):
5025 """Test that an image with an OpenSBI binary can be created"""
5026 data = self._DoReadFile('201_opensbi.dts')
5027 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
5028
Simon Glass76f496d2021-07-06 10:36:37 -06005029 def testSectionsSingleThread(self):
5030 """Test sections without multithreading"""
5031 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07005032 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
5033 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
5034 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06005035 self.assertEqual(expected, data)
5036
5037 def testThreadTimeout(self):
5038 """Test handling a thread that takes too long"""
5039 with self.assertRaises(ValueError) as e:
5040 self._DoTestFile('202_section_timeout.dts',
5041 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06005042 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06005043
Simon Glass748a1d42021-07-06 10:36:41 -06005044 def testTiming(self):
5045 """Test output of timing information"""
5046 data = self._DoReadFile('055_sections.dts')
5047 with test_util.capture_sys_output() as (stdout, stderr):
5048 state.TimingShow()
5049 self.assertIn('read:', stdout.getvalue())
5050 self.assertIn('compress:', stdout.getvalue())
5051
Simon Glassadfb8492021-11-03 21:09:18 -06005052 def testUpdateFdtInElf(self):
5053 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005054 if not elf.ELF_TOOLS:
5055 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005056 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5057 outfile = os.path.join(self._indir, 'u-boot.out')
5058 begin_sym = 'dtb_embed_begin'
5059 end_sym = 'dtb_embed_end'
5060 retcode = self._DoTestFile(
5061 '060_fdt_update.dts', update_dtb=True,
5062 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5063 self.assertEqual(0, retcode)
5064
5065 # Check that the output file does in fact contact a dtb with the binman
5066 # definition in the correct place
5067 syms = elf.GetSymbolFileOffset(infile,
5068 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07005069 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06005070 dtb_data = data[syms['dtb_embed_begin'].offset:
5071 syms['dtb_embed_end'].offset]
5072
5073 dtb = fdt.Fdt.FromData(dtb_data)
5074 dtb.Scan()
5075 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
5076 self.assertEqual({
5077 'image-pos': 0,
5078 'offset': 0,
5079 '_testing:offset': 32,
5080 '_testing:size': 2,
5081 '_testing:image-pos': 32,
5082 'section@0/u-boot:offset': 0,
5083 'section@0/u-boot:size': len(U_BOOT_DATA),
5084 'section@0/u-boot:image-pos': 0,
5085 'section@0:offset': 0,
5086 'section@0:size': 16,
5087 'section@0:image-pos': 0,
5088
5089 'section@1/u-boot:offset': 0,
5090 'section@1/u-boot:size': len(U_BOOT_DATA),
5091 'section@1/u-boot:image-pos': 16,
5092 'section@1:offset': 16,
5093 'section@1:size': 16,
5094 'section@1:image-pos': 16,
5095 'size': 40
5096 }, props)
5097
5098 def testUpdateFdtInElfInvalid(self):
5099 """Test that invalid args are detected with --update-fdt-in-elf"""
5100 with self.assertRaises(ValueError) as e:
5101 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5102 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5103 str(e.exception))
5104
5105 def testUpdateFdtInElfNoSyms(self):
5106 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005107 if not elf.ELF_TOOLS:
5108 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005109 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5110 outfile = ''
5111 begin_sym = 'wrong_begin'
5112 end_sym = 'wrong_end'
5113 with self.assertRaises(ValueError) as e:
5114 self._DoTestFile(
5115 '060_fdt_update.dts',
5116 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5117 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5118 str(e.exception))
5119
5120 def testUpdateFdtInElfTooSmall(self):
5121 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005122 if not elf.ELF_TOOLS:
5123 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005124 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5125 outfile = os.path.join(self._indir, 'u-boot.out')
5126 begin_sym = 'dtb_embed_begin'
5127 end_sym = 'dtb_embed_end'
5128 with self.assertRaises(ValueError) as e:
5129 self._DoTestFile(
5130 '060_fdt_update.dts', update_dtb=True,
5131 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5132 self.assertRegex(
5133 str(e.exception),
5134 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5135
Simon Glass88e04da2021-11-23 11:03:42 -07005136 def testVersion(self):
5137 """Test we can get the binman version"""
5138 version = '(unreleased)'
5139 self.assertEqual(version, state.GetVersion(self._indir))
5140
5141 with self.assertRaises(SystemExit):
5142 with test_util.capture_sys_output() as (_, stderr):
5143 self._DoBinman('-V')
5144 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5145
5146 # Try running the tool too, just to be safe
5147 result = self._RunBinman('-V')
5148 self.assertEqual('Binman %s\n' % version, result.stderr)
5149
5150 # Set up a version file to make sure that works
5151 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005152 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005153 binary=False)
5154 self.assertEqual(version, state.GetVersion(self._indir))
5155
Simon Glass637958f2021-11-23 21:09:50 -07005156 def testAltFormat(self):
5157 """Test that alternative formats can be used to extract"""
5158 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5159
5160 try:
5161 tmpdir, updated_fname = self._SetupImageInTmpdir()
5162 with test_util.capture_sys_output() as (stdout, _):
5163 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5164 self.assertEqual(
5165 '''Flag (-F) Entry type Description
5166fdt fdtmap Extract the devicetree blob from the fdtmap
5167''',
5168 stdout.getvalue())
5169
5170 dtb = os.path.join(tmpdir, 'fdt.dtb')
5171 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5172 dtb, 'fdtmap')
5173
5174 # Check that we can read it and it can be scanning, meaning it does
5175 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005176 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005177 dtb = fdt.Fdt.FromData(data)
5178 dtb.Scan()
5179
5180 # Now check u-boot which has no alt_format
5181 fname = os.path.join(tmpdir, 'fdt.dtb')
5182 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5183 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005184 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005185 self.assertEqual(U_BOOT_DATA, data)
5186
5187 finally:
5188 shutil.rmtree(tmpdir)
5189
Simon Glass0b00ae62021-11-23 21:09:52 -07005190 def testExtblobList(self):
5191 """Test an image with an external blob list"""
5192 data = self._DoReadFile('215_blob_ext_list.dts')
5193 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5194
5195 def testExtblobListMissing(self):
5196 """Test an image with a missing external blob"""
5197 with self.assertRaises(ValueError) as e:
5198 self._DoReadFile('216_blob_ext_list_missing.dts')
5199 self.assertIn("Filename 'missing-file' not found in input path",
5200 str(e.exception))
5201
5202 def testExtblobListMissingOk(self):
5203 """Test an image with an missing external blob that is allowed"""
5204 with test_util.capture_sys_output() as (stdout, stderr):
5205 self._DoTestFile('216_blob_ext_list_missing.dts',
5206 allow_missing=True)
5207 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005208 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005209
Simon Glass3efb2972021-11-23 21:08:59 -07005210 def testFip(self):
5211 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5212 data = self._DoReadFile('203_fip.dts')
5213 hdr, fents = fip_util.decode_fip(data)
5214 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5215 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5216 self.assertEqual(0x123, hdr.flags)
5217
5218 self.assertEqual(2, len(fents))
5219
5220 fent = fents[0]
5221 self.assertEqual(
5222 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5223 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5224 self.assertEqual('soc-fw', fent.fip_type)
5225 self.assertEqual(0x88, fent.offset)
5226 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5227 self.assertEqual(0x123456789abcdef, fent.flags)
5228 self.assertEqual(ATF_BL31_DATA, fent.data)
5229 self.assertEqual(True, fent.valid)
5230
5231 fent = fents[1]
5232 self.assertEqual(
5233 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5234 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5235 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5236 self.assertEqual(0x8c, fent.offset)
5237 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5238 self.assertEqual(0, fent.flags)
5239 self.assertEqual(ATF_BL2U_DATA, fent.data)
5240 self.assertEqual(True, fent.valid)
5241
5242 def testFipOther(self):
5243 """Basic FIP with something that isn't a external blob"""
5244 data = self._DoReadFile('204_fip_other.dts')
5245 hdr, fents = fip_util.decode_fip(data)
5246
5247 self.assertEqual(2, len(fents))
5248 fent = fents[1]
5249 self.assertEqual('rot-cert', fent.fip_type)
5250 self.assertEqual(b'aa', fent.data)
5251
Simon Glass3efb2972021-11-23 21:08:59 -07005252 def testFipNoType(self):
5253 """FIP with an entry of an unknown type"""
5254 with self.assertRaises(ValueError) as e:
5255 self._DoReadFile('205_fip_no_type.dts')
5256 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5257 str(e.exception))
5258
5259 def testFipUuid(self):
5260 """Basic FIP with a manual uuid"""
5261 data = self._DoReadFile('206_fip_uuid.dts')
5262 hdr, fents = fip_util.decode_fip(data)
5263
5264 self.assertEqual(2, len(fents))
5265 fent = fents[1]
5266 self.assertEqual(None, fent.fip_type)
5267 self.assertEqual(
5268 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5269 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5270 fent.uuid)
5271 self.assertEqual(U_BOOT_DATA, fent.data)
5272
5273 def testFipLs(self):
5274 """Test listing a FIP"""
5275 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5276 hdr, fents = fip_util.decode_fip(data)
5277
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005278 tmpdir = None
Simon Glass3efb2972021-11-23 21:08:59 -07005279 try:
5280 tmpdir, updated_fname = self._SetupImageInTmpdir()
5281 with test_util.capture_sys_output() as (stdout, stderr):
5282 self._DoBinman('ls', '-i', updated_fname)
5283 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005284 if tmpdir:
5285 shutil.rmtree(tmpdir)
Simon Glass3efb2972021-11-23 21:08:59 -07005286 lines = stdout.getvalue().splitlines()
5287 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005288'Name Image-pos Size Entry-type Offset Uncomp-size',
5289'--------------------------------------------------------------',
5290'image 0 2d3 section 0',
5291' atf-fip 0 90 atf-fip 0',
5292' soc-fw 88 4 blob-ext 88',
5293' u-boot 8c 4 u-boot 8c',
5294' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005295]
5296 self.assertEqual(expected, lines)
5297
5298 image = control.images['image']
5299 entries = image.GetEntries()
5300 fdtmap = entries['fdtmap']
5301
5302 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5303 magic = fdtmap_data[:8]
5304 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005305 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005306
5307 fdt_data = fdtmap_data[16:]
5308 dtb = fdt.Fdt.FromData(fdt_data)
5309 dtb.Scan()
5310 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5311 self.assertEqual({
5312 'atf-fip/soc-fw:image-pos': 136,
5313 'atf-fip/soc-fw:offset': 136,
5314 'atf-fip/soc-fw:size': 4,
5315 'atf-fip/u-boot:image-pos': 140,
5316 'atf-fip/u-boot:offset': 140,
5317 'atf-fip/u-boot:size': 4,
5318 'atf-fip:image-pos': 0,
5319 'atf-fip:offset': 0,
5320 'atf-fip:size': 144,
5321 'image-pos': 0,
5322 'offset': 0,
5323 'fdtmap:image-pos': fdtmap.image_pos,
5324 'fdtmap:offset': fdtmap.offset,
5325 'fdtmap:size': len(fdtmap_data),
5326 'size': len(data),
5327 }, props)
5328
5329 def testFipExtractOneEntry(self):
5330 """Test extracting a single entry fron an FIP"""
5331 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005332 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005333 fname = os.path.join(self._indir, 'output.extact')
5334 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005335 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005336 self.assertEqual(U_BOOT_DATA, data)
5337
5338 def testFipReplace(self):
5339 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005340 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005341 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005342 updated_fname = tools.get_output_filename('image-updated.bin')
5343 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005344 entry_name = 'atf-fip/u-boot'
5345 control.WriteEntry(updated_fname, entry_name, expected,
5346 allow_resize=True)
5347 actual = control.ReadEntry(updated_fname, entry_name)
5348 self.assertEqual(expected, actual)
5349
Simon Glass80025522022-01-29 14:14:04 -07005350 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005351 hdr, fents = fip_util.decode_fip(new_data)
5352
5353 self.assertEqual(2, len(fents))
5354
5355 # Check that the FIP entry is updated
5356 fent = fents[1]
5357 self.assertEqual(0x8c, fent.offset)
5358 self.assertEqual(len(expected), fent.size)
5359 self.assertEqual(0, fent.flags)
5360 self.assertEqual(expected, fent.data)
5361 self.assertEqual(True, fent.valid)
5362
5363 def testFipMissing(self):
5364 with test_util.capture_sys_output() as (stdout, stderr):
5365 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5366 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005367 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005368
5369 def testFipSize(self):
5370 """Test a FIP with a size property"""
5371 data = self._DoReadFile('210_fip_size.dts')
5372 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5373 hdr, fents = fip_util.decode_fip(data)
5374 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5375 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5376
5377 self.assertEqual(1, len(fents))
5378
5379 fent = fents[0]
5380 self.assertEqual('soc-fw', fent.fip_type)
5381 self.assertEqual(0x60, fent.offset)
5382 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5383 self.assertEqual(ATF_BL31_DATA, fent.data)
5384 self.assertEqual(True, fent.valid)
5385
5386 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005387 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005388
5389 def testFipBadAlign(self):
5390 """Test that an invalid alignment value in a FIP is detected"""
5391 with self.assertRaises(ValueError) as e:
5392 self._DoTestFile('211_fip_bad_align.dts')
5393 self.assertIn(
5394 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5395 str(e.exception))
5396
5397 def testFipCollection(self):
5398 """Test using a FIP in a collection"""
5399 data = self._DoReadFile('212_fip_collection.dts')
5400 entry1 = control.images['image'].GetEntries()['collection']
5401 data1 = data[:entry1.size]
5402 hdr1, fents2 = fip_util.decode_fip(data1)
5403
5404 entry2 = control.images['image'].GetEntries()['atf-fip']
5405 data2 = data[entry2.offset:entry2.offset + entry2.size]
5406 hdr1, fents2 = fip_util.decode_fip(data2)
5407
5408 # The 'collection' entry should have U-Boot included at the end
5409 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5410 self.assertEqual(data1, data2 + U_BOOT_DATA)
5411 self.assertEqual(U_BOOT_DATA, data1[-4:])
5412
5413 # There should be a U-Boot after the final FIP
5414 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005415
Simon Glassccae6862022-01-12 13:10:35 -07005416 def testFakeBlob(self):
5417 """Test handling of faking an external blob"""
5418 with test_util.capture_sys_output() as (stdout, stderr):
5419 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5420 allow_fake_blobs=True)
5421 err = stderr.getvalue()
5422 self.assertRegex(
5423 err,
5424 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005425
Simon Glassceb5f912022-01-09 20:13:46 -07005426 def testExtblobListFaked(self):
5427 """Test an extblob with missing external blob that are faked"""
5428 with test_util.capture_sys_output() as (stdout, stderr):
5429 self._DoTestFile('216_blob_ext_list_missing.dts',
5430 allow_fake_blobs=True)
5431 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005432 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005433
Simon Glass162017b2022-01-09 20:13:57 -07005434 def testListBintools(self):
5435 args = ['tool', '--list']
5436 with test_util.capture_sys_output() as (stdout, _):
5437 self._DoBinman(*args)
5438 out = stdout.getvalue().splitlines()
5439 self.assertTrue(len(out) >= 2)
5440
5441 def testFetchBintools(self):
5442 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005443 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005444 raise urllib.error.URLError('my error')
5445
5446 args = ['tool']
5447 with self.assertRaises(ValueError) as e:
5448 self._DoBinman(*args)
5449 self.assertIn("Invalid arguments to 'tool' subcommand",
5450 str(e.exception))
5451
5452 args = ['tool', '--fetch']
5453 with self.assertRaises(ValueError) as e:
5454 self._DoBinman(*args)
5455 self.assertIn('Please specify bintools to fetch', str(e.exception))
5456
5457 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005458 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005459 side_effect=fail_download):
5460 with test_util.capture_sys_output() as (stdout, _):
5461 self._DoBinman(*args)
5462 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5463
Simon Glass620c4462022-01-09 20:14:11 -07005464 def testBintoolDocs(self):
5465 """Test for creation of bintool documentation"""
5466 with test_util.capture_sys_output() as (stdout, stderr):
5467 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5468 self.assertTrue(len(stdout.getvalue()) > 0)
5469
5470 def testBintoolDocsMissing(self):
5471 """Test handling of missing bintool documentation"""
5472 with self.assertRaises(ValueError) as e:
5473 with test_util.capture_sys_output() as (stdout, stderr):
5474 control.write_bintool_docs(
5475 control.bintool.Bintool.get_tool_list(), 'mkimage')
5476 self.assertIn('Documentation is missing for modules: mkimage',
5477 str(e.exception))
5478
Jan Kiszka58c407f2022-01-28 20:37:53 +01005479 def testListWithGenNode(self):
5480 """Check handling of an FDT map when the section cannot be found"""
5481 entry_args = {
5482 'of-list': 'test-fdt1 test-fdt2',
5483 }
5484 data = self._DoReadFileDtb(
5485 '219_fit_gennode.dts',
5486 entry_args=entry_args,
5487 use_real_dtb=True,
5488 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5489
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005490 tmpdir = None
Jan Kiszka58c407f2022-01-28 20:37:53 +01005491 try:
5492 tmpdir, updated_fname = self._SetupImageInTmpdir()
5493 with test_util.capture_sys_output() as (stdout, stderr):
5494 self._RunBinman('ls', '-i', updated_fname)
5495 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005496 if tmpdir:
5497 shutil.rmtree(tmpdir)
Jan Kiszka58c407f2022-01-28 20:37:53 +01005498
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005499 def testFitSubentryUsesBintool(self):
5500 """Test that binman FIT subentries can use bintools"""
5501 command.test_result = self._HandleGbbCommand
5502 entry_args = {
5503 'keydir': 'devkeys',
5504 'bmpblk': 'bmpblk.bin',
5505 }
5506 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5507 entry_args=entry_args)
5508
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005509 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5510 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005511 self.assertIn(expected, data)
5512
5513 def testFitSubentryMissingBintool(self):
5514 """Test that binman reports missing bintools for FIT subentries"""
5515 entry_args = {
5516 'keydir': 'devkeys',
5517 }
5518 with test_util.capture_sys_output() as (_, stderr):
5519 self._DoTestFile('220_fit_subentry_bintool.dts',
5520 force_missing_bintools='futility', entry_args=entry_args)
5521 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005522 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005523
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005524 def testFitSubentryHashSubnode(self):
5525 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005526 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005527 data, _, _, out_dtb_name = self._DoReadFileDtb(
5528 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5529
5530 mkimage_dtb = fdt.Fdt.FromData(data)
5531 mkimage_dtb.Scan()
5532 binman_dtb = fdt.Fdt(out_dtb_name)
5533 binman_dtb.Scan()
5534
5535 # Check that binman didn't add hash values
5536 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5537 self.assertNotIn('value', fnode.props)
5538
5539 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5540 self.assertNotIn('value', fnode.props)
5541
5542 # Check that mkimage added hash values
5543 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5544 self.assertIn('value', fnode.props)
5545
5546 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5547 self.assertIn('value', fnode.props)
5548
Roger Quadros5cdcea02022-02-19 20:50:04 +02005549 def testPackTeeOs(self):
5550 """Test that an image with an TEE binary can be created"""
5551 data = self._DoReadFile('222_tee_os.dts')
5552 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5553
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305554 def testPackTiDm(self):
5555 """Test that an image with a TI DM binary can be created"""
5556 data = self._DoReadFile('225_ti_dm.dts')
5557 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5558
Simon Glass912339f2022-02-08 11:50:03 -07005559 def testFitFdtOper(self):
5560 """Check handling of a specified FIT operation"""
5561 entry_args = {
5562 'of-list': 'test-fdt1 test-fdt2',
5563 'default-dt': 'test-fdt2',
5564 }
5565 self._DoReadFileDtb(
5566 '223_fit_fdt_oper.dts',
5567 entry_args=entry_args,
5568 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5569
5570 def testFitFdtBadOper(self):
5571 """Check handling of an FDT map when the section cannot be found"""
5572 with self.assertRaises(ValueError) as exc:
5573 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005574 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005575 str(exc.exception))
5576
Simon Glassdd156a42022-03-05 20:18:59 -07005577 def test_uses_expand_size(self):
5578 """Test that the 'expand-size' property cannot be used anymore"""
5579 with self.assertRaises(ValueError) as e:
5580 data = self._DoReadFile('225_expand_size_bad.dts')
5581 self.assertIn(
5582 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5583 str(e.exception))
5584
Simon Glass5f423422022-03-05 20:19:12 -07005585 def testFitSplitElf(self):
5586 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005587 if not elf.ELF_TOOLS:
5588 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005589 entry_args = {
5590 'of-list': 'test-fdt1 test-fdt2',
5591 'default-dt': 'test-fdt2',
5592 'atf-bl31-path': 'bl31.elf',
5593 'tee-os-path': 'tee.elf',
5594 }
5595 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5596 data = self._DoReadFileDtb(
5597 '226_fit_split_elf.dts',
5598 entry_args=entry_args,
5599 extra_indirs=[test_subdir])[0]
5600
5601 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5602 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5603
5604 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5605 'data', 'load'}
5606 dtb = fdt.Fdt.FromData(fit_data)
5607 dtb.Scan()
5608
5609 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5610 segments, entry = elf.read_loadable_segments(elf_data)
5611
5612 # We assume there are two segments
Brandon Maiera657bc62024-06-04 16:16:05 +00005613 self.assertEqual(2, len(segments))
Simon Glass5f423422022-03-05 20:19:12 -07005614
5615 atf1 = dtb.GetNode('/images/atf-1')
5616 _, start, data = segments[0]
5617 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5618 self.assertEqual(entry,
5619 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5620 self.assertEqual(start,
5621 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5622 self.assertEqual(data, atf1.props['data'].bytes)
5623
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005624 hash_node = atf1.FindNode('hash')
5625 self.assertIsNotNone(hash_node)
5626 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5627
Simon Glass5f423422022-03-05 20:19:12 -07005628 atf2 = dtb.GetNode('/images/atf-2')
5629 self.assertEqual(base_keys, atf2.props.keys())
5630 _, start, data = segments[1]
5631 self.assertEqual(start,
5632 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5633 self.assertEqual(data, atf2.props['data'].bytes)
5634
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005635 hash_node = atf2.FindNode('hash')
5636 self.assertIsNotNone(hash_node)
5637 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5638
5639 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5640 self.assertIsNotNone(hash_node)
5641 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5642
Simon Glass5f423422022-03-05 20:19:12 -07005643 conf = dtb.GetNode('/configurations')
5644 self.assertEqual({'default'}, conf.props.keys())
5645
5646 for subnode in conf.subnodes:
5647 self.assertEqual({'description', 'fdt', 'loadables'},
5648 subnode.props.keys())
5649 self.assertEqual(
5650 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5651 fdt_util.GetStringList(subnode, 'loadables'))
5652
5653 def _check_bad_fit(self, dts):
5654 """Check a bad FIT
5655
5656 This runs with the given dts and returns the assertion raised
5657
5658 Args:
5659 dts (str): dts filename to use
5660
5661 Returns:
5662 str: Assertion string raised
5663 """
5664 entry_args = {
5665 'of-list': 'test-fdt1 test-fdt2',
5666 'default-dt': 'test-fdt2',
5667 'atf-bl31-path': 'bl31.elf',
5668 'tee-os-path': 'tee.elf',
5669 }
5670 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5671 with self.assertRaises(ValueError) as exc:
5672 self._DoReadFileDtb(dts, entry_args=entry_args,
5673 extra_indirs=[test_subdir])[0]
5674 return str(exc.exception)
5675
5676 def testFitSplitElfBadElf(self):
5677 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005678 if not elf.ELF_TOOLS:
5679 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005680 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5681 entry_args = {
5682 'of-list': 'test-fdt1 test-fdt2',
5683 'default-dt': 'test-fdt2',
5684 'atf-bl31-path': 'bad.elf',
5685 'tee-os-path': 'tee.elf',
5686 }
5687 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5688 with self.assertRaises(ValueError) as exc:
5689 self._DoReadFileDtb(
5690 '226_fit_split_elf.dts',
5691 entry_args=entry_args,
5692 extra_indirs=[test_subdir])[0]
5693 self.assertIn(
5694 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5695 str(exc.exception))
5696
Simon Glass5f423422022-03-05 20:19:12 -07005697 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005698 """Test an split-elf FIT with a missing ELF file
5699
5700 Args:
5701 kwargs (dict of str): Arguments to pass to _DoTestFile()
5702
5703 Returns:
5704 tuple:
5705 str: stdout result
5706 str: stderr result
5707 """
Simon Glass5f423422022-03-05 20:19:12 -07005708 entry_args = {
5709 'of-list': 'test-fdt1 test-fdt2',
5710 'default-dt': 'test-fdt2',
5711 'atf-bl31-path': 'bl31.elf',
5712 'tee-os-path': 'missing.elf',
5713 }
5714 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5715 with test_util.capture_sys_output() as (stdout, stderr):
5716 self._DoTestFile(
5717 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005718 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5719 out = stdout.getvalue()
5720 err = stderr.getvalue()
5721 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005722
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005723 def testFitSplitElfBadDirective(self):
5724 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5725 if not elf.ELF_TOOLS:
5726 self.skipTest('Python elftools not available')
5727 err = self._check_bad_fit('227_fit_bad_dir.dts')
5728 self.assertIn(
5729 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5730 err)
5731
5732 def testFitSplitElfBadDirectiveConfig(self):
5733 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5734 if not elf.ELF_TOOLS:
5735 self.skipTest('Python elftools not available')
5736 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5737 self.assertEqual(
5738 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5739 err)
5740
5741
Simon Glass5f423422022-03-05 20:19:12 -07005742 def testFitSplitElfMissing(self):
5743 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005744 if not elf.ELF_TOOLS:
5745 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005746 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005747 self.assertRegex(
5748 err,
5749 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005750 self.assertNotRegex(out, '.*Faked blob.*')
5751 fname = tools.get_output_filename('binman-fake/missing.elf')
5752 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005753
5754 def testFitSplitElfFaked(self):
5755 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005756 if not elf.ELF_TOOLS:
5757 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005758 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005759 self.assertRegex(
5760 err,
5761 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005762 self.assertRegex(
5763 out,
5764 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5765 fname = tools.get_output_filename('binman-fake/missing.elf')
5766 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005767
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005768 def testMkimageMissingBlob(self):
5769 """Test using mkimage to build an image"""
5770 with test_util.capture_sys_output() as (stdout, stderr):
5771 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5772 allow_fake_blobs=True)
5773 err = stderr.getvalue()
5774 self.assertRegex(
5775 err,
5776 "Image '.*' has faked external blobs and is non-functional: .*")
5777
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005778 def testPreLoad(self):
5779 """Test an image with a pre-load header"""
5780 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005781 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005782 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005783 data = self._DoReadFileDtb(
5784 '230_pre_load.dts', entry_args=entry_args,
5785 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005786 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5787 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5788 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Simon Glasse2dfb962023-07-24 09:19:57 -06005789
5790 def testPreLoadNoKey(self):
5791 """Test an image with a pre-load heade0r with missing key"""
5792 with self.assertRaises(FileNotFoundError) as exc:
5793 self._DoReadFile('230_pre_load.dts')
5794 self.assertIn("No such file or directory: 'dev.key'",
5795 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005796
5797 def testPreLoadPkcs(self):
5798 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005799 entry_args = {
5800 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5801 }
5802 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5803 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005804 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5805 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5806 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5807
5808 def testPreLoadPss(self):
5809 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005810 entry_args = {
5811 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5812 }
5813 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5814 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005815 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5816 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5817 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5818
5819 def testPreLoadInvalidPadding(self):
5820 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005821 entry_args = {
5822 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5823 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005824 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005825 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5826 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005827
5828 def testPreLoadInvalidSha(self):
5829 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005830 entry_args = {
5831 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5832 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005833 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005834 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5835 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005836
5837 def testPreLoadInvalidAlgo(self):
5838 """Test an image with a pre-load header with an invalid algo"""
5839 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005840 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005841
5842 def testPreLoadInvalidKey(self):
5843 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005844 entry_args = {
5845 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5846 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005847 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005848 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5849 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005850
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005851 def _CheckSafeUniqueNames(self, *images):
5852 """Check all entries of given images for unsafe unique names"""
5853 for image in images:
5854 entries = {}
5855 image._CollectEntries(entries, {}, image)
5856 for entry in entries.values():
5857 uniq = entry.GetUniqueName()
5858
5859 # Used as part of a filename, so must not be absolute paths.
5860 self.assertFalse(os.path.isabs(uniq))
5861
5862 def testSafeUniqueNames(self):
5863 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005864 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005865
5866 orig_image = control.images['image']
5867 image_fname = tools.get_output_filename('image.bin')
5868 image = Image.FromFile(image_fname)
5869
5870 self._CheckSafeUniqueNames(orig_image, image)
5871
5872 def testSafeUniqueNamesMulti(self):
5873 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005874 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005875
5876 orig_image = control.images['image']
5877 image_fname = tools.get_output_filename('image.bin')
5878 image = Image.FromFile(image_fname)
5879
5880 self._CheckSafeUniqueNames(orig_image, image)
5881
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005882 def testReplaceCmdWithBintool(self):
5883 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005884 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005885 expected = U_BOOT_DATA + b'aa'
5886 self.assertEqual(expected, data[:len(expected)])
5887
5888 try:
5889 tmpdir, updated_fname = self._SetupImageInTmpdir()
5890 fname = os.path.join(tmpdir, 'update-testing.bin')
5891 tools.write_file(fname, b'zz')
5892 self._DoBinman('replace', '-i', updated_fname,
5893 '_testing', '-f', fname)
5894
5895 data = tools.read_file(updated_fname)
5896 expected = U_BOOT_DATA + b'zz'
5897 self.assertEqual(expected, data[:len(expected)])
5898 finally:
5899 shutil.rmtree(tmpdir)
5900
5901 def testReplaceCmdOtherWithBintool(self):
5902 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005903 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005904 expected = U_BOOT_DATA + b'aa'
5905 self.assertEqual(expected, data[:len(expected)])
5906
5907 try:
5908 tmpdir, updated_fname = self._SetupImageInTmpdir()
5909 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5910 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5911 self._DoBinman('replace', '-i', updated_fname,
5912 'u-boot', '-f', fname)
5913
5914 data = tools.read_file(updated_fname)
5915 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5916 self.assertEqual(expected, data[:len(expected)])
5917 finally:
5918 shutil.rmtree(tmpdir)
5919
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005920 def testReplaceResizeNoRepackSameSize(self):
5921 """Test replacing entries with same-size data without repacking"""
5922 expected = b'x' * len(U_BOOT_DATA)
5923 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5924 self.assertEqual(expected, data)
5925
5926 path, fdtmap = state.GetFdtContents('fdtmap')
5927 self.assertIsNotNone(path)
5928 self.assertEqual(expected_fdtmap, fdtmap)
5929
5930 def testReplaceResizeNoRepackSmallerSize(self):
5931 """Test replacing entries with smaller-size data without repacking"""
5932 new_data = b'x'
5933 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5934 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5935 self.assertEqual(expected, data)
5936
5937 path, fdtmap = state.GetFdtContents('fdtmap')
5938 self.assertIsNotNone(path)
5939 self.assertEqual(expected_fdtmap, fdtmap)
5940
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005941 def testExtractFit(self):
5942 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005943 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005944 image_fname = tools.get_output_filename('image.bin')
5945
5946 fit_data = control.ReadEntry(image_fname, 'fit')
5947 fit = fdt.Fdt.FromData(fit_data)
5948 fit.Scan()
5949
5950 # Check subentry data inside the extracted fit
5951 for node_path, expected in [
5952 ('/images/kernel', U_BOOT_DATA),
5953 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5954 ('/images/scr-1', COMPRESS_DATA),
5955 ]:
5956 node = fit.GetNode(node_path)
5957 data = fit.GetProps(node)['data'].bytes
5958 self.assertEqual(expected, data)
5959
5960 def testExtractFitSubentries(self):
5961 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005962 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005963 image_fname = tools.get_output_filename('image.bin')
5964
5965 for entry_path, expected in [
5966 ('fit/kernel', U_BOOT_DATA),
5967 ('fit/kernel/u-boot', U_BOOT_DATA),
5968 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5969 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5970 ('fit/scr-1', COMPRESS_DATA),
5971 ('fit/scr-1/blob', COMPRESS_DATA),
5972 ]:
5973 data = control.ReadEntry(image_fname, entry_path)
5974 self.assertEqual(expected, data)
5975
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005976 def testReplaceFitSubentryLeafSameSize(self):
5977 """Test replacing a FIT leaf subentry with same-size data"""
5978 new_data = b'x' * len(U_BOOT_DATA)
5979 data, expected_fdtmap, _ = self._RunReplaceCmd(
5980 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005981 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005982 self.assertEqual(new_data, data)
5983
5984 path, fdtmap = state.GetFdtContents('fdtmap')
5985 self.assertIsNotNone(path)
5986 self.assertEqual(expected_fdtmap, fdtmap)
5987
5988 def testReplaceFitSubentryLeafBiggerSize(self):
5989 """Test replacing a FIT leaf subentry with bigger-size data"""
5990 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5991 data, expected_fdtmap, _ = self._RunReplaceCmd(
5992 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005993 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005994 self.assertEqual(new_data, data)
5995
5996 # Will be repacked, so fdtmap must change
5997 path, fdtmap = state.GetFdtContents('fdtmap')
5998 self.assertIsNotNone(path)
5999 self.assertNotEqual(expected_fdtmap, fdtmap)
6000
6001 def testReplaceFitSubentryLeafSmallerSize(self):
6002 """Test replacing a FIT leaf subentry with smaller-size data"""
6003 new_data = b'x'
6004 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
6005 data, expected_fdtmap, _ = self._RunReplaceCmd(
6006 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006007 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006008 self.assertEqual(expected, data)
6009
6010 path, fdtmap = state.GetFdtContents('fdtmap')
6011 self.assertIsNotNone(path)
6012 self.assertEqual(expected_fdtmap, fdtmap)
6013
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006014 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07006015 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006016 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07006017 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6018 new_data, dts='241_replace_section_simple.dts')
6019 self.assertEqual(new_data, data)
6020
6021 entries = image.GetEntries()
6022 self.assertIn('section', entries)
6023 entry = entries['section']
6024 self.assertEqual(len(new_data), entry.size)
6025
6026 def testReplaceSectionLarger(self):
6027 """Test replacing a simple section with larger data"""
6028 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6029 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6030 new_data, dts='241_replace_section_simple.dts')
6031 self.assertEqual(new_data, data)
6032
6033 entries = image.GetEntries()
6034 self.assertIn('section', entries)
6035 entry = entries['section']
6036 self.assertEqual(len(new_data), entry.size)
6037 fentry = entries['fdtmap']
6038 self.assertEqual(entry.offset + entry.size, fentry.offset)
6039
6040 def testReplaceSectionSmaller(self):
6041 """Test replacing a simple section with smaller data"""
6042 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
6043 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6044 new_data, dts='241_replace_section_simple.dts')
6045 self.assertEqual(new_data, data)
6046
6047 # The new size is the same as the old, just with a pad byte at the end
6048 entries = image.GetEntries()
6049 self.assertIn('section', entries)
6050 entry = entries['section']
6051 self.assertEqual(len(new_data), entry.size)
6052
6053 def testReplaceSectionSmallerAllow(self):
6054 """Test failing to replace a simple section with smaller data"""
6055 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
6056 try:
6057 state.SetAllowEntryContraction(True)
6058 with self.assertRaises(ValueError) as exc:
6059 self._RunReplaceCmd('section', new_data,
6060 dts='241_replace_section_simple.dts')
6061 finally:
6062 state.SetAllowEntryContraction(False)
6063
6064 # Since we have no information about the position of things within the
6065 # section, we cannot adjust the position of /section-u-boot so it ends
6066 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06006067 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07006068 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
6069 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06006070 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006071
Simon Glass8fbca772022-08-13 11:40:48 -06006072 def testMkimageImagename(self):
6073 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006074 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006075 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06006076
6077 # Check that the data appears in the file somewhere
6078 self.assertIn(U_BOOT_SPL_DATA, data)
6079
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006080 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06006081 name = data[0x20:0x40]
6082
6083 # Build the filename that we expect to be placed in there, by virtue of
6084 # the -n paraameter
6085 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6086
6087 # Check that the image name is set to the temporary filename used
6088 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6089
Simon Glassb1669752022-08-13 11:40:49 -06006090 def testMkimageImage(self):
6091 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006092 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006093 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006094
6095 # Check that the data appears in the file somewhere
6096 self.assertIn(U_BOOT_SPL_DATA, data)
6097
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006098 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006099 name = data[0x20:0x40]
6100
6101 # Build the filename that we expect to be placed in there, by virtue of
6102 # the -n paraameter
6103 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6104
6105 # Check that the image name is set to the temporary filename used
6106 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6107
6108 # Check the corect data is in the imagename file
6109 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6110
6111 def testMkimageImageNoContent(self):
6112 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006113 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006114 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006115 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006116 self.assertIn('Could not complete processing of contents',
6117 str(exc.exception))
6118
6119 def testMkimageImageBad(self):
6120 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006121 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006122 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006123 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006124 self.assertIn('Cannot use both imagename node and data-to-imagename',
6125 str(exc.exception))
6126
Simon Glassbd5cd882022-08-13 11:40:50 -06006127 def testCollectionOther(self):
6128 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006129 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006130 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6131 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6132 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6133 data)
6134
6135 def testMkimageCollection(self):
6136 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006137 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006138 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006139 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6140 self.assertEqual(expect, data[:len(expect)])
6141
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006142 def testCompressDtbPrependInvalid(self):
6143 """Test that invalid header is detected"""
6144 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006145 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006146 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6147 "'u-boot-dtb': 'invalid'", str(e.exception))
6148
6149 def testCompressDtbPrependLength(self):
6150 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006151 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006152 image = control.images['image']
6153 entries = image.GetEntries()
6154 self.assertIn('u-boot-dtb', entries)
6155 u_boot_dtb = entries['u-boot-dtb']
6156 self.assertIn('fdtmap', entries)
6157 fdtmap = entries['fdtmap']
6158
6159 image_fname = tools.get_output_filename('image.bin')
6160 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6161 dtb = fdt.Fdt.FromData(orig)
6162 dtb.Scan()
6163 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6164 expected = {
6165 'u-boot:size': len(U_BOOT_DATA),
6166 'u-boot-dtb:uncomp-size': len(orig),
6167 'u-boot-dtb:size': u_boot_dtb.size,
6168 'fdtmap:size': fdtmap.size,
6169 'size': len(data),
6170 }
6171 self.assertEqual(expected, props)
6172
6173 # Check implementation
6174 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6175 rest = data[len(U_BOOT_DATA):]
6176 comp_data_len = struct.unpack('<I', rest[:4])[0]
6177 comp_data = rest[4:4 + comp_data_len]
6178 orig2 = self._decompress(comp_data)
6179 self.assertEqual(orig, orig2)
6180
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006181 def testInvalidCompress(self):
6182 """Test that invalid compress algorithm is detected"""
6183 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006184 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006185 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6186
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006187 def testCompUtilCompressions(self):
6188 """Test compression algorithms"""
6189 for bintool in self.comp_bintools.values():
6190 self._CheckBintool(bintool)
6191 data = bintool.compress(COMPRESS_DATA)
6192 self.assertNotEqual(COMPRESS_DATA, data)
6193 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006194 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006195
6196 def testCompUtilVersions(self):
6197 """Test tool version of compression algorithms"""
6198 for bintool in self.comp_bintools.values():
6199 self._CheckBintool(bintool)
6200 version = bintool.version()
6201 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6202
6203 def testCompUtilPadding(self):
6204 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006205 # Skip zstd because it doesn't support padding
6206 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006207 self._CheckBintool(bintool)
6208 data = bintool.compress(COMPRESS_DATA)
6209 self.assertNotEqual(COMPRESS_DATA, data)
6210 data += tools.get_bytes(0, 64)
6211 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006212 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006213
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006214 def testCompressDtbZstd(self):
6215 """Test that zstd compress of device-tree files failed"""
6216 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006217 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006218 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6219 "requires a length header", str(e.exception))
6220
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006221 def testMkimageMultipleDataFiles(self):
6222 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006223 self._SetupSplElf()
6224 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006225 data = self._DoReadFile('252_mkimage_mult_data.dts')
6226 # Size of files are packed in their 4B big-endian format
6227 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6228 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6229 # Size info is always followed by a 4B zero value.
6230 expect += tools.get_bytes(0, 4)
6231 expect += U_BOOT_TPL_DATA
6232 # All but last files are 4B-aligned
6233 align_pad = len(U_BOOT_TPL_DATA) % 4
6234 if align_pad:
6235 expect += tools.get_bytes(0, align_pad)
6236 expect += U_BOOT_SPL_DATA
6237 self.assertEqual(expect, data[-len(expect):])
6238
Marek Vasutf7413f02023-07-18 07:23:58 -06006239 def testMkimageMultipleExpanded(self):
6240 """Test passing multiple files to mkimage in a mkimage entry"""
6241 self._SetupSplElf()
6242 self._SetupTplElf()
6243 entry_args = {
6244 'spl-bss-pad': 'y',
6245 'spl-dtb': 'y',
6246 }
6247 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6248 use_expanded=True, entry_args=entry_args)[0]
6249 pad_len = 10
6250 tpl_expect = U_BOOT_TPL_DATA
6251 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6252 spl_expect += U_BOOT_SPL_DTB_DATA
6253
6254 content = data[0x40:]
6255 lens = struct.unpack('>III', content[:12])
6256
6257 # Size of files are packed in their 4B big-endian format
6258 # Size info is always followed by a 4B zero value.
6259 self.assertEqual(len(tpl_expect), lens[0])
6260 self.assertEqual(len(spl_expect), lens[1])
6261 self.assertEqual(0, lens[2])
6262
6263 rest = content[12:]
6264 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6265
6266 rest = rest[len(tpl_expect):]
6267 align_pad = len(tpl_expect) % 4
6268 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6269 rest = rest[align_pad:]
6270 self.assertEqual(spl_expect, rest)
6271
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006272 def testMkimageMultipleNoContent(self):
6273 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006274 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006275 with self.assertRaises(ValueError) as exc:
6276 self._DoReadFile('253_mkimage_mult_no_content.dts')
6277 self.assertIn('Could not complete processing of contents',
6278 str(exc.exception))
6279
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006280 def testMkimageFilename(self):
6281 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006282 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006283 retcode = self._DoTestFile('254_mkimage_filename.dts')
6284 self.assertEqual(0, retcode)
6285 fname = tools.get_output_filename('mkimage-test.bin')
6286 self.assertTrue(os.path.exists(fname))
6287
Simon Glass56d05412022-02-28 07:16:54 -07006288 def testVpl(self):
6289 """Test that an image with VPL and its device tree can be created"""
6290 # ELF file with a '__bss_size' symbol
6291 self._SetupVplElf()
6292 data = self._DoReadFile('255_u_boot_vpl.dts')
6293 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6294
6295 def testVplNoDtb(self):
6296 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6297 self._SetupVplElf()
6298 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6299 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6300 data[:len(U_BOOT_VPL_NODTB_DATA)])
6301
6302 def testExpandedVpl(self):
6303 """Test that an expanded entry type is selected for TPL when needed"""
6304 self._SetupVplElf()
6305
6306 entry_args = {
6307 'vpl-bss-pad': 'y',
6308 'vpl-dtb': 'y',
6309 }
6310 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6311 entry_args=entry_args)
6312 image = control.images['image']
6313 entries = image.GetEntries()
6314 self.assertEqual(1, len(entries))
6315
6316 # We only have u-boot-vpl, which be expanded
6317 self.assertIn('u-boot-vpl', entries)
6318 entry = entries['u-boot-vpl']
6319 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6320 subent = entry.GetEntries()
6321 self.assertEqual(3, len(subent))
6322 self.assertIn('u-boot-vpl-nodtb', subent)
6323 self.assertIn('u-boot-vpl-bss-pad', subent)
6324 self.assertIn('u-boot-vpl-dtb', subent)
6325
6326 def testVplBssPadMissing(self):
6327 """Test that a missing symbol is detected"""
6328 self._SetupVplElf('u_boot_ucode_ptr')
6329 with self.assertRaises(ValueError) as e:
6330 self._DoReadFile('258_vpl_bss_pad.dts')
6331 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6332 str(e.exception))
6333
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306334 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306335 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306336 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6337 self.assertEqual(0, retcode)
6338 image = control.images['test_image']
6339 fname = tools.get_output_filename('test_image.bin')
6340 sname = tools.get_output_filename('symlink_to_test.bin')
6341 self.assertTrue(os.path.islink(sname))
6342 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006343
Andrew Davis6b463da2023-07-22 00:14:44 +05306344 def testSymlinkOverwrite(self):
6345 """Test that symlinked images can be overwritten"""
6346 testdir = TestFunctional._MakeInputDir('symlinktest')
6347 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6348 # build the same image again in the same directory so that existing symlink is present
6349 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6350 fname = tools.get_output_filename('test_image.bin')
6351 sname = tools.get_output_filename('symlink_to_test.bin')
6352 self.assertTrue(os.path.islink(sname))
6353 self.assertEqual(os.readlink(sname), fname)
6354
Simon Glass37f85de2022-10-20 18:22:47 -06006355 def testSymbolsElf(self):
6356 """Test binman can assign symbols embedded in an ELF file"""
6357 if not elf.ELF_TOOLS:
6358 self.skipTest('Python elftools not available')
6359 self._SetupTplElf('u_boot_binman_syms')
6360 self._SetupVplElf('u_boot_binman_syms')
6361 self._SetupSplElf('u_boot_binman_syms')
6362 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6363 image_fname = tools.get_output_filename('image.bin')
6364
6365 image = control.images['image']
6366 entries = image.GetEntries()
6367
6368 for entry in entries.values():
6369 # No symbols in u-boot and it has faked contents anyway
6370 if entry.name == 'u-boot':
6371 continue
6372 edata = data[entry.image_pos:entry.image_pos + entry.size]
6373 efname = tools.get_output_filename(f'edata-{entry.name}')
6374 tools.write_file(efname, edata)
6375
6376 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6377 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6378 for name, sym in syms.items():
6379 msg = 'test'
6380 val = elf.GetSymbolValue(sym, edata, msg)
6381 entry_m = re_name.match(name)
6382 if entry_m:
6383 ename, prop = entry_m.group(1), entry_m.group(3)
6384 entry, entry_name, prop_name = image.LookupEntry(entries,
6385 name, msg)
6386 if prop_name == 'offset':
6387 expect_val = entry.offset
6388 elif prop_name == 'image_pos':
6389 expect_val = entry.image_pos
6390 elif prop_name == 'size':
6391 expect_val = entry.size
6392 self.assertEqual(expect_val, val)
6393
6394 def testSymbolsElfBad(self):
6395 """Check error when trying to write symbols without the elftools lib"""
6396 if not elf.ELF_TOOLS:
6397 self.skipTest('Python elftools not available')
6398 self._SetupTplElf('u_boot_binman_syms')
6399 self._SetupVplElf('u_boot_binman_syms')
6400 self._SetupSplElf('u_boot_binman_syms')
6401 try:
6402 elf.ELF_TOOLS = False
6403 with self.assertRaises(ValueError) as exc:
6404 self._DoReadFileDtb('260_symbols_elf.dts')
6405 finally:
6406 elf.ELF_TOOLS = True
6407 self.assertIn(
6408 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6409 'Cannot write symbols to an ELF file without Python elftools',
6410 str(exc.exception))
6411
Simon Glassde244162023-01-07 14:07:08 -07006412 def testSectionFilename(self):
6413 """Check writing of section contents to a file"""
6414 data = self._DoReadFile('261_section_fname.dts')
6415 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6416 tools.get_bytes(ord('!'), 7) +
6417 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6418 self.assertEqual(expected, data)
6419
6420 sect_fname = tools.get_output_filename('outfile.bin')
6421 self.assertTrue(os.path.exists(sect_fname))
6422 sect_data = tools.read_file(sect_fname)
6423 self.assertEqual(U_BOOT_DATA, sect_data)
6424
Simon Glass1e9e61c2023-01-07 14:07:12 -07006425 def testAbsent(self):
6426 """Check handling of absent entries"""
6427 data = self._DoReadFile('262_absent.dts')
6428 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6429
Simon Glassad5cfe12023-01-07 14:07:14 -07006430 def testPackTeeOsOptional(self):
6431 """Test that an image with an optional TEE binary can be created"""
6432 entry_args = {
6433 'tee-os-path': 'tee.elf',
6434 }
6435 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6436 entry_args=entry_args)[0]
6437 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6438
6439 def checkFitTee(self, dts, tee_fname):
6440 """Check that a tee-os entry works and returns data
6441
6442 Args:
6443 dts (str): Device tree filename to use
6444 tee_fname (str): filename containing tee-os
6445
6446 Returns:
6447 bytes: Image contents
6448 """
6449 if not elf.ELF_TOOLS:
6450 self.skipTest('Python elftools not available')
6451 entry_args = {
6452 'of-list': 'test-fdt1 test-fdt2',
6453 'default-dt': 'test-fdt2',
6454 'tee-os-path': tee_fname,
6455 }
6456 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6457 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6458 extra_indirs=[test_subdir])[0]
6459 return data
6460
6461 def testFitTeeOsOptionalFit(self):
6462 """Test an image with a FIT with an optional OP-TEE binary"""
6463 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6464
6465 # There should be only one node, holding the data set up in SetUpClass()
6466 # for tee.bin
6467 dtb = fdt.Fdt.FromData(data)
6468 dtb.Scan()
6469 node = dtb.GetNode('/images/tee-1')
6470 self.assertEqual(TEE_ADDR,
6471 fdt_util.fdt32_to_cpu(node.props['load'].value))
6472 self.assertEqual(TEE_ADDR,
6473 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6474 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6475
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006476 with test_util.capture_sys_output() as (stdout, stderr):
6477 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6478 err = stderr.getvalue()
6479 self.assertRegex(
6480 err,
6481 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6482
Simon Glassad5cfe12023-01-07 14:07:14 -07006483 def testFitTeeOsOptionalFitBad(self):
6484 """Test an image with a FIT with an optional OP-TEE binary"""
6485 with self.assertRaises(ValueError) as exc:
6486 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6487 self.assertIn(
6488 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6489 str(exc.exception))
6490
6491 def testFitTeeOsBad(self):
6492 """Test an OP-TEE binary with wrong formats"""
6493 self.make_tee_bin('tee.bad1', 123)
6494 with self.assertRaises(ValueError) as exc:
6495 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6496 self.assertIn(
6497 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6498 str(exc.exception))
6499
6500 self.make_tee_bin('tee.bad2', 0, b'extra data')
6501 with self.assertRaises(ValueError) as exc:
6502 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6503 self.assertIn(
6504 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6505 str(exc.exception))
6506
Simon Glass63328f12023-01-07 14:07:15 -07006507 def testExtblobOptional(self):
6508 """Test an image with an external blob that is optional"""
6509 with test_util.capture_sys_output() as (stdout, stderr):
6510 data = self._DoReadFile('266_blob_ext_opt.dts')
6511 self.assertEqual(REFCODE_DATA, data)
6512 err = stderr.getvalue()
6513 self.assertRegex(
6514 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006515 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006516
Simon Glass7447a9d2023-01-11 16:10:12 -07006517 def testSectionInner(self):
6518 """Test an inner section with a size"""
6519 data = self._DoReadFile('267_section_inner.dts')
6520 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6521 self.assertEqual(expected, data)
6522
Simon Glassa4948b22023-01-11 16:10:14 -07006523 def testNull(self):
6524 """Test an image with a null entry"""
6525 data = self._DoReadFile('268_null.dts')
6526 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6527
Simon Glassf1ee03b2023-01-11 16:10:16 -07006528 def testOverlap(self):
6529 """Test an image with a overlapping entry"""
6530 data = self._DoReadFile('269_overlap.dts')
6531 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6532
6533 image = control.images['image']
6534 entries = image.GetEntries()
6535
6536 self.assertIn('inset', entries)
6537 inset = entries['inset']
6538 self.assertEqual(1, inset.offset);
6539 self.assertEqual(1, inset.image_pos);
6540 self.assertEqual(2, inset.size);
6541
6542 def testOverlapNull(self):
6543 """Test an image with a null overlap"""
6544 data = self._DoReadFile('270_overlap_null.dts')
6545 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6546
6547 # Check the FMAP
6548 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6549 self.assertEqual(4, fhdr.nareas)
6550 fiter = iter(fentries)
6551
6552 fentry = next(fiter)
6553 self.assertEqual(b'SECTION', fentry.name)
6554 self.assertEqual(0, fentry.offset)
6555 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6556 self.assertEqual(0, fentry.flags)
6557
6558 fentry = next(fiter)
6559 self.assertEqual(b'U_BOOT', fentry.name)
6560 self.assertEqual(0, fentry.offset)
6561 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6562 self.assertEqual(0, fentry.flags)
6563
6564 # Make sure that the NULL entry appears in the FMAP
6565 fentry = next(fiter)
6566 self.assertEqual(b'NULL', fentry.name)
6567 self.assertEqual(1, fentry.offset)
6568 self.assertEqual(2, fentry.size)
6569 self.assertEqual(0, fentry.flags)
6570
6571 fentry = next(fiter)
6572 self.assertEqual(b'FMAP', fentry.name)
6573 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6574
6575 def testOverlapBad(self):
6576 """Test an image with a bad overlapping entry"""
6577 with self.assertRaises(ValueError) as exc:
6578 self._DoReadFile('271_overlap_bad.dts')
6579 self.assertIn(
6580 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6581 str(exc.exception))
6582
6583 def testOverlapNoOffset(self):
6584 """Test an image with a bad overlapping entry"""
6585 with self.assertRaises(ValueError) as exc:
6586 self._DoReadFile('272_overlap_no_size.dts')
6587 self.assertIn(
6588 "Node '/binman/inset': 'fill' entry is missing properties: size",
6589 str(exc.exception))
6590
Simon Glasse0035c92023-01-11 16:10:17 -07006591 def testBlobSymbol(self):
6592 """Test a blob with symbols read from an ELF file"""
6593 elf_fname = self.ElfTestFile('blob_syms')
6594 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6595 TestFunctional._MakeInputFile('blob_syms.bin',
6596 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6597
6598 data = self._DoReadFile('273_blob_symbol.dts')
6599
6600 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6601 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6602 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6603 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6604 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6605
6606 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6607 expected = sym_values
6608 self.assertEqual(expected, data[:len(expected)])
6609
Simon Glass49e9c002023-01-11 16:10:19 -07006610 def testOffsetFromElf(self):
6611 """Test a blob with symbols read from an ELF file"""
6612 elf_fname = self.ElfTestFile('blob_syms')
6613 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6614 TestFunctional._MakeInputFile('blob_syms.bin',
6615 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6616
6617 data = self._DoReadFile('274_offset_from_elf.dts')
6618
6619 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6620 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6621
6622 image = control.images['image']
6623 entries = image.GetEntries()
6624
6625 self.assertIn('inset', entries)
6626 inset = entries['inset']
6627
6628 self.assertEqual(base + 4, inset.offset);
6629 self.assertEqual(base + 4, inset.image_pos);
6630 self.assertEqual(4, inset.size);
6631
6632 self.assertIn('inset2', entries)
6633 inset = entries['inset2']
6634 self.assertEqual(base + 8, inset.offset);
6635 self.assertEqual(base + 8, inset.image_pos);
6636 self.assertEqual(4, inset.size);
6637
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006638 def testFitAlign(self):
6639 """Test an image with an FIT with aligned external data"""
6640 data = self._DoReadFile('275_fit_align.dts')
6641 self.assertEqual(4096, len(data))
6642
6643 dtb = fdt.Fdt.FromData(data)
6644 dtb.Scan()
6645
6646 props = self._GetPropTree(dtb, ['data-position'])
6647 expected = {
6648 'u-boot:data-position': 1024,
6649 'fdt-1:data-position': 2048,
6650 'fdt-2:data-position': 3072,
6651 }
6652 self.assertEqual(expected, props)
6653
Jonas Karlman490f73c2023-01-21 19:02:12 +00006654 def testFitFirmwareLoadables(self):
6655 """Test an image with an FIT that use fit,firmware"""
6656 if not elf.ELF_TOOLS:
6657 self.skipTest('Python elftools not available')
6658 entry_args = {
6659 'of-list': 'test-fdt1',
6660 'default-dt': 'test-fdt1',
6661 'atf-bl31-path': 'bl31.elf',
6662 'tee-os-path': 'missing.bin',
6663 }
6664 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006665 with test_util.capture_sys_output() as (stdout, stderr):
6666 data = self._DoReadFileDtb(
6667 '276_fit_firmware_loadables.dts',
6668 entry_args=entry_args,
6669 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006670
6671 dtb = fdt.Fdt.FromData(data)
6672 dtb.Scan()
6673
6674 node = dtb.GetNode('/configurations/conf-uboot-1')
6675 self.assertEqual('u-boot', node.props['firmware'].value)
6676 self.assertEqual(['atf-1', 'atf-2'],
6677 fdt_util.GetStringList(node, 'loadables'))
6678
6679 node = dtb.GetNode('/configurations/conf-atf-1')
6680 self.assertEqual('atf-1', node.props['firmware'].value)
6681 self.assertEqual(['u-boot', 'atf-2'],
6682 fdt_util.GetStringList(node, 'loadables'))
6683
6684 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6685 self.assertEqual('u-boot', node.props['firmware'].value)
6686 self.assertEqual(['atf-1', 'atf-2'],
6687 fdt_util.GetStringList(node, 'loadables'))
6688
6689 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6690 self.assertEqual('atf-1', node.props['firmware'].value)
6691 self.assertEqual(['u-boot', 'atf-2'],
6692 fdt_util.GetStringList(node, 'loadables'))
6693
6694 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6695 self.assertEqual('atf-1', node.props['firmware'].value)
6696 self.assertEqual(['u-boot', 'atf-2'],
6697 fdt_util.GetStringList(node, 'loadables'))
6698
Simon Glass9a1c7262023-02-22 12:14:49 -07006699 def testTooldir(self):
6700 """Test that we can specify the tooldir"""
6701 with test_util.capture_sys_output() as (stdout, stderr):
6702 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6703 'tool', '-l'))
6704 self.assertEqual('fred', bintool.Bintool.tooldir)
6705
6706 # Check that the toolpath is updated correctly
6707 self.assertEqual(['fred'], tools.tool_search_paths)
6708
6709 # Try with a few toolpaths; the tooldir should be at the end
6710 with test_util.capture_sys_output() as (stdout, stderr):
6711 self.assertEqual(0, self._DoBinman(
6712 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6713 'tool', '-l'))
6714 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6715
Simon Glass49b77e82023-03-02 17:02:44 -07006716 def testReplaceSectionEntry(self):
6717 """Test replacing an entry in a section"""
6718 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6719 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6720 expect_data, dts='241_replace_section_simple.dts')
6721 self.assertEqual(expect_data, entry_data)
6722
6723 entries = image.GetEntries()
6724 self.assertIn('section', entries)
6725 section = entries['section']
6726
6727 sect_entries = section.GetEntries()
6728 self.assertIn('blob', sect_entries)
6729 entry = sect_entries['blob']
6730 self.assertEqual(len(expect_data), entry.size)
6731
6732 fname = tools.get_output_filename('image-updated.bin')
6733 data = tools.read_file(fname)
6734
6735 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6736 self.assertEqual(expect_data, new_blob_data)
6737
6738 self.assertEqual(U_BOOT_DATA,
6739 data[entry.image_pos + len(expect_data):]
6740 [:len(U_BOOT_DATA)])
6741
6742 def testReplaceSectionDeep(self):
6743 """Test replacing an entry in two levels of sections"""
6744 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6745 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6746 'section/section/blob', expect_data,
6747 dts='278_replace_section_deep.dts')
6748 self.assertEqual(expect_data, entry_data)
6749
6750 entries = image.GetEntries()
6751 self.assertIn('section', entries)
6752 section = entries['section']
6753
6754 subentries = section.GetEntries()
6755 self.assertIn('section', subentries)
6756 section = subentries['section']
6757
6758 sect_entries = section.GetEntries()
6759 self.assertIn('blob', sect_entries)
6760 entry = sect_entries['blob']
6761 self.assertEqual(len(expect_data), entry.size)
6762
6763 fname = tools.get_output_filename('image-updated.bin')
6764 data = tools.read_file(fname)
6765
6766 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6767 self.assertEqual(expect_data, new_blob_data)
6768
6769 self.assertEqual(U_BOOT_DATA,
6770 data[entry.image_pos + len(expect_data):]
6771 [:len(U_BOOT_DATA)])
6772
6773 def testReplaceFitSibling(self):
6774 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006775 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006776 fname = TestFunctional._MakeInputFile('once', b'available once')
6777 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6778 os.remove(fname)
6779
6780 try:
6781 tmpdir, updated_fname = self._SetupImageInTmpdir()
6782
6783 fname = os.path.join(tmpdir, 'update-blob')
6784 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6785 tools.write_file(fname, expected)
6786
6787 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6788 data = tools.read_file(updated_fname)
6789 start = len(U_BOOT_DTB_DATA)
6790 self.assertEqual(expected, data[start:start + len(expected)])
6791 map_fname = os.path.join(tmpdir, 'image-updated.map')
6792 self.assertFalse(os.path.exists(map_fname))
6793 finally:
6794 shutil.rmtree(tmpdir)
6795
Simon Glassc3fe97f2023-03-02 17:02:45 -07006796 def testX509Cert(self):
6797 """Test creating an X509 certificate"""
6798 keyfile = self.TestFile('key.key')
6799 entry_args = {
6800 'keyfile': keyfile,
6801 }
6802 data = self._DoReadFileDtb('279_x509_cert.dts',
6803 entry_args=entry_args)[0]
6804 cert = data[:-4]
6805 self.assertEqual(U_BOOT_DATA, data[-4:])
6806
6807 # TODO: verify the signature
6808
6809 def testX509CertMissing(self):
6810 """Test that binman still produces an image if openssl is missing"""
6811 keyfile = self.TestFile('key.key')
6812 entry_args = {
6813 'keyfile': 'keyfile',
6814 }
6815 with test_util.capture_sys_output() as (_, stderr):
6816 self._DoTestFile('279_x509_cert.dts',
6817 force_missing_bintools='openssl',
6818 entry_args=entry_args)
6819 err = stderr.getvalue()
6820 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6821
Jonas Karlman35305492023-02-25 19:01:33 +00006822 def testPackRockchipTpl(self):
6823 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006824 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006825 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6826
Jonas Karlman1016ec72023-02-25 19:01:35 +00006827 def testMkimageMissingBlobMultiple(self):
6828 """Test missing blob with mkimage entry and multiple-data-files"""
6829 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006830 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006831 err = stderr.getvalue()
6832 self.assertIn("is missing external blobs and is non-functional", err)
6833
6834 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006835 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006836 self.assertIn("not found in input path", str(e.exception))
6837
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006838 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6839 """Prepare sign environment
6840
6841 Create private and public keys, add pubkey into dtb.
6842
6843 Returns:
6844 Tuple:
6845 FIT container
6846 Image name
6847 Private key
6848 DTB
6849 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006850 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006851 data = self._DoReadFileRealDtb(dts)
6852 updated_fname = tools.get_output_filename('image-updated.bin')
6853 tools.write_file(updated_fname, data)
6854 dtb = tools.get_output_filename('source.dtb')
6855 private_key = tools.get_output_filename('test_key.key')
6856 public_key = tools.get_output_filename('test_key.crt')
6857 fit = tools.get_output_filename('fit.fit')
6858 key_dir = tools.get_output_dir()
6859
6860 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6861 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6862 private_key, '-out', public_key)
6863 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6864 '-n', 'test_key', '-r', 'conf', dtb)
6865
6866 return fit, updated_fname, private_key, dtb
6867
6868 def testSignSimple(self):
6869 """Test that a FIT container can be signed in image"""
6870 is_signed = False
6871 fit, fname, private_key, dtb = self._PrepareSignEnv()
6872
6873 # do sign with private key
6874 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6875 ['fit'])
6876 is_signed = self._CheckSign(fit, dtb)
6877
6878 self.assertEqual(is_signed, True)
6879
6880 def testSignExactFIT(self):
6881 """Test that a FIT container can be signed and replaced in image"""
6882 is_signed = False
6883 fit, fname, private_key, dtb = self._PrepareSignEnv()
6884
6885 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6886 args = []
6887 if self.toolpath:
6888 for path in self.toolpath:
6889 args += ['--toolpath', path]
6890
6891 # do sign with private key
6892 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6893 'sha256,rsa4096', '-f', fit, 'fit')
6894 is_signed = self._CheckSign(fit, dtb)
6895
6896 self.assertEqual(is_signed, True)
6897
6898 def testSignNonFit(self):
6899 """Test a non-FIT entry cannot be signed"""
6900 is_signed = False
6901 fit, fname, private_key, _ = self._PrepareSignEnv(
6902 '281_sign_non_fit.dts')
6903
6904 # do sign with private key
6905 with self.assertRaises(ValueError) as e:
6906 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6907 'sha256,rsa4096', '-f', fit, 'u-boot')
6908 self.assertIn(
6909 "Node '/u-boot': Updating signatures is not supported with this entry type",
6910 str(e.exception))
6911
6912 def testSignMissingMkimage(self):
6913 """Test that FIT signing handles a missing mkimage tool"""
6914 fit, fname, private_key, _ = self._PrepareSignEnv()
6915
6916 # try to sign with a missing mkimage tool
6917 bintool.Bintool.set_missing_list(['mkimage'])
6918 with self.assertRaises(ValueError) as e:
6919 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6920 ['fit'])
6921 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6922
Simon Glass4abf7842023-07-18 07:23:54 -06006923 def testSymbolNoWrite(self):
6924 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006925 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006926 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6927 no_write_symbols=True)
6928
6929 def testSymbolNoWriteExpanded(self):
6930 """Test disabling of symbol writing in expanded entries"""
6931 entry_args = {
6932 'spl-dtb': '1',
6933 }
6934 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6935 U_BOOT_SPL_DTB_DATA, 0x38,
6936 entry_args=entry_args, use_expanded=True,
6937 no_write_symbols=True)
6938
Marek Vasutf7413f02023-07-18 07:23:58 -06006939 def testMkimageSpecial(self):
6940 """Test mkimage ignores special hash-1 node"""
6941 data = self._DoReadFile('283_mkimage_special.dts')
6942
6943 # Just check that the data appears in the file somewhere
6944 self.assertIn(U_BOOT_DATA, data)
6945
Simon Glass2d94c422023-07-18 07:23:59 -06006946 def testFitFdtList(self):
6947 """Test an image with an FIT with the fit,fdt-list-val option"""
6948 entry_args = {
6949 'default-dt': 'test-fdt2',
6950 }
6951 data = self._DoReadFileDtb(
6952 '284_fit_fdt_list.dts',
6953 entry_args=entry_args,
6954 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6955 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6956 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6957
Simon Glass83b8bfe2023-07-18 07:24:01 -06006958 def testSplEmptyBss(self):
6959 """Test an expanded SPL with a zero-size BSS"""
6960 # ELF file with a '__bss_size' symbol
6961 self._SetupSplElf(src_fname='bss_data_zero')
6962
6963 entry_args = {
6964 'spl-bss-pad': 'y',
6965 'spl-dtb': 'y',
6966 }
6967 data = self._DoReadFileDtb('285_spl_expand.dts',
6968 use_expanded=True, entry_args=entry_args)[0]
6969
Simon Glassfc792842023-07-18 07:24:04 -06006970 def testTemplate(self):
6971 """Test using a template"""
6972 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6973 data = self._DoReadFile('286_template.dts')
6974 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6975 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6976 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6977
Simon Glass09490b02023-07-22 21:43:52 -06006978 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6979 self.assertTrue(os.path.exists(dtb_fname1))
6980 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6981 dtb.Scan()
6982 node1 = dtb.GetNode('/binman/template')
6983 self.assertTrue(node1)
6984 vga = dtb.GetNode('/binman/first/intel-vga')
6985 self.assertTrue(vga)
6986
Simon Glass54825e12023-07-22 21:43:56 -06006987 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6988 self.assertTrue(os.path.exists(dtb_fname2))
6989 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6990 dtb2.Scan()
6991 node2 = dtb2.GetNode('/binman/template')
6992 self.assertFalse(node2)
6993
Simon Glass9909c112023-07-18 07:24:05 -06006994 def testTemplateBlobMulti(self):
6995 """Test using a template with 'multiple-images' enabled"""
6996 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6997 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6998 retcode = self._DoTestFile('287_template_multi.dts')
6999
7000 self.assertEqual(0, retcode)
7001 image = control.images['image']
7002 image_fname = tools.get_output_filename('my-image.bin')
7003 data = tools.read_file(image_fname)
7004 self.assertEqual(b'blob@@@@other', data)
7005
Simon Glass5dc511b2023-07-18 07:24:06 -06007006 def testTemplateFit(self):
7007 """Test using a template in a FIT"""
7008 fit_data = self._DoReadFile('288_template_fit.dts')
7009 fname = os.path.join(self._indir, 'fit_data.fit')
7010 tools.write_file(fname, fit_data)
7011 out = tools.run('dumpimage', '-l', fname)
7012
Simon Glassaa6e0552023-07-18 07:24:07 -06007013 def testTemplateSection(self):
7014 """Test using a template in a section (not at top level)"""
7015 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
7016 data = self._DoReadFile('289_template_section.dts')
7017 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
7018 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
7019 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
7020
Simon Glassf53a7bc2023-07-18 07:24:08 -06007021 def testMkimageSymbols(self):
7022 """Test using mkimage to build an image with symbols in it"""
7023 self._SetupSplElf('u_boot_binman_syms')
7024 data = self._DoReadFile('290_mkimage_sym.dts')
7025
7026 image = control.images['image']
7027 entries = image.GetEntries()
7028 self.assertIn('u-boot', entries)
7029 u_boot = entries['u-boot']
7030
7031 mkim = entries['mkimage']
7032 mkim_entries = mkim.GetEntries()
7033 self.assertIn('u-boot-spl', mkim_entries)
7034 spl = mkim_entries['u-boot-spl']
7035 self.assertIn('u-boot-spl2', mkim_entries)
7036 spl2 = mkim_entries['u-boot-spl2']
7037
7038 # skip the mkimage header and the area sizes
7039 mk_data = data[mkim.offset + 0x40:]
7040 size, term = struct.unpack('>LL', mk_data[:8])
7041
7042 # There should be only one image, so check that the zero terminator is
7043 # present
7044 self.assertEqual(0, term)
7045
7046 content = mk_data[8:8 + size]
7047
7048 # The image should contain the symbols from u_boot_binman_syms.c
7049 # Note that image_pos is adjusted by the base address of the image,
7050 # which is 0x10 in our test image
7051 spl_data = content[:0x18]
7052 content = content[0x1b:]
7053
7054 # After the header is a table of offsets for each image. There should
7055 # only be one image, then a 0 terminator, so figure out the real start
7056 # of the image data
7057 base = 0x40 + 8
7058
7059 # Check symbols in both u-boot-spl and u-boot-spl2
7060 for i in range(2):
7061 vals = struct.unpack('<LLQLL', spl_data)
7062
7063 # The image should contain the symbols from u_boot_binman_syms.c
7064 # Note that image_pos is adjusted by the base address of the image,
7065 # which is 0x10 in our 'u_boot_binman_syms' test image
7066 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
7067 self.assertEqual(base, vals[1])
7068 self.assertEqual(spl2.offset, vals[2])
7069 # figure out the internal positions of its components
7070 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
7071
7072 # Check that spl and spl2 are actually at the indicated positions
7073 self.assertEqual(
7074 elf.BINMAN_SYM_MAGIC_VALUE,
7075 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
7076 self.assertEqual(
7077 elf.BINMAN_SYM_MAGIC_VALUE,
7078 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
7079
7080 self.assertEqual(len(U_BOOT_DATA), vals[4])
7081
7082 # Move to next
7083 spl_data = content[:0x18]
7084
Simon Glass86b3e472023-07-22 21:43:57 -06007085 def testTemplatePhandle(self):
7086 """Test using a template in a node containing a phandle"""
7087 entry_args = {
7088 'atf-bl31-path': 'bl31.elf',
7089 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06007090 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007091 entry_args=entry_args)
7092 fname = tools.get_output_filename('image.bin')
7093 out = tools.run('dumpimage', '-l', fname)
7094
7095 # We should see the FIT description and one for each of the two images
7096 lines = out.splitlines()
7097 descs = [line.split()[-1] for line in lines if 'escription' in line]
7098 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7099
7100 def testTemplatePhandleDup(self):
7101 """Test using a template in a node containing a phandle"""
7102 entry_args = {
7103 'atf-bl31-path': 'bl31.elf',
7104 }
7105 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007106 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007107 entry_args=entry_args)
7108 self.assertIn(
7109 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7110 str(e.exception))
7111
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307112 def testTIBoardConfig(self):
7113 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007114 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307115 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7116
Neha Malcom Francis8cd04512024-01-05 17:09:17 +05307117 def testTIBoardConfigLint(self):
7118 """Test that an incorrectly linted config file would generate error"""
7119 with self.assertRaises(ValueError) as e:
7120 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7121 self.assertIn("Yamllint error", str(e.exception))
7122
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307123 def testTIBoardConfigCombined(self):
7124 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007125 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307126 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7127 self.assertGreater(data, configlen_noheader)
7128
7129 def testTIBoardConfigNoDataType(self):
7130 """Test that error is thrown when data type is not supported"""
7131 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007132 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307133 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007134
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307135 def testPackTiSecure(self):
7136 """Test that an image with a TI secured binary can be created"""
7137 keyfile = self.TestFile('key.key')
7138 entry_args = {
7139 'keyfile': keyfile,
7140 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007141 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307142 entry_args=entry_args)[0]
7143 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7144
Manorit Chawdhry2e523b02023-12-29 16:16:27 +05307145 def testPackTiSecureFirewall(self):
7146 """Test that an image with a TI secured binary can be created"""
7147 keyfile = self.TestFile('key.key')
7148 entry_args = {
7149 'keyfile': keyfile,
7150 }
7151 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7152 entry_args=entry_args)[0]
7153 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7154 entry_args=entry_args)[0]
7155 self.assertGreater(len(data_firewall),len(data_no_firewall))
7156
7157 def testPackTiSecureFirewallMissingProperty(self):
7158 """Test that an image with a TI secured binary can be created"""
7159 keyfile = self.TestFile('key.key')
7160 entry_args = {
7161 'keyfile': keyfile,
7162 }
7163 with self.assertRaises(ValueError) as e:
7164 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7165 entry_args=entry_args)[0]
7166 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7167
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307168 def testPackTiSecureMissingTool(self):
7169 """Test that an image with a TI secured binary (non-functional) can be created
7170 when openssl is missing"""
7171 keyfile = self.TestFile('key.key')
7172 entry_args = {
7173 'keyfile': keyfile,
7174 }
7175 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007176 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307177 force_missing_bintools='openssl',
7178 entry_args=entry_args)
7179 err = stderr.getvalue()
7180 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7181
7182 def testPackTiSecureROM(self):
7183 """Test that a ROM image with a TI secured binary can be created"""
7184 keyfile = self.TestFile('key.key')
7185 entry_args = {
7186 'keyfile': keyfile,
7187 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007188 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307189 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007190 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307191 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007192 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307193 entry_args=entry_args)[0]
7194 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7195 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7196 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7197
7198 def testPackTiSecureROMCombined(self):
7199 """Test that a ROM image with a TI secured binary can be created"""
7200 keyfile = self.TestFile('key.key')
7201 entry_args = {
7202 'keyfile': keyfile,
7203 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007204 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307205 entry_args=entry_args)[0]
7206 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7207
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007208 def testEncryptedNoAlgo(self):
7209 """Test encrypted node with missing required properties"""
7210 with self.assertRaises(ValueError) as e:
7211 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7212 self.assertIn(
7213 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7214 str(e.exception))
7215
7216 def testEncryptedInvalidIvfile(self):
7217 """Test encrypted node with invalid iv file"""
7218 with self.assertRaises(ValueError) as e:
7219 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7220 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7221 str(e.exception))
7222
7223 def testEncryptedMissingKey(self):
7224 """Test encrypted node with missing key properties"""
7225 with self.assertRaises(ValueError) as e:
7226 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7227 self.assertIn(
7228 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7229 str(e.exception))
7230
7231 def testEncryptedKeySource(self):
7232 """Test encrypted node with key-source property"""
7233 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7234
7235 dtb = fdt.Fdt.FromData(data)
7236 dtb.Scan()
7237
7238 node = dtb.GetNode('/images/u-boot/cipher')
7239 self.assertEqual('algo-name', node.props['algo'].value)
7240 self.assertEqual('key-source-value', node.props['key-source'].value)
7241 self.assertEqual(ENCRYPTED_IV_DATA,
7242 tools.to_bytes(''.join(node.props['iv'].value)))
7243 self.assertNotIn('key', node.props)
7244
7245 def testEncryptedKeyFile(self):
7246 """Test encrypted node with key-filename property"""
7247 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7248
7249 dtb = fdt.Fdt.FromData(data)
7250 dtb.Scan()
7251
7252 node = dtb.GetNode('/images/u-boot/cipher')
7253 self.assertEqual('algo-name', node.props['algo'].value)
7254 self.assertEqual(ENCRYPTED_IV_DATA,
7255 tools.to_bytes(''.join(node.props['iv'].value)))
7256 self.assertEqual(ENCRYPTED_KEY_DATA,
7257 tools.to_bytes(''.join(node.props['key'].value)))
7258 self.assertNotIn('key-source', node.props)
7259
Lukas Funkee901faf2023-07-18 13:53:13 +02007260
7261 def testSplPubkeyDtb(self):
Simon Glass4b861272024-07-20 11:49:41 +01007262 """Test u_boot_spl_pubkey_dtb etype"""
7263 data = tools.read_file(self.TestFile("key.pem"))
7264 self._MakeInputFile("key.crt", data)
7265 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7266 image = control.images['image']
7267 entries = image.GetEntries()
7268 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7269 dtb_data = dtb_entry.GetData()
7270 dtb = fdt.Fdt.FromData(dtb_data)
7271 dtb.Scan()
Lukas Funkee901faf2023-07-18 13:53:13 +02007272
Simon Glass4b861272024-07-20 11:49:41 +01007273 signature_node = dtb.GetNode('/signature')
7274 self.assertIsNotNone(signature_node)
7275 key_node = signature_node.FindNode("key-key")
7276 self.assertIsNotNone(key_node)
7277 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7278 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7279 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007280
Lukas Funke712e1062023-08-03 17:22:14 +02007281 def testXilinxBootgenSigning(self):
7282 """Test xilinx-bootgen etype"""
7283 bootgen = bintool.Bintool.create('bootgen')
7284 self._CheckBintool(bootgen)
7285 data = tools.read_file(self.TestFile("key.key"))
7286 self._MakeInputFile("psk.pem", data)
7287 self._MakeInputFile("ssk.pem", data)
7288 self._SetupPmuFwlElf()
7289 self._SetupSplElf()
7290 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7291 image_fname = tools.get_output_filename('image.bin')
7292
7293 # Read partition header table and check if authentication is enabled
7294 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7295 "-read", image_fname, "pht").splitlines()
7296 attributes = {"authentication": None,
7297 "core": None,
7298 "encryption": None}
7299
7300 for l in bootgen_out:
7301 for a in attributes.keys():
7302 if a in l:
7303 m = re.match(fr".*{a} \[([^]]+)\]", l)
7304 attributes[a] = m.group(1)
7305
7306 self.assertTrue(attributes['authentication'] == "rsa")
7307 self.assertTrue(attributes['core'] == "a53-0")
7308 self.assertTrue(attributes['encryption'] == "no")
7309
7310 def testXilinxBootgenSigningEncryption(self):
7311 """Test xilinx-bootgen etype"""
7312 bootgen = bintool.Bintool.create('bootgen')
7313 self._CheckBintool(bootgen)
7314 data = tools.read_file(self.TestFile("key.key"))
7315 self._MakeInputFile("psk.pem", data)
7316 self._MakeInputFile("ssk.pem", data)
7317 self._SetupPmuFwlElf()
7318 self._SetupSplElf()
7319 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7320 image_fname = tools.get_output_filename('image.bin')
7321
7322 # Read boot header in order to verify encryption source and
7323 # encryption parameter
7324 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7325 "-read", image_fname, "bh").splitlines()
7326 attributes = {"auth_only":
7327 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7328 "encryption_keystore":
7329 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7330 "value": None},
7331 }
7332
7333 for l in bootgen_out:
7334 for a in attributes.keys():
7335 if a in l:
7336 m = re.match(attributes[a]['re'], l)
7337 attributes[a] = m.group(1)
7338
7339 # Check if fsbl-attribute is set correctly
7340 self.assertTrue(attributes['auth_only'] == "true")
7341 # Check if key is stored in efuse
7342 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7343
7344 def testXilinxBootgenMissing(self):
7345 """Test that binman still produces an image if bootgen is missing"""
7346 data = tools.read_file(self.TestFile("key.key"))
7347 self._MakeInputFile("psk.pem", data)
7348 self._MakeInputFile("ssk.pem", data)
7349 self._SetupPmuFwlElf()
7350 self._SetupSplElf()
7351 with test_util.capture_sys_output() as (_, stderr):
7352 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7353 force_missing_bintools='bootgen')
7354 err = stderr.getvalue()
7355 self.assertRegex(err,
7356 "Image 'image'.*missing bintools.*: bootgen")
7357
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307358 def _GetCapsuleHeaders(self, data):
7359 """Get the capsule header contents
7360
7361 Args:
7362 data: Capsule file contents
7363
7364 Returns:
7365 Dict:
7366 key: Capsule Header name (str)
7367 value: Header field value (str)
7368 """
7369 capsule_file = os.path.join(self._indir, 'test.capsule')
7370 tools.write_file(capsule_file, data)
7371
7372 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7373 lines = out.splitlines()
7374
7375 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7376 vals = {}
7377 for line in lines:
7378 mat = re_line.match(line)
7379 if mat:
7380 vals[mat.group(1)] = mat.group(2)
7381
7382 return vals
7383
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307384 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7385 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307386 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7387 fmp_size = "00000010"
7388 fmp_fw_version = "00000002"
7389 capsule_image_index = "00000001"
7390 oemflag = "00018000"
7391 auth_hdr_revision = "00000200"
7392 auth_hdr_cert_type = "00000EF1"
7393
7394 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307395
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307396 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307397
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307398 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307399
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307400 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7401 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7402 self.assertEqual(capsule_image_index,
7403 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307404
7405 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307406 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7407
7408 if signed_capsule:
7409 self.assertEqual(auth_hdr_revision,
7410 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7411 self.assertEqual(auth_hdr_cert_type,
7412 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7413 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7414 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7415
7416 if version_check:
7417 self.assertEqual(fmp_signature,
7418 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7419 self.assertEqual(fmp_size,
7420 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7421 self.assertEqual(fmp_fw_version,
7422 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7423
7424 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307425
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307426 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7427 if accept_capsule:
7428 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7429 else:
7430 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7431
7432 hdr = self._GetCapsuleHeaders(data)
7433
7434 self.assertEqual(capsule_hdr_guid.upper(),
7435 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7436
7437 if accept_capsule:
7438 capsule_size = "0000002C"
7439 else:
7440 capsule_size = "0000001C"
7441 self.assertEqual(capsule_size,
7442 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7443
7444 if accept_capsule:
7445 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7446
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307447 def testCapsuleGen(self):
7448 """Test generation of EFI capsule"""
7449 data = self._DoReadFile('311_capsule.dts')
7450
7451 self._CheckCapsule(data)
7452
7453 def testSignedCapsuleGen(self):
7454 """Test generation of EFI capsule"""
7455 data = tools.read_file(self.TestFile("key.key"))
7456 self._MakeInputFile("key.key", data)
7457 data = tools.read_file(self.TestFile("key.pem"))
7458 self._MakeInputFile("key.crt", data)
7459
7460 data = self._DoReadFile('312_capsule_signed.dts')
7461
7462 self._CheckCapsule(data, signed_capsule=True)
7463
7464 def testCapsuleGenVersionSupport(self):
7465 """Test generation of EFI capsule with version support"""
7466 data = self._DoReadFile('313_capsule_version.dts')
7467
7468 self._CheckCapsule(data, version_check=True)
7469
7470 def testCapsuleGenSignedVer(self):
7471 """Test generation of signed EFI capsule with version information"""
7472 data = tools.read_file(self.TestFile("key.key"))
7473 self._MakeInputFile("key.key", data)
7474 data = tools.read_file(self.TestFile("key.pem"))
7475 self._MakeInputFile("key.crt", data)
7476
7477 data = self._DoReadFile('314_capsule_signed_ver.dts')
7478
7479 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7480
7481 def testCapsuleGenCapOemFlags(self):
7482 """Test generation of EFI capsule with OEM Flags set"""
7483 data = self._DoReadFile('315_capsule_oemflags.dts')
7484
7485 self._CheckCapsule(data, capoemflags=True)
7486
7487 def testCapsuleGenKeyMissing(self):
7488 """Test that binman errors out on missing key"""
7489 with self.assertRaises(ValueError) as e:
7490 self._DoReadFile('316_capsule_missing_key.dts')
7491
7492 self.assertIn("Both private key and public key certificate need to be provided",
7493 str(e.exception))
7494
7495 def testCapsuleGenIndexMissing(self):
7496 """Test that binman errors out on missing image index"""
7497 with self.assertRaises(ValueError) as e:
7498 self._DoReadFile('317_capsule_missing_index.dts')
7499
7500 self.assertIn("entry is missing properties: image-index",
7501 str(e.exception))
7502
7503 def testCapsuleGenGuidMissing(self):
7504 """Test that binman errors out on missing image GUID"""
7505 with self.assertRaises(ValueError) as e:
7506 self._DoReadFile('318_capsule_missing_guid.dts')
7507
7508 self.assertIn("entry is missing properties: image-guid",
7509 str(e.exception))
7510
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307511 def testCapsuleGenAcceptCapsule(self):
7512 """Test generationg of accept EFI capsule"""
7513 data = self._DoReadFile('319_capsule_accept.dts')
7514
7515 self._CheckEmptyCapsule(data, accept_capsule=True)
7516
7517 def testCapsuleGenRevertCapsule(self):
7518 """Test generationg of revert EFI capsule"""
7519 data = self._DoReadFile('320_capsule_revert.dts')
7520
7521 self._CheckEmptyCapsule(data)
7522
7523 def testCapsuleGenAcceptGuidMissing(self):
7524 """Test that binman errors out on missing image GUID for accept capsule"""
7525 with self.assertRaises(ValueError) as e:
7526 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7527
7528 self.assertIn("Image GUID needed for generating accept capsule",
7529 str(e.exception))
7530
7531 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7532 """Test that capsule-type is specified"""
7533 with self.assertRaises(ValueError) as e:
7534 self._DoReadFile('322_empty_capsule_type_missing.dts')
7535
7536 self.assertIn("entry is missing properties: capsule-type",
7537 str(e.exception))
7538
7539 def testCapsuleGenAcceptOrRevertMissing(self):
7540 """Test that both accept and revert capsule are not specified"""
7541 with self.assertRaises(ValueError) as e:
7542 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7543
Simon Glassa360b8f2024-06-23 11:55:06 -06007544 def test_assume_size(self):
7545 """Test handling of the assume-size property for external blob"""
7546 with self.assertRaises(ValueError) as e:
7547 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7548 allow_fake_blobs=True)
7549 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7550 str(e.exception))
7551
7552 def test_assume_size_ok(self):
7553 """Test handling of the assume-size where it fits OK"""
7554 with test_util.capture_sys_output() as (stdout, stderr):
7555 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7556 allow_fake_blobs=True)
7557 err = stderr.getvalue()
7558 self.assertRegex(
7559 err,
7560 "Image '.*' has faked external blobs and is non-functional: .*")
7561
7562 def test_assume_size_no_fake(self):
7563 """Test handling of the assume-size where it fits OK"""
7564 with test_util.capture_sys_output() as (stdout, stderr):
7565 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7566 err = stderr.getvalue()
7567 self.assertRegex(
7568 err,
7569 "Image '.*' is missing external blobs and is non-functional: .*")
7570
Simon Glass5f7aadf2024-07-20 11:49:47 +01007571 def SetupAlternateDts(self):
7572 """Compile the .dts test files for alternative-fdt
7573
7574 Returns:
7575 tuple:
7576 str: Test directory created
7577 list of str: '.bin' files which we expect Binman to create
7578 """
7579 testdir = TestFunctional._MakeInputDir('dtb')
7580 dtb_list = []
7581 for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
7582 tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
7583 base = os.path.splitext(os.path.basename(fname))[0]
7584 dtb_list.append(base + '.bin')
7585 shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
7586
7587 return testdir, dtb_list
7588
Simon Glassf3598922024-07-20 11:49:45 +01007589 def CheckAlternates(self, dts, phase, xpl_data):
7590 """Run the test for the alterative-fdt etype
7591
7592 Args:
7593 dts (str): Devicetree file to process
7594 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7595 xpl_data (bytes): Expected data for the phase's binary
7596
7597 Returns:
7598 dict of .dtb files produced
7599 key: str filename
7600 value: Fdt object
7601 """
Simon Glass5f7aadf2024-07-20 11:49:47 +01007602 dtb_list = self.SetupAlternateDts()[1]
Simon Glassf3598922024-07-20 11:49:45 +01007603
7604 entry_args = {
7605 f'{phase}-dtb': '1',
7606 f'{phase}-bss-pad': 'y',
7607 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7608 }
7609 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7610 use_expanded=True, entry_args=entry_args)[0]
7611 self.assertEqual(xpl_data, data[:len(xpl_data)])
7612 rest = data[len(xpl_data):]
7613 pad_len = 10
7614 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7615
7616 # Check the dtb is using the test file
7617 dtb_data = rest[pad_len:]
7618 dtb = fdt.Fdt.FromData(dtb_data)
7619 dtb.Scan()
7620 fdt_size = dtb.GetFdtObj().totalsize()
7621 self.assertEqual('model-not-set',
7622 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7623
7624 pad_len = 10
7625
7626 # Check the other output files
7627 dtbs = {}
7628 for fname in dtb_list:
7629 pathname = tools.get_output_filename(fname)
7630 self.assertTrue(os.path.exists(pathname))
7631
7632 data = tools.read_file(pathname)
7633 self.assertEqual(xpl_data, data[:len(xpl_data)])
7634 rest = data[len(xpl_data):]
7635
7636 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7637 rest = rest[pad_len:]
7638
7639 dtb = fdt.Fdt.FromData(rest)
7640 dtb.Scan()
7641 dtbs[fname] = dtb
7642
7643 expected = 'one' if '1' in fname else 'two'
7644 self.assertEqual(f'u-boot,model-{expected}',
7645 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7646
7647 # Make sure the FDT is the same size as the 'main' one
7648 rest = rest[fdt_size:]
7649
7650 self.assertEqual(b'', rest)
7651 return dtbs
7652
7653 def testAlternatesFdt(self):
7654 """Test handling of alternates-fdt etype"""
7655 self._SetupTplElf()
7656 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7657 U_BOOT_TPL_NODTB_DATA)
7658 for dtb in dtbs.values():
7659 # Check for the node with the tag
7660 node = dtb.GetNode('/node')
7661 self.assertIsNotNone(node)
7662 self.assertEqual(5, len(node.props.keys()))
7663
7664 # Make sure the other node is still there
7665 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7666
7667 def testAlternatesFdtgrep(self):
7668 """Test handling of alternates-fdt etype using fdtgrep"""
7669 self._SetupTplElf()
7670 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7671 U_BOOT_TPL_NODTB_DATA)
7672 for dtb in dtbs.values():
7673 # Check for the node with the tag
7674 node = dtb.GetNode('/node')
7675 self.assertIsNotNone(node)
7676 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7677 node.props.keys())
7678
7679 # Make sure the other node is gone
7680 self.assertIsNone(dtb.GetNode('/node/other-node'))
7681
7682 def testAlternatesFdtgrepVpl(self):
7683 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7684 self._SetupVplElf()
7685 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7686 U_BOOT_VPL_NODTB_DATA)
7687
7688 def testAlternatesFdtgrepSpl(self):
7689 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7690 self._SetupSplElf()
7691 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7692 U_BOOT_SPL_NODTB_DATA)
7693
7694 def testAlternatesFdtgrepInval(self):
7695 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7696 self._SetupSplElf()
7697 with self.assertRaises(ValueError) as e:
7698 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7699 U_BOOT_SPL_NODTB_DATA)
7700 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7701 str(e.exception))
7702
Simon Glasscd2783e2024-07-20 11:49:46 +01007703 def testFitFdtListDir(self):
7704 """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
Simon Glass1bba8942024-08-26 13:11:34 -06007705 old_dir = os.getcwd()
7706 try:
7707 os.chdir(self._indir)
7708 self.CheckFitFdt('333_fit_fdt_dir.dts', False)
7709 finally:
7710 os.chdir(old_dir)
Simon Glasscd2783e2024-07-20 11:49:46 +01007711
Simon Glassd2a9d6e2024-08-26 13:11:37 -06007712 def testFitFdtListDirDefault(self):
7713 """Test an FIT fit,fdt-list-dir where the default DT in is a subdir"""
7714 old_dir = os.getcwd()
7715 try:
7716 os.chdir(self._indir)
7717 self.CheckFitFdt('333_fit_fdt_dir.dts', False,
7718 default_dt='rockchip/test-fdt2')
7719 finally:
7720 os.chdir(old_dir)
7721
Simon Glass5f7aadf2024-07-20 11:49:47 +01007722 def testFitFdtCompat(self):
7723 """Test an image with an FIT with compatible in the config nodes"""
7724 entry_args = {
7725 'of-list': 'model1 model2',
7726 'default-dt': 'model2',
7727 }
7728 testdir, dtb_list = self.SetupAlternateDts()
7729 data = self._DoReadFileDtb(
7730 '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
7731 entry_args=entry_args, extra_indirs=[testdir])[0]
7732
7733 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7734
7735 fit = fdt.Fdt.FromData(fit_data)
7736 fit.Scan()
7737
7738 cnode = fit.GetNode('/configurations')
7739 self.assertIn('default', cnode.props)
7740 self.assertEqual('config-2', cnode.props['default'].value)
7741
7742 for seq in range(1, 2):
7743 name = f'config-{seq}'
7744 fnode = fit.GetNode('/configurations/%s' % name)
7745 self.assertIsNotNone(fnode)
7746 self.assertIn('compatible', fnode.props.keys())
7747 expected = 'one' if seq == 1 else 'two'
7748 self.assertEqual(f'u-boot,model-{expected}',
7749 fnode.props['compatible'].value)
7750
Simon Glassa04b9942024-07-20 11:49:48 +01007751 def testFitFdtPhase(self):
7752 """Test an image with an FIT with fdt-phase in the fdt nodes"""
7753 phase = 'tpl'
7754 entry_args = {
7755 f'{phase}-dtb': '1',
7756 f'{phase}-bss-pad': 'y',
7757 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7758 'of-list': 'model1 model2',
7759 'default-dt': 'model2',
7760 }
7761 testdir, dtb_list = self.SetupAlternateDts()
7762 data = self._DoReadFileDtb(
7763 '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
7764 entry_args=entry_args, extra_indirs=[testdir])[0]
7765 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7766 fit = fdt.Fdt.FromData(fit_data)
7767 fit.Scan()
7768
7769 # Check that each FDT has only the expected properties for the phase
7770 for seq in range(1, 2):
7771 fnode = fit.GetNode(f'/images/fdt-{seq}')
7772 self.assertIsNotNone(fnode)
7773 dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
7774 dtb.Scan()
7775
7776 # Make sure that the 'bootph-pre-sram' tag in /node protects it from
7777 # removal
7778 node = dtb.GetNode('/node')
7779 self.assertIsNotNone(node)
7780 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7781 node.props.keys())
7782
7783 # Make sure the other node is gone
7784 self.assertIsNone(dtb.GetNode('/node/other-node'))
7785
Simon Glassb553e8a2024-08-26 13:11:29 -06007786 def testMkeficapsuleMissing(self):
7787 """Test that binman complains if mkeficapsule is missing"""
7788 with self.assertRaises(ValueError) as e:
7789 self._DoTestFile('311_capsule.dts',
7790 force_missing_bintools='mkeficapsule')
7791 self.assertIn("Node '/binman/efi-capsule': Missing tool: 'mkeficapsule'",
7792 str(e.exception))
7793
7794 def testMkeficapsuleMissingOk(self):
7795 """Test that binman deals with mkeficapsule being missing"""
7796 with test_util.capture_sys_output() as (stdout, stderr):
7797 ret = self._DoTestFile('311_capsule.dts',
7798 force_missing_bintools='mkeficapsule',
7799 allow_missing=True)
7800 self.assertEqual(103, ret)
7801 err = stderr.getvalue()
7802 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkeficapsule")
7803
Simon Glass4b0f4142024-08-26 13:11:40 -06007804 def testSymbolsBase(self):
7805 """Test handling of symbols-base"""
7806 self.checkSymbols('336_symbols_base.dts', U_BOOT_SPL_DATA, 0x1c,
7807 symbols_base=0)
7808
7809 def testSymbolsBaseExpanded(self):
7810 """Test handling of symbols-base with expanded entries"""
7811 entry_args = {
7812 'spl-dtb': '1',
7813 }
7814 self.checkSymbols('337_symbols_base_expand.dts', U_BOOT_SPL_NODTB_DATA +
7815 U_BOOT_SPL_DTB_DATA, 0x38,
7816 entry_args=entry_args, use_expanded=True,
7817 symbols_base=0)
7818
Simon Glass3eb30a42024-08-26 13:11:42 -06007819 def testSymbolsCompressed(self):
7820 """Test binman complains about symbols from a compressed section"""
7821 with test_util.capture_sys_output() as (stdout, stderr):
7822 self.checkSymbols('338_symbols_comp.dts', U_BOOT_SPL_DATA, None)
7823 out = stdout.getvalue()
7824 self.assertIn('Symbol-writing: no value for /binman/section/u-boot',
7825 out)
7826
Simon Glass9c25ef22024-08-26 13:11:43 -06007827 def testNxpImx8Image(self):
7828 """Test that binman can produce an iMX8 image"""
7829 self._DoTestFile('339_nxp_imx8.dts')
7830
Alexander Kochetkova730a282024-09-16 11:24:46 +03007831 def testFitSignSimple(self):
7832 """Test that image with FIT and signature nodes can be signed"""
7833 if not elf.ELF_TOOLS:
7834 self.skipTest('Python elftools not available')
7835 entry_args = {
7836 'of-list': 'test-fdt1',
7837 'default-dt': 'test-fdt1',
7838 'atf-bl31-path': 'bl31.elf',
7839 }
7840 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7841 self._MakeInputFile("keys/rsa2048.key", data)
7842
7843 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7844 keys_subdir = os.path.join(self._indir, "keys")
7845 data = self._DoReadFileDtb(
7846 '340_fit_signature.dts',
7847 entry_args=entry_args,
7848 extra_indirs=[test_subdir, keys_subdir])[0]
7849
7850 dtb = fdt.Fdt.FromData(data)
7851 dtb.Scan()
7852
7853 conf = dtb.GetNode('/configurations/conf-uboot-1')
7854 self.assertIsNotNone(conf)
7855 signature = conf.FindNode('signature')
7856 self.assertIsNotNone(signature)
7857 self.assertIsNotNone(signature.props.get('value'))
7858
7859 images = dtb.GetNode('/images')
7860 self.assertIsNotNone(images)
7861 for subnode in images.subnodes:
7862 signature = subnode.FindNode('signature')
7863 self.assertIsNotNone(signature)
7864 self.assertIsNotNone(signature.props.get('value'))
7865
7866 def testFitSignKeyNotFound(self):
7867 """Test that missing keys raise an error"""
7868 if not elf.ELF_TOOLS:
7869 self.skipTest('Python elftools not available')
7870 entry_args = {
7871 'of-list': 'test-fdt1',
7872 'default-dt': 'test-fdt1',
7873 'atf-bl31-path': 'bl31.elf',
7874 }
7875 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7876 with self.assertRaises(ValueError) as e:
7877 self._DoReadFileDtb(
7878 '340_fit_signature.dts',
7879 entry_args=entry_args,
7880 extra_indirs=[test_subdir])[0]
7881 self.assertIn(
7882 'Filename \'rsa2048.key\' not found in input path',
7883 str(e.exception))
7884
7885 def testFitSignMultipleKeyPaths(self):
7886 """Test that keys found in multiple paths raise an error"""
7887 if not elf.ELF_TOOLS:
7888 self.skipTest('Python elftools not available')
7889 entry_args = {
7890 'of-list': 'test-fdt1',
7891 'default-dt': 'test-fdt1',
7892 'atf-bl31-path': 'bl31.elf',
7893 }
7894 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7895 self._MakeInputFile("keys1/rsa2048.key", data)
7896 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7897 self._MakeInputFile("keys2/conf-rsa2048.key", data)
7898
7899 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7900 keys_subdir1 = os.path.join(self._indir, "keys1")
7901 keys_subdir2 = os.path.join(self._indir, "keys2")
7902 with self.assertRaises(ValueError) as e:
7903 self._DoReadFileDtb(
7904 '341_fit_signature.dts',
7905 entry_args=entry_args,
7906 extra_indirs=[test_subdir, keys_subdir1, keys_subdir2])[0]
7907 self.assertIn(
7908 'Node \'/binman/fit\': multiple key paths found',
7909 str(e.exception))
7910
7911 def testFitSignNoSingatureNodes(self):
7912 """Test that fit,sign doens't raise error if no signature nodes found"""
7913 if not elf.ELF_TOOLS:
7914 self.skipTest('Python elftools not available')
7915 entry_args = {
7916 'of-list': 'test-fdt1',
7917 'default-dt': 'test-fdt1',
7918 'atf-bl31-path': 'bl31.elf',
7919 }
7920 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7921 self._DoReadFileDtb(
7922 '342_fit_signature.dts',
7923 entry_args=entry_args,
7924 extra_indirs=[test_subdir])[0]
7925
Simon Glassa360b8f2024-06-23 11:55:06 -06007926
Paul HENRYSff318462024-11-25 18:47:17 +01007927 def testSimpleFitEncryptedData(self):
7928 """Test an image with a FIT containing data to be encrypted"""
7929 data = tools.read_file(self.TestFile("aes256.bin"))
7930 self._MakeInputFile("keys/aes256.bin", data)
7931
7932 keys_subdir = os.path.join(self._indir, "keys")
7933 data = self._DoReadFileDtb(
7934 '343_fit_encrypt_data.dts',
7935 extra_indirs=[keys_subdir])[0]
7936
7937 fit = fdt.Fdt.FromData(data)
7938 fit.Scan()
7939
7940 # Extract the encrypted data and the Initialization Vector from the FIT
7941 node = fit.GetNode('/images/u-boot')
7942 subnode = fit.GetNode('/images/u-boot/cipher')
7943 data_size_unciphered = int.from_bytes(fit.GetProps(node)['data-size-unciphered'].bytes,
7944 byteorder='big')
7945 self.assertEqual(data_size_unciphered, len(U_BOOT_NODTB_DATA))
7946
7947 # Retrieve the key name from the FIT removing any null byte
7948 key_name = fit.GetProps(subnode)['key-name-hint'].bytes.replace(b'\x00', b'')
7949 with open(self.TestFile(key_name.decode('ascii') + '.bin'), 'rb') as file:
7950 key = file.read()
7951 iv = fit.GetProps(subnode)['iv'].bytes.hex()
7952 enc_data = fit.GetProps(node)['data'].bytes
7953 outdir = tools.get_output_dir()
7954 enc_data_file = os.path.join(outdir, 'encrypted_data.bin')
7955 tools.write_file(enc_data_file, enc_data)
7956 data_file = os.path.join(outdir, 'data.bin')
7957
7958 # Decrypt the encrypted data from the FIT and compare the data
7959 tools.run('openssl', 'enc', '-aes-256-cbc', '-nosalt', '-d', '-in',
7960 enc_data_file, '-out', data_file, '-K', key.hex(), '-iv', iv)
7961 with open(data_file, 'r') as file:
7962 dec_data = file.read()
7963 self.assertEqual(U_BOOT_NODTB_DATA, dec_data.encode('ascii'))
7964
7965 def testSimpleFitEncryptedDataMissingKey(self):
7966 """Test an image with a FIT containing data to be encrypted but with a missing key"""
7967 with self.assertRaises(ValueError) as e:
7968 self._DoReadFile('344_fit_encrypt_data_no_key.dts')
7969
7970 self.assertIn("Filename 'aes256.bin' not found in input path", str(e.exception))
7971
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01007972 def testFitFdtName(self):
7973 """Test an image with an FIT with multiple FDT images using NAME"""
7974 self.CheckFitFdt('345_fit_fdt_name.dts', use_seq_num=False)
7975
Simon Glassac599912017-11-12 21:52:22 -07007976if __name__ == "__main__":
7977 unittest.main()