blob: a553ca9e5642b685b908e817972b42bfba1d8a0a [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass57454f42016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass57454f42016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glass45d556d2020-07-09 18:39:45 -06009import collections
Simon Glassf3598922024-07-20 11:49:45 +010010import glob
Simon Glassc585dd42020-04-17 18:09:03 -060011import gzip
Simon Glassae7cf032018-09-14 04:57:31 -060012import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070013from optparse import OptionParser
14import os
Simon Glass45d556d2020-07-09 18:39:45 -060015import re
Simon Glass57454f42016-11-25 20:15:52 -070016import shutil
17import struct
18import sys
19import tempfile
20import unittest
Simon Glass162017b2022-01-09 20:13:57 -070021import unittest.mock
22import urllib.error
Simon Glass57454f42016-11-25 20:15:52 -070023
Simon Glass4eae9252022-01-09 20:13:50 -070024from binman import bintool
Simon Glassc585dd42020-04-17 18:09:03 -060025from binman import cbfs_util
26from binman import cmdline
27from binman import control
28from binman import elf
29from binman import elf_test
Simon Glass3efb2972021-11-23 21:08:59 -070030from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060031from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060032from binman import state
33from dtoc import fdt
34from dtoc import fdt_util
35from binman.etype import fdtmap
36from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060037from binman.image import Image
Simon Glass131444f2023-02-23 18:18:04 -070038from u_boot_pylib import command
39from u_boot_pylib import test_util
40from u_boot_pylib import tools
41from u_boot_pylib import tout
Simon Glass57454f42016-11-25 20:15:52 -070042
43# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060044U_BOOT_DATA = b'1234'
45U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +030046U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass56d05412022-02-28 07:16:54 -070048U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glass303f62f2019-05-17 22:00:46 -060049BLOB_DATA = b'89'
50ME_DATA = b'0abcd'
51VGA_DATA = b'vga'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +053052EFI_CAPSULE_DATA = b'efi'
Simon Glass303f62f2019-05-17 22:00:46 -060053U_BOOT_DTB_DATA = b'udtb'
54U_BOOT_SPL_DTB_DATA = b'spldtb'
55U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass56d05412022-02-28 07:16:54 -070056U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glass303f62f2019-05-17 22:00:46 -060057X86_START16_DATA = b'start16'
58X86_START16_SPL_DATA = b'start16spl'
59X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060060X86_RESET16_DATA = b'reset16'
61X86_RESET16_SPL_DATA = b'reset16spl'
62X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060063PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
64U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
65U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
66U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass56d05412022-02-28 07:16:54 -070067U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +030068U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
69U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
70U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glass303f62f2019-05-17 22:00:46 -060071FSP_DATA = b'fsp'
72CMC_DATA = b'cmc'
73VBT_DATA = b'vbt'
74MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060075TEXT_DATA = 'text'
76TEXT_DATA2 = 'text2'
77TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060078CROS_EC_RW_DATA = b'ecrw'
79GBB_DATA = b'gbbd'
80BMPBLK_DATA = b'bmp'
81VBLOCK_DATA = b'vblk'
82FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
83 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060084COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060085COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060086REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060087FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060088FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060089FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060090ATF_BL31_DATA = b'bl31'
Roger Quadros5cdcea02022-02-19 20:50:04 +020091TEE_OS_DATA = b'this is some tee OS data'
Neha Malcom Francis59be2552023-12-05 15:12:18 +053092TI_DM_DATA = b'tidmtidm'
Simon Glass3efb2972021-11-23 21:08:59 -070093ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080094OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050095SCP_DATA = b'scp'
Jonas Karlman35305492023-02-25 19:01:33 +000096ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glassa435cd12020-09-01 05:13:59 -060097TEST_FDT1_DATA = b'fdt1'
98TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060099ENV_DATA = b'var1=1\nvar2="2"'
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200100ENCRYPTED_IV_DATA = b'123456'
101ENCRYPTED_KEY_DATA = b'abcde'
Philippe Reynesebe96cb2022-03-28 22:57:04 +0200102PRE_LOAD_MAGIC = b'UBSH'
103PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
104PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530105TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530106TI_UNSECURE_DATA = b'unsecuredata'
Simon Glassa435cd12020-09-01 05:13:59 -0600107
108# Subdirectory of the input dir to use to put test FDTs
109TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600110
Simon Glass2c6adba2019-07-20 12:23:47 -0600111# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600112EXTRACT_DTB_SIZE = 0x3c9
113
Simon Glass2c6adba2019-07-20 12:23:47 -0600114# Properties expected to be in the device tree when update_dtb is used
115BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
116
Simon Glassfb30e292019-07-20 12:23:51 -0600117# Extra properties expected to be in the device tree when allow-repack is used
118REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
119
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200120# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200121COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700122
Simon Glassad5cfe12023-01-07 14:07:14 -0700123TEE_ADDR = 0x5678
124
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530125# Firmware Management Protocol(FMP) GUID
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530126FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530127# Image GUID specified in the DTS
Caleb Connolly4bdc9602024-08-30 13:34:35 +0100128CAPSULE_IMAGE_GUID = '985F2937-7C2E-5E9A-8A5E-8E063312964B'
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530129# Windows cert GUID
130WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +0530131# Empty capsule GUIDs
132EMPTY_CAPSULE_ACCEPT_GUID = '0c996046-bcc0-4d04-85ec-e1fcedf1c6f8'
133EMPTY_CAPSULE_REVERT_GUID = 'acd58b4b-c0e8-475f-99b5-6b3f7e07aaf0'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530134
Simon Glass57454f42016-11-25 20:15:52 -0700135class TestFunctional(unittest.TestCase):
136 """Functional tests for binman
137
138 Most of these use a sample .dts file to build an image and then check
139 that it looks correct. The sample files are in the test/ subdirectory
140 and are numbered.
141
142 For each entry type a very small test file is created using fixed
143 string contents. This makes it easy to test that things look right, and
144 debug problems.
145
146 In some cases a 'real' file must be used - these are also supplied in
147 the test/ diurectory.
148 """
149 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600150 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700151 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600152 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700153
Simon Glass57454f42016-11-25 20:15:52 -0700154 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600155 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
156 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700157
158 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600159 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700160
161 # Create some test files
162 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
163 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
164 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600165 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700166 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700167 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700168 TestFunctional._MakeInputFile('me.bin', ME_DATA)
169 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600170 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600171
Jagdish Gediya311d4842018-09-03 21:35:08 +0530172 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600173
Simon Glassabab18c2019-08-24 07:22:49 -0600174 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
175 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700176 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600177 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600178 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600179
180 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
181 X86_RESET16_DATA)
182 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
183 X86_RESET16_SPL_DATA)
184 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
185 X86_RESET16_TPL_DATA)
186
Simon Glass57454f42016-11-25 20:15:52 -0700187 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700188 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
189 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600190 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
191 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700192 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
193 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700194 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
195 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700196 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700197 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600198 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600199 TestFunctional._MakeInputDir('devkeys')
200 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600201 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600202 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600203 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600204 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700205
Simon Glassf6290892019-08-24 07:22:53 -0600206 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
207 elf_test.BuildElfTestFiles(cls._elf_testdir)
208
Simon Glass72232452016-11-25 20:15:53 -0700209 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600210 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700211 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700212
213 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600214 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700215
Simon Glass862f8e22019-08-24 07:22:43 -0600216 shutil.copytree(cls.TestFile('files'),
217 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600218
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530219 shutil.copytree(cls.TestFile('yaml'),
220 os.path.join(cls._indir, 'yaml'))
221
Simon Glass7ba33592018-09-14 04:57:26 -0600222 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600223 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600224 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200225 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Neha Malcom Francis59be2552023-12-05 15:12:18 +0530226 TestFunctional._MakeInputFile('dm.bin', TI_DM_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700227 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800228 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500229 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman35305492023-02-25 19:01:33 +0000230 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530231 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530232 TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600233
Simon Glassa435cd12020-09-01 05:13:59 -0600234 # Add a few .dtb files for testing
235 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
236 TEST_FDT1_DATA)
237 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
238 TEST_FDT2_DATA)
239
Simon Glassa0729502020-09-06 10:35:33 -0600240 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
241
Simon Glass5f423422022-03-05 20:19:12 -0700242 # ELF file with two sections in different parts of memory, used for both
243 # ATF and OP_TEE
244 TestFunctional._MakeInputFile('bl31.elf',
245 tools.read_file(cls.ElfTestFile('elf_sections')))
246 TestFunctional._MakeInputFile('tee.elf',
247 tools.read_file(cls.ElfTestFile('elf_sections')))
248
Simon Glassad5cfe12023-01-07 14:07:14 -0700249 # Newer OP_TEE file in v1 binary format
250 cls.make_tee_bin('tee.bin')
251
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200252 # test files for encrypted tests
253 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
254 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
255
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200256 cls.comp_bintools = {}
257 for name in COMP_BINTOOLS:
258 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600259
Simon Glass57454f42016-11-25 20:15:52 -0700260 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600261 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700262 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600263 if cls.preserve_indir:
264 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600265 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600266 if cls._indir:
267 shutil.rmtree(cls._indir)
268 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700269
Simon Glass1c420c92019-07-08 13:18:49 -0600270 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600271 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600272 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600273 """Accept arguments controlling test execution
274
275 Args:
276 preserve_indir: Preserve the shared input directory used by all
277 tests in this class.
278 preserve_outdir: Preserve the output directories used by tests. Each
279 test has its own, so this is normally only useful when running a
280 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600281 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600282 """
283 cls.preserve_indir = preserve_indir
284 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600285 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600286 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600287
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200288 def _CheckBintool(self, bintool):
289 if not bintool.is_present():
290 self.skipTest('%s not available' % bintool.name)
291
Simon Glass1de34482019-07-08 13:18:53 -0600292 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200293 bintool = self.comp_bintools['lz4']
294 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600295
Simon Glassee9d10d2019-07-20 12:24:09 -0600296 def _CleanupOutputDir(self):
297 """Remove the temporary output directory"""
298 if self.preserve_outdirs:
299 print('Preserving output dir: %s' % tools.outdir)
300 else:
Simon Glass80025522022-01-29 14:14:04 -0700301 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600302
Simon Glass57454f42016-11-25 20:15:52 -0700303 def setUp(self):
304 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700305 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700306 command.test_result = None
307
308 def tearDown(self):
309 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600310 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700311
Simon Glassb3d6fc72019-07-20 12:24:10 -0600312 def _SetupImageInTmpdir(self):
313 """Set up the output image in a new temporary directory
314
315 This is used when an image has been generated in the output directory,
316 but we want to run binman again. This will create a new output
317 directory and fail to delete the original one.
318
319 This creates a new temporary directory, copies the image to it (with a
320 new name) and removes the old output directory.
321
322 Returns:
323 Tuple:
324 Temporary directory to use
325 New image filename
326 """
Simon Glass80025522022-01-29 14:14:04 -0700327 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600328 tmpdir = tempfile.mkdtemp(prefix='binman.')
329 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700330 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600331 self._CleanupOutputDir()
332 return tmpdir, updated_fname
333
Simon Glass8425a1f2018-07-17 13:25:48 -0600334 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600335 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600336 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
337 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
338 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700339 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600340
Simon Glass57454f42016-11-25 20:15:52 -0700341 def _RunBinman(self, *args, **kwargs):
342 """Run binman using the command line
343
344 Args:
345 Arguments to pass, as a list of strings
346 kwargs: Arguments to pass to Command.RunPipe()
347 """
Simon Glass840be732022-01-29 14:14:05 -0700348 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700349 capture=True, capture_stderr=True, raise_on_error=False)
350 if result.return_code and kwargs.get('raise_on_error', True):
351 raise Exception("Error running '%s': %s" % (' '.join(args),
352 result.stdout + result.stderr))
353 return result
354
Simon Glassf46732a2019-07-08 14:25:29 -0600355 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700356 """Run binman using directly (in the same process)
357
358 Args:
359 Arguments to pass, as a list of strings
360 Returns:
361 Return value (0 for success)
362 """
Simon Glassf46732a2019-07-08 14:25:29 -0600363 argv = list(argv)
364 args = cmdline.ParseArgs(argv)
365 args.pager = 'binman-invalid-pager'
366 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700367
368 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600369 # args.verbosity = tout.DEBUG
370 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700371
Simon Glass91710b32018-07-17 13:25:32 -0600372 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600373 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300374 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100375 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700376 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis6b463da2023-07-22 00:14:44 +0530377 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass57454f42016-11-25 20:15:52 -0700378 """Run binman with a given test file
379
380 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600381 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600382 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600383 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600384 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600385 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600386 entry_args: Dict of entry args to supply to binman
387 key: arg name
388 value: value of that arg
389 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600390 use_real_dtb: True to use the test file as the contents of
391 the u-boot-dtb entry. Normally this is not needed and the
392 test contents (the U_BOOT_DTB_DATA string) can be used.
393 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300394 use_expanded: True to use expanded entries where available, e.g.
395 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600396 verbosity: Verbosity level to use (0-3, None=don't set it)
397 allow_missing: Set the '--allow-missing' flag so that missing
398 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100399 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600400 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600401 threads: Number of threads to use (None for default, 0 for
402 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600403 test_section_timeout: True to force the first time to timeout, as
404 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600405 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glassb553e8a2024-08-26 13:11:29 -0600406 force_missing_bintools (str): comma-separated list of bintools to
Simon Glass66152ce2022-01-09 20:14:09 -0700407 regard as missing
Simon Glassb553e8a2024-08-26 13:11:29 -0600408 ignore_missing (bool): True to return success even if there are
409 missing blobs or bintools
Andrew Davis6b463da2023-07-22 00:14:44 +0530410 output_dir: Specific output directory to use for image using -O
Simon Glass9a798402021-11-03 21:09:17 -0600411
412 Returns:
413 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700414 """
Simon Glassf46732a2019-07-08 14:25:29 -0600415 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700416 if debug:
417 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600418 if verbosity is not None:
419 args.append('-v%d' % verbosity)
420 elif self.verbosity:
421 args.append('-v%d' % self.verbosity)
422 if self.toolpath:
423 for path in self.toolpath:
424 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600425 if threads is not None:
426 args.append('-T%d' % threads)
427 if test_section_timeout:
428 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600429 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600430 if map:
431 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600432 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600433 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600434 if not use_real_dtb:
435 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300436 if not use_expanded:
437 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600438 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600439 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600440 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600441 if allow_missing:
442 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700443 if ignore_missing:
444 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100445 if allow_fake_blobs:
446 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700447 if force_missing_bintools:
448 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600449 if update_fdt_in_elf:
450 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600451 if images:
452 for image in images:
453 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600454 if extra_indirs:
455 for indir in extra_indirs:
456 args += ['-I', indir]
Andrew Davis6b463da2023-07-22 00:14:44 +0530457 if output_dir:
458 args += ['-O', output_dir]
Simon Glass075a45c2017-11-13 18:55:00 -0700459 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700460
461 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700462 """Set up a new test device-tree file
463
464 The given file is compiled and set up as the device tree to be used
465 for ths test.
466
467 Args:
468 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600469 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700470
471 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600472 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700473 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600474 tmpdir = tempfile.mkdtemp(prefix='binmant.')
475 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600476 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700477 data = fd.read()
478 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600479 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600480 return data
Simon Glass57454f42016-11-25 20:15:52 -0700481
Simon Glass56d05412022-02-28 07:16:54 -0700482 def _GetDtbContentsForSpls(self, dtb_data, name):
483 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600484
485 For testing we don't actually have different versions of the DTB. With
486 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
487 we don't normally have any unwanted nodes.
488
489 We still want the DTBs for SPL and TPL to be different though, since
490 otherwise it is confusing to know which one we are looking at. So add
491 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600492
493 Args:
494 dtb_data: dtb data to modify (this should be a value devicetree)
495 name: Name of a new property to add
496
497 Returns:
498 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600499 """
500 dtb = fdt.Fdt.FromData(dtb_data)
501 dtb.Scan()
502 dtb.GetNode('/binman').AddZeroProp(name)
503 dtb.Sync(auto_resize=True)
504 dtb.Pack()
505 return dtb.GetContents()
506
Simon Glassed930672021-03-18 20:25:05 +1300507 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
Simon Glass3eb30a42024-08-26 13:11:42 -0600508 verbosity=None, map=False, update_dtb=False,
509 entry_args=None, reset_dtbs=True, extra_indirs=None,
510 threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700511 """Run binman and return the resulting image
512
513 This runs binman with a given test file and then reads the resulting
514 output file. It is a shortcut function since most tests need to do
515 these steps.
516
517 Raises an assertion failure if binman returns a non-zero exit code.
518
519 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600520 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700521 use_real_dtb: True to use the test file as the contents of
522 the u-boot-dtb entry. Normally this is not needed and the
523 test contents (the U_BOOT_DTB_DATA string) can be used.
524 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300525 use_expanded: True to use expanded entries where available, e.g.
526 'u-boot-expanded' instead of 'u-boot'
Simon Glass3eb30a42024-08-26 13:11:42 -0600527 verbosity: Verbosity level to use (0-3, None=don't set it)
Simon Glass30732662018-06-01 09:38:20 -0600528 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600529 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600530 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600531 entry_args: Dict of entry args to supply to binman
532 key: arg name
533 value: value of that arg
534 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
535 function. If reset_dtbs is True, then the original test dtb
536 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600537 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600538 threads: Number of threads to use (None for default, 0 for
539 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700540
541 Returns:
542 Tuple:
543 Resulting image contents
544 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600545 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600546 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700547 """
Simon Glass72232452016-11-25 20:15:53 -0700548 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700549 # Use the compiled test file as the u-boot-dtb input
550 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700551 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600552
553 # For testing purposes, make a copy of the DT for SPL and TPL. Add
Simon Glassd9e01d22024-07-20 11:49:40 +0100554 # a node indicating which it is, to aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700555 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600556 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
557 outfile = os.path.join(self._indir, dtb_fname)
558 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700559 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700560
561 try:
Simon Glass91710b32018-07-17 13:25:32 -0600562 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600563 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass3eb30a42024-08-26 13:11:42 -0600564 use_expanded=use_expanded, verbosity=verbosity,
565 extra_indirs=extra_indirs,
Simon Glass76f496d2021-07-06 10:36:37 -0600566 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700567 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700568 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700569
570 # Find the (only) image, read it and return its contents
571 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700572 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600573 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600574 if map:
Simon Glass80025522022-01-29 14:14:04 -0700575 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600576 with open(map_fname) as fd:
577 map_data = fd.read()
578 else:
579 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600580 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600581 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700582 finally:
583 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600584 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600585 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700586
Simon Glass5b4bce32019-07-08 14:25:26 -0600587 def _DoReadFileRealDtb(self, fname):
588 """Run binman with a real .dtb file and return the resulting data
589
590 Args:
591 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
592
593 Returns:
594 Resulting image contents
595 """
596 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
597
Simon Glass72232452016-11-25 20:15:53 -0700598 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600599 """Helper function which discards the device-tree binary
600
601 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600602 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600603 use_real_dtb: True to use the test file as the contents of
604 the u-boot-dtb entry. Normally this is not needed and the
605 test contents (the U_BOOT_DTB_DATA string) can be used.
606 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600607
608 Returns:
609 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600610 """
Simon Glass72232452016-11-25 20:15:53 -0700611 return self._DoReadFileDtb(fname, use_real_dtb)[0]
612
Simon Glass57454f42016-11-25 20:15:52 -0700613 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600614 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700615 """Create a new test input file, creating directories as needed
616
617 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600618 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700619 contents: File contents to write in to the file
620 Returns:
621 Full pathname of file created
622 """
Simon Glass862f8e22019-08-24 07:22:43 -0600623 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700624 dirname = os.path.dirname(pathname)
625 if dirname and not os.path.exists(dirname):
626 os.makedirs(dirname)
627 with open(pathname, 'wb') as fd:
628 fd.write(contents)
629 return pathname
630
631 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600632 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600633 """Create a new test input directory, creating directories as needed
634
635 Args:
636 dirname: Directory name to create
637
638 Returns:
639 Full pathname of directory created
640 """
Simon Glass862f8e22019-08-24 07:22:43 -0600641 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600642 if not os.path.exists(pathname):
643 os.makedirs(pathname)
644 return pathname
645
646 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600647 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600648 """Set up an ELF file with a '_dt_ucode_base_size' symbol
649
650 Args:
651 Filename of ELF file to use as SPL
652 """
Simon Glass93a806f2019-08-24 07:22:59 -0600653 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700654 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600655
656 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600657 def _SetupTplElf(cls, src_fname='bss_data'):
658 """Set up an ELF file with a '_dt_ucode_base_size' symbol
659
660 Args:
661 Filename of ELF file to use as TPL
662 """
663 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700664 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600665
666 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700667 def _SetupVplElf(cls, src_fname='bss_data'):
668 """Set up an ELF file with a '_dt_ucode_base_size' symbol
669
670 Args:
671 Filename of ELF file to use as VPL
672 """
673 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
674 tools.read_file(cls.ElfTestFile(src_fname)))
675
676 @classmethod
Lukas Funkee901faf2023-07-18 13:53:13 +0200677 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
678 """Set up an ELF file with a '_dt_ucode_base_size' symbol
679
680 Args:
681 Filename of ELF file to use as VPL
682 """
683 TestFunctional._MakeInputFile('pmu-firmware.elf',
684 tools.read_file(cls.ElfTestFile(src_fname)))
685
686 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600687 def _SetupDescriptor(cls):
688 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
689 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
690
691 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600692 def TestFile(cls, fname):
693 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700694
Simon Glassf6290892019-08-24 07:22:53 -0600695 @classmethod
696 def ElfTestFile(cls, fname):
697 return os.path.join(cls._elf_testdir, fname)
698
Simon Glassad5cfe12023-01-07 14:07:14 -0700699 @classmethod
700 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
701 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
702 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
703 dummy, paged_sz) + U_BOOT_DATA
704 data += extra_data
705 TestFunctional._MakeInputFile(fname, data)
706
Simon Glass57454f42016-11-25 20:15:52 -0700707 def AssertInList(self, grep_list, target):
708 """Assert that at least one of a list of things is in a target
709
710 Args:
711 grep_list: List of strings to check
712 target: Target string
713 """
714 for grep in grep_list:
715 if grep in target:
716 return
Simon Glass848cdb52019-05-17 22:00:50 -0600717 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700718
719 def CheckNoGaps(self, entries):
720 """Check that all entries fit together without gaps
721
722 Args:
723 entries: List of entries to check
724 """
Simon Glasse8561af2018-08-01 15:22:37 -0600725 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700726 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600727 self.assertEqual(offset, entry.offset)
728 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700729
Simon Glass72232452016-11-25 20:15:53 -0700730 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600731 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700732
733 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600734 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700735
736 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600737 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700738 """
739 return struct.unpack('>L', dtb[4:8])[0]
740
Simon Glass0f621332019-07-08 14:25:27 -0600741 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600742 def AddNode(node, path):
743 if node.name != '/':
744 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600745 for prop in node.props.values():
746 if prop.name in prop_names:
747 prop_path = path + ':' + prop.name
748 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
749 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600750 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600751 AddNode(subnode, path)
752
753 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600754 AddNode(dtb.GetRoot(), '')
755 return tree
756
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000757 def _CheckSign(self, fit, key):
758 try:
759 tools.run('fit_check_sign', '-k', key, '-f', fit)
760 except:
761 self.fail('Expected signed FIT container')
762 return False
763 return True
764
Simon Glass57454f42016-11-25 20:15:52 -0700765 def testRun(self):
766 """Test a basic run with valid args"""
767 result = self._RunBinman('-h')
768
769 def testFullHelp(self):
770 """Test that the full help is displayed with -H"""
771 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300772 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500773 # Remove possible extraneous strings
774 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
775 gothelp = result.stdout.replace(extra, '')
776 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700777 self.assertEqual(0, len(result.stderr))
778 self.assertEqual(0, result.return_code)
779
780 def testFullHelpInternal(self):
781 """Test that the full help is displayed with -H"""
782 try:
783 command.test_result = command.CommandResult()
784 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300785 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700786 finally:
787 command.test_result = None
788
789 def testHelp(self):
790 """Test that the basic help is displayed with -h"""
791 result = self._RunBinman('-h')
792 self.assertTrue(len(result.stdout) > 200)
793 self.assertEqual(0, len(result.stderr))
794 self.assertEqual(0, result.return_code)
795
Simon Glass57454f42016-11-25 20:15:52 -0700796 def testBoard(self):
797 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600798 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700799 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300800 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700801 self.assertEqual(0, result)
802
803 def testNeedBoard(self):
804 """Test that we get an error when no board ius supplied"""
805 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600806 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700807 self.assertIn("Must provide a board to process (use -b <board>)",
808 str(e.exception))
809
810 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600811 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700812 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600813 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700814 # We get one error from libfdt, and a different one from fdtget.
815 self.AssertInList(["Couldn't open blob from 'missing_file'",
816 'No such file or directory'], str(e.exception))
817
818 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600819 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700820
821 Since this is a source file it should be compiled and the error
822 will come from the device-tree compiler (dtc).
823 """
824 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600825 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700826 self.assertIn("FATAL ERROR: Unable to parse input tree",
827 str(e.exception))
828
829 def testMissingNode(self):
830 """Test that a device tree without a 'binman' node generates an error"""
831 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600832 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700833 self.assertIn("does not have a 'binman' node", str(e.exception))
834
835 def testEmpty(self):
836 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600837 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700838 self.assertEqual(0, len(result.stderr))
839 self.assertEqual(0, result.return_code)
840
841 def testInvalidEntry(self):
842 """Test that an invalid entry is flagged"""
843 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600844 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600845 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700846 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
847 "'/binman/not-a-valid-type'", str(e.exception))
848
849 def testSimple(self):
850 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600851 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700852 self.assertEqual(U_BOOT_DATA, data)
853
Simon Glass075a45c2017-11-13 18:55:00 -0700854 def testSimpleDebug(self):
855 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600856 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700857
Simon Glass57454f42016-11-25 20:15:52 -0700858 def testDual(self):
859 """Test that we can handle creating two images
860
861 This also tests image padding.
862 """
Simon Glass511f6582018-10-01 12:22:30 -0600863 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700864 self.assertEqual(0, retcode)
865
866 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600867 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700868 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700869 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600870 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700871 data = fd.read()
872 self.assertEqual(U_BOOT_DATA, data)
873
874 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600875 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700876 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700877 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600878 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700879 data = fd.read()
880 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700881 self.assertEqual(tools.get_bytes(0, 3), data[:3])
882 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700883
884 def testBadAlign(self):
885 """Test that an invalid alignment value is detected"""
886 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600887 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700888 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
889 "of two", str(e.exception))
890
891 def testPackSimple(self):
892 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600893 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700894 self.assertEqual(0, retcode)
895 self.assertIn('image', control.images)
896 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600897 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700898 self.assertEqual(5, len(entries))
899
900 # First u-boot
901 self.assertIn('u-boot', entries)
902 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600903 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700904 self.assertEqual(len(U_BOOT_DATA), entry.size)
905
906 # Second u-boot, aligned to 16-byte boundary
907 self.assertIn('u-boot-align', entries)
908 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600909 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700910 self.assertEqual(len(U_BOOT_DATA), entry.size)
911
912 # Third u-boot, size 23 bytes
913 self.assertIn('u-boot-size', entries)
914 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600915 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700916 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
917 self.assertEqual(23, entry.size)
918
919 # Fourth u-boot, placed immediate after the above
920 self.assertIn('u-boot-next', entries)
921 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600922 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700923 self.assertEqual(len(U_BOOT_DATA), entry.size)
924
Simon Glasse8561af2018-08-01 15:22:37 -0600925 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700926 self.assertIn('u-boot-fixed', entries)
927 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600928 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700929 self.assertEqual(len(U_BOOT_DATA), entry.size)
930
Simon Glass39dd2152019-07-08 14:25:47 -0600931 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700932
933 def testPackExtra(self):
934 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600935 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
936 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700937
Simon Glass57454f42016-11-25 20:15:52 -0700938 self.assertIn('image', control.images)
939 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600940 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600941 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700942
Samuel Hollande2574022023-01-21 17:25:16 -0600943 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700944 self.assertIn('u-boot', entries)
945 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600946 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700947 self.assertEqual(3, entry.pad_before)
948 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600949 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700950 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
951 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600952 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700953
954 # Second u-boot has an aligned size, but it has no effect
955 self.assertIn('u-boot-align-size-nop', entries)
956 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600957 self.assertEqual(pos, entry.offset)
958 self.assertEqual(len(U_BOOT_DATA), entry.size)
959 self.assertEqual(U_BOOT_DATA, entry.data)
960 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
961 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700962
963 # Third u-boot has an aligned size too
964 self.assertIn('u-boot-align-size', entries)
965 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600966 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700967 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600968 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700969 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600970 data[pos:pos + entry.size])
971 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700972
973 # Fourth u-boot has an aligned end
974 self.assertIn('u-boot-align-end', entries)
975 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600976 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700977 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600978 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700979 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600980 data[pos:pos + entry.size])
981 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700982
983 # Fifth u-boot immediately afterwards
984 self.assertIn('u-boot-align-both', entries)
985 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600986 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700987 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600988 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700989 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600990 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700991
Samuel Hollande2574022023-01-21 17:25:16 -0600992 # Sixth u-boot with both minimum size and aligned size
993 self.assertIn('u-boot-min-size', entries)
994 entry = entries['u-boot-min-size']
995 self.assertEqual(128, entry.offset)
996 self.assertEqual(32, entry.size)
997 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
998 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
999 data[pos:pos + entry.size])
1000
Simon Glass57454f42016-11-25 20:15:52 -07001001 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -06001002 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001003
Simon Glassafb9caa2020-10-26 17:40:10 -06001004 dtb = fdt.Fdt(out_dtb_fname)
1005 dtb.Scan()
1006 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
1007 expected = {
1008 'image-pos': 0,
1009 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -06001010 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -06001011
1012 'u-boot:image-pos': 0,
1013 'u-boot:offset': 0,
1014 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1015
1016 'u-boot-align-size-nop:image-pos': 12,
1017 'u-boot-align-size-nop:offset': 12,
1018 'u-boot-align-size-nop:size': 4,
1019
1020 'u-boot-align-size:image-pos': 16,
1021 'u-boot-align-size:offset': 16,
1022 'u-boot-align-size:size': 32,
1023
1024 'u-boot-align-end:image-pos': 48,
1025 'u-boot-align-end:offset': 48,
1026 'u-boot-align-end:size': 16,
1027
1028 'u-boot-align-both:image-pos': 64,
1029 'u-boot-align-both:offset': 64,
1030 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -06001031
1032 'u-boot-min-size:image-pos': 128,
1033 'u-boot-min-size:offset': 128,
1034 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -06001035 }
1036 self.assertEqual(expected, props)
1037
Simon Glass57454f42016-11-25 20:15:52 -07001038 def testPackAlignPowerOf2(self):
1039 """Test that invalid entry alignment is detected"""
1040 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001041 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001042 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1043 "of two", str(e.exception))
1044
1045 def testPackAlignSizePowerOf2(self):
1046 """Test that invalid entry size alignment is detected"""
1047 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001048 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001049 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1050 "power of two", str(e.exception))
1051
1052 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001053 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001054 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001055 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001056 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001057 "align 0x4 (4)", str(e.exception))
1058
1059 def testPackInvalidSizeAlign(self):
1060 """Test that invalid entry size alignment is detected"""
1061 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001062 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001063 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1064 "align-size 0x4 (4)", str(e.exception))
1065
1066 def testPackOverlap(self):
1067 """Test that overlapping regions are detected"""
1068 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001069 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001070 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001071 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1072 str(e.exception))
1073
1074 def testPackEntryOverflow(self):
1075 """Test that entries that overflow their size are detected"""
1076 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001077 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001078 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1079 "but entry size is 0x3 (3)", str(e.exception))
1080
1081 def testPackImageOverflow(self):
1082 """Test that entries which overflow the image size are detected"""
1083 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001084 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001085 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001086 "size 0x3 (3)", str(e.exception))
1087
1088 def testPackImageSize(self):
1089 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001090 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001091 self.assertEqual(0, retcode)
1092 self.assertIn('image', control.images)
1093 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001094 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001095
1096 def testPackImageSizeAlign(self):
1097 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001098 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001099 self.assertEqual(0, retcode)
1100 self.assertIn('image', control.images)
1101 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001102 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001103
1104 def testPackInvalidImageAlign(self):
1105 """Test that invalid image alignment is detected"""
1106 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001107 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001108 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001109 "align-size 0x8 (8)", str(e.exception))
1110
Simon Glass2a0fa982022-02-11 13:23:21 -07001111 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001112 """Test that invalid image alignment is detected"""
1113 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001114 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001115 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001116 "two", str(e.exception))
1117
1118 def testImagePadByte(self):
1119 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001120 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001121 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001122 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001123 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001124
1125 def testImageName(self):
1126 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001127 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001128 self.assertEqual(0, retcode)
1129 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001130 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001131 self.assertTrue(os.path.exists(fname))
1132
1133 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001134 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001135 self.assertTrue(os.path.exists(fname))
1136
1137 def testBlobFilename(self):
1138 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001139 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001140 self.assertEqual(BLOB_DATA, data)
1141
1142 def testPackSorted(self):
1143 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001144 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001145 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001146 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1147 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001148
Simon Glasse8561af2018-08-01 15:22:37 -06001149 def testPackZeroOffset(self):
1150 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001151 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001152 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001153 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001154 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001155 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1156 str(e.exception))
1157
1158 def testPackUbootDtb(self):
1159 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001160 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001161 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001162
1163 def testPackX86RomNoSize(self):
1164 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001165 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001166 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001167 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001168 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001169 "using end-at-4gb", str(e.exception))
1170
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301171 def test4gbAndSkipAtStartTogether(self):
1172 """Test that the end-at-4gb and skip-at-size property can't be used
1173 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001174 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301175 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001176 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001177 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301178 "'skip-at-start'", str(e.exception))
1179
Simon Glass72232452016-11-25 20:15:53 -07001180 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001181 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001182 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001183 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001184 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001185 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1186 "is outside the section '/binman' starting at "
1187 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001188 str(e.exception))
1189
1190 def testPackX86Rom(self):
1191 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001192 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001193 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001194 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1195 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001196
1197 def testPackX86RomMeNoDesc(self):
1198 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001199 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001200 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001201 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001202 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001203 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1204 str(e.exception))
1205 finally:
1206 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001207
1208 def testPackX86RomBadDesc(self):
1209 """Test that the Intel requires a descriptor entry"""
1210 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001211 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001212 self.assertIn("Node '/binman/intel-me': No offset set with "
1213 "offset-unset: should another entry provide this correct "
1214 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001215
1216 def testPackX86RomMe(self):
1217 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001218 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001219 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001220 if data[:0x1000] != expected_desc:
1221 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001222 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1223
1224 def testPackVga(self):
1225 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001226 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001227 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1228
1229 def testPackStart16(self):
1230 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001231 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001232 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1233
Jagdish Gediya311d4842018-09-03 21:35:08 +05301234 def testPackPowerpcMpc85xxBootpgResetvec(self):
1235 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1236 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001237 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301238 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1239
Simon Glass6ba679c2018-07-06 10:27:17 -06001240 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001241 """Handle running a test for insertion of microcode
1242
1243 Args:
1244 dts_fname: Name of test .dts file
1245 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001246 ucode_second: True if the microsecond entry is second instead of
1247 third
Simon Glass820af1d2018-07-06 10:27:16 -06001248
1249 Returns:
1250 Tuple:
1251 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001252 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001253 in the above (two 4-byte words)
1254 """
Simon Glass3d274232017-11-12 21:52:27 -07001255 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001256
1257 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001258 if ucode_second:
1259 ucode_content = data[len(nodtb_data):]
1260 ucode_pos = len(nodtb_data)
1261 dtb_with_ucode = ucode_content[16:]
1262 fdt_len = self.GetFdtLen(dtb_with_ucode)
1263 else:
1264 dtb_with_ucode = data[len(nodtb_data):]
1265 fdt_len = self.GetFdtLen(dtb_with_ucode)
1266 ucode_content = dtb_with_ucode[fdt_len:]
1267 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001268 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001269 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001270 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001271 dtb = fdt.FdtScan(fname)
1272 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001273 self.assertTrue(ucode)
1274 for node in ucode.subnodes:
1275 self.assertFalse(node.props.get('data'))
1276
Simon Glass72232452016-11-25 20:15:53 -07001277 # Check that the microcode appears immediately after the Fdt
1278 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001279 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001280 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1281 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001282 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001283
1284 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001285 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001286 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1287 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001288 u_boot = data[:len(nodtb_data)]
1289 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001290
1291 def testPackUbootMicrocode(self):
1292 """Test that x86 microcode can be handled correctly
1293
1294 We expect to see the following in the image, in order:
1295 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1296 place
1297 u-boot.dtb with the microcode removed
1298 the microcode
1299 """
Simon Glass511f6582018-10-01 12:22:30 -06001300 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001301 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001302 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1303 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001304
Simon Glassbac25c82017-05-27 07:38:26 -06001305 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001306 """Test that x86 microcode can be handled correctly
1307
1308 We expect to see the following in the image, in order:
1309 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1310 place
1311 u-boot.dtb with the microcode
1312 an empty microcode region
1313 """
1314 # We need the libfdt library to run this test since only that allows
1315 # finding the offset of a property. This is required by
1316 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001317 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001318
1319 second = data[len(U_BOOT_NODTB_DATA):]
1320
1321 fdt_len = self.GetFdtLen(second)
1322 third = second[fdt_len:]
1323 second = second[:fdt_len]
1324
Simon Glassbac25c82017-05-27 07:38:26 -06001325 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1326 self.assertIn(ucode_data, second)
1327 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001328
Simon Glassbac25c82017-05-27 07:38:26 -06001329 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001330 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001331 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1332 len(ucode_data))
1333 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001334 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1335 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001336
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001337 def testPackUbootSingleMicrocode(self):
1338 """Test that x86 microcode can be handled correctly with fdt_normal.
1339 """
Simon Glassbac25c82017-05-27 07:38:26 -06001340 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001341
Simon Glass996021e2016-11-25 20:15:54 -07001342 def testUBootImg(self):
1343 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001344 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001345 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001346
1347 def testNoMicrocode(self):
1348 """Test that a missing microcode region is detected"""
1349 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001350 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001351 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1352 "node found in ", str(e.exception))
1353
1354 def testMicrocodeWithoutNode(self):
1355 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1356 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001357 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001358 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1359 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1360
1361 def testMicrocodeWithoutNode2(self):
1362 """Test that a missing u-boot-ucode node is detected"""
1363 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001364 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001365 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1366 "microcode region u-boot-ucode", str(e.exception))
1367
1368 def testMicrocodeWithoutPtrInElf(self):
1369 """Test that a U-Boot binary without the microcode symbol is detected"""
1370 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001371 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001372 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001373 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001374
1375 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001376 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001377 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1378 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1379
1380 finally:
1381 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001382 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001383 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001384
1385 def testMicrocodeNotInImage(self):
1386 """Test that microcode must be placed within the image"""
1387 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001388 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001389 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1390 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001391 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001392
1393 def testWithoutMicrocode(self):
1394 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001395 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001396 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001397 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001398
1399 # Now check the device tree has no microcode
1400 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1401 second = data[len(U_BOOT_NODTB_DATA):]
1402
1403 fdt_len = self.GetFdtLen(second)
1404 self.assertEqual(dtb, second[:fdt_len])
1405
1406 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1407 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001408 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001409
1410 def testUnknownPosSize(self):
1411 """Test that microcode must be placed within the image"""
1412 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001413 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001414 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001415 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001416
1417 def testPackFsp(self):
1418 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001419 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001420 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1421
1422 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001423 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001424 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001425 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001426
1427 def testPackVbt(self):
1428 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001429 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001430 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001431
Simon Glass7f94e832017-11-12 21:52:25 -07001432 def testSplBssPad(self):
1433 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001434 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001435 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001436 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001437 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001438 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001439
Simon Glass04cda032018-10-01 21:12:42 -06001440 def testSplBssPadMissing(self):
1441 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001442 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001443 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001444 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001445 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1446 str(e.exception))
1447
Simon Glasse83679d2017-11-12 21:52:26 -07001448 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001449 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001450 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001451 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1452
Simon Glass6ba679c2018-07-06 10:27:17 -06001453 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1454 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001455
1456 We expect to see the following in the image, in order:
1457 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1458 correct place
1459 u-boot.dtb with the microcode removed
1460 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001461
1462 Args:
1463 dts: Device tree file to use for test
1464 ucode_second: True if the microsecond entry is second instead of
1465 third
Simon Glass3d274232017-11-12 21:52:27 -07001466 """
Simon Glass7057d022018-10-01 21:12:47 -06001467 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001468 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1469 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001470 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1471 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001472
Simon Glass6ba679c2018-07-06 10:27:17 -06001473 def testPackUbootSplMicrocode(self):
1474 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001475 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001476 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001477
1478 def testPackUbootSplMicrocodeReorder(self):
1479 """Test that order doesn't matter for microcode entries
1480
1481 This is the same as testPackUbootSplMicrocode but when we process the
1482 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1483 entry, so we reply on binman to try later.
1484 """
Simon Glass511f6582018-10-01 12:22:30 -06001485 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001486 ucode_second=True)
1487
Simon Glassa409c932017-11-12 21:52:28 -07001488 def testPackMrc(self):
1489 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001490 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001491 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1492
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001493 def testSplDtb(self):
1494 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001495 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001496 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001497 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1498
Simon Glass0a6da312017-11-13 18:54:56 -07001499 def testSplNoDtb(self):
1500 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001501 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001502 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001503 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1504
Simon Glass7098b7f2021-03-21 18:24:30 +13001505 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4b0f4142024-08-26 13:11:40 -06001506 use_expanded=False, no_write_symbols=False,
1507 symbols_base=None):
Simon Glass31e04cb2021-03-18 20:24:56 +13001508 """Check the image contains the expected symbol values
1509
1510 Args:
1511 dts: Device tree file to use for test
1512 base_data: Data before and after 'u-boot' section
Simon Glass3eb30a42024-08-26 13:11:42 -06001513 u_boot_offset (int): Offset of 'u-boot' section in image, or None if
1514 the offset not available due to it being in a compressed section
Simon Glass7098b7f2021-03-21 18:24:30 +13001515 entry_args: Dict of entry args to supply to binman
1516 key: arg name
1517 value: value of that arg
1518 use_expanded: True to use expanded entries where available, e.g.
1519 'u-boot-expanded' instead of 'u-boot'
Simon Glass4b0f4142024-08-26 13:11:40 -06001520 symbols_base (int): Value to expect for symbols-base in u-boot-spl,
1521 None if none
Simon Glass31e04cb2021-03-18 20:24:56 +13001522 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001523 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001524 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1525 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001526 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001527 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001528 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001529
Simon Glass7057d022018-10-01 21:12:47 -06001530 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001531 data = self._DoReadFileDtb(dts, entry_args=entry_args,
Simon Glass3eb30a42024-08-26 13:11:42 -06001532 use_expanded=use_expanded,
1533 verbosity=None if u_boot_offset else 3)[0]
1534
1535 # The lz4-compressed version of the U-Boot data is 19 bytes long
1536 comp_uboot_len = 19
1537
Simon Glass31e04cb2021-03-18 20:24:56 +13001538 # The image should contain the symbols from u_boot_binman_syms.c
1539 # Note that image_pos is adjusted by the base address of the image,
1540 # which is 0x10 in our test image
Simon Glass3eb30a42024-08-26 13:11:42 -06001541 # If u_boot_offset is None, Binman should write -1U into the image
Simon Glass4b0f4142024-08-26 13:11:40 -06001542 vals2 = (elf.BINMAN_SYM_MAGIC_VALUE, 0x00,
Simon Glass3eb30a42024-08-26 13:11:42 -06001543 u_boot_offset + len(U_BOOT_DATA) if u_boot_offset else
1544 len(U_BOOT_SPL_DATA) + 1 + comp_uboot_len,
1545 0x10 + u_boot_offset if u_boot_offset else 0xffffffff, 0x04)
Simon Glass4b0f4142024-08-26 13:11:40 -06001546
1547 # u-boot-spl has a symbols-base property, so take that into account if
1548 # required. The caller must supply the value
1549 vals = list(vals2)
1550 if symbols_base is not None:
1551 vals[3] = symbols_base + u_boot_offset
1552 vals = tuple(vals)
1553
Simon Glass4b4049e2024-08-26 13:11:39 -06001554 sym_values = struct.pack('<LLQLL', *vals)
Simon Glass4b0f4142024-08-26 13:11:40 -06001555 sym_values2 = struct.pack('<LLQLL', *vals2)
Simon Glass4abf7842023-07-18 07:23:54 -06001556 if no_write_symbols:
Simon Glass4b4049e2024-08-26 13:11:39 -06001557 self.assertEqual(
1558 base_data +
1559 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1560 U_BOOT_DATA + base_data, data)
Simon Glass4abf7842023-07-18 07:23:54 -06001561 else:
Simon Glass4b4049e2024-08-26 13:11:39 -06001562 got_vals = struct.unpack('<LLQLL', data[:24])
1563
1564 # For debugging:
1565 #print('expect:', list(f'{v:x}' for v in vals))
1566 #print(' got:', list(f'{v:x}' for v in got_vals))
1567
1568 self.assertEqual(vals, got_vals)
1569 self.assertEqual(sym_values, data[:24])
1570
1571 blen = len(base_data)
1572 self.assertEqual(base_data[24:], data[24:blen])
1573 self.assertEqual(0xff, data[blen])
1574
Simon Glass3eb30a42024-08-26 13:11:42 -06001575 if u_boot_offset:
1576 ofs = blen + 1 + len(U_BOOT_DATA)
1577 self.assertEqual(U_BOOT_DATA, data[blen + 1:ofs])
1578 else:
1579 ofs = blen + 1 + comp_uboot_len
Simon Glass4b4049e2024-08-26 13:11:39 -06001580
Simon Glass4b0f4142024-08-26 13:11:40 -06001581 self.assertEqual(sym_values2, data[ofs:ofs + 24])
Simon Glass4b4049e2024-08-26 13:11:39 -06001582 self.assertEqual(base_data[24:], data[ofs + 24:])
1583
1584 # Just repeating the above asserts all at once, for clarity
Simon Glass3eb30a42024-08-26 13:11:42 -06001585 if u_boot_offset:
1586 expected = (sym_values + base_data[24:] +
1587 tools.get_bytes(0xff, 1) + U_BOOT_DATA +
1588 sym_values2 + base_data[24:])
1589 self.assertEqual(expected, data)
Simon Glass4ca8e042017-11-13 18:55:01 -07001590
Simon Glass31e04cb2021-03-18 20:24:56 +13001591 def testSymbols(self):
1592 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001593 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001594
1595 def testSymbolsNoDtb(self):
1596 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001597 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001598 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1599 0x38)
1600
Simon Glasse76a3e62018-06-01 09:38:11 -06001601 def testPackUnitAddress(self):
1602 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001603 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001604 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1605
Simon Glassa91e1152018-06-01 09:38:16 -06001606 def testSections(self):
1607 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001608 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001609 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1610 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1611 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001612 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001613
Simon Glass30732662018-06-01 09:38:20 -06001614 def testMap(self):
1615 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001616 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001617 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700161800000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600161900000000 00000000 00000010 section@0
162000000000 00000000 00000004 u-boot
162100000010 00000010 00000010 section@1
162200000010 00000000 00000004 u-boot
162300000020 00000020 00000004 section@2
162400000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001625''', map_data)
1626
Simon Glass3b78d532018-06-01 09:38:21 -06001627 def testNamePrefix(self):
1628 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001629 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001630 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700163100000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600163200000000 00000000 00000010 section@0
163300000000 00000000 00000004 ro-u-boot
163400000010 00000010 00000010 section@1
163500000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001636''', map_data)
1637
Simon Glass6ba679c2018-07-06 10:27:17 -06001638 def testUnknownContents(self):
1639 """Test that obtaining the contents works as expected"""
1640 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001641 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001642 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001643 "processing of contents: remaining ["
1644 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001645
Simon Glass2e1169f2018-07-06 10:27:19 -06001646 def testBadChangeSize(self):
1647 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001648 try:
1649 state.SetAllowEntryExpansion(False)
1650 with self.assertRaises(ValueError) as e:
1651 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001652 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001653 str(e.exception))
1654 finally:
1655 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001656
Simon Glassa87014e2018-07-06 10:27:42 -06001657 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001658 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001659 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001660 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001661 dtb = fdt.Fdt(out_dtb_fname)
1662 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001663 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001664 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001665 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001666 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001667 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001668 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001669 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001670 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001671 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001672 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001673 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001674 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001675 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001676
Simon Glasse8561af2018-08-01 15:22:37 -06001677 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001678 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001679 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001680 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001681 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001682 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001683 'size': 40
1684 }, props)
1685
1686 def testUpdateFdtBad(self):
1687 """Test that we detect when ProcessFdt never completes"""
1688 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001689 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001690 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001691 '[<binman.etype._testing.Entry__testing',
1692 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001693
Simon Glass91710b32018-07-17 13:25:32 -06001694 def testEntryArgs(self):
1695 """Test passing arguments to entries from the command line"""
1696 entry_args = {
1697 'test-str-arg': 'test1',
1698 'test-int-arg': '456',
1699 }
Simon Glass511f6582018-10-01 12:22:30 -06001700 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001701 self.assertIn('image', control.images)
1702 entry = control.images['image'].GetEntries()['_testing']
1703 self.assertEqual('test0', entry.test_str_fdt)
1704 self.assertEqual('test1', entry.test_str_arg)
1705 self.assertEqual(123, entry.test_int_fdt)
1706 self.assertEqual(456, entry.test_int_arg)
1707
1708 def testEntryArgsMissing(self):
1709 """Test missing arguments and properties"""
1710 entry_args = {
1711 'test-int-arg': '456',
1712 }
Simon Glass511f6582018-10-01 12:22:30 -06001713 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001714 entry = control.images['image'].GetEntries()['_testing']
1715 self.assertEqual('test0', entry.test_str_fdt)
1716 self.assertEqual(None, entry.test_str_arg)
1717 self.assertEqual(None, entry.test_int_fdt)
1718 self.assertEqual(456, entry.test_int_arg)
1719
1720 def testEntryArgsRequired(self):
1721 """Test missing arguments and properties"""
1722 entry_args = {
1723 'test-int-arg': '456',
1724 }
1725 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001726 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001727 self.assertIn("Node '/binman/_testing': "
1728 'Missing required properties/entry args: test-str-arg, '
1729 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001730 str(e.exception))
1731
1732 def testEntryArgsInvalidFormat(self):
1733 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001734 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1735 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001736 with self.assertRaises(ValueError) as e:
1737 self._DoBinman(*args)
1738 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1739
1740 def testEntryArgsInvalidInteger(self):
1741 """Test that an invalid entry-argument integer is detected"""
1742 entry_args = {
1743 'test-int-arg': 'abc',
1744 }
1745 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001746 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001747 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1748 "'test-int-arg' (value 'abc') to integer",
1749 str(e.exception))
1750
1751 def testEntryArgsInvalidDatatype(self):
1752 """Test that an invalid entry-argument datatype is detected
1753
1754 This test could be written in entry_test.py except that it needs
1755 access to control.entry_args, which seems more than that module should
1756 be able to see.
1757 """
1758 entry_args = {
1759 'test-bad-datatype-arg': '12',
1760 }
1761 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001762 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001763 entry_args=entry_args)
1764 self.assertIn('GetArg() internal error: Unknown data type ',
1765 str(e.exception))
1766
Simon Glass2ca52032018-07-17 13:25:33 -06001767 def testText(self):
1768 """Test for a text entry type"""
1769 entry_args = {
1770 'test-id': TEXT_DATA,
1771 'test-id2': TEXT_DATA2,
1772 'test-id3': TEXT_DATA3,
1773 }
Simon Glass511f6582018-10-01 12:22:30 -06001774 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001775 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001776 expected = (tools.to_bytes(TEXT_DATA) +
1777 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1778 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001779 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001780 self.assertEqual(expected, data)
1781
Simon Glass969616c2018-07-17 13:25:36 -06001782 def testEntryDocs(self):
1783 """Test for creation of entry documentation"""
1784 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001785 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001786 self.assertTrue(len(stdout.getvalue()) > 0)
1787
1788 def testEntryDocsMissing(self):
1789 """Test handling of missing entry documentation"""
1790 with self.assertRaises(ValueError) as e:
1791 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001792 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001793 self.assertIn('Documentation is missing for modules: u_boot',
1794 str(e.exception))
1795
Simon Glass704784b2018-07-17 13:25:38 -06001796 def testFmap(self):
1797 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001798 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001799 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001800 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1801 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001802 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001803 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001804 self.assertEqual(1, fhdr.ver_major)
1805 self.assertEqual(0, fhdr.ver_minor)
1806 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001807 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001808 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001809 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001810 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001811 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001812
Simon Glass82059c22021-04-03 11:05:09 +13001813 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001814 self.assertEqual(b'SECTION0', fentry.name)
1815 self.assertEqual(0, fentry.offset)
1816 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001817 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001818
1819 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001820 self.assertEqual(b'RO_U_BOOT', fentry.name)
1821 self.assertEqual(0, fentry.offset)
1822 self.assertEqual(4, fentry.size)
1823 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001824
Simon Glass82059c22021-04-03 11:05:09 +13001825 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001826 self.assertEqual(b'SECTION1', fentry.name)
1827 self.assertEqual(16, fentry.offset)
1828 self.assertEqual(16, fentry.size)
1829 self.assertEqual(0, fentry.flags)
1830
1831 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001832 self.assertEqual(b'RW_U_BOOT', fentry.name)
1833 self.assertEqual(16, fentry.offset)
1834 self.assertEqual(4, fentry.size)
1835 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001836
Simon Glass82059c22021-04-03 11:05:09 +13001837 fentry = next(fiter)
1838 self.assertEqual(b'FMAP', fentry.name)
1839 self.assertEqual(32, fentry.offset)
1840 self.assertEqual(expect_size, fentry.size)
1841 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001842
Simon Glassdb168d42018-07-17 13:25:39 -06001843 def testBlobNamedByArg(self):
1844 """Test we can add a blob with the filename coming from an entry arg"""
1845 entry_args = {
1846 'cros-ec-rw-path': 'ecrw.bin',
1847 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001848 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001849
Simon Glass53f53992018-07-17 13:25:40 -06001850 def testFill(self):
1851 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001852 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001853 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001854 self.assertEqual(expected, data)
1855
1856 def testFillNoSize(self):
1857 """Test for an fill entry type with no size"""
1858 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001859 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001860 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001861 str(e.exception))
1862
Simon Glassc1ae83c2018-07-17 13:25:44 -06001863 def _HandleGbbCommand(self, pipe_list):
1864 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001865 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001866 fname = pipe_list[0][-1]
1867 # Append our GBB data to the file, which will happen every time the
1868 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001869 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001870 fd.write(GBB_DATA)
1871 return command.CommandResult()
1872
1873 def testGbb(self):
1874 """Test for the Chromium OS Google Binary Block"""
1875 command.test_result = self._HandleGbbCommand
1876 entry_args = {
1877 'keydir': 'devkeys',
1878 'bmpblk': 'bmpblk.bin',
1879 }
Simon Glass511f6582018-10-01 12:22:30 -06001880 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001881
1882 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001883 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1884 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001885 self.assertEqual(expected, data)
1886
1887 def testGbbTooSmall(self):
1888 """Test for the Chromium OS Google Binary Block being large enough"""
1889 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001890 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001891 self.assertIn("Node '/binman/gbb': GBB is too small",
1892 str(e.exception))
1893
1894 def testGbbNoSize(self):
1895 """Test for the Chromium OS Google Binary Block having a size"""
1896 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001897 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001898 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1899 str(e.exception))
1900
Simon Glass66152ce2022-01-09 20:14:09 -07001901 def testGbbMissing(self):
1902 """Test that binman still produces an image if futility is missing"""
1903 entry_args = {
1904 'keydir': 'devkeys',
1905 }
1906 with test_util.capture_sys_output() as (_, stderr):
1907 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1908 entry_args=entry_args)
1909 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001910 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001911
Simon Glass5c350162018-07-17 13:25:47 -06001912 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001913 """Fake calls to the futility utility
1914
1915 The expected pipe is:
1916
1917 [('futility', 'vbutil_firmware', '--vblock',
1918 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1919 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1920 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1921 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1922
1923 This writes to the output file (here, 'vblock.vblock'). If
1924 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1925 of the input data (here, 'input.vblock').
1926 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001927 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001928 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001929 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001930 if self._hash_data:
1931 infile = pipe_list[0][11]
1932 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001933 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001934 m.update(data)
1935 fd.write(m.digest())
1936 else:
1937 fd.write(VBLOCK_DATA)
1938
Simon Glass5c350162018-07-17 13:25:47 -06001939 return command.CommandResult()
1940
1941 def testVblock(self):
1942 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001943 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001944 command.test_result = self._HandleVblockCommand
1945 entry_args = {
1946 'keydir': 'devkeys',
1947 }
Simon Glass511f6582018-10-01 12:22:30 -06001948 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001949 entry_args=entry_args)
1950 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1951 self.assertEqual(expected, data)
1952
1953 def testVblockNoContent(self):
1954 """Test we detect a vblock which has no content to sign"""
1955 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001956 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001957 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001958 'property', str(e.exception))
1959
1960 def testVblockBadPhandle(self):
1961 """Test that we detect a vblock with an invalid phandle in contents"""
1962 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001963 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001964 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1965 '1000', str(e.exception))
1966
1967 def testVblockBadEntry(self):
1968 """Test that we detect an entry that points to a non-entry"""
1969 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001970 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001971 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1972 "'other'", str(e.exception))
1973
Simon Glass220c6222021-01-06 21:35:17 -07001974 def testVblockContent(self):
1975 """Test that the vblock signs the right data"""
1976 self._hash_data = True
1977 command.test_result = self._HandleVblockCommand
1978 entry_args = {
1979 'keydir': 'devkeys',
1980 }
1981 data = self._DoReadFileDtb(
1982 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1983 entry_args=entry_args)[0]
1984 hashlen = 32 # SHA256 hash is 32 bytes
1985 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1986 hashval = data[-hashlen:]
1987 dtb = data[len(U_BOOT_DATA):-hashlen]
1988
1989 expected_data = U_BOOT_DATA + dtb
1990
1991 # The hashval should be a hash of the dtb
1992 m = hashlib.sha256()
1993 m.update(expected_data)
1994 expected_hashval = m.digest()
1995 self.assertEqual(expected_hashval, hashval)
1996
Simon Glass66152ce2022-01-09 20:14:09 -07001997 def testVblockMissing(self):
1998 """Test that binman still produces an image if futility is missing"""
1999 entry_args = {
2000 'keydir': 'devkeys',
2001 }
2002 with test_util.capture_sys_output() as (_, stderr):
2003 self._DoTestFile('074_vblock.dts',
2004 force_missing_bintools='futility',
2005 entry_args=entry_args)
2006 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07002007 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07002008
Simon Glass8425a1f2018-07-17 13:25:48 -06002009 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06002010 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06002011 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06002012 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06002013 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06002014 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
2015
Simon Glass24b97442018-07-17 13:25:51 -06002016 def testUsesPos(self):
2017 """Test that the 'pos' property cannot be used anymore"""
2018 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002019 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06002020 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
2021 "'pos'", str(e.exception))
2022
Simon Glass274bf092018-09-14 04:57:08 -06002023 def testFillZero(self):
2024 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06002025 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07002026 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06002027
Simon Glass267de432018-09-14 04:57:09 -06002028 def testTextMissing(self):
2029 """Test for a text entry type where there is no text"""
2030 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002031 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06002032 self.assertIn("Node '/binman/text': No value provided for text label "
2033 "'test-id'", str(e.exception))
2034
Simon Glassed40e962018-09-14 04:57:10 -06002035 def testPackStart16Tpl(self):
2036 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06002037 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06002038 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
2039
Simon Glass3b376c32018-09-14 04:57:12 -06002040 def testSelectImage(self):
2041 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06002042 expected = 'Skipping images: image1'
2043
2044 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06002045 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06002046 with test_util.capture_sys_output() as (stdout, stderr):
2047 retcode = self._DoTestFile('006_dual_image.dts',
2048 verbosity=verbosity,
2049 images=['image2'])
2050 self.assertEqual(0, retcode)
2051 if verbosity:
2052 self.assertIn(expected, stdout.getvalue())
2053 else:
2054 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06002055
Simon Glass80025522022-01-29 14:14:04 -07002056 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2057 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06002058 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06002059
Simon Glasse219aa42018-09-14 04:57:24 -06002060 def testUpdateFdtAll(self):
2061 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06002062 self._SetupSplElf()
2063 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06002064 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06002065
2066 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06002067 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002068 'image-pos': 0,
2069 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06002070 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002071 'section:image-pos': 0,
2072 'section:size': 565,
2073 'section/u-boot-dtb:offset': 0,
2074 'section/u-boot-dtb:image-pos': 0,
2075 'section/u-boot-dtb:size': 565,
2076 'u-boot-spl-dtb:offset': 565,
2077 'u-boot-spl-dtb:image-pos': 565,
2078 'u-boot-spl-dtb:size': 585,
2079 'u-boot-tpl-dtb:offset': 1150,
2080 'u-boot-tpl-dtb:image-pos': 1150,
2081 'u-boot-tpl-dtb:size': 585,
2082 'u-boot-vpl-dtb:image-pos': 1735,
2083 'u-boot-vpl-dtb:offset': 1735,
2084 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002085 }
2086
2087 # We expect three device-tree files in the output, one after the other.
2088 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2089 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2090 # main U-Boot tree. All three should have the same postions and offset.
2091 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002092 self.maxDiff = None
2093 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002094 dtb = fdt.Fdt.FromData(data[start:])
2095 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002096 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002097 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002098 expected = dict(base_expected)
2099 if item:
2100 expected[item] = 0
2101 self.assertEqual(expected, props)
2102 start += dtb._fdt_obj.totalsize()
2103
2104 def testUpdateFdtOutput(self):
2105 """Test that output DTB files are updated"""
2106 try:
Simon Glass511f6582018-10-01 12:22:30 -06002107 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002108 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2109
2110 # Unfortunately, compiling a source file always results in a file
2111 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002112 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002113 # binman as a file called u-boot.dtb. To fix this, copy the file
2114 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002115 start = 0
2116 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002117 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002118 dtb = fdt.Fdt.FromData(data[start:])
2119 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002120 pathname = tools.get_output_filename(os.path.split(fname)[1])
2121 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002122 name = os.path.split(fname)[0]
2123
2124 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002125 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002126 else:
2127 orig_indata = dtb_data
2128 self.assertNotEqual(outdata, orig_indata,
2129 "Expected output file '%s' be updated" % pathname)
2130 self.assertEqual(outdata, data[start:start + size],
2131 "Expected output file '%s' to match output image" %
2132 pathname)
2133 start += size
2134 finally:
2135 self._ResetDtbs()
2136
Simon Glass7ba33592018-09-14 04:57:26 -06002137 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002138 bintool = self.comp_bintools['lz4']
2139 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002140
2141 def testCompress(self):
2142 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002143 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002144 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002145 use_real_dtb=True, update_dtb=True)
2146 dtb = fdt.Fdt(out_dtb_fname)
2147 dtb.Scan()
2148 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2149 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00002150 self.assertEqual(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002151
2152 # Do a sanity check on various fields
2153 image = control.images['image']
2154 entries = image.GetEntries()
2155 self.assertEqual(1, len(entries))
2156
2157 entry = entries['blob']
2158 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2159 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2160 orig = self._decompress(entry.data)
2161 self.assertEqual(orig, entry.uncomp_data)
2162
Simon Glass72eeff12020-10-26 17:40:16 -06002163 self.assertEqual(image.data, entry.data)
2164
Simon Glass7ba33592018-09-14 04:57:26 -06002165 expected = {
2166 'blob:uncomp-size': len(COMPRESS_DATA),
2167 'blob:size': len(data),
2168 'size': len(data),
2169 }
2170 self.assertEqual(expected, props)
2171
Simon Glassac6328c2018-09-14 04:57:28 -06002172 def testFiles(self):
2173 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002174 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002175 self.assertEqual(FILES_DATA, data)
2176
2177 def testFilesCompress(self):
2178 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002179 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002180 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002181
2182 image = control.images['image']
2183 entries = image.GetEntries()
2184 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002185 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002186
Simon Glass303f62f2019-05-17 22:00:46 -06002187 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002188 for i in range(1, 3):
2189 key = '%d.dat' % i
2190 start = entries[key].image_pos
2191 len = entries[key].size
2192 chunk = data[start:start + len]
2193 orig += self._decompress(chunk)
2194
2195 self.assertEqual(FILES_DATA, orig)
2196
2197 def testFilesMissing(self):
2198 """Test missing files"""
2199 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002200 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002201 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2202 'no files', str(e.exception))
2203
2204 def testFilesNoPattern(self):
2205 """Test missing files"""
2206 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002207 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002208 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2209 str(e.exception))
2210
Simon Glassdd156a42022-03-05 20:18:59 -07002211 def testExtendSize(self):
2212 """Test an extending entry"""
2213 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002214 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002215 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2216 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2217 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2218 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002219 self.assertEqual(expect, data)
2220 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700222100000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600222200000000 00000000 00000008 fill
222300000008 00000008 00000004 u-boot
22240000000c 0000000c 00000004 section
22250000000c 00000000 00000003 intel-mrc
222600000010 00000010 00000004 u-boot2
222700000014 00000014 0000000c section2
222800000014 00000000 00000008 fill
22290000001c 00000008 00000004 u-boot
223000000020 00000020 00000008 fill2
2231''', map_data)
2232
Simon Glassdd156a42022-03-05 20:18:59 -07002233 def testExtendSizeBad(self):
2234 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002235 with test_util.capture_sys_output() as (stdout, stderr):
2236 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002237 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002238 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2239 'expanding entry', str(e.exception))
2240
Simon Glassae7cf032018-09-14 04:57:31 -06002241 def testHash(self):
2242 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002243 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002244 use_real_dtb=True, update_dtb=True)
2245 dtb = fdt.Fdt(out_dtb_fname)
2246 dtb.Scan()
2247 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2248 m = hashlib.sha256()
2249 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002250 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002251
2252 def testHashNoAlgo(self):
2253 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002254 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002255 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2256 'hash node', str(e.exception))
2257
2258 def testHashBadAlgo(self):
2259 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002260 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002261 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002262 str(e.exception))
2263
2264 def testHashSection(self):
2265 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002266 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002267 use_real_dtb=True, update_dtb=True)
2268 dtb = fdt.Fdt(out_dtb_fname)
2269 dtb.Scan()
2270 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2271 m = hashlib.sha256()
2272 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002273 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002274 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002275
Simon Glass3fb4f422018-09-14 04:57:32 -06002276 def testPackUBootTplMicrocode(self):
2277 """Test that x86 microcode can be handled correctly in TPL
2278
2279 We expect to see the following in the image, in order:
2280 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2281 place
2282 u-boot-tpl.dtb with the microcode removed
2283 the microcode
2284 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002285 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002286 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002287 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002288 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2289 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002290
Simon Glassc64aea52018-09-14 04:57:34 -06002291 def testFmapX86(self):
2292 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002293 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002294 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002295 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002296 self.assertEqual(expected, data[:32])
2297 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2298
2299 self.assertEqual(0x100, fhdr.image_size)
2300
2301 self.assertEqual(0, fentries[0].offset)
2302 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002303 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002304
2305 self.assertEqual(4, fentries[1].offset)
2306 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002307 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002308
2309 self.assertEqual(32, fentries[2].offset)
2310 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2311 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002312 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002313
2314 def testFmapX86Section(self):
2315 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002316 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002317 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002318 self.assertEqual(expected, data[:32])
2319 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2320
Simon Glassb1d414c2021-04-03 11:05:10 +13002321 self.assertEqual(0x180, fhdr.image_size)
2322 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002323 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002324
Simon Glass82059c22021-04-03 11:05:09 +13002325 fentry = next(fiter)
2326 self.assertEqual(b'U_BOOT', fentry.name)
2327 self.assertEqual(0, fentry.offset)
2328 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002329
Simon Glass82059c22021-04-03 11:05:09 +13002330 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002331 self.assertEqual(b'SECTION', fentry.name)
2332 self.assertEqual(4, fentry.offset)
2333 self.assertEqual(0x20 + expect_size, fentry.size)
2334
2335 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002336 self.assertEqual(b'INTEL_MRC', fentry.name)
2337 self.assertEqual(4, fentry.offset)
2338 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002339
Simon Glass82059c22021-04-03 11:05:09 +13002340 fentry = next(fiter)
2341 self.assertEqual(b'FMAP', fentry.name)
2342 self.assertEqual(36, fentry.offset)
2343 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002344
Simon Glassb1714232018-09-14 04:57:35 -06002345 def testElf(self):
2346 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002347 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002348 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002349 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002350 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002351 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002352
Simon Glass0d673792019-07-08 13:18:25 -06002353 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002354 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002355 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002356 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002357 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002358 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002359
Simon Glasscd817d52018-09-14 04:57:36 -06002360 def testPackOverlapMap(self):
2361 """Test that overlapping regions are detected"""
2362 with test_util.capture_sys_output() as (stdout, stderr):
2363 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002364 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002365 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002366 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2367 stdout.getvalue())
2368
2369 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002370 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002371 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002372 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002373 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002374<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002375<none> 00000000 00000004 u-boot
2376<none> 00000003 00000004 u-boot-align
2377''', map_data)
2378
Simon Glass0d673792019-07-08 13:18:25 -06002379 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002380 """Test that an image with an Intel Reference code binary works"""
2381 data = self._DoReadFile('100_intel_refcode.dts')
2382 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2383
Simon Glasseb023b32019-04-25 21:58:39 -06002384 def testSectionOffset(self):
2385 """Tests use of a section with an offset"""
2386 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2387 map=True)
2388 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700238900000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600239000000004 00000004 00000010 section@0
239100000004 00000000 00000004 u-boot
239200000018 00000018 00000010 section@1
239300000018 00000000 00000004 u-boot
23940000002c 0000002c 00000004 section@2
23950000002c 00000000 00000004 u-boot
2396''', map_data)
2397 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002398 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2399 tools.get_bytes(0x21, 12) +
2400 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2401 tools.get_bytes(0x61, 12) +
2402 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2403 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002404
Simon Glass1de34482019-07-08 13:18:53 -06002405 def testCbfsRaw(self):
2406 """Test base handling of a Coreboot Filesystem (CBFS)
2407
2408 The exact contents of the CBFS is verified by similar tests in
2409 cbfs_util_test.py. The tests here merely check that the files added to
2410 the CBFS can be found in the final image.
2411 """
2412 data = self._DoReadFile('102_cbfs_raw.dts')
2413 size = 0xb0
2414
2415 cbfs = cbfs_util.CbfsReader(data)
2416 self.assertEqual(size, cbfs.rom_size)
2417
2418 self.assertIn('u-boot-dtb', cbfs.files)
2419 cfile = cbfs.files['u-boot-dtb']
2420 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2421
2422 def testCbfsArch(self):
2423 """Test on non-x86 architecture"""
2424 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2425 size = 0x100
2426
2427 cbfs = cbfs_util.CbfsReader(data)
2428 self.assertEqual(size, cbfs.rom_size)
2429
2430 self.assertIn('u-boot-dtb', cbfs.files)
2431 cfile = cbfs.files['u-boot-dtb']
2432 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2433
2434 def testCbfsStage(self):
2435 """Tests handling of a Coreboot Filesystem (CBFS)"""
2436 if not elf.ELF_TOOLS:
2437 self.skipTest('Python elftools not available')
2438 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2439 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2440 size = 0xb0
2441
2442 data = self._DoReadFile('104_cbfs_stage.dts')
2443 cbfs = cbfs_util.CbfsReader(data)
2444 self.assertEqual(size, cbfs.rom_size)
2445
2446 self.assertIn('u-boot', cbfs.files)
2447 cfile = cbfs.files['u-boot']
2448 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2449
2450 def testCbfsRawCompress(self):
2451 """Test handling of compressing raw files"""
2452 self._CheckLz4()
2453 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2454 size = 0x140
2455
2456 cbfs = cbfs_util.CbfsReader(data)
2457 self.assertIn('u-boot', cbfs.files)
2458 cfile = cbfs.files['u-boot']
2459 self.assertEqual(COMPRESS_DATA, cfile.data)
2460
2461 def testCbfsBadArch(self):
2462 """Test handling of a bad architecture"""
2463 with self.assertRaises(ValueError) as e:
2464 self._DoReadFile('106_cbfs_bad_arch.dts')
2465 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2466
2467 def testCbfsNoSize(self):
2468 """Test handling of a missing size property"""
2469 with self.assertRaises(ValueError) as e:
2470 self._DoReadFile('107_cbfs_no_size.dts')
2471 self.assertIn('entry must have a size property', str(e.exception))
2472
Simon Glass3e28f4f2021-11-23 11:03:54 -07002473 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002474 """Test handling of a CBFS entry which does not provide contentsy"""
2475 with self.assertRaises(ValueError) as e:
2476 self._DoReadFile('108_cbfs_no_contents.dts')
2477 self.assertIn('Could not complete processing of contents',
2478 str(e.exception))
2479
2480 def testCbfsBadCompress(self):
2481 """Test handling of a bad architecture"""
2482 with self.assertRaises(ValueError) as e:
2483 self._DoReadFile('109_cbfs_bad_compress.dts')
2484 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2485 str(e.exception))
2486
2487 def testCbfsNamedEntries(self):
2488 """Test handling of named entries"""
2489 data = self._DoReadFile('110_cbfs_name.dts')
2490
2491 cbfs = cbfs_util.CbfsReader(data)
2492 self.assertIn('FRED', cbfs.files)
2493 cfile1 = cbfs.files['FRED']
2494 self.assertEqual(U_BOOT_DATA, cfile1.data)
2495
2496 self.assertIn('hello', cbfs.files)
2497 cfile2 = cbfs.files['hello']
2498 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2499
Simon Glass759af872019-07-08 13:18:54 -06002500 def _SetupIfwi(self, fname):
2501 """Set up to run an IFWI test
2502
2503 Args:
2504 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2505 """
2506 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002507 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002508
2509 # Intel Integrated Firmware Image (IFWI) file
2510 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2511 data = fd.read()
2512 TestFunctional._MakeInputFile(fname,data)
2513
2514 def _CheckIfwi(self, data):
2515 """Check that an image with an IFWI contains the correct output
2516
2517 Args:
2518 data: Conents of output file
2519 """
Simon Glass80025522022-01-29 14:14:04 -07002520 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002521 if data[:0x1000] != expected_desc:
2522 self.fail('Expected descriptor binary at start of image')
2523
2524 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002525 image_fname = tools.get_output_filename('image.bin')
2526 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002527 ifwitool = bintool.Bintool.create('ifwitool')
2528 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002529
Simon Glass80025522022-01-29 14:14:04 -07002530 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002531 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002532
2533 def testPackX86RomIfwi(self):
2534 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2535 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002536 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002537 self._CheckIfwi(data)
2538
2539 def testPackX86RomIfwiNoDesc(self):
2540 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2541 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002542 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002543 self._CheckIfwi(data)
2544
2545 def testPackX86RomIfwiNoData(self):
2546 """Test that an x86 ROM with IFWI handles missing data"""
2547 self._SetupIfwi('ifwi.bin')
2548 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002549 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002550 self.assertIn('Could not complete processing of contents',
2551 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002552
Simon Glass66152ce2022-01-09 20:14:09 -07002553 def testIfwiMissing(self):
2554 """Test that binman still produces an image if ifwitool is missing"""
2555 self._SetupIfwi('fitimage.bin')
2556 with test_util.capture_sys_output() as (_, stderr):
2557 self._DoTestFile('111_x86_rom_ifwi.dts',
2558 force_missing_bintools='ifwitool')
2559 err = stderr.getvalue()
2560 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002561 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002562
Simon Glassc2f1aed2019-07-08 13:18:56 -06002563 def testCbfsOffset(self):
2564 """Test a CBFS with files at particular offsets
2565
2566 Like all CFBS tests, this is just checking the logic that calls
2567 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2568 """
2569 data = self._DoReadFile('114_cbfs_offset.dts')
2570 size = 0x200
2571
2572 cbfs = cbfs_util.CbfsReader(data)
2573 self.assertEqual(size, cbfs.rom_size)
2574
2575 self.assertIn('u-boot', cbfs.files)
2576 cfile = cbfs.files['u-boot']
2577 self.assertEqual(U_BOOT_DATA, cfile.data)
2578 self.assertEqual(0x40, cfile.cbfs_offset)
2579
2580 self.assertIn('u-boot-dtb', cbfs.files)
2581 cfile2 = cbfs.files['u-boot-dtb']
2582 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2583 self.assertEqual(0x140, cfile2.cbfs_offset)
2584
Simon Glass0f621332019-07-08 14:25:27 -06002585 def testFdtmap(self):
2586 """Test an FDT map can be inserted in the image"""
2587 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2588 fdtmap_data = data[len(U_BOOT_DATA):]
2589 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002590 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002591 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002592
2593 fdt_data = fdtmap_data[16:]
2594 dtb = fdt.Fdt.FromData(fdt_data)
2595 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002596 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002597 self.assertEqual({
2598 'image-pos': 0,
2599 'offset': 0,
2600 'u-boot:offset': 0,
2601 'u-boot:size': len(U_BOOT_DATA),
2602 'u-boot:image-pos': 0,
2603 'fdtmap:image-pos': 4,
2604 'fdtmap:offset': 4,
2605 'fdtmap:size': len(fdtmap_data),
2606 'size': len(data),
2607 }, props)
2608
2609 def testFdtmapNoMatch(self):
2610 """Check handling of an FDT map when the section cannot be found"""
2611 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2612
2613 # Mangle the section name, which should cause a mismatch between the
2614 # correct FDT path and the one expected by the section
2615 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002616 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002617 entries = image.GetEntries()
2618 fdtmap = entries['fdtmap']
2619 with self.assertRaises(ValueError) as e:
2620 fdtmap._GetFdtmap()
2621 self.assertIn("Cannot locate node for path '/binman-suffix'",
2622 str(e.exception))
2623
Simon Glasscec34ba2019-07-08 14:25:28 -06002624 def testFdtmapHeader(self):
2625 """Test an FDT map and image header can be inserted in the image"""
2626 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2627 fdtmap_pos = len(U_BOOT_DATA)
2628 fdtmap_data = data[fdtmap_pos:]
2629 fdt_data = fdtmap_data[16:]
2630 dtb = fdt.Fdt.FromData(fdt_data)
2631 fdt_size = dtb.GetFdtObj().totalsize()
2632 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002633 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002634 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2635 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2636
2637 def testFdtmapHeaderStart(self):
2638 """Test an image header can be inserted at the image start"""
2639 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2640 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2641 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002642 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002643 offset = struct.unpack('<I', hdr_data[4:])[0]
2644 self.assertEqual(fdtmap_pos, offset)
2645
2646 def testFdtmapHeaderPos(self):
2647 """Test an image header can be inserted at a chosen position"""
2648 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2649 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2650 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002651 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002652 offset = struct.unpack('<I', hdr_data[4:])[0]
2653 self.assertEqual(fdtmap_pos, offset)
2654
2655 def testHeaderMissingFdtmap(self):
2656 """Test an image header requires an fdtmap"""
2657 with self.assertRaises(ValueError) as e:
2658 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2659 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2660 str(e.exception))
2661
2662 def testHeaderNoLocation(self):
2663 """Test an image header with a no specified location is detected"""
2664 with self.assertRaises(ValueError) as e:
2665 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2666 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2667 str(e.exception))
2668
Simon Glasse61b6f62019-07-08 14:25:37 -06002669 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002670 """Test extending an entry after it is packed"""
2671 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002672 self.assertEqual(b'aaa', data[:3])
2673 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2674 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002675
Simon Glassdd156a42022-03-05 20:18:59 -07002676 def testEntryExtendBad(self):
2677 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002678 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002679 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002680 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002681 str(e.exception))
2682
Simon Glassdd156a42022-03-05 20:18:59 -07002683 def testEntryExtendSection(self):
2684 """Test extending an entry within a section after it is packed"""
2685 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002686 self.assertEqual(b'aaa', data[:3])
2687 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2688 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002689
Simon Glass90d29682019-07-08 14:25:38 -06002690 def testCompressDtb(self):
2691 """Test that compress of device-tree files is supported"""
2692 self._CheckLz4()
2693 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2694 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2695 comp_data = data[len(U_BOOT_DATA):]
2696 orig = self._decompress(comp_data)
2697 dtb = fdt.Fdt.FromData(orig)
2698 dtb.Scan()
2699 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2700 expected = {
2701 'u-boot:size': len(U_BOOT_DATA),
2702 'u-boot-dtb:uncomp-size': len(orig),
2703 'u-boot-dtb:size': len(comp_data),
2704 'size': len(data),
2705 }
2706 self.assertEqual(expected, props)
2707
Simon Glass151bbbf2019-07-08 14:25:41 -06002708 def testCbfsUpdateFdt(self):
2709 """Test that we can update the device tree with CBFS offset/size info"""
2710 self._CheckLz4()
2711 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2712 update_dtb=True)
2713 dtb = fdt.Fdt(out_dtb_fname)
2714 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002715 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002716 del props['cbfs/u-boot:size']
2717 self.assertEqual({
2718 'offset': 0,
2719 'size': len(data),
2720 'image-pos': 0,
2721 'cbfs:offset': 0,
2722 'cbfs:size': len(data),
2723 'cbfs:image-pos': 0,
Simon Glassfa144222023-10-14 14:40:28 -06002724 'cbfs/u-boot:offset': 0x30,
Simon Glass151bbbf2019-07-08 14:25:41 -06002725 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002726 'cbfs/u-boot:image-pos': 0x30,
2727 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002728 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002729 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002730 }, props)
2731
Simon Glass3c9b4f22019-07-08 14:25:42 -06002732 def testCbfsBadType(self):
2733 """Test an image header with a no specified location is detected"""
2734 with self.assertRaises(ValueError) as e:
2735 self._DoReadFile('126_cbfs_bad_type.dts')
2736 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2737
Simon Glass6b156f82019-07-08 14:25:43 -06002738 def testList(self):
2739 """Test listing the files in an image"""
2740 self._CheckLz4()
2741 data = self._DoReadFile('127_list.dts')
2742 image = control.images['image']
2743 entries = image.BuildEntryList()
2744 self.assertEqual(7, len(entries))
2745
2746 ent = entries[0]
2747 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002748 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002749 self.assertEqual('section', ent.etype)
2750 self.assertEqual(len(data), ent.size)
2751 self.assertEqual(0, ent.image_pos)
2752 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002753 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002754
2755 ent = entries[1]
2756 self.assertEqual(1, ent.indent)
2757 self.assertEqual('u-boot', ent.name)
2758 self.assertEqual('u-boot', ent.etype)
2759 self.assertEqual(len(U_BOOT_DATA), ent.size)
2760 self.assertEqual(0, ent.image_pos)
2761 self.assertEqual(None, ent.uncomp_size)
2762 self.assertEqual(0, ent.offset)
2763
2764 ent = entries[2]
2765 self.assertEqual(1, ent.indent)
2766 self.assertEqual('section', ent.name)
2767 self.assertEqual('section', ent.etype)
2768 section_size = ent.size
2769 self.assertEqual(0x100, ent.image_pos)
2770 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002771 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002772
2773 ent = entries[3]
2774 self.assertEqual(2, ent.indent)
2775 self.assertEqual('cbfs', ent.name)
2776 self.assertEqual('cbfs', ent.etype)
2777 self.assertEqual(0x400, ent.size)
2778 self.assertEqual(0x100, ent.image_pos)
2779 self.assertEqual(None, ent.uncomp_size)
2780 self.assertEqual(0, ent.offset)
2781
2782 ent = entries[4]
2783 self.assertEqual(3, ent.indent)
2784 self.assertEqual('u-boot', ent.name)
2785 self.assertEqual('u-boot', ent.etype)
2786 self.assertEqual(len(U_BOOT_DATA), ent.size)
2787 self.assertEqual(0x138, ent.image_pos)
2788 self.assertEqual(None, ent.uncomp_size)
2789 self.assertEqual(0x38, ent.offset)
2790
2791 ent = entries[5]
2792 self.assertEqual(3, ent.indent)
2793 self.assertEqual('u-boot-dtb', ent.name)
2794 self.assertEqual('text', ent.etype)
2795 self.assertGreater(len(COMPRESS_DATA), ent.size)
2796 self.assertEqual(0x178, ent.image_pos)
2797 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2798 self.assertEqual(0x78, ent.offset)
2799
2800 ent = entries[6]
2801 self.assertEqual(2, ent.indent)
2802 self.assertEqual('u-boot-dtb', ent.name)
2803 self.assertEqual('u-boot-dtb', ent.etype)
2804 self.assertEqual(0x500, ent.image_pos)
2805 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2806 dtb_size = ent.size
2807 # Compressing this data expands it since headers are added
2808 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2809 self.assertEqual(0x400, ent.offset)
2810
2811 self.assertEqual(len(data), 0x100 + section_size)
2812 self.assertEqual(section_size, 0x400 + dtb_size)
2813
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002814 def testFindFdtmap(self):
2815 """Test locating an FDT map in an image"""
2816 self._CheckLz4()
2817 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2818 image = control.images['image']
2819 entries = image.GetEntries()
2820 entry = entries['fdtmap']
2821 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2822
2823 def testFindFdtmapMissing(self):
2824 """Test failing to locate an FDP map"""
2825 data = self._DoReadFile('005_simple.dts')
2826 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2827
Simon Glassed39a3c2019-07-08 14:25:45 -06002828 def testFindImageHeader(self):
2829 """Test locating a image header"""
2830 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002831 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002832 image = control.images['image']
2833 entries = image.GetEntries()
2834 entry = entries['fdtmap']
2835 # The header should point to the FDT map
2836 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2837
2838 def testFindImageHeaderStart(self):
2839 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002840 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002841 image = control.images['image']
2842 entries = image.GetEntries()
2843 entry = entries['fdtmap']
2844 # The header should point to the FDT map
2845 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2846
2847 def testFindImageHeaderMissing(self):
2848 """Test failing to locate an image header"""
2849 data = self._DoReadFile('005_simple.dts')
2850 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2851
Simon Glassb8424fa2019-07-08 14:25:46 -06002852 def testReadImage(self):
2853 """Test reading an image and accessing its FDT map"""
2854 self._CheckLz4()
2855 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002856 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002857 orig_image = control.images['image']
2858 image = Image.FromFile(image_fname)
2859 self.assertEqual(orig_image.GetEntries().keys(),
2860 image.GetEntries().keys())
2861
2862 orig_entry = orig_image.GetEntries()['fdtmap']
2863 entry = image.GetEntries()['fdtmap']
Brandon Maiera657bc62024-06-04 16:16:05 +00002864 self.assertEqual(orig_entry.offset, entry.offset)
2865 self.assertEqual(orig_entry.size, entry.size)
2866 self.assertEqual(orig_entry.image_pos, entry.image_pos)
Simon Glassb8424fa2019-07-08 14:25:46 -06002867
2868 def testReadImageNoHeader(self):
2869 """Test accessing an image's FDT map without an image header"""
2870 self._CheckLz4()
2871 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002872 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002873 image = Image.FromFile(image_fname)
2874 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002875 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002876
2877 def testReadImageFail(self):
2878 """Test failing to read an image image's FDT map"""
2879 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002880 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002881 with self.assertRaises(ValueError) as e:
2882 image = Image.FromFile(image_fname)
2883 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002884
Simon Glassb2fd11d2019-07-08 14:25:48 -06002885 def testListCmd(self):
2886 """Test listing the files in an image using an Fdtmap"""
2887 self._CheckLz4()
2888 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2889
2890 # lz4 compression size differs depending on the version
2891 image = control.images['image']
2892 entries = image.GetEntries()
2893 section_size = entries['section'].size
2894 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2895 fdtmap_offset = entries['fdtmap'].offset
2896
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002897 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002898 try:
2899 tmpdir, updated_fname = self._SetupImageInTmpdir()
2900 with test_util.capture_sys_output() as (stdout, stderr):
2901 self._DoBinman('ls', '-i', updated_fname)
2902 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002903 if tmpdir:
2904 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002905 lines = stdout.getvalue().splitlines()
2906 expected = [
2907'Name Image-pos Size Entry-type Offset Uncomp-size',
2908'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002909'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002910' u-boot 0 4 u-boot 0',
2911' section 100 %x section 100' % section_size,
2912' cbfs 100 400 cbfs 0',
Simon Glassfa144222023-10-14 14:40:28 -06002913' u-boot 120 4 u-boot 20',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002914' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002915' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002916' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002917 (fdtmap_offset, fdtmap_offset),
2918' image-header bf8 8 image-header bf8',
2919 ]
2920 self.assertEqual(expected, lines)
2921
2922 def testListCmdFail(self):
2923 """Test failing to list an image"""
2924 self._DoReadFile('005_simple.dts')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002925 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002926 try:
2927 tmpdir, updated_fname = self._SetupImageInTmpdir()
2928 with self.assertRaises(ValueError) as e:
2929 self._DoBinman('ls', '-i', updated_fname)
2930 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002931 if tmpdir:
2932 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002933 self.assertIn("Cannot find FDT map in image", str(e.exception))
2934
2935 def _RunListCmd(self, paths, expected):
2936 """List out entries and check the result
2937
2938 Args:
2939 paths: List of paths to pass to the list command
2940 expected: Expected list of filenames to be returned, in order
2941 """
2942 self._CheckLz4()
2943 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002944 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002945 image = Image.FromFile(image_fname)
2946 lines = image.GetListEntries(paths)[1]
2947 files = [line[0].strip() for line in lines[1:]]
2948 self.assertEqual(expected, files)
2949
2950 def testListCmdSection(self):
2951 """Test listing the files in a section"""
2952 self._RunListCmd(['section'],
2953 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2954
2955 def testListCmdFile(self):
2956 """Test listing a particular file"""
2957 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2958
2959 def testListCmdWildcard(self):
2960 """Test listing a wildcarded file"""
2961 self._RunListCmd(['*boot*'],
2962 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2963
2964 def testListCmdWildcardMulti(self):
2965 """Test listing a wildcarded file"""
2966 self._RunListCmd(['*cb*', '*head*'],
2967 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2968
2969 def testListCmdEmpty(self):
2970 """Test listing a wildcarded file"""
2971 self._RunListCmd(['nothing'], [])
2972
2973 def testListCmdPath(self):
2974 """Test listing the files in a sub-entry of a section"""
2975 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2976
Simon Glass4c613bf2019-07-08 14:25:50 -06002977 def _RunExtractCmd(self, entry_name, decomp=True):
2978 """Extract an entry from an image
2979
2980 Args:
2981 entry_name: Entry name to extract
2982 decomp: True to decompress the data if compressed, False to leave
2983 it in its raw uncompressed format
2984
2985 Returns:
2986 data from entry
2987 """
2988 self._CheckLz4()
2989 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002990 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002991 return control.ReadEntry(image_fname, entry_name, decomp)
2992
2993 def testExtractSimple(self):
2994 """Test extracting a single file"""
2995 data = self._RunExtractCmd('u-boot')
2996 self.assertEqual(U_BOOT_DATA, data)
2997
Simon Glass980a2842019-07-08 14:25:52 -06002998 def testExtractSection(self):
2999 """Test extracting the files in a section"""
3000 data = self._RunExtractCmd('section')
3001 cbfs_data = data[:0x400]
3002 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06003003 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06003004 dtb_data = data[0x400:]
3005 dtb = self._decompress(dtb_data)
3006 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3007
3008 def testExtractCompressed(self):
3009 """Test extracting compressed data"""
3010 data = self._RunExtractCmd('section/u-boot-dtb')
3011 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3012
3013 def testExtractRaw(self):
3014 """Test extracting compressed data without decompressing it"""
3015 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
3016 dtb = self._decompress(data)
3017 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3018
3019 def testExtractCbfs(self):
3020 """Test extracting CBFS data"""
3021 data = self._RunExtractCmd('section/cbfs/u-boot')
3022 self.assertEqual(U_BOOT_DATA, data)
3023
3024 def testExtractCbfsCompressed(self):
3025 """Test extracting CBFS compressed data"""
3026 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
3027 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3028
3029 def testExtractCbfsRaw(self):
3030 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003031 bintool = self.comp_bintools['lzma_alone']
3032 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06003033 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003034 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06003035 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3036
Simon Glass4c613bf2019-07-08 14:25:50 -06003037 def testExtractBadEntry(self):
3038 """Test extracting a bad section path"""
3039 with self.assertRaises(ValueError) as e:
3040 self._RunExtractCmd('section/does-not-exist')
3041 self.assertIn("Entry 'does-not-exist' not found in '/section'",
3042 str(e.exception))
3043
3044 def testExtractMissingFile(self):
3045 """Test extracting file that does not exist"""
3046 with self.assertRaises(IOError) as e:
3047 control.ReadEntry('missing-file', 'name')
3048
3049 def testExtractBadFile(self):
3050 """Test extracting an invalid file"""
3051 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07003052 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06003053 with self.assertRaises(ValueError) as e:
3054 control.ReadEntry(fname, 'name')
3055
Simon Glass980a2842019-07-08 14:25:52 -06003056 def testExtractCmd(self):
3057 """Test extracting a file fron an image on the command line"""
3058 self._CheckLz4()
3059 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06003060 fname = os.path.join(self._indir, 'output.extact')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003061 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06003062 try:
3063 tmpdir, updated_fname = self._SetupImageInTmpdir()
3064 with test_util.capture_sys_output() as (stdout, stderr):
3065 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3066 '-f', fname)
3067 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003068 if tmpdir:
3069 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07003070 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003071 self.assertEqual(U_BOOT_DATA, data)
3072
3073 def testExtractOneEntry(self):
3074 """Test extracting a single entry fron an image """
3075 self._CheckLz4()
3076 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003077 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003078 fname = os.path.join(self._indir, 'output.extact')
3079 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003080 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003081 self.assertEqual(U_BOOT_DATA, data)
3082
3083 def _CheckExtractOutput(self, decomp):
3084 """Helper to test file output with and without decompression
3085
3086 Args:
3087 decomp: True to decompress entry data, False to output it raw
3088 """
3089 def _CheckPresent(entry_path, expect_data, expect_size=None):
3090 """Check and remove expected file
3091
3092 This checks the data/size of a file and removes the file both from
3093 the outfiles set and from the output directory. Once all files are
3094 processed, both the set and directory should be empty.
3095
3096 Args:
3097 entry_path: Entry path
3098 expect_data: Data to expect in file, or None to skip check
3099 expect_size: Size of data to expect in file, or None to skip
3100 """
3101 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003102 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003103 os.remove(path)
3104 if expect_data:
3105 self.assertEqual(expect_data, data)
3106 elif expect_size:
3107 self.assertEqual(expect_size, len(data))
3108 outfiles.remove(path)
3109
3110 def _CheckDirPresent(name):
3111 """Remove expected directory
3112
3113 This gives an error if the directory does not exist as expected
3114
3115 Args:
3116 name: Name of directory to remove
3117 """
3118 path = os.path.join(outdir, name)
3119 os.rmdir(path)
3120
3121 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003122 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003123 outdir = os.path.join(self._indir, 'extract')
3124 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3125
3126 # Create a set of all file that were output (should be 9)
3127 outfiles = set()
3128 for root, dirs, files in os.walk(outdir):
3129 outfiles |= set([os.path.join(root, fname) for fname in files])
3130 self.assertEqual(9, len(outfiles))
3131 self.assertEqual(9, len(einfos))
3132
3133 image = control.images['image']
3134 entries = image.GetEntries()
3135
3136 # Check the 9 files in various ways
3137 section = entries['section']
3138 section_entries = section.GetEntries()
3139 cbfs_entries = section_entries['cbfs'].GetEntries()
3140 _CheckPresent('u-boot', U_BOOT_DATA)
3141 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3142 dtb_len = EXTRACT_DTB_SIZE
3143 if not decomp:
3144 dtb_len = cbfs_entries['u-boot-dtb'].size
3145 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3146 if not decomp:
3147 dtb_len = section_entries['u-boot-dtb'].size
3148 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3149
3150 fdtmap = entries['fdtmap']
3151 _CheckPresent('fdtmap', fdtmap.data)
3152 hdr = entries['image-header']
3153 _CheckPresent('image-header', hdr.data)
3154
3155 _CheckPresent('section/root', section.data)
3156 cbfs = section_entries['cbfs']
3157 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003158 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003159 _CheckPresent('root', data)
3160
3161 # There should be no files left. Remove all the directories to check.
3162 # If there are any files/dirs remaining, one of these checks will fail.
3163 self.assertEqual(0, len(outfiles))
3164 _CheckDirPresent('section/cbfs')
3165 _CheckDirPresent('section')
3166 _CheckDirPresent('')
3167 self.assertFalse(os.path.exists(outdir))
3168
3169 def testExtractAllEntries(self):
3170 """Test extracting all entries"""
3171 self._CheckLz4()
3172 self._CheckExtractOutput(decomp=True)
3173
3174 def testExtractAllEntriesRaw(self):
3175 """Test extracting all entries without decompressing them"""
3176 self._CheckLz4()
3177 self._CheckExtractOutput(decomp=False)
3178
3179 def testExtractSelectedEntries(self):
3180 """Test extracting some entries"""
3181 self._CheckLz4()
3182 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003183 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003184 outdir = os.path.join(self._indir, 'extract')
3185 einfos = control.ExtractEntries(image_fname, None, outdir,
3186 ['*cb*', '*head*'])
3187
3188 # File output is tested by testExtractAllEntries(), so just check that
3189 # the expected entries are selected
3190 names = [einfo.name for einfo in einfos]
3191 self.assertEqual(names,
3192 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3193
3194 def testExtractNoEntryPaths(self):
3195 """Test extracting some entries"""
3196 self._CheckLz4()
3197 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003198 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003199 with self.assertRaises(ValueError) as e:
3200 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003201 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003202 str(e.exception))
3203
3204 def testExtractTooManyEntryPaths(self):
3205 """Test extracting some entries"""
3206 self._CheckLz4()
3207 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003208 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003209 with self.assertRaises(ValueError) as e:
3210 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003211 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003212 str(e.exception))
3213
Simon Glass52d06212019-07-08 14:25:53 -06003214 def testPackAlignSection(self):
3215 """Test that sections can have alignment"""
3216 self._DoReadFile('131_pack_align_section.dts')
3217
3218 self.assertIn('image', control.images)
3219 image = control.images['image']
3220 entries = image.GetEntries()
3221 self.assertEqual(3, len(entries))
3222
3223 # First u-boot
3224 self.assertIn('u-boot', entries)
3225 entry = entries['u-boot']
3226 self.assertEqual(0, entry.offset)
3227 self.assertEqual(0, entry.image_pos)
3228 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3229 self.assertEqual(len(U_BOOT_DATA), entry.size)
3230
3231 # Section0
3232 self.assertIn('section0', entries)
3233 section0 = entries['section0']
3234 self.assertEqual(0x10, section0.offset)
3235 self.assertEqual(0x10, section0.image_pos)
3236 self.assertEqual(len(U_BOOT_DATA), section0.size)
3237
3238 # Second u-boot
3239 section_entries = section0.GetEntries()
3240 self.assertIn('u-boot', section_entries)
3241 entry = section_entries['u-boot']
3242 self.assertEqual(0, entry.offset)
3243 self.assertEqual(0x10, entry.image_pos)
3244 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3245 self.assertEqual(len(U_BOOT_DATA), entry.size)
3246
3247 # Section1
3248 self.assertIn('section1', entries)
3249 section1 = entries['section1']
3250 self.assertEqual(0x14, section1.offset)
3251 self.assertEqual(0x14, section1.image_pos)
3252 self.assertEqual(0x20, section1.size)
3253
3254 # Second u-boot
3255 section_entries = section1.GetEntries()
3256 self.assertIn('u-boot', section_entries)
3257 entry = section_entries['u-boot']
3258 self.assertEqual(0, entry.offset)
3259 self.assertEqual(0x14, entry.image_pos)
3260 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3261 self.assertEqual(len(U_BOOT_DATA), entry.size)
3262
3263 # Section2
3264 self.assertIn('section2', section_entries)
3265 section2 = section_entries['section2']
3266 self.assertEqual(0x4, section2.offset)
3267 self.assertEqual(0x18, section2.image_pos)
3268 self.assertEqual(4, section2.size)
3269
3270 # Third u-boot
3271 section_entries = section2.GetEntries()
3272 self.assertIn('u-boot', section_entries)
3273 entry = section_entries['u-boot']
3274 self.assertEqual(0, entry.offset)
3275 self.assertEqual(0x18, entry.image_pos)
3276 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3277 self.assertEqual(len(U_BOOT_DATA), entry.size)
3278
Simon Glassf8a54bc2019-07-20 12:23:56 -06003279 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3280 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003281 """Replace an entry in an image
3282
3283 This writes the entry data to update it, then opens the updated file and
3284 returns the value that it now finds there.
3285
3286 Args:
3287 entry_name: Entry name to replace
3288 data: Data to replace it with
3289 decomp: True to compress the data if needed, False if data is
3290 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003291 allow_resize: True to allow entries to change size, False to raise
3292 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003293
3294 Returns:
3295 Tuple:
3296 data from entry
3297 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003298 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003299 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003300 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003301 update_dtb=True)[1]
3302
3303 self.assertIn('image', control.images)
3304 image = control.images['image']
3305 entries = image.GetEntries()
3306 orig_dtb_data = entries['u-boot-dtb'].data
3307 orig_fdtmap_data = entries['fdtmap'].data
3308
Simon Glass80025522022-01-29 14:14:04 -07003309 image_fname = tools.get_output_filename('image.bin')
3310 updated_fname = tools.get_output_filename('image-updated.bin')
3311 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003312 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3313 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003314 data = control.ReadEntry(updated_fname, entry_name, decomp)
3315
Simon Glassf8a54bc2019-07-20 12:23:56 -06003316 # The DT data should not change unless resized:
3317 if not allow_resize:
3318 new_dtb_data = entries['u-boot-dtb'].data
3319 self.assertEqual(new_dtb_data, orig_dtb_data)
3320 new_fdtmap_data = entries['fdtmap'].data
3321 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003322
Simon Glassf8a54bc2019-07-20 12:23:56 -06003323 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003324
3325 def testReplaceSimple(self):
3326 """Test replacing a single file"""
3327 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003328 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3329 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003330 self.assertEqual(expected, data)
3331
3332 # Test that the state looks right. There should be an FDT for the fdtmap
3333 # that we jsut read back in, and it should match what we find in the
3334 # 'control' tables. Checking for an FDT that does not exist should
3335 # return None.
3336 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003337 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003338 self.assertEqual(expected_fdtmap, fdtmap)
3339
3340 dtb = state.GetFdtForEtype('fdtmap')
3341 self.assertEqual(dtb.GetContents(), fdtmap)
3342
3343 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3344 self.assertIsNone(missing_path)
3345 self.assertIsNone(missing_fdtmap)
3346
3347 missing_dtb = state.GetFdtForEtype('missing')
3348 self.assertIsNone(missing_dtb)
3349
3350 self.assertEqual('/binman', state.fdt_path_prefix)
3351
3352 def testReplaceResizeFail(self):
3353 """Test replacing a file by something larger"""
3354 expected = U_BOOT_DATA + b'x'
3355 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003356 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3357 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003358 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3359 str(e.exception))
3360
3361 def testReplaceMulti(self):
3362 """Test replacing entry data where multiple images are generated"""
3363 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3364 update_dtb=True)[0]
3365 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003366 updated_fname = tools.get_output_filename('image-updated.bin')
3367 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003368 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003369 control.WriteEntry(updated_fname, entry_name, expected,
3370 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003371 data = control.ReadEntry(updated_fname, entry_name)
3372 self.assertEqual(expected, data)
3373
3374 # Check the state looks right.
3375 self.assertEqual('/binman/image', state.fdt_path_prefix)
3376
3377 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003378 image_fname = tools.get_output_filename('first-image.bin')
3379 updated_fname = tools.get_output_filename('first-updated.bin')
3380 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003381 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003382 control.WriteEntry(updated_fname, entry_name, expected,
3383 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003384 data = control.ReadEntry(updated_fname, entry_name)
3385 self.assertEqual(expected, data)
3386
3387 # Check the state looks right.
3388 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003389
Simon Glassfb30e292019-07-20 12:23:51 -06003390 def testUpdateFdtAllRepack(self):
3391 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003392 self._SetupSplElf()
3393 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003394 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3395 SECTION_SIZE = 0x300
3396 DTB_SIZE = 602
3397 FDTMAP_SIZE = 608
3398 base_expected = {
3399 'offset': 0,
3400 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3401 'image-pos': 0,
3402 'section:offset': 0,
3403 'section:size': SECTION_SIZE,
3404 'section:image-pos': 0,
3405 'section/u-boot-dtb:offset': 4,
3406 'section/u-boot-dtb:size': 636,
3407 'section/u-boot-dtb:image-pos': 4,
3408 'u-boot-spl-dtb:offset': SECTION_SIZE,
3409 'u-boot-spl-dtb:size': DTB_SIZE,
3410 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3411 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3412 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3413 'u-boot-tpl-dtb:size': DTB_SIZE,
3414 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3415 'fdtmap:size': FDTMAP_SIZE,
3416 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3417 }
3418 main_expected = {
3419 'section:orig-size': SECTION_SIZE,
3420 'section/u-boot-dtb:orig-offset': 4,
3421 }
3422
3423 # We expect three device-tree files in the output, with the first one
3424 # within a fixed-size section.
3425 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3426 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3427 # main U-Boot tree. All three should have the same positions and offset
3428 # except that the main tree should include the main_expected properties
3429 start = 4
3430 for item in ['', 'spl', 'tpl', None]:
3431 if item is None:
3432 start += 16 # Move past fdtmap header
3433 dtb = fdt.Fdt.FromData(data[start:])
3434 dtb.Scan()
3435 props = self._GetPropTree(dtb,
3436 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3437 prefix='/' if item is None else '/binman/')
3438 expected = dict(base_expected)
3439 if item:
3440 expected[item] = 0
3441 else:
3442 # Main DTB and fdtdec should include the 'orig-' properties
3443 expected.update(main_expected)
3444 # Helpful for debugging:
3445 #for prop in sorted(props):
3446 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3447 self.assertEqual(expected, props)
3448 if item == '':
3449 start = SECTION_SIZE
3450 else:
3451 start += dtb._fdt_obj.totalsize()
3452
Simon Glass11453762019-07-20 12:23:55 -06003453 def testFdtmapHeaderMiddle(self):
3454 """Test an FDT map in the middle of an image when it should be at end"""
3455 with self.assertRaises(ValueError) as e:
3456 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3457 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3458 str(e.exception))
3459
3460 def testFdtmapHeaderStartBad(self):
3461 """Test an FDT map in middle of an image when it should be at start"""
3462 with self.assertRaises(ValueError) as e:
3463 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3464 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3465 str(e.exception))
3466
3467 def testFdtmapHeaderEndBad(self):
3468 """Test an FDT map at the start of an image when it should be at end"""
3469 with self.assertRaises(ValueError) as e:
3470 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3471 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3472 str(e.exception))
3473
3474 def testFdtmapHeaderNoSize(self):
3475 """Test an image header at the end of an image with undefined size"""
3476 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3477
Simon Glassf8a54bc2019-07-20 12:23:56 -06003478 def testReplaceResize(self):
3479 """Test replacing a single file in an entry with a larger file"""
3480 expected = U_BOOT_DATA + b'x'
3481 data, _, image = self._RunReplaceCmd('u-boot', expected,
3482 dts='139_replace_repack.dts')
3483 self.assertEqual(expected, data)
3484
3485 entries = image.GetEntries()
3486 dtb_data = entries['u-boot-dtb'].data
3487 dtb = fdt.Fdt.FromData(dtb_data)
3488 dtb.Scan()
3489
3490 # The u-boot section should now be larger in the dtb
3491 node = dtb.GetNode('/binman/u-boot')
3492 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3493
3494 # Same for the fdtmap
3495 fdata = entries['fdtmap'].data
3496 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3497 fdtb.Scan()
3498 fnode = fdtb.GetNode('/u-boot')
3499 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3500
3501 def testReplaceResizeNoRepack(self):
3502 """Test replacing an entry with a larger file when not allowed"""
3503 expected = U_BOOT_DATA + b'x'
3504 with self.assertRaises(ValueError) as e:
3505 self._RunReplaceCmd('u-boot', expected)
3506 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3507 str(e.exception))
3508
Simon Glass9d8ee322019-07-20 12:23:58 -06003509 def testEntryShrink(self):
3510 """Test contracting an entry after it is packed"""
3511 try:
3512 state.SetAllowEntryContraction(True)
3513 data = self._DoReadFileDtb('140_entry_shrink.dts',
3514 update_dtb=True)[0]
3515 finally:
3516 state.SetAllowEntryContraction(False)
3517 self.assertEqual(b'a', data[:1])
3518 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3519 self.assertEqual(b'a', data[-1:])
3520
3521 def testEntryShrinkFail(self):
3522 """Test not being allowed to contract an entry after it is packed"""
3523 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3524
3525 # In this case there is a spare byte at the end of the data. The size of
3526 # the contents is only 1 byte but we still have the size before it
3527 # shrunk.
3528 self.assertEqual(b'a\0', data[:2])
3529 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3530 self.assertEqual(b'a\0', data[-2:])
3531
Simon Glass70e32982019-07-20 12:24:01 -06003532 def testDescriptorOffset(self):
3533 """Test that the Intel descriptor is always placed at at the start"""
3534 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3535 image = control.images['image']
3536 entries = image.GetEntries()
3537 desc = entries['intel-descriptor']
3538 self.assertEqual(0xff800000, desc.offset);
3539 self.assertEqual(0xff800000, desc.image_pos);
3540
Simon Glass37fdd142019-07-20 12:24:06 -06003541 def testReplaceCbfs(self):
3542 """Test replacing a single file in CBFS without changing the size"""
3543 self._CheckLz4()
3544 expected = b'x' * len(U_BOOT_DATA)
3545 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003546 updated_fname = tools.get_output_filename('image-updated.bin')
3547 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003548 entry_name = 'section/cbfs/u-boot'
3549 control.WriteEntry(updated_fname, entry_name, expected,
3550 allow_resize=True)
3551 data = control.ReadEntry(updated_fname, entry_name)
3552 self.assertEqual(expected, data)
3553
3554 def testReplaceResizeCbfs(self):
3555 """Test replacing a single file in CBFS with one of a different size"""
3556 self._CheckLz4()
3557 expected = U_BOOT_DATA + b'x'
3558 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003559 updated_fname = tools.get_output_filename('image-updated.bin')
3560 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003561 entry_name = 'section/cbfs/u-boot'
3562 control.WriteEntry(updated_fname, entry_name, expected,
3563 allow_resize=True)
3564 data = control.ReadEntry(updated_fname, entry_name)
3565 self.assertEqual(expected, data)
3566
Simon Glass30033c22019-07-20 12:24:15 -06003567 def _SetupForReplace(self):
3568 """Set up some files to use to replace entries
3569
3570 This generates an image, copies it to a new file, extracts all the files
3571 in it and updates some of them
3572
3573 Returns:
3574 List
3575 Image filename
3576 Output directory
3577 Expected values for updated entries, each a string
3578 """
3579 data = self._DoReadFileRealDtb('143_replace_all.dts')
3580
Simon Glass80025522022-01-29 14:14:04 -07003581 updated_fname = tools.get_output_filename('image-updated.bin')
3582 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003583
3584 outdir = os.path.join(self._indir, 'extract')
3585 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3586
3587 expected1 = b'x' + U_BOOT_DATA + b'y'
3588 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003589 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003590
3591 expected2 = b'a' + U_BOOT_DATA + b'b'
3592 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003593 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003594
3595 expected_text = b'not the same text'
3596 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003597 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003598
3599 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3600 dtb = fdt.FdtScan(dtb_fname)
3601 node = dtb.GetNode('/binman/text')
3602 node.AddString('my-property', 'the value')
3603 dtb.Sync(auto_resize=True)
3604 dtb.Flush()
3605
3606 return updated_fname, outdir, expected1, expected2, expected_text
3607
3608 def _CheckReplaceMultiple(self, entry_paths):
3609 """Handle replacing the contents of multiple entries
3610
3611 Args:
3612 entry_paths: List of entry paths to replace
3613
3614 Returns:
3615 List
3616 Dict of entries in the image:
3617 key: Entry name
3618 Value: Entry object
3619 Expected values for updated entries, each a string
3620 """
3621 updated_fname, outdir, expected1, expected2, expected_text = (
3622 self._SetupForReplace())
3623 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3624
3625 image = Image.FromFile(updated_fname)
3626 image.LoadData()
3627 return image.GetEntries(), expected1, expected2, expected_text
3628
3629 def testReplaceAll(self):
3630 """Test replacing the contents of all entries"""
3631 entries, expected1, expected2, expected_text = (
3632 self._CheckReplaceMultiple([]))
3633 data = entries['u-boot'].data
3634 self.assertEqual(expected1, data)
3635
3636 data = entries['u-boot2'].data
3637 self.assertEqual(expected2, data)
3638
3639 data = entries['text'].data
3640 self.assertEqual(expected_text, data)
3641
3642 # Check that the device tree is updated
3643 data = entries['u-boot-dtb'].data
3644 dtb = fdt.Fdt.FromData(data)
3645 dtb.Scan()
3646 node = dtb.GetNode('/binman/text')
3647 self.assertEqual('the value', node.props['my-property'].value)
3648
3649 def testReplaceSome(self):
3650 """Test replacing the contents of a few entries"""
3651 entries, expected1, expected2, expected_text = (
3652 self._CheckReplaceMultiple(['u-boot2', 'text']))
3653
3654 # This one should not change
3655 data = entries['u-boot'].data
3656 self.assertEqual(U_BOOT_DATA, data)
3657
3658 data = entries['u-boot2'].data
3659 self.assertEqual(expected2, data)
3660
3661 data = entries['text'].data
3662 self.assertEqual(expected_text, data)
3663
3664 def testReplaceCmd(self):
3665 """Test replacing a file fron an image on the command line"""
3666 self._DoReadFileRealDtb('143_replace_all.dts')
3667
3668 try:
3669 tmpdir, updated_fname = self._SetupImageInTmpdir()
3670
3671 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3672 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003673 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003674
3675 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003676 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003677 self.assertEqual(expected, data[:len(expected)])
3678 map_fname = os.path.join(tmpdir, 'image-updated.map')
3679 self.assertFalse(os.path.exists(map_fname))
3680 finally:
3681 shutil.rmtree(tmpdir)
3682
3683 def testReplaceCmdSome(self):
3684 """Test replacing some files fron an image on the command line"""
3685 updated_fname, outdir, expected1, expected2, expected_text = (
3686 self._SetupForReplace())
3687
3688 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3689 'u-boot2', 'text')
3690
Simon Glass80025522022-01-29 14:14:04 -07003691 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003692 image = Image.FromFile(updated_fname)
3693 image.LoadData()
3694 entries = image.GetEntries()
3695
3696 # This one should not change
3697 data = entries['u-boot'].data
3698 self.assertEqual(U_BOOT_DATA, data)
3699
3700 data = entries['u-boot2'].data
3701 self.assertEqual(expected2, data)
3702
3703 data = entries['text'].data
3704 self.assertEqual(expected_text, data)
3705
3706 def testReplaceMissing(self):
3707 """Test replacing entries where the file is missing"""
3708 updated_fname, outdir, expected1, expected2, expected_text = (
3709 self._SetupForReplace())
3710
3711 # Remove one of the files, to generate a warning
3712 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3713 os.remove(u_boot_fname1)
3714
3715 with test_util.capture_sys_output() as (stdout, stderr):
3716 control.ReplaceEntries(updated_fname, None, outdir, [])
3717 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003718 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003719
3720 def testReplaceCmdMap(self):
3721 """Test replacing a file fron an image on the command line"""
3722 self._DoReadFileRealDtb('143_replace_all.dts')
3723
3724 try:
3725 tmpdir, updated_fname = self._SetupImageInTmpdir()
3726
3727 fname = os.path.join(self._indir, 'update-u-boot.bin')
3728 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003729 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003730
3731 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3732 '-f', fname, '-m')
3733 map_fname = os.path.join(tmpdir, 'image-updated.map')
3734 self.assertTrue(os.path.exists(map_fname))
3735 finally:
3736 shutil.rmtree(tmpdir)
3737
3738 def testReplaceNoEntryPaths(self):
3739 """Test replacing an entry without an entry path"""
3740 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003741 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003742 with self.assertRaises(ValueError) as e:
3743 control.ReplaceEntries(image_fname, 'fname', None, [])
3744 self.assertIn('Must specify an entry path to read with -f',
3745 str(e.exception))
3746
3747 def testReplaceTooManyEntryPaths(self):
3748 """Test extracting some entries"""
3749 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003750 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003751 with self.assertRaises(ValueError) as e:
3752 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3753 self.assertIn('Must specify exactly one entry path to write with -f',
3754 str(e.exception))
3755
Simon Glass0b074d62019-08-24 07:22:48 -06003756 def testPackReset16(self):
3757 """Test that an image with an x86 reset16 region can be created"""
3758 data = self._DoReadFile('144_x86_reset16.dts')
3759 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3760
3761 def testPackReset16Spl(self):
3762 """Test that an image with an x86 reset16-spl region can be created"""
3763 data = self._DoReadFile('145_x86_reset16_spl.dts')
3764 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3765
3766 def testPackReset16Tpl(self):
3767 """Test that an image with an x86 reset16-tpl region can be created"""
3768 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3769 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3770
Simon Glass232f90c2019-08-24 07:22:50 -06003771 def testPackIntelFit(self):
3772 """Test that an image with an Intel FIT and pointer can be created"""
3773 data = self._DoReadFile('147_intel_fit.dts')
3774 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3775 fit = data[16:32];
3776 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3777 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3778
3779 image = control.images['image']
3780 entries = image.GetEntries()
3781 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3782 self.assertEqual(expected_ptr, ptr)
3783
3784 def testPackIntelFitMissing(self):
3785 """Test detection of a FIT pointer with not FIT region"""
3786 with self.assertRaises(ValueError) as e:
3787 self._DoReadFile('148_intel_fit_missing.dts')
3788 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3789 str(e.exception))
3790
Simon Glass72555fa2019-11-06 17:22:44 -07003791 def _CheckSymbolsTplSection(self, dts, expected_vals):
3792 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003793 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003794 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003795 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003796 self.assertEqual(expected1, data[:upto1])
3797
3798 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003799 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003800 self.assertEqual(expected2, data[upto1:upto2])
3801
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003802 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003803 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003804 self.assertEqual(expected3, data[upto2:upto3])
3805
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003806 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003807 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3808
3809 def testSymbolsTplSection(self):
3810 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3811 self._SetupSplElf('u_boot_binman_syms')
3812 self._SetupTplElf('u_boot_binman_syms')
3813 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003814 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003815
3816 def testSymbolsTplSectionX86(self):
3817 """Test binman can assign symbols in a section with end-at-4gb"""
3818 self._SetupSplElf('u_boot_binman_syms_x86')
3819 self._SetupTplElf('u_boot_binman_syms_x86')
3820 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003821 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003822 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003823
Simon Glass98c59572019-08-24 07:23:03 -06003824 def testPackX86RomIfwiSectiom(self):
3825 """Test that a section can be placed in an IFWI region"""
3826 self._SetupIfwi('fitimage.bin')
3827 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3828 self._CheckIfwi(data)
3829
Simon Glassba7985d2019-08-24 07:23:07 -06003830 def testPackFspM(self):
3831 """Test that an image with a FSP memory-init binary can be created"""
3832 data = self._DoReadFile('152_intel_fsp_m.dts')
3833 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3834
Simon Glass4d9086d2019-10-20 21:31:35 -06003835 def testPackFspS(self):
3836 """Test that an image with a FSP silicon-init binary can be created"""
3837 data = self._DoReadFile('153_intel_fsp_s.dts')
3838 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003839
Simon Glass9ea87b22019-10-20 21:31:36 -06003840 def testPackFspT(self):
3841 """Test that an image with a FSP temp-ram-init binary can be created"""
3842 data = self._DoReadFile('154_intel_fsp_t.dts')
3843 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3844
Simon Glass48f3aad2020-07-09 18:39:31 -06003845 def testMkimage(self):
3846 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003847 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003848 data = self._DoReadFile('156_mkimage.dts')
3849
3850 # Just check that the data appears in the file somewhere
3851 self.assertIn(U_BOOT_SPL_DATA, data)
3852
Simon Glass66152ce2022-01-09 20:14:09 -07003853 def testMkimageMissing(self):
3854 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003855 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003856 with test_util.capture_sys_output() as (_, stderr):
3857 self._DoTestFile('156_mkimage.dts',
3858 force_missing_bintools='mkimage')
3859 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003860 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003861
Simon Glass5e560182020-07-09 18:39:36 -06003862 def testExtblob(self):
3863 """Test an image with an external blob"""
3864 data = self._DoReadFile('157_blob_ext.dts')
3865 self.assertEqual(REFCODE_DATA, data)
3866
3867 def testExtblobMissing(self):
3868 """Test an image with a missing external blob"""
3869 with self.assertRaises(ValueError) as e:
3870 self._DoReadFile('158_blob_ext_missing.dts')
3871 self.assertIn("Filename 'missing-file' not found in input path",
3872 str(e.exception))
3873
Simon Glass5d94cc62020-07-09 18:39:38 -06003874 def testExtblobMissingOk(self):
3875 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003876 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003877 ret = self._DoTestFile('158_blob_ext_missing.dts',
3878 allow_missing=True)
3879 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003880 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003881 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003882 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003883 self.assertIn('Some images are invalid', err)
3884
3885 def testExtblobMissingOkFlag(self):
3886 """Test an image with an missing external blob allowed with -W"""
3887 with test_util.capture_sys_output() as (stdout, stderr):
3888 ret = self._DoTestFile('158_blob_ext_missing.dts',
3889 allow_missing=True, ignore_missing=True)
3890 self.assertEqual(0, ret)
3891 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003892 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003893 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003894 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003895
3896 def testExtblobMissingOkSect(self):
3897 """Test an image with an missing external blob that is allowed"""
3898 with test_util.capture_sys_output() as (stdout, stderr):
3899 self._DoTestFile('159_blob_ext_missing_sect.dts',
3900 allow_missing=True)
3901 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003902 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003903
Simon Glasse88cef92020-07-09 18:39:41 -06003904 def testPackX86RomMeMissingDesc(self):
3905 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003906 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003907 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003908 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003909 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003910
3911 def testPackX86RomMissingIfwi(self):
3912 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3913 self._SetupIfwi('fitimage.bin')
3914 pathname = os.path.join(self._indir, 'fitimage.bin')
3915 os.remove(pathname)
3916 with test_util.capture_sys_output() as (stdout, stderr):
3917 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3918 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003919 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003920
Simon Glass2a0fa982022-02-11 13:23:21 -07003921 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003922 """Test that zero-size overlapping regions are ignored"""
3923 self._DoTestFile('160_pack_overlap_zero.dts')
3924
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003925 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003926 # The data should be inside the FIT
3927 dtb = fdt.Fdt.FromData(fit_data)
3928 dtb.Scan()
3929 fnode = dtb.GetNode('/images/kernel')
3930 self.assertIn('data', fnode.props)
3931
3932 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003933 tools.write_file(fname, fit_data)
3934 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003935
3936 # Check a few features to make sure the plumbing works. We don't need
3937 # to test the operation of mkimage or dumpimage here. First convert the
3938 # output into a dict where the keys are the fields printed by dumpimage
3939 # and the values are a list of values for each field
3940 lines = out.splitlines()
3941
3942 # Converts "Compression: gzip compressed" into two groups:
3943 # 'Compression' and 'gzip compressed'
3944 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3945 vals = collections.defaultdict(list)
3946 for line in lines:
3947 mat = re_line.match(line)
3948 vals[mat.group(1)].append(mat.group(2))
3949
Brandon Maiera657bc62024-06-04 16:16:05 +00003950 self.assertEqual('FIT description: test-desc', lines[0])
Simon Glass45d556d2020-07-09 18:39:45 -06003951 self.assertIn('Created:', lines[1])
3952 self.assertIn('Image 0 (kernel)', vals)
3953 self.assertIn('Hash value', vals)
3954 data_sizes = vals.get('Data Size')
3955 self.assertIsNotNone(data_sizes)
3956 self.assertEqual(2, len(data_sizes))
3957 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003958 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3959 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3960
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003961 # Check if entry listing correctly omits /images/
3962 image = control.images['image']
3963 fit_entry = image.GetEntries()['fit']
3964 subentries = list(fit_entry.GetEntries().keys())
3965 expected = ['kernel', 'fdt-1']
3966 self.assertEqual(expected, subentries)
3967
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003968 def testSimpleFit(self):
3969 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003970 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003971 data = self._DoReadFile('161_fit.dts')
3972 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3973 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3974 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3975
3976 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3977
3978 def testSimpleFitExpandsSubentries(self):
3979 """Test that FIT images expand their subentries"""
3980 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3981 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3982 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3983 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3984
3985 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003986
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003987 def testSimpleFitImagePos(self):
3988 """Test that we have correct image-pos for FIT subentries"""
3989 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3990 update_dtb=True)
3991 dtb = fdt.Fdt(out_dtb_fname)
3992 dtb.Scan()
3993 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3994
Simon Glassb7bad182022-03-05 20:19:01 -07003995 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003996 self.assertEqual({
3997 'image-pos': 0,
3998 'offset': 0,
3999 'size': 1890,
4000
4001 'u-boot:image-pos': 0,
4002 'u-boot:offset': 0,
4003 'u-boot:size': 4,
4004
4005 'fit:image-pos': 4,
4006 'fit:offset': 4,
4007 'fit:size': 1840,
4008
Simon Glassb7bad182022-03-05 20:19:01 -07004009 'fit/images/kernel:image-pos': 304,
4010 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004011 'fit/images/kernel:size': 4,
4012
Simon Glassb7bad182022-03-05 20:19:01 -07004013 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004014 'fit/images/kernel/u-boot:offset': 0,
4015 'fit/images/kernel/u-boot:size': 4,
4016
Simon Glassb7bad182022-03-05 20:19:01 -07004017 'fit/images/fdt-1:image-pos': 552,
4018 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004019 'fit/images/fdt-1:size': 6,
4020
Simon Glassb7bad182022-03-05 20:19:01 -07004021 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004022 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
4023 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
4024
4025 'u-boot-nodtb:image-pos': 1844,
4026 'u-boot-nodtb:offset': 1844,
4027 'u-boot-nodtb:size': 46,
4028 }, props)
4029
4030 # Actually check the data is where we think it is
4031 for node, expected in [
4032 ("u-boot", U_BOOT_DATA),
4033 ("fit/images/kernel", U_BOOT_DATA),
4034 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4035 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
4036 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
4037 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4038 ]:
4039 image_pos = props[f"{node}:image-pos"]
4040 size = props[f"{node}:size"]
4041 self.assertEqual(len(expected), size)
4042 self.assertEqual(expected, data[image_pos:image_pos+size])
4043
Simon Glass45d556d2020-07-09 18:39:45 -06004044 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06004045 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06004046 data = self._DoReadFile('162_fit_external.dts')
4047 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
4048
Simon Glass7932c882022-01-09 20:13:39 -07004049 # Size of the external-data region as set up by mkimage
4050 external_data_size = len(U_BOOT_DATA) + 2
4051 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07004052 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07004053 len(U_BOOT_NODTB_DATA))
4054
Simon Glass45d556d2020-07-09 18:39:45 -06004055 # The data should be outside the FIT
4056 dtb = fdt.Fdt.FromData(fit_data)
4057 dtb.Scan()
4058 fnode = dtb.GetNode('/images/kernel')
4059 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07004060 self.assertEqual(len(U_BOOT_DATA),
4061 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4062 fit_pos = 0x400;
4063 self.assertEqual(
4064 fit_pos,
4065 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4066
Brandon Maiera657bc62024-06-04 16:16:05 +00004067 self.assertEqual(expected_size, len(data))
Simon Glass7932c882022-01-09 20:13:39 -07004068 actual_pos = len(U_BOOT_DATA) + fit_pos
4069 self.assertEqual(U_BOOT_DATA + b'aa',
4070 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004071
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004072 def testFitExternalImagePos(self):
4073 """Test that we have correct image-pos for external FIT subentries"""
4074 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4075 update_dtb=True)
4076 dtb = fdt.Fdt(out_dtb_fname)
4077 dtb.Scan()
4078 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4079
4080 self.assertEqual({
4081 'image-pos': 0,
4082 'offset': 0,
4083 'size': 1082,
4084
4085 'u-boot:image-pos': 0,
4086 'u-boot:offset': 0,
4087 'u-boot:size': 4,
4088
4089 'fit:size': 1032,
4090 'fit:offset': 4,
4091 'fit:image-pos': 4,
4092
4093 'fit/images/kernel:size': 4,
4094 'fit/images/kernel:offset': 1024,
4095 'fit/images/kernel:image-pos': 1028,
4096
4097 'fit/images/kernel/u-boot:size': 4,
4098 'fit/images/kernel/u-boot:offset': 0,
4099 'fit/images/kernel/u-boot:image-pos': 1028,
4100
4101 'fit/images/fdt-1:size': 2,
4102 'fit/images/fdt-1:offset': 1028,
4103 'fit/images/fdt-1:image-pos': 1032,
4104
4105 'fit/images/fdt-1/_testing:size': 2,
4106 'fit/images/fdt-1/_testing:offset': 0,
4107 'fit/images/fdt-1/_testing:image-pos': 1032,
4108
4109 'u-boot-nodtb:image-pos': 1036,
4110 'u-boot-nodtb:offset': 1036,
4111 'u-boot-nodtb:size': 46,
4112 }, props)
4113
4114 # Actually check the data is where we think it is
4115 for node, expected in [
4116 ("u-boot", U_BOOT_DATA),
4117 ("fit/images/kernel", U_BOOT_DATA),
4118 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4119 ("fit/images/fdt-1", b'aa'),
4120 ("fit/images/fdt-1/_testing", b'aa'),
4121 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4122 ]:
4123 image_pos = props[f"{node}:image-pos"]
4124 size = props[f"{node}:size"]
4125 self.assertEqual(len(expected), size)
4126 self.assertEqual(expected, data[image_pos:image_pos+size])
4127
Simon Glass66152ce2022-01-09 20:14:09 -07004128 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004129 """Test that binman complains if mkimage is missing"""
4130 with self.assertRaises(ValueError) as e:
4131 self._DoTestFile('162_fit_external.dts',
4132 force_missing_bintools='mkimage')
4133 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4134 str(e.exception))
4135
4136 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004137 """Test that binman still produces a FIT image if mkimage is missing"""
4138 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004139 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004140 force_missing_bintools='mkimage')
4141 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004142 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004143
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004144 def testSectionIgnoreHashSignature(self):
4145 """Test that sections ignore hash, signature nodes for its data"""
4146 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4147 expected = (U_BOOT_DATA + U_BOOT_DATA)
4148 self.assertEqual(expected, data)
4149
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004150 def testPadInSections(self):
4151 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004152 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4153 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004154 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4155 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004156 U_BOOT_DATA)
4157 self.assertEqual(expected, data)
4158
Simon Glassd12599d2020-10-26 17:40:09 -06004159 dtb = fdt.Fdt(out_dtb_fname)
4160 dtb.Scan()
4161 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4162 expected = {
4163 'image-pos': 0,
4164 'offset': 0,
4165 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4166
4167 'section:image-pos': 0,
4168 'section:offset': 0,
4169 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4170
4171 'section/before:image-pos': 0,
4172 'section/before:offset': 0,
4173 'section/before:size': len(U_BOOT_DATA),
4174
4175 'section/u-boot:image-pos': 4,
4176 'section/u-boot:offset': 4,
4177 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4178
4179 'section/after:image-pos': 26,
4180 'section/after:offset': 26,
4181 'section/after:size': len(U_BOOT_DATA),
4182 }
4183 self.assertEqual(expected, props)
4184
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004185 def testFitImageSubentryAlignment(self):
4186 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004187 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004188 entry_args = {
4189 'test-id': TEXT_DATA,
4190 }
4191 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4192 entry_args=entry_args)
4193 dtb = fdt.Fdt.FromData(data)
4194 dtb.Scan()
4195
4196 node = dtb.GetNode('/images/kernel')
4197 data = dtb.GetProps(node)["data"].bytes
4198 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004199 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4200 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004201 self.assertEqual(expected, data)
4202
4203 node = dtb.GetNode('/images/fdt-1')
4204 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004205 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4206 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004207 U_BOOT_DTB_DATA)
4208 self.assertEqual(expected, data)
4209
4210 def testFitExtblobMissingOk(self):
4211 """Test a FIT with a missing external blob that is allowed"""
4212 with test_util.capture_sys_output() as (stdout, stderr):
4213 self._DoTestFile('168_fit_missing_blob.dts',
4214 allow_missing=True)
4215 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004216 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004217
Simon Glass21db0ff2020-09-01 05:13:54 -06004218 def testBlobNamedByArgMissing(self):
4219 """Test handling of a missing entry arg"""
4220 with self.assertRaises(ValueError) as e:
4221 self._DoReadFile('068_blob_named_by_arg.dts')
4222 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4223 str(e.exception))
4224
Simon Glass559c4de2020-09-01 05:13:58 -06004225 def testPackBl31(self):
4226 """Test that an image with an ATF BL31 binary can be created"""
4227 data = self._DoReadFile('169_atf_bl31.dts')
4228 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4229
Samuel Holland9d8cc632020-10-21 21:12:15 -05004230 def testPackScp(self):
4231 """Test that an image with an SCP binary can be created"""
4232 data = self._DoReadFile('172_scp.dts')
4233 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4234
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004235 def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True,
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004236 default_dt=None, use_seq_num=True):
Simon Glasscd2783e2024-07-20 11:49:46 +01004237 """Check an image with an FIT with multiple FDT images"""
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004238 def _CheckFdt(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004239 """Check the FDT nodes
4240
4241 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004242 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004243 expected_data: Expected contents of 'data' property
4244 """
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004245 name = 'fdt-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004246 fnode = dtb.GetNode('/images/%s' % name)
4247 self.assertIsNotNone(fnode)
4248 self.assertEqual({'description','type', 'compression', 'data'},
4249 set(fnode.props.keys()))
4250 self.assertEqual(expected_data, fnode.props['data'].bytes)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004251 description = (
4252 'fdt-test-fdt%s.dtb' % val if len(val) == 1 else
4253 'fdt-%s.dtb' % val
4254 )
4255 self.assertEqual(description, fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004256 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004257
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004258 def _CheckConfig(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004259 """Check the configuration nodes
4260
4261 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004262 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004263 expected_data: Expected contents of 'data' property
4264 """
4265 cnode = dtb.GetNode('/configurations')
4266 self.assertIn('default', cnode.props)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004267 default = (
4268 'config-2' if len(val) == 1 else
4269 'config-test-fdt2'
4270 )
4271 self.assertEqual(default, cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004272
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004273 name = 'config-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004274 fnode = dtb.GetNode('/configurations/%s' % name)
4275 self.assertIsNotNone(fnode)
4276 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4277 set(fnode.props.keys()))
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004278 description = (
4279 'conf-test-fdt%s.dtb' % val if len(val) == 1 else
4280 'conf-%s.dtb' % val
4281 )
4282 self.assertEqual(description, fnode.props['description'].value)
4283 self.assertEqual('fdt-%s' % val, fnode.props['fdt'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004284
4285 entry_args = {
Simon Glass1032acc2020-09-06 10:39:08 -06004286 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004287 }
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004288 extra_indirs = None
Simon Glasscd2783e2024-07-20 11:49:46 +01004289 if use_fdt_list:
4290 entry_args['of-list'] = 'test-fdt1 test-fdt2'
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004291 if default_dt:
4292 entry_args['default-dt'] = default_dt
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004293 if use_fdt_list:
4294 extra_indirs = [os.path.join(self._indir, TEST_FDT_SUBDIR)]
Simon Glassa435cd12020-09-01 05:13:59 -06004295 data = self._DoReadFileDtb(
Simon Glasscd2783e2024-07-20 11:49:46 +01004296 dts,
Simon Glassa435cd12020-09-01 05:13:59 -06004297 entry_args=entry_args,
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004298 extra_indirs=extra_indirs)[0]
Simon Glassa435cd12020-09-01 05:13:59 -06004299 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4300 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4301
4302 dtb = fdt.Fdt.FromData(fit_data)
4303 dtb.Scan()
4304 fnode = dtb.GetNode('/images/kernel')
4305 self.assertIn('data', fnode.props)
4306
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004307 if use_seq_num == True:
4308 # Check all the properties in fdt-1 and fdt-2
4309 _CheckFdt('1', TEST_FDT1_DATA)
4310 _CheckFdt('2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004311
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004312 # Check configurations
4313 _CheckConfig('1', TEST_FDT1_DATA)
4314 _CheckConfig('2', TEST_FDT2_DATA)
4315 else:
4316 # Check all the properties in fdt-1 and fdt-2
4317 _CheckFdt('test-fdt1', TEST_FDT1_DATA)
4318 _CheckFdt('test-fdt2', TEST_FDT2_DATA)
4319
4320 # Check configurations
4321 _CheckConfig('test-fdt1', TEST_FDT1_DATA)
4322 _CheckConfig('test-fdt2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004323
Simon Glasscd2783e2024-07-20 11:49:46 +01004324 def testFitFdt(self):
4325 """Test an image with an FIT with multiple FDT images"""
4326 self.CheckFitFdt()
4327
Simon Glassa435cd12020-09-01 05:13:59 -06004328 def testFitFdtMissingList(self):
4329 """Test handling of a missing 'of-list' entry arg"""
4330 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004331 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004332 self.assertIn("Generator node requires 'of-list' entry argument",
4333 str(e.exception))
4334
4335 def testFitFdtEmptyList(self):
4336 """Test handling of an empty 'of-list' entry arg"""
4337 entry_args = {
4338 'of-list': '',
4339 }
4340 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4341
4342 def testFitFdtMissingProp(self):
4343 """Test handling of a missing 'fit,fdt-list' property"""
4344 with self.assertRaises(ValueError) as e:
4345 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4346 self.assertIn("Generator node requires 'fit,fdt-list' property",
4347 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004348
Simon Glass1032acc2020-09-06 10:39:08 -06004349 def testFitFdtMissing(self):
4350 """Test handling of a missing 'default-dt' entry arg"""
4351 entry_args = {
4352 'of-list': 'test-fdt1 test-fdt2',
4353 }
4354 with self.assertRaises(ValueError) as e:
4355 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004356 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004357 entry_args=entry_args,
4358 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4359 self.assertIn("Generated 'default' node requires default-dt entry argument",
4360 str(e.exception))
4361
4362 def testFitFdtNotInList(self):
4363 """Test handling of a default-dt that is not in the of-list"""
4364 entry_args = {
4365 'of-list': 'test-fdt1 test-fdt2',
4366 'default-dt': 'test-fdt3',
4367 }
4368 with self.assertRaises(ValueError) as e:
4369 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004370 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004371 entry_args=entry_args,
4372 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4373 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4374 str(e.exception))
4375
Simon Glassa820af72020-09-06 10:39:09 -06004376 def testFitExtblobMissingHelp(self):
4377 """Test display of help messages when an external blob is missing"""
4378 control.missing_blob_help = control._ReadMissingBlobHelp()
4379 control.missing_blob_help['wibble'] = 'Wibble test'
4380 control.missing_blob_help['another'] = 'Another test'
4381 with test_util.capture_sys_output() as (stdout, stderr):
4382 self._DoTestFile('168_fit_missing_blob.dts',
4383 allow_missing=True)
4384 err = stderr.getvalue()
4385
4386 # We can get the tag from the name, the type or the missing-msg
4387 # property. Check all three.
4388 self.assertIn('You may need to build ARM Trusted', err)
4389 self.assertIn('Wibble test', err)
4390 self.assertIn('Another test', err)
4391
Simon Glass6f1f4d42020-09-06 10:35:32 -06004392 def testMissingBlob(self):
4393 """Test handling of a blob containing a missing file"""
4394 with self.assertRaises(ValueError) as e:
4395 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4396 self.assertIn("Filename 'missing' not found in input path",
4397 str(e.exception))
4398
Simon Glassa0729502020-09-06 10:35:33 -06004399 def testEnvironment(self):
4400 """Test adding a U-Boot environment"""
4401 data = self._DoReadFile('174_env.dts')
4402 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4403 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4404 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4405 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4406 env)
4407
4408 def testEnvironmentNoSize(self):
4409 """Test that a missing 'size' property is detected"""
4410 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004411 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004412 self.assertIn("'u-boot-env' entry must have a size property",
4413 str(e.exception))
4414
4415 def testEnvironmentTooSmall(self):
4416 """Test handling of an environment that does not fit"""
4417 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004418 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004419
4420 # checksum, start byte, environment with \0 terminator, final \0
4421 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4422 short = need - 0x8
4423 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4424 str(e.exception))
4425
Simon Glassd1fdf752020-10-26 17:40:01 -06004426 def testSkipAtStart(self):
4427 """Test handling of skip-at-start section"""
4428 data = self._DoReadFile('177_skip_at_start.dts')
4429 self.assertEqual(U_BOOT_DATA, data)
4430
4431 image = control.images['image']
4432 entries = image.GetEntries()
4433 section = entries['section']
4434 self.assertEqual(0, section.offset)
4435 self.assertEqual(len(U_BOOT_DATA), section.size)
4436 self.assertEqual(U_BOOT_DATA, section.GetData())
4437
4438 entry = section.GetEntries()['u-boot']
4439 self.assertEqual(16, entry.offset)
4440 self.assertEqual(len(U_BOOT_DATA), entry.size)
4441 self.assertEqual(U_BOOT_DATA, entry.data)
4442
4443 def testSkipAtStartPad(self):
4444 """Test handling of skip-at-start section with padded entry"""
4445 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004446 before = tools.get_bytes(0, 8)
4447 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004448 all = before + U_BOOT_DATA + after
4449 self.assertEqual(all, data)
4450
4451 image = control.images['image']
4452 entries = image.GetEntries()
4453 section = entries['section']
4454 self.assertEqual(0, section.offset)
4455 self.assertEqual(len(all), section.size)
4456 self.assertEqual(all, section.GetData())
4457
4458 entry = section.GetEntries()['u-boot']
4459 self.assertEqual(16, entry.offset)
4460 self.assertEqual(len(all), entry.size)
4461 self.assertEqual(U_BOOT_DATA, entry.data)
4462
4463 def testSkipAtStartSectionPad(self):
4464 """Test handling of skip-at-start section with padding"""
4465 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004466 before = tools.get_bytes(0, 8)
4467 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004468 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004469 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004470
4471 image = control.images['image']
4472 entries = image.GetEntries()
4473 section = entries['section']
4474 self.assertEqual(0, section.offset)
4475 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004476 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004477 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004478
4479 entry = section.GetEntries()['u-boot']
4480 self.assertEqual(16, entry.offset)
4481 self.assertEqual(len(U_BOOT_DATA), entry.size)
4482 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004483
Simon Glassbb395742020-10-26 17:40:14 -06004484 def testSectionPad(self):
4485 """Testing padding with sections"""
4486 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004487 expected = (tools.get_bytes(ord('&'), 3) +
4488 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004489 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004490 tools.get_bytes(ord('!'), 1) +
4491 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004492 self.assertEqual(expected, data)
4493
4494 def testSectionAlign(self):
4495 """Testing alignment with sections"""
4496 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4497 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004498 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004499 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004500 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004501 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004502 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4503 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004504 self.assertEqual(expected, data)
4505
Simon Glassd92c8362020-10-26 17:40:25 -06004506 def testCompressImage(self):
4507 """Test compression of the entire image"""
4508 self._CheckLz4()
4509 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4510 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4511 dtb = fdt.Fdt(out_dtb_fname)
4512 dtb.Scan()
4513 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4514 'uncomp-size'])
4515 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004516 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004517
4518 # Do a sanity check on various fields
4519 image = control.images['image']
4520 entries = image.GetEntries()
4521 self.assertEqual(2, len(entries))
4522
4523 entry = entries['blob']
4524 self.assertEqual(COMPRESS_DATA, entry.data)
4525 self.assertEqual(len(COMPRESS_DATA), entry.size)
4526
4527 entry = entries['u-boot']
4528 self.assertEqual(U_BOOT_DATA, entry.data)
4529 self.assertEqual(len(U_BOOT_DATA), entry.size)
4530
4531 self.assertEqual(len(data), image.size)
4532 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4533 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4534 orig = self._decompress(image.data)
4535 self.assertEqual(orig, image.uncomp_data)
4536
4537 expected = {
4538 'blob:offset': 0,
4539 'blob:size': len(COMPRESS_DATA),
4540 'u-boot:offset': len(COMPRESS_DATA),
4541 'u-boot:size': len(U_BOOT_DATA),
4542 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4543 'offset': 0,
4544 'image-pos': 0,
4545 'size': len(data),
4546 }
4547 self.assertEqual(expected, props)
4548
4549 def testCompressImageLess(self):
4550 """Test compression where compression reduces the image size"""
4551 self._CheckLz4()
4552 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4553 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4554 dtb = fdt.Fdt(out_dtb_fname)
4555 dtb.Scan()
4556 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4557 'uncomp-size'])
4558 orig = self._decompress(data)
4559
Brandon Maiera657bc62024-06-04 16:16:05 +00004560 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004561
4562 # Do a sanity check on various fields
4563 image = control.images['image']
4564 entries = image.GetEntries()
4565 self.assertEqual(2, len(entries))
4566
4567 entry = entries['blob']
4568 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4569 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4570
4571 entry = entries['u-boot']
4572 self.assertEqual(U_BOOT_DATA, entry.data)
4573 self.assertEqual(len(U_BOOT_DATA), entry.size)
4574
4575 self.assertEqual(len(data), image.size)
4576 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4577 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4578 image.uncomp_size)
4579 orig = self._decompress(image.data)
4580 self.assertEqual(orig, image.uncomp_data)
4581
4582 expected = {
4583 'blob:offset': 0,
4584 'blob:size': len(COMPRESS_DATA_BIG),
4585 'u-boot:offset': len(COMPRESS_DATA_BIG),
4586 'u-boot:size': len(U_BOOT_DATA),
4587 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4588 'offset': 0,
4589 'image-pos': 0,
4590 'size': len(data),
4591 }
4592 self.assertEqual(expected, props)
4593
4594 def testCompressSectionSize(self):
4595 """Test compression of a section with a fixed size"""
4596 self._CheckLz4()
4597 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4598 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4599 dtb = fdt.Fdt(out_dtb_fname)
4600 dtb.Scan()
4601 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4602 'uncomp-size'])
4603 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004604 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004605 expected = {
4606 'section/blob:offset': 0,
4607 'section/blob:size': len(COMPRESS_DATA),
4608 'section/u-boot:offset': len(COMPRESS_DATA),
4609 'section/u-boot:size': len(U_BOOT_DATA),
4610 'section:offset': 0,
4611 'section:image-pos': 0,
4612 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4613 'section:size': 0x30,
4614 'offset': 0,
4615 'image-pos': 0,
4616 'size': 0x30,
4617 }
4618 self.assertEqual(expected, props)
4619
4620 def testCompressSection(self):
4621 """Test compression of a section with no fixed size"""
4622 self._CheckLz4()
4623 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4624 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4625 dtb = fdt.Fdt(out_dtb_fname)
4626 dtb.Scan()
4627 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4628 'uncomp-size'])
4629 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004630 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004631 expected = {
4632 'section/blob:offset': 0,
4633 'section/blob:size': len(COMPRESS_DATA),
4634 'section/u-boot:offset': len(COMPRESS_DATA),
4635 'section/u-boot:size': len(U_BOOT_DATA),
4636 'section:offset': 0,
4637 'section:image-pos': 0,
4638 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4639 'section:size': len(data),
4640 'offset': 0,
4641 'image-pos': 0,
4642 'size': len(data),
4643 }
4644 self.assertEqual(expected, props)
4645
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004646 def testLz4Missing(self):
4647 """Test that binman still produces an image if lz4 is missing"""
4648 with test_util.capture_sys_output() as (_, stderr):
4649 self._DoTestFile('185_compress_section.dts',
4650 force_missing_bintools='lz4')
4651 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004652 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004653
Simon Glassd92c8362020-10-26 17:40:25 -06004654 def testCompressExtra(self):
4655 """Test compression of a section with no fixed size"""
4656 self._CheckLz4()
4657 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4658 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4659 dtb = fdt.Fdt(out_dtb_fname)
4660 dtb.Scan()
4661 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4662 'uncomp-size'])
4663
4664 base = data[len(U_BOOT_DATA):]
Brandon Maiera657bc62024-06-04 16:16:05 +00004665 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glassd92c8362020-10-26 17:40:25 -06004666 rest = base[len(U_BOOT_DATA):]
4667
4668 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004669 bintool = self.comp_bintools['lz4']
4670 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004671 data1 = rest[:len(expect1)]
4672 section1 = self._decompress(data1)
Brandon Maiera657bc62024-06-04 16:16:05 +00004673 self.assertEqual(expect1, data1)
4674 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glassd92c8362020-10-26 17:40:25 -06004675 rest1 = rest[len(expect1):]
4676
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004677 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004678 data2 = rest1[:len(expect2)]
4679 section2 = self._decompress(data2)
Brandon Maiera657bc62024-06-04 16:16:05 +00004680 self.assertEqual(expect2, data2)
4681 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glassd92c8362020-10-26 17:40:25 -06004682 rest2 = rest1[len(expect2):]
4683
4684 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4685 len(expect2) + len(U_BOOT_DATA))
Brandon Maiera657bc62024-06-04 16:16:05 +00004686 #self.assertEqual(expect_size, len(data))
Simon Glassd92c8362020-10-26 17:40:25 -06004687
Brandon Maiera657bc62024-06-04 16:16:05 +00004688 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glassd92c8362020-10-26 17:40:25 -06004689
4690 self.maxDiff = None
4691 expected = {
4692 'u-boot:offset': 0,
4693 'u-boot:image-pos': 0,
4694 'u-boot:size': len(U_BOOT_DATA),
4695
4696 'base:offset': len(U_BOOT_DATA),
4697 'base:image-pos': len(U_BOOT_DATA),
4698 'base:size': len(data) - len(U_BOOT_DATA),
4699 'base/u-boot:offset': 0,
4700 'base/u-boot:image-pos': len(U_BOOT_DATA),
4701 'base/u-boot:size': len(U_BOOT_DATA),
4702 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4703 len(expect2),
4704 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4705 len(expect2),
4706 'base/u-boot2:size': len(U_BOOT_DATA),
4707
4708 'base/section:offset': len(U_BOOT_DATA),
4709 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4710 'base/section:size': len(expect1),
4711 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4712 'base/section/blob:offset': 0,
4713 'base/section/blob:size': len(COMPRESS_DATA),
4714 'base/section/u-boot:offset': len(COMPRESS_DATA),
4715 'base/section/u-boot:size': len(U_BOOT_DATA),
4716
4717 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4718 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4719 'base/section2:size': len(expect2),
4720 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4721 'base/section2/blob:offset': 0,
4722 'base/section2/blob:size': len(COMPRESS_DATA),
4723 'base/section2/blob2:offset': len(COMPRESS_DATA),
4724 'base/section2/blob2:size': len(COMPRESS_DATA),
4725
4726 'offset': 0,
4727 'image-pos': 0,
4728 'size': len(data),
4729 }
4730 self.assertEqual(expected, props)
4731
Simon Glassecbe4732021-01-06 21:35:15 -07004732 def testSymbolsSubsection(self):
4733 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004734 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004735
Simon Glass3fb25402021-01-06 21:35:16 -07004736 def testReadImageEntryArg(self):
4737 """Test reading an image that would need an entry arg to generate"""
4738 entry_args = {
4739 'cros-ec-rw-path': 'ecrw.bin',
4740 }
4741 data = self.data = self._DoReadFileDtb(
4742 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4743 entry_args=entry_args)
4744
Simon Glass80025522022-01-29 14:14:04 -07004745 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004746 orig_image = control.images['image']
4747
4748 # This should not generate an error about the missing 'cros-ec-rw-path'
4749 # since we are reading the image from a file. Compare with
4750 # testEntryArgsRequired()
4751 image = Image.FromFile(image_fname)
4752 self.assertEqual(orig_image.GetEntries().keys(),
4753 image.GetEntries().keys())
4754
Simon Glassa2af7302021-01-06 21:35:18 -07004755 def testFilesAlign(self):
4756 """Test alignment with files"""
4757 data = self._DoReadFile('190_files_align.dts')
4758
4759 # The first string is 15 bytes so will align to 16
4760 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4761 self.assertEqual(expect, data)
4762
Simon Glassdb84b562021-01-06 21:35:19 -07004763 def testReadImageSkip(self):
4764 """Test reading an image and accessing its FDT map"""
4765 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004766 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004767 orig_image = control.images['image']
4768 image = Image.FromFile(image_fname)
4769 self.assertEqual(orig_image.GetEntries().keys(),
4770 image.GetEntries().keys())
4771
4772 orig_entry = orig_image.GetEntries()['fdtmap']
4773 entry = image.GetEntries()['fdtmap']
4774 self.assertEqual(orig_entry.offset, entry.offset)
4775 self.assertEqual(orig_entry.size, entry.size)
4776 self.assertEqual(16, entry.image_pos)
4777
4778 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4779
Brandon Maiera657bc62024-06-04 16:16:05 +00004780 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glassdb84b562021-01-06 21:35:19 -07004781
Simon Glassc98de972021-03-18 20:24:57 +13004782 def testTplNoDtb(self):
4783 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004784 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004785 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4786 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4787 data[:len(U_BOOT_TPL_NODTB_DATA)])
4788
Simon Glass63f41d42021-03-18 20:24:58 +13004789 def testTplBssPad(self):
4790 """Test that we can pad TPL's BSS with zeros"""
4791 # ELF file with a '__bss_size' symbol
4792 self._SetupTplElf()
4793 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004794 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004795 data)
4796
4797 def testTplBssPadMissing(self):
4798 """Test that a missing symbol is detected"""
4799 self._SetupTplElf('u_boot_ucode_ptr')
4800 with self.assertRaises(ValueError) as e:
4801 self._DoReadFile('193_tpl_bss_pad.dts')
4802 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4803 str(e.exception))
4804
Simon Glass718b5292021-03-18 20:25:07 +13004805 def checkDtbSizes(self, data, pad_len, start):
4806 """Check the size arguments in a dtb embedded in an image
4807
4808 Args:
4809 data: The image data
4810 pad_len: Length of the pad section in the image, in bytes
4811 start: Start offset of the devicetree to examine, within the image
4812
4813 Returns:
4814 Size of the devicetree in bytes
4815 """
4816 dtb_data = data[start:]
4817 dtb = fdt.Fdt.FromData(dtb_data)
4818 fdt_size = dtb.GetFdtObj().totalsize()
4819 dtb.Scan()
4820 props = self._GetPropTree(dtb, 'size')
4821 self.assertEqual({
4822 'size': len(data),
4823 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4824 'u-boot-spl/u-boot-spl-dtb:size': 801,
4825 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4826 'u-boot-spl:size': 860,
4827 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4828 'u-boot/u-boot-dtb:size': 781,
4829 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4830 'u-boot:size': 827,
4831 }, props)
4832 return fdt_size
4833
4834 def testExpanded(self):
4835 """Test that an expanded entry type is selected when needed"""
4836 self._SetupSplElf()
4837 self._SetupTplElf()
4838
4839 # SPL has a devicetree, TPL does not
4840 entry_args = {
4841 'spl-dtb': '1',
4842 'spl-bss-pad': 'y',
4843 'tpl-dtb': '',
4844 }
4845 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4846 entry_args=entry_args)
4847 image = control.images['image']
4848 entries = image.GetEntries()
4849 self.assertEqual(3, len(entries))
4850
4851 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4852 self.assertIn('u-boot', entries)
4853 entry = entries['u-boot']
4854 self.assertEqual('u-boot-expanded', entry.etype)
4855 subent = entry.GetEntries()
4856 self.assertEqual(2, len(subent))
4857 self.assertIn('u-boot-nodtb', subent)
4858 self.assertIn('u-boot-dtb', subent)
4859
4860 # Second, u-boot-spl, which should be expanded into three parts
4861 self.assertIn('u-boot-spl', entries)
4862 entry = entries['u-boot-spl']
4863 self.assertEqual('u-boot-spl-expanded', entry.etype)
4864 subent = entry.GetEntries()
4865 self.assertEqual(3, len(subent))
4866 self.assertIn('u-boot-spl-nodtb', subent)
4867 self.assertIn('u-boot-spl-bss-pad', subent)
4868 self.assertIn('u-boot-spl-dtb', subent)
4869
4870 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4871 # devicetree
4872 self.assertIn('u-boot-tpl', entries)
4873 entry = entries['u-boot-tpl']
4874 self.assertEqual('u-boot-tpl', entry.etype)
4875 self.assertEqual(None, entry.GetEntries())
4876
4877 def testExpandedTpl(self):
4878 """Test that an expanded entry type is selected for TPL when needed"""
4879 self._SetupTplElf()
4880
4881 entry_args = {
4882 'tpl-bss-pad': 'y',
4883 'tpl-dtb': 'y',
4884 }
4885 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4886 entry_args=entry_args)
4887 image = control.images['image']
4888 entries = image.GetEntries()
4889 self.assertEqual(1, len(entries))
4890
4891 # We only have u-boot-tpl, which be expanded
4892 self.assertIn('u-boot-tpl', entries)
4893 entry = entries['u-boot-tpl']
4894 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4895 subent = entry.GetEntries()
4896 self.assertEqual(3, len(subent))
4897 self.assertIn('u-boot-tpl-nodtb', subent)
4898 self.assertIn('u-boot-tpl-bss-pad', subent)
4899 self.assertIn('u-boot-tpl-dtb', subent)
4900
4901 def testExpandedNoPad(self):
4902 """Test an expanded entry without BSS pad enabled"""
4903 self._SetupSplElf()
4904 self._SetupTplElf()
4905
4906 # SPL has a devicetree, TPL does not
4907 entry_args = {
4908 'spl-dtb': 'something',
4909 'spl-bss-pad': 'n',
4910 'tpl-dtb': '',
4911 }
4912 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4913 entry_args=entry_args)
4914 image = control.images['image']
4915 entries = image.GetEntries()
4916
4917 # Just check u-boot-spl, which should be expanded into two parts
4918 self.assertIn('u-boot-spl', entries)
4919 entry = entries['u-boot-spl']
4920 self.assertEqual('u-boot-spl-expanded', entry.etype)
4921 subent = entry.GetEntries()
4922 self.assertEqual(2, len(subent))
4923 self.assertIn('u-boot-spl-nodtb', subent)
4924 self.assertIn('u-boot-spl-dtb', subent)
4925
4926 def testExpandedTplNoPad(self):
4927 """Test that an expanded entry type with padding disabled in TPL"""
4928 self._SetupTplElf()
4929
4930 entry_args = {
4931 'tpl-bss-pad': '',
4932 'tpl-dtb': 'y',
4933 }
4934 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4935 entry_args=entry_args)
4936 image = control.images['image']
4937 entries = image.GetEntries()
4938 self.assertEqual(1, len(entries))
4939
4940 # We only have u-boot-tpl, which be expanded
4941 self.assertIn('u-boot-tpl', entries)
4942 entry = entries['u-boot-tpl']
4943 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4944 subent = entry.GetEntries()
4945 self.assertEqual(2, len(subent))
4946 self.assertIn('u-boot-tpl-nodtb', subent)
4947 self.assertIn('u-boot-tpl-dtb', subent)
4948
4949 def testFdtInclude(self):
4950 """Test that an Fdt is update within all binaries"""
4951 self._SetupSplElf()
4952 self._SetupTplElf()
4953
4954 # SPL has a devicetree, TPL does not
4955 self.maxDiff = None
4956 entry_args = {
4957 'spl-dtb': '1',
4958 'spl-bss-pad': 'y',
4959 'tpl-dtb': '',
4960 }
4961 # Build the image. It includes two separate devicetree binaries, each
4962 # with their own contents, but all contain the binman definition.
4963 data = self._DoReadFileDtb(
4964 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4965 update_dtb=True, entry_args=entry_args)[0]
4966 pad_len = 10
4967
4968 # Check the U-Boot dtb
4969 start = len(U_BOOT_NODTB_DATA)
4970 fdt_size = self.checkDtbSizes(data, pad_len, start)
4971
4972 # Now check SPL
4973 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4974 fdt_size = self.checkDtbSizes(data, pad_len, start)
4975
4976 # TPL has no devicetree
4977 start += fdt_size + len(U_BOOT_TPL_DATA)
4978 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004979
Simon Glass7098b7f2021-03-21 18:24:30 +13004980 def testSymbolsExpanded(self):
4981 """Test binman can assign symbols in expanded entries"""
4982 entry_args = {
4983 'spl-dtb': '1',
4984 }
4985 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4986 U_BOOT_SPL_DTB_DATA, 0x38,
4987 entry_args=entry_args, use_expanded=True)
4988
Simon Glasse1915782021-03-21 18:24:31 +13004989 def testCollection(self):
4990 """Test a collection"""
4991 data = self._DoReadFile('198_collection.dts')
4992 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004993 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4994 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004995 data)
4996
Simon Glass27a7f772021-03-21 18:24:32 +13004997 def testCollectionSection(self):
4998 """Test a collection where a section must be built first"""
4999 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07005000 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13005001 # building the contents, producing an error is anything is still
5002 # missing.
5003 data = self._DoReadFile('199_collection_section.dts')
5004 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07005005 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
5006 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13005007 data)
5008
Simon Glassf427c5f2021-03-21 18:24:33 +13005009 def testAlignDefault(self):
5010 """Test that default alignment works on sections"""
5011 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07005012 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13005013 U_BOOT_DATA)
5014 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07005015 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13005016 # No alignment within the nested section
5017 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
5018 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07005019 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13005020 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13005021
Bin Mengc0b15742021-05-10 20:23:33 +08005022 def testPackOpenSBI(self):
5023 """Test that an image with an OpenSBI binary can be created"""
5024 data = self._DoReadFile('201_opensbi.dts')
5025 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
5026
Simon Glass76f496d2021-07-06 10:36:37 -06005027 def testSectionsSingleThread(self):
5028 """Test sections without multithreading"""
5029 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07005030 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
5031 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
5032 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06005033 self.assertEqual(expected, data)
5034
5035 def testThreadTimeout(self):
5036 """Test handling a thread that takes too long"""
5037 with self.assertRaises(ValueError) as e:
5038 self._DoTestFile('202_section_timeout.dts',
5039 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06005040 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06005041
Simon Glass748a1d42021-07-06 10:36:41 -06005042 def testTiming(self):
5043 """Test output of timing information"""
5044 data = self._DoReadFile('055_sections.dts')
5045 with test_util.capture_sys_output() as (stdout, stderr):
5046 state.TimingShow()
5047 self.assertIn('read:', stdout.getvalue())
5048 self.assertIn('compress:', stdout.getvalue())
5049
Simon Glassadfb8492021-11-03 21:09:18 -06005050 def testUpdateFdtInElf(self):
5051 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005052 if not elf.ELF_TOOLS:
5053 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005054 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5055 outfile = os.path.join(self._indir, 'u-boot.out')
5056 begin_sym = 'dtb_embed_begin'
5057 end_sym = 'dtb_embed_end'
5058 retcode = self._DoTestFile(
5059 '060_fdt_update.dts', update_dtb=True,
5060 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5061 self.assertEqual(0, retcode)
5062
5063 # Check that the output file does in fact contact a dtb with the binman
5064 # definition in the correct place
5065 syms = elf.GetSymbolFileOffset(infile,
5066 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07005067 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06005068 dtb_data = data[syms['dtb_embed_begin'].offset:
5069 syms['dtb_embed_end'].offset]
5070
5071 dtb = fdt.Fdt.FromData(dtb_data)
5072 dtb.Scan()
5073 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
5074 self.assertEqual({
5075 'image-pos': 0,
5076 'offset': 0,
5077 '_testing:offset': 32,
5078 '_testing:size': 2,
5079 '_testing:image-pos': 32,
5080 'section@0/u-boot:offset': 0,
5081 'section@0/u-boot:size': len(U_BOOT_DATA),
5082 'section@0/u-boot:image-pos': 0,
5083 'section@0:offset': 0,
5084 'section@0:size': 16,
5085 'section@0:image-pos': 0,
5086
5087 'section@1/u-boot:offset': 0,
5088 'section@1/u-boot:size': len(U_BOOT_DATA),
5089 'section@1/u-boot:image-pos': 16,
5090 'section@1:offset': 16,
5091 'section@1:size': 16,
5092 'section@1:image-pos': 16,
5093 'size': 40
5094 }, props)
5095
5096 def testUpdateFdtInElfInvalid(self):
5097 """Test that invalid args are detected with --update-fdt-in-elf"""
5098 with self.assertRaises(ValueError) as e:
5099 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5100 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5101 str(e.exception))
5102
5103 def testUpdateFdtInElfNoSyms(self):
5104 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005105 if not elf.ELF_TOOLS:
5106 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005107 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5108 outfile = ''
5109 begin_sym = 'wrong_begin'
5110 end_sym = 'wrong_end'
5111 with self.assertRaises(ValueError) as e:
5112 self._DoTestFile(
5113 '060_fdt_update.dts',
5114 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5115 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5116 str(e.exception))
5117
5118 def testUpdateFdtInElfTooSmall(self):
5119 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005120 if not elf.ELF_TOOLS:
5121 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005122 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5123 outfile = os.path.join(self._indir, 'u-boot.out')
5124 begin_sym = 'dtb_embed_begin'
5125 end_sym = 'dtb_embed_end'
5126 with self.assertRaises(ValueError) as e:
5127 self._DoTestFile(
5128 '060_fdt_update.dts', update_dtb=True,
5129 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5130 self.assertRegex(
5131 str(e.exception),
5132 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5133
Simon Glass88e04da2021-11-23 11:03:42 -07005134 def testVersion(self):
5135 """Test we can get the binman version"""
5136 version = '(unreleased)'
5137 self.assertEqual(version, state.GetVersion(self._indir))
5138
5139 with self.assertRaises(SystemExit):
5140 with test_util.capture_sys_output() as (_, stderr):
5141 self._DoBinman('-V')
5142 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5143
5144 # Try running the tool too, just to be safe
5145 result = self._RunBinman('-V')
5146 self.assertEqual('Binman %s\n' % version, result.stderr)
5147
5148 # Set up a version file to make sure that works
5149 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005150 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005151 binary=False)
5152 self.assertEqual(version, state.GetVersion(self._indir))
5153
Simon Glass637958f2021-11-23 21:09:50 -07005154 def testAltFormat(self):
5155 """Test that alternative formats can be used to extract"""
5156 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5157
5158 try:
5159 tmpdir, updated_fname = self._SetupImageInTmpdir()
5160 with test_util.capture_sys_output() as (stdout, _):
5161 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5162 self.assertEqual(
5163 '''Flag (-F) Entry type Description
5164fdt fdtmap Extract the devicetree blob from the fdtmap
5165''',
5166 stdout.getvalue())
5167
5168 dtb = os.path.join(tmpdir, 'fdt.dtb')
5169 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5170 dtb, 'fdtmap')
5171
5172 # Check that we can read it and it can be scanning, meaning it does
5173 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005174 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005175 dtb = fdt.Fdt.FromData(data)
5176 dtb.Scan()
5177
5178 # Now check u-boot which has no alt_format
5179 fname = os.path.join(tmpdir, 'fdt.dtb')
5180 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5181 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005182 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005183 self.assertEqual(U_BOOT_DATA, data)
5184
5185 finally:
5186 shutil.rmtree(tmpdir)
5187
Simon Glass0b00ae62021-11-23 21:09:52 -07005188 def testExtblobList(self):
5189 """Test an image with an external blob list"""
5190 data = self._DoReadFile('215_blob_ext_list.dts')
5191 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5192
5193 def testExtblobListMissing(self):
5194 """Test an image with a missing external blob"""
5195 with self.assertRaises(ValueError) as e:
5196 self._DoReadFile('216_blob_ext_list_missing.dts')
5197 self.assertIn("Filename 'missing-file' not found in input path",
5198 str(e.exception))
5199
5200 def testExtblobListMissingOk(self):
5201 """Test an image with an missing external blob that is allowed"""
5202 with test_util.capture_sys_output() as (stdout, stderr):
5203 self._DoTestFile('216_blob_ext_list_missing.dts',
5204 allow_missing=True)
5205 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005206 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005207
Simon Glass3efb2972021-11-23 21:08:59 -07005208 def testFip(self):
5209 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5210 data = self._DoReadFile('203_fip.dts')
5211 hdr, fents = fip_util.decode_fip(data)
5212 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5213 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5214 self.assertEqual(0x123, hdr.flags)
5215
5216 self.assertEqual(2, len(fents))
5217
5218 fent = fents[0]
5219 self.assertEqual(
5220 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5221 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5222 self.assertEqual('soc-fw', fent.fip_type)
5223 self.assertEqual(0x88, fent.offset)
5224 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5225 self.assertEqual(0x123456789abcdef, fent.flags)
5226 self.assertEqual(ATF_BL31_DATA, fent.data)
5227 self.assertEqual(True, fent.valid)
5228
5229 fent = fents[1]
5230 self.assertEqual(
5231 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5232 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5233 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5234 self.assertEqual(0x8c, fent.offset)
5235 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5236 self.assertEqual(0, fent.flags)
5237 self.assertEqual(ATF_BL2U_DATA, fent.data)
5238 self.assertEqual(True, fent.valid)
5239
5240 def testFipOther(self):
5241 """Basic FIP with something that isn't a external blob"""
5242 data = self._DoReadFile('204_fip_other.dts')
5243 hdr, fents = fip_util.decode_fip(data)
5244
5245 self.assertEqual(2, len(fents))
5246 fent = fents[1]
5247 self.assertEqual('rot-cert', fent.fip_type)
5248 self.assertEqual(b'aa', fent.data)
5249
Simon Glass3efb2972021-11-23 21:08:59 -07005250 def testFipNoType(self):
5251 """FIP with an entry of an unknown type"""
5252 with self.assertRaises(ValueError) as e:
5253 self._DoReadFile('205_fip_no_type.dts')
5254 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5255 str(e.exception))
5256
5257 def testFipUuid(self):
5258 """Basic FIP with a manual uuid"""
5259 data = self._DoReadFile('206_fip_uuid.dts')
5260 hdr, fents = fip_util.decode_fip(data)
5261
5262 self.assertEqual(2, len(fents))
5263 fent = fents[1]
5264 self.assertEqual(None, fent.fip_type)
5265 self.assertEqual(
5266 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5267 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5268 fent.uuid)
5269 self.assertEqual(U_BOOT_DATA, fent.data)
5270
5271 def testFipLs(self):
5272 """Test listing a FIP"""
5273 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5274 hdr, fents = fip_util.decode_fip(data)
5275
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005276 tmpdir = None
Simon Glass3efb2972021-11-23 21:08:59 -07005277 try:
5278 tmpdir, updated_fname = self._SetupImageInTmpdir()
5279 with test_util.capture_sys_output() as (stdout, stderr):
5280 self._DoBinman('ls', '-i', updated_fname)
5281 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005282 if tmpdir:
5283 shutil.rmtree(tmpdir)
Simon Glass3efb2972021-11-23 21:08:59 -07005284 lines = stdout.getvalue().splitlines()
5285 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005286'Name Image-pos Size Entry-type Offset Uncomp-size',
5287'--------------------------------------------------------------',
5288'image 0 2d3 section 0',
5289' atf-fip 0 90 atf-fip 0',
5290' soc-fw 88 4 blob-ext 88',
5291' u-boot 8c 4 u-boot 8c',
5292' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005293]
5294 self.assertEqual(expected, lines)
5295
5296 image = control.images['image']
5297 entries = image.GetEntries()
5298 fdtmap = entries['fdtmap']
5299
5300 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5301 magic = fdtmap_data[:8]
5302 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005303 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005304
5305 fdt_data = fdtmap_data[16:]
5306 dtb = fdt.Fdt.FromData(fdt_data)
5307 dtb.Scan()
5308 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5309 self.assertEqual({
5310 'atf-fip/soc-fw:image-pos': 136,
5311 'atf-fip/soc-fw:offset': 136,
5312 'atf-fip/soc-fw:size': 4,
5313 'atf-fip/u-boot:image-pos': 140,
5314 'atf-fip/u-boot:offset': 140,
5315 'atf-fip/u-boot:size': 4,
5316 'atf-fip:image-pos': 0,
5317 'atf-fip:offset': 0,
5318 'atf-fip:size': 144,
5319 'image-pos': 0,
5320 'offset': 0,
5321 'fdtmap:image-pos': fdtmap.image_pos,
5322 'fdtmap:offset': fdtmap.offset,
5323 'fdtmap:size': len(fdtmap_data),
5324 'size': len(data),
5325 }, props)
5326
5327 def testFipExtractOneEntry(self):
5328 """Test extracting a single entry fron an FIP"""
5329 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005330 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005331 fname = os.path.join(self._indir, 'output.extact')
5332 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005333 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005334 self.assertEqual(U_BOOT_DATA, data)
5335
5336 def testFipReplace(self):
5337 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005338 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005339 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005340 updated_fname = tools.get_output_filename('image-updated.bin')
5341 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005342 entry_name = 'atf-fip/u-boot'
5343 control.WriteEntry(updated_fname, entry_name, expected,
5344 allow_resize=True)
5345 actual = control.ReadEntry(updated_fname, entry_name)
5346 self.assertEqual(expected, actual)
5347
Simon Glass80025522022-01-29 14:14:04 -07005348 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005349 hdr, fents = fip_util.decode_fip(new_data)
5350
5351 self.assertEqual(2, len(fents))
5352
5353 # Check that the FIP entry is updated
5354 fent = fents[1]
5355 self.assertEqual(0x8c, fent.offset)
5356 self.assertEqual(len(expected), fent.size)
5357 self.assertEqual(0, fent.flags)
5358 self.assertEqual(expected, fent.data)
5359 self.assertEqual(True, fent.valid)
5360
5361 def testFipMissing(self):
5362 with test_util.capture_sys_output() as (stdout, stderr):
5363 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5364 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005365 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005366
5367 def testFipSize(self):
5368 """Test a FIP with a size property"""
5369 data = self._DoReadFile('210_fip_size.dts')
5370 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5371 hdr, fents = fip_util.decode_fip(data)
5372 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5373 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5374
5375 self.assertEqual(1, len(fents))
5376
5377 fent = fents[0]
5378 self.assertEqual('soc-fw', fent.fip_type)
5379 self.assertEqual(0x60, fent.offset)
5380 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5381 self.assertEqual(ATF_BL31_DATA, fent.data)
5382 self.assertEqual(True, fent.valid)
5383
5384 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005385 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005386
5387 def testFipBadAlign(self):
5388 """Test that an invalid alignment value in a FIP is detected"""
5389 with self.assertRaises(ValueError) as e:
5390 self._DoTestFile('211_fip_bad_align.dts')
5391 self.assertIn(
5392 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5393 str(e.exception))
5394
5395 def testFipCollection(self):
5396 """Test using a FIP in a collection"""
5397 data = self._DoReadFile('212_fip_collection.dts')
5398 entry1 = control.images['image'].GetEntries()['collection']
5399 data1 = data[:entry1.size]
5400 hdr1, fents2 = fip_util.decode_fip(data1)
5401
5402 entry2 = control.images['image'].GetEntries()['atf-fip']
5403 data2 = data[entry2.offset:entry2.offset + entry2.size]
5404 hdr1, fents2 = fip_util.decode_fip(data2)
5405
5406 # The 'collection' entry should have U-Boot included at the end
5407 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5408 self.assertEqual(data1, data2 + U_BOOT_DATA)
5409 self.assertEqual(U_BOOT_DATA, data1[-4:])
5410
5411 # There should be a U-Boot after the final FIP
5412 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005413
Simon Glassccae6862022-01-12 13:10:35 -07005414 def testFakeBlob(self):
5415 """Test handling of faking an external blob"""
5416 with test_util.capture_sys_output() as (stdout, stderr):
5417 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5418 allow_fake_blobs=True)
5419 err = stderr.getvalue()
5420 self.assertRegex(
5421 err,
5422 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005423
Simon Glassceb5f912022-01-09 20:13:46 -07005424 def testExtblobListFaked(self):
5425 """Test an extblob with missing external blob that are faked"""
5426 with test_util.capture_sys_output() as (stdout, stderr):
5427 self._DoTestFile('216_blob_ext_list_missing.dts',
5428 allow_fake_blobs=True)
5429 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005430 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005431
Simon Glass162017b2022-01-09 20:13:57 -07005432 def testListBintools(self):
5433 args = ['tool', '--list']
5434 with test_util.capture_sys_output() as (stdout, _):
5435 self._DoBinman(*args)
5436 out = stdout.getvalue().splitlines()
5437 self.assertTrue(len(out) >= 2)
5438
5439 def testFetchBintools(self):
5440 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005441 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005442 raise urllib.error.URLError('my error')
5443
5444 args = ['tool']
5445 with self.assertRaises(ValueError) as e:
5446 self._DoBinman(*args)
5447 self.assertIn("Invalid arguments to 'tool' subcommand",
5448 str(e.exception))
5449
5450 args = ['tool', '--fetch']
5451 with self.assertRaises(ValueError) as e:
5452 self._DoBinman(*args)
5453 self.assertIn('Please specify bintools to fetch', str(e.exception))
5454
5455 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005456 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005457 side_effect=fail_download):
5458 with test_util.capture_sys_output() as (stdout, _):
5459 self._DoBinman(*args)
5460 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5461
Simon Glass620c4462022-01-09 20:14:11 -07005462 def testBintoolDocs(self):
5463 """Test for creation of bintool documentation"""
5464 with test_util.capture_sys_output() as (stdout, stderr):
5465 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5466 self.assertTrue(len(stdout.getvalue()) > 0)
5467
5468 def testBintoolDocsMissing(self):
5469 """Test handling of missing bintool documentation"""
5470 with self.assertRaises(ValueError) as e:
5471 with test_util.capture_sys_output() as (stdout, stderr):
5472 control.write_bintool_docs(
5473 control.bintool.Bintool.get_tool_list(), 'mkimage')
5474 self.assertIn('Documentation is missing for modules: mkimage',
5475 str(e.exception))
5476
Jan Kiszka58c407f2022-01-28 20:37:53 +01005477 def testListWithGenNode(self):
5478 """Check handling of an FDT map when the section cannot be found"""
5479 entry_args = {
5480 'of-list': 'test-fdt1 test-fdt2',
5481 }
5482 data = self._DoReadFileDtb(
5483 '219_fit_gennode.dts',
5484 entry_args=entry_args,
5485 use_real_dtb=True,
5486 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5487
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005488 tmpdir = None
Jan Kiszka58c407f2022-01-28 20:37:53 +01005489 try:
5490 tmpdir, updated_fname = self._SetupImageInTmpdir()
5491 with test_util.capture_sys_output() as (stdout, stderr):
5492 self._RunBinman('ls', '-i', updated_fname)
5493 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005494 if tmpdir:
5495 shutil.rmtree(tmpdir)
Jan Kiszka58c407f2022-01-28 20:37:53 +01005496
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005497 def testFitSubentryUsesBintool(self):
5498 """Test that binman FIT subentries can use bintools"""
5499 command.test_result = self._HandleGbbCommand
5500 entry_args = {
5501 'keydir': 'devkeys',
5502 'bmpblk': 'bmpblk.bin',
5503 }
5504 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5505 entry_args=entry_args)
5506
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005507 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5508 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005509 self.assertIn(expected, data)
5510
5511 def testFitSubentryMissingBintool(self):
5512 """Test that binman reports missing bintools for FIT subentries"""
5513 entry_args = {
5514 'keydir': 'devkeys',
5515 }
5516 with test_util.capture_sys_output() as (_, stderr):
5517 self._DoTestFile('220_fit_subentry_bintool.dts',
5518 force_missing_bintools='futility', entry_args=entry_args)
5519 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005520 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005521
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005522 def testFitSubentryHashSubnode(self):
5523 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005524 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005525 data, _, _, out_dtb_name = self._DoReadFileDtb(
5526 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5527
5528 mkimage_dtb = fdt.Fdt.FromData(data)
5529 mkimage_dtb.Scan()
5530 binman_dtb = fdt.Fdt(out_dtb_name)
5531 binman_dtb.Scan()
5532
5533 # Check that binman didn't add hash values
5534 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5535 self.assertNotIn('value', fnode.props)
5536
5537 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5538 self.assertNotIn('value', fnode.props)
5539
5540 # Check that mkimage added hash values
5541 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5542 self.assertIn('value', fnode.props)
5543
5544 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5545 self.assertIn('value', fnode.props)
5546
Roger Quadros5cdcea02022-02-19 20:50:04 +02005547 def testPackTeeOs(self):
5548 """Test that an image with an TEE binary can be created"""
5549 data = self._DoReadFile('222_tee_os.dts')
5550 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5551
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305552 def testPackTiDm(self):
5553 """Test that an image with a TI DM binary can be created"""
5554 data = self._DoReadFile('225_ti_dm.dts')
5555 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5556
Simon Glass912339f2022-02-08 11:50:03 -07005557 def testFitFdtOper(self):
5558 """Check handling of a specified FIT operation"""
5559 entry_args = {
5560 'of-list': 'test-fdt1 test-fdt2',
5561 'default-dt': 'test-fdt2',
5562 }
5563 self._DoReadFileDtb(
5564 '223_fit_fdt_oper.dts',
5565 entry_args=entry_args,
5566 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5567
5568 def testFitFdtBadOper(self):
5569 """Check handling of an FDT map when the section cannot be found"""
5570 with self.assertRaises(ValueError) as exc:
5571 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005572 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005573 str(exc.exception))
5574
Simon Glassdd156a42022-03-05 20:18:59 -07005575 def test_uses_expand_size(self):
5576 """Test that the 'expand-size' property cannot be used anymore"""
5577 with self.assertRaises(ValueError) as e:
5578 data = self._DoReadFile('225_expand_size_bad.dts')
5579 self.assertIn(
5580 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5581 str(e.exception))
5582
Simon Glass5f423422022-03-05 20:19:12 -07005583 def testFitSplitElf(self):
5584 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005585 if not elf.ELF_TOOLS:
5586 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005587 entry_args = {
5588 'of-list': 'test-fdt1 test-fdt2',
5589 'default-dt': 'test-fdt2',
5590 'atf-bl31-path': 'bl31.elf',
5591 'tee-os-path': 'tee.elf',
5592 }
5593 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5594 data = self._DoReadFileDtb(
5595 '226_fit_split_elf.dts',
5596 entry_args=entry_args,
5597 extra_indirs=[test_subdir])[0]
5598
5599 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5600 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5601
5602 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5603 'data', 'load'}
5604 dtb = fdt.Fdt.FromData(fit_data)
5605 dtb.Scan()
5606
5607 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5608 segments, entry = elf.read_loadable_segments(elf_data)
5609
5610 # We assume there are two segments
Brandon Maiera657bc62024-06-04 16:16:05 +00005611 self.assertEqual(2, len(segments))
Simon Glass5f423422022-03-05 20:19:12 -07005612
5613 atf1 = dtb.GetNode('/images/atf-1')
5614 _, start, data = segments[0]
5615 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5616 self.assertEqual(entry,
5617 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5618 self.assertEqual(start,
5619 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5620 self.assertEqual(data, atf1.props['data'].bytes)
5621
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005622 hash_node = atf1.FindNode('hash')
5623 self.assertIsNotNone(hash_node)
5624 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5625
Simon Glass5f423422022-03-05 20:19:12 -07005626 atf2 = dtb.GetNode('/images/atf-2')
5627 self.assertEqual(base_keys, atf2.props.keys())
5628 _, start, data = segments[1]
5629 self.assertEqual(start,
5630 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5631 self.assertEqual(data, atf2.props['data'].bytes)
5632
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005633 hash_node = atf2.FindNode('hash')
5634 self.assertIsNotNone(hash_node)
5635 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5636
5637 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5638 self.assertIsNotNone(hash_node)
5639 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5640
Simon Glass5f423422022-03-05 20:19:12 -07005641 conf = dtb.GetNode('/configurations')
5642 self.assertEqual({'default'}, conf.props.keys())
5643
5644 for subnode in conf.subnodes:
5645 self.assertEqual({'description', 'fdt', 'loadables'},
5646 subnode.props.keys())
5647 self.assertEqual(
5648 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5649 fdt_util.GetStringList(subnode, 'loadables'))
5650
5651 def _check_bad_fit(self, dts):
5652 """Check a bad FIT
5653
5654 This runs with the given dts and returns the assertion raised
5655
5656 Args:
5657 dts (str): dts filename to use
5658
5659 Returns:
5660 str: Assertion string raised
5661 """
5662 entry_args = {
5663 'of-list': 'test-fdt1 test-fdt2',
5664 'default-dt': 'test-fdt2',
5665 'atf-bl31-path': 'bl31.elf',
5666 'tee-os-path': 'tee.elf',
5667 }
5668 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5669 with self.assertRaises(ValueError) as exc:
5670 self._DoReadFileDtb(dts, entry_args=entry_args,
5671 extra_indirs=[test_subdir])[0]
5672 return str(exc.exception)
5673
5674 def testFitSplitElfBadElf(self):
5675 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005676 if not elf.ELF_TOOLS:
5677 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005678 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5679 entry_args = {
5680 'of-list': 'test-fdt1 test-fdt2',
5681 'default-dt': 'test-fdt2',
5682 'atf-bl31-path': 'bad.elf',
5683 'tee-os-path': 'tee.elf',
5684 }
5685 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5686 with self.assertRaises(ValueError) as exc:
5687 self._DoReadFileDtb(
5688 '226_fit_split_elf.dts',
5689 entry_args=entry_args,
5690 extra_indirs=[test_subdir])[0]
5691 self.assertIn(
5692 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5693 str(exc.exception))
5694
Simon Glass5f423422022-03-05 20:19:12 -07005695 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005696 """Test an split-elf FIT with a missing ELF file
5697
5698 Args:
5699 kwargs (dict of str): Arguments to pass to _DoTestFile()
5700
5701 Returns:
5702 tuple:
5703 str: stdout result
5704 str: stderr result
5705 """
Simon Glass5f423422022-03-05 20:19:12 -07005706 entry_args = {
5707 'of-list': 'test-fdt1 test-fdt2',
5708 'default-dt': 'test-fdt2',
5709 'atf-bl31-path': 'bl31.elf',
5710 'tee-os-path': 'missing.elf',
5711 }
5712 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5713 with test_util.capture_sys_output() as (stdout, stderr):
5714 self._DoTestFile(
5715 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005716 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5717 out = stdout.getvalue()
5718 err = stderr.getvalue()
5719 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005720
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005721 def testFitSplitElfBadDirective(self):
5722 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5723 if not elf.ELF_TOOLS:
5724 self.skipTest('Python elftools not available')
5725 err = self._check_bad_fit('227_fit_bad_dir.dts')
5726 self.assertIn(
5727 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5728 err)
5729
5730 def testFitSplitElfBadDirectiveConfig(self):
5731 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5732 if not elf.ELF_TOOLS:
5733 self.skipTest('Python elftools not available')
5734 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5735 self.assertEqual(
5736 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5737 err)
5738
5739
Simon Glass5f423422022-03-05 20:19:12 -07005740 def testFitSplitElfMissing(self):
5741 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005742 if not elf.ELF_TOOLS:
5743 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005744 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005745 self.assertRegex(
5746 err,
5747 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005748 self.assertNotRegex(out, '.*Faked blob.*')
5749 fname = tools.get_output_filename('binman-fake/missing.elf')
5750 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005751
5752 def testFitSplitElfFaked(self):
5753 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005754 if not elf.ELF_TOOLS:
5755 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005756 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005757 self.assertRegex(
5758 err,
5759 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005760 self.assertRegex(
5761 out,
5762 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5763 fname = tools.get_output_filename('binman-fake/missing.elf')
5764 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005765
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005766 def testMkimageMissingBlob(self):
5767 """Test using mkimage to build an image"""
5768 with test_util.capture_sys_output() as (stdout, stderr):
5769 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5770 allow_fake_blobs=True)
5771 err = stderr.getvalue()
5772 self.assertRegex(
5773 err,
5774 "Image '.*' has faked external blobs and is non-functional: .*")
5775
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005776 def testPreLoad(self):
5777 """Test an image with a pre-load header"""
5778 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005779 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005780 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005781 data = self._DoReadFileDtb(
5782 '230_pre_load.dts', entry_args=entry_args,
5783 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005784 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5785 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5786 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Simon Glasse2dfb962023-07-24 09:19:57 -06005787
5788 def testPreLoadNoKey(self):
5789 """Test an image with a pre-load heade0r with missing key"""
5790 with self.assertRaises(FileNotFoundError) as exc:
5791 self._DoReadFile('230_pre_load.dts')
5792 self.assertIn("No such file or directory: 'dev.key'",
5793 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005794
5795 def testPreLoadPkcs(self):
5796 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005797 entry_args = {
5798 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5799 }
5800 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5801 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005802 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5803 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5804 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5805
5806 def testPreLoadPss(self):
5807 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005808 entry_args = {
5809 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5810 }
5811 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5812 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005813 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5814 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5815 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5816
5817 def testPreLoadInvalidPadding(self):
5818 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005819 entry_args = {
5820 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5821 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005822 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005823 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5824 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005825
5826 def testPreLoadInvalidSha(self):
5827 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005828 entry_args = {
5829 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5830 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005831 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005832 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5833 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005834
5835 def testPreLoadInvalidAlgo(self):
5836 """Test an image with a pre-load header with an invalid algo"""
5837 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005838 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005839
5840 def testPreLoadInvalidKey(self):
5841 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005842 entry_args = {
5843 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5844 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005845 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005846 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5847 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005848
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005849 def _CheckSafeUniqueNames(self, *images):
5850 """Check all entries of given images for unsafe unique names"""
5851 for image in images:
5852 entries = {}
5853 image._CollectEntries(entries, {}, image)
5854 for entry in entries.values():
5855 uniq = entry.GetUniqueName()
5856
5857 # Used as part of a filename, so must not be absolute paths.
5858 self.assertFalse(os.path.isabs(uniq))
5859
5860 def testSafeUniqueNames(self):
5861 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005862 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005863
5864 orig_image = control.images['image']
5865 image_fname = tools.get_output_filename('image.bin')
5866 image = Image.FromFile(image_fname)
5867
5868 self._CheckSafeUniqueNames(orig_image, image)
5869
5870 def testSafeUniqueNamesMulti(self):
5871 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005872 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005873
5874 orig_image = control.images['image']
5875 image_fname = tools.get_output_filename('image.bin')
5876 image = Image.FromFile(image_fname)
5877
5878 self._CheckSafeUniqueNames(orig_image, image)
5879
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005880 def testReplaceCmdWithBintool(self):
5881 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005882 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005883 expected = U_BOOT_DATA + b'aa'
5884 self.assertEqual(expected, data[:len(expected)])
5885
5886 try:
5887 tmpdir, updated_fname = self._SetupImageInTmpdir()
5888 fname = os.path.join(tmpdir, 'update-testing.bin')
5889 tools.write_file(fname, b'zz')
5890 self._DoBinman('replace', '-i', updated_fname,
5891 '_testing', '-f', fname)
5892
5893 data = tools.read_file(updated_fname)
5894 expected = U_BOOT_DATA + b'zz'
5895 self.assertEqual(expected, data[:len(expected)])
5896 finally:
5897 shutil.rmtree(tmpdir)
5898
5899 def testReplaceCmdOtherWithBintool(self):
5900 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005901 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005902 expected = U_BOOT_DATA + b'aa'
5903 self.assertEqual(expected, data[:len(expected)])
5904
5905 try:
5906 tmpdir, updated_fname = self._SetupImageInTmpdir()
5907 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5908 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5909 self._DoBinman('replace', '-i', updated_fname,
5910 'u-boot', '-f', fname)
5911
5912 data = tools.read_file(updated_fname)
5913 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5914 self.assertEqual(expected, data[:len(expected)])
5915 finally:
5916 shutil.rmtree(tmpdir)
5917
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005918 def testReplaceResizeNoRepackSameSize(self):
5919 """Test replacing entries with same-size data without repacking"""
5920 expected = b'x' * len(U_BOOT_DATA)
5921 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5922 self.assertEqual(expected, data)
5923
5924 path, fdtmap = state.GetFdtContents('fdtmap')
5925 self.assertIsNotNone(path)
5926 self.assertEqual(expected_fdtmap, fdtmap)
5927
5928 def testReplaceResizeNoRepackSmallerSize(self):
5929 """Test replacing entries with smaller-size data without repacking"""
5930 new_data = b'x'
5931 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5932 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5933 self.assertEqual(expected, data)
5934
5935 path, fdtmap = state.GetFdtContents('fdtmap')
5936 self.assertIsNotNone(path)
5937 self.assertEqual(expected_fdtmap, fdtmap)
5938
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005939 def testExtractFit(self):
5940 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005941 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005942 image_fname = tools.get_output_filename('image.bin')
5943
5944 fit_data = control.ReadEntry(image_fname, 'fit')
5945 fit = fdt.Fdt.FromData(fit_data)
5946 fit.Scan()
5947
5948 # Check subentry data inside the extracted fit
5949 for node_path, expected in [
5950 ('/images/kernel', U_BOOT_DATA),
5951 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5952 ('/images/scr-1', COMPRESS_DATA),
5953 ]:
5954 node = fit.GetNode(node_path)
5955 data = fit.GetProps(node)['data'].bytes
5956 self.assertEqual(expected, data)
5957
5958 def testExtractFitSubentries(self):
5959 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005960 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005961 image_fname = tools.get_output_filename('image.bin')
5962
5963 for entry_path, expected in [
5964 ('fit/kernel', U_BOOT_DATA),
5965 ('fit/kernel/u-boot', U_BOOT_DATA),
5966 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5967 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5968 ('fit/scr-1', COMPRESS_DATA),
5969 ('fit/scr-1/blob', COMPRESS_DATA),
5970 ]:
5971 data = control.ReadEntry(image_fname, entry_path)
5972 self.assertEqual(expected, data)
5973
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005974 def testReplaceFitSubentryLeafSameSize(self):
5975 """Test replacing a FIT leaf subentry with same-size data"""
5976 new_data = b'x' * len(U_BOOT_DATA)
5977 data, expected_fdtmap, _ = self._RunReplaceCmd(
5978 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005979 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005980 self.assertEqual(new_data, data)
5981
5982 path, fdtmap = state.GetFdtContents('fdtmap')
5983 self.assertIsNotNone(path)
5984 self.assertEqual(expected_fdtmap, fdtmap)
5985
5986 def testReplaceFitSubentryLeafBiggerSize(self):
5987 """Test replacing a FIT leaf subentry with bigger-size data"""
5988 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5989 data, expected_fdtmap, _ = self._RunReplaceCmd(
5990 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005991 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005992 self.assertEqual(new_data, data)
5993
5994 # Will be repacked, so fdtmap must change
5995 path, fdtmap = state.GetFdtContents('fdtmap')
5996 self.assertIsNotNone(path)
5997 self.assertNotEqual(expected_fdtmap, fdtmap)
5998
5999 def testReplaceFitSubentryLeafSmallerSize(self):
6000 """Test replacing a FIT leaf subentry with smaller-size data"""
6001 new_data = b'x'
6002 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
6003 data, expected_fdtmap, _ = self._RunReplaceCmd(
6004 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006005 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006006 self.assertEqual(expected, data)
6007
6008 path, fdtmap = state.GetFdtContents('fdtmap')
6009 self.assertIsNotNone(path)
6010 self.assertEqual(expected_fdtmap, fdtmap)
6011
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006012 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07006013 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006014 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07006015 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6016 new_data, dts='241_replace_section_simple.dts')
6017 self.assertEqual(new_data, data)
6018
6019 entries = image.GetEntries()
6020 self.assertIn('section', entries)
6021 entry = entries['section']
6022 self.assertEqual(len(new_data), entry.size)
6023
6024 def testReplaceSectionLarger(self):
6025 """Test replacing a simple section with larger data"""
6026 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6027 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6028 new_data, dts='241_replace_section_simple.dts')
6029 self.assertEqual(new_data, data)
6030
6031 entries = image.GetEntries()
6032 self.assertIn('section', entries)
6033 entry = entries['section']
6034 self.assertEqual(len(new_data), entry.size)
6035 fentry = entries['fdtmap']
6036 self.assertEqual(entry.offset + entry.size, fentry.offset)
6037
6038 def testReplaceSectionSmaller(self):
6039 """Test replacing a simple section with smaller data"""
6040 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
6041 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6042 new_data, dts='241_replace_section_simple.dts')
6043 self.assertEqual(new_data, data)
6044
6045 # The new size is the same as the old, just with a pad byte at the end
6046 entries = image.GetEntries()
6047 self.assertIn('section', entries)
6048 entry = entries['section']
6049 self.assertEqual(len(new_data), entry.size)
6050
6051 def testReplaceSectionSmallerAllow(self):
6052 """Test failing to replace a simple section with smaller data"""
6053 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
6054 try:
6055 state.SetAllowEntryContraction(True)
6056 with self.assertRaises(ValueError) as exc:
6057 self._RunReplaceCmd('section', new_data,
6058 dts='241_replace_section_simple.dts')
6059 finally:
6060 state.SetAllowEntryContraction(False)
6061
6062 # Since we have no information about the position of things within the
6063 # section, we cannot adjust the position of /section-u-boot so it ends
6064 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06006065 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07006066 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
6067 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06006068 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006069
Simon Glass8fbca772022-08-13 11:40:48 -06006070 def testMkimageImagename(self):
6071 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006072 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006073 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06006074
6075 # Check that the data appears in the file somewhere
6076 self.assertIn(U_BOOT_SPL_DATA, data)
6077
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006078 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06006079 name = data[0x20:0x40]
6080
6081 # Build the filename that we expect to be placed in there, by virtue of
6082 # the -n paraameter
6083 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6084
6085 # Check that the image name is set to the temporary filename used
6086 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6087
Simon Glassb1669752022-08-13 11:40:49 -06006088 def testMkimageImage(self):
6089 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006090 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006091 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006092
6093 # Check that the data appears in the file somewhere
6094 self.assertIn(U_BOOT_SPL_DATA, data)
6095
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006096 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006097 name = data[0x20:0x40]
6098
6099 # Build the filename that we expect to be placed in there, by virtue of
6100 # the -n paraameter
6101 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6102
6103 # Check that the image name is set to the temporary filename used
6104 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6105
6106 # Check the corect data is in the imagename file
6107 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6108
6109 def testMkimageImageNoContent(self):
6110 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006111 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006112 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006113 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006114 self.assertIn('Could not complete processing of contents',
6115 str(exc.exception))
6116
6117 def testMkimageImageBad(self):
6118 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006119 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006120 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006121 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006122 self.assertIn('Cannot use both imagename node and data-to-imagename',
6123 str(exc.exception))
6124
Simon Glassbd5cd882022-08-13 11:40:50 -06006125 def testCollectionOther(self):
6126 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006127 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006128 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6129 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6130 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6131 data)
6132
6133 def testMkimageCollection(self):
6134 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006135 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006136 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006137 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6138 self.assertEqual(expect, data[:len(expect)])
6139
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006140 def testCompressDtbPrependInvalid(self):
6141 """Test that invalid header is detected"""
6142 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006143 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006144 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6145 "'u-boot-dtb': 'invalid'", str(e.exception))
6146
6147 def testCompressDtbPrependLength(self):
6148 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006149 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006150 image = control.images['image']
6151 entries = image.GetEntries()
6152 self.assertIn('u-boot-dtb', entries)
6153 u_boot_dtb = entries['u-boot-dtb']
6154 self.assertIn('fdtmap', entries)
6155 fdtmap = entries['fdtmap']
6156
6157 image_fname = tools.get_output_filename('image.bin')
6158 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6159 dtb = fdt.Fdt.FromData(orig)
6160 dtb.Scan()
6161 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6162 expected = {
6163 'u-boot:size': len(U_BOOT_DATA),
6164 'u-boot-dtb:uncomp-size': len(orig),
6165 'u-boot-dtb:size': u_boot_dtb.size,
6166 'fdtmap:size': fdtmap.size,
6167 'size': len(data),
6168 }
6169 self.assertEqual(expected, props)
6170
6171 # Check implementation
6172 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6173 rest = data[len(U_BOOT_DATA):]
6174 comp_data_len = struct.unpack('<I', rest[:4])[0]
6175 comp_data = rest[4:4 + comp_data_len]
6176 orig2 = self._decompress(comp_data)
6177 self.assertEqual(orig, orig2)
6178
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006179 def testInvalidCompress(self):
6180 """Test that invalid compress algorithm is detected"""
6181 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006182 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006183 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6184
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006185 def testCompUtilCompressions(self):
6186 """Test compression algorithms"""
6187 for bintool in self.comp_bintools.values():
6188 self._CheckBintool(bintool)
6189 data = bintool.compress(COMPRESS_DATA)
6190 self.assertNotEqual(COMPRESS_DATA, data)
6191 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006192 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006193
6194 def testCompUtilVersions(self):
6195 """Test tool version of compression algorithms"""
6196 for bintool in self.comp_bintools.values():
6197 self._CheckBintool(bintool)
6198 version = bintool.version()
6199 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6200
6201 def testCompUtilPadding(self):
6202 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006203 # Skip zstd because it doesn't support padding
6204 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006205 self._CheckBintool(bintool)
6206 data = bintool.compress(COMPRESS_DATA)
6207 self.assertNotEqual(COMPRESS_DATA, data)
6208 data += tools.get_bytes(0, 64)
6209 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006210 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006211
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006212 def testCompressDtbZstd(self):
6213 """Test that zstd compress of device-tree files failed"""
6214 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006215 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006216 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6217 "requires a length header", str(e.exception))
6218
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006219 def testMkimageMultipleDataFiles(self):
6220 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006221 self._SetupSplElf()
6222 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006223 data = self._DoReadFile('252_mkimage_mult_data.dts')
6224 # Size of files are packed in their 4B big-endian format
6225 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6226 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6227 # Size info is always followed by a 4B zero value.
6228 expect += tools.get_bytes(0, 4)
6229 expect += U_BOOT_TPL_DATA
6230 # All but last files are 4B-aligned
6231 align_pad = len(U_BOOT_TPL_DATA) % 4
6232 if align_pad:
6233 expect += tools.get_bytes(0, align_pad)
6234 expect += U_BOOT_SPL_DATA
6235 self.assertEqual(expect, data[-len(expect):])
6236
Marek Vasutf7413f02023-07-18 07:23:58 -06006237 def testMkimageMultipleExpanded(self):
6238 """Test passing multiple files to mkimage in a mkimage entry"""
6239 self._SetupSplElf()
6240 self._SetupTplElf()
6241 entry_args = {
6242 'spl-bss-pad': 'y',
6243 'spl-dtb': 'y',
6244 }
6245 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6246 use_expanded=True, entry_args=entry_args)[0]
6247 pad_len = 10
6248 tpl_expect = U_BOOT_TPL_DATA
6249 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6250 spl_expect += U_BOOT_SPL_DTB_DATA
6251
6252 content = data[0x40:]
6253 lens = struct.unpack('>III', content[:12])
6254
6255 # Size of files are packed in their 4B big-endian format
6256 # Size info is always followed by a 4B zero value.
6257 self.assertEqual(len(tpl_expect), lens[0])
6258 self.assertEqual(len(spl_expect), lens[1])
6259 self.assertEqual(0, lens[2])
6260
6261 rest = content[12:]
6262 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6263
6264 rest = rest[len(tpl_expect):]
6265 align_pad = len(tpl_expect) % 4
6266 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6267 rest = rest[align_pad:]
6268 self.assertEqual(spl_expect, rest)
6269
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006270 def testMkimageMultipleNoContent(self):
6271 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006272 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006273 with self.assertRaises(ValueError) as exc:
6274 self._DoReadFile('253_mkimage_mult_no_content.dts')
6275 self.assertIn('Could not complete processing of contents',
6276 str(exc.exception))
6277
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006278 def testMkimageFilename(self):
6279 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006280 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006281 retcode = self._DoTestFile('254_mkimage_filename.dts')
6282 self.assertEqual(0, retcode)
6283 fname = tools.get_output_filename('mkimage-test.bin')
6284 self.assertTrue(os.path.exists(fname))
6285
Simon Glass56d05412022-02-28 07:16:54 -07006286 def testVpl(self):
6287 """Test that an image with VPL and its device tree can be created"""
6288 # ELF file with a '__bss_size' symbol
6289 self._SetupVplElf()
6290 data = self._DoReadFile('255_u_boot_vpl.dts')
6291 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6292
6293 def testVplNoDtb(self):
6294 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6295 self._SetupVplElf()
6296 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6297 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6298 data[:len(U_BOOT_VPL_NODTB_DATA)])
6299
6300 def testExpandedVpl(self):
6301 """Test that an expanded entry type is selected for TPL when needed"""
6302 self._SetupVplElf()
6303
6304 entry_args = {
6305 'vpl-bss-pad': 'y',
6306 'vpl-dtb': 'y',
6307 }
6308 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6309 entry_args=entry_args)
6310 image = control.images['image']
6311 entries = image.GetEntries()
6312 self.assertEqual(1, len(entries))
6313
6314 # We only have u-boot-vpl, which be expanded
6315 self.assertIn('u-boot-vpl', entries)
6316 entry = entries['u-boot-vpl']
6317 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6318 subent = entry.GetEntries()
6319 self.assertEqual(3, len(subent))
6320 self.assertIn('u-boot-vpl-nodtb', subent)
6321 self.assertIn('u-boot-vpl-bss-pad', subent)
6322 self.assertIn('u-boot-vpl-dtb', subent)
6323
6324 def testVplBssPadMissing(self):
6325 """Test that a missing symbol is detected"""
6326 self._SetupVplElf('u_boot_ucode_ptr')
6327 with self.assertRaises(ValueError) as e:
6328 self._DoReadFile('258_vpl_bss_pad.dts')
6329 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6330 str(e.exception))
6331
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306332 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306333 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306334 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6335 self.assertEqual(0, retcode)
6336 image = control.images['test_image']
6337 fname = tools.get_output_filename('test_image.bin')
6338 sname = tools.get_output_filename('symlink_to_test.bin')
6339 self.assertTrue(os.path.islink(sname))
6340 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006341
Andrew Davis6b463da2023-07-22 00:14:44 +05306342 def testSymlinkOverwrite(self):
6343 """Test that symlinked images can be overwritten"""
6344 testdir = TestFunctional._MakeInputDir('symlinktest')
6345 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6346 # build the same image again in the same directory so that existing symlink is present
6347 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6348 fname = tools.get_output_filename('test_image.bin')
6349 sname = tools.get_output_filename('symlink_to_test.bin')
6350 self.assertTrue(os.path.islink(sname))
6351 self.assertEqual(os.readlink(sname), fname)
6352
Simon Glass37f85de2022-10-20 18:22:47 -06006353 def testSymbolsElf(self):
6354 """Test binman can assign symbols embedded in an ELF file"""
6355 if not elf.ELF_TOOLS:
6356 self.skipTest('Python elftools not available')
6357 self._SetupTplElf('u_boot_binman_syms')
6358 self._SetupVplElf('u_boot_binman_syms')
6359 self._SetupSplElf('u_boot_binman_syms')
6360 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6361 image_fname = tools.get_output_filename('image.bin')
6362
6363 image = control.images['image']
6364 entries = image.GetEntries()
6365
6366 for entry in entries.values():
6367 # No symbols in u-boot and it has faked contents anyway
6368 if entry.name == 'u-boot':
6369 continue
6370 edata = data[entry.image_pos:entry.image_pos + entry.size]
6371 efname = tools.get_output_filename(f'edata-{entry.name}')
6372 tools.write_file(efname, edata)
6373
6374 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6375 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6376 for name, sym in syms.items():
6377 msg = 'test'
6378 val = elf.GetSymbolValue(sym, edata, msg)
6379 entry_m = re_name.match(name)
6380 if entry_m:
6381 ename, prop = entry_m.group(1), entry_m.group(3)
6382 entry, entry_name, prop_name = image.LookupEntry(entries,
6383 name, msg)
6384 if prop_name == 'offset':
6385 expect_val = entry.offset
6386 elif prop_name == 'image_pos':
6387 expect_val = entry.image_pos
6388 elif prop_name == 'size':
6389 expect_val = entry.size
6390 self.assertEqual(expect_val, val)
6391
6392 def testSymbolsElfBad(self):
6393 """Check error when trying to write symbols without the elftools lib"""
6394 if not elf.ELF_TOOLS:
6395 self.skipTest('Python elftools not available')
6396 self._SetupTplElf('u_boot_binman_syms')
6397 self._SetupVplElf('u_boot_binman_syms')
6398 self._SetupSplElf('u_boot_binman_syms')
6399 try:
6400 elf.ELF_TOOLS = False
6401 with self.assertRaises(ValueError) as exc:
6402 self._DoReadFileDtb('260_symbols_elf.dts')
6403 finally:
6404 elf.ELF_TOOLS = True
6405 self.assertIn(
6406 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6407 'Cannot write symbols to an ELF file without Python elftools',
6408 str(exc.exception))
6409
Simon Glassde244162023-01-07 14:07:08 -07006410 def testSectionFilename(self):
6411 """Check writing of section contents to a file"""
6412 data = self._DoReadFile('261_section_fname.dts')
6413 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6414 tools.get_bytes(ord('!'), 7) +
6415 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6416 self.assertEqual(expected, data)
6417
6418 sect_fname = tools.get_output_filename('outfile.bin')
6419 self.assertTrue(os.path.exists(sect_fname))
6420 sect_data = tools.read_file(sect_fname)
6421 self.assertEqual(U_BOOT_DATA, sect_data)
6422
Simon Glass1e9e61c2023-01-07 14:07:12 -07006423 def testAbsent(self):
6424 """Check handling of absent entries"""
6425 data = self._DoReadFile('262_absent.dts')
6426 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6427
Simon Glassad5cfe12023-01-07 14:07:14 -07006428 def testPackTeeOsOptional(self):
6429 """Test that an image with an optional TEE binary can be created"""
6430 entry_args = {
6431 'tee-os-path': 'tee.elf',
6432 }
6433 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6434 entry_args=entry_args)[0]
6435 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6436
6437 def checkFitTee(self, dts, tee_fname):
6438 """Check that a tee-os entry works and returns data
6439
6440 Args:
6441 dts (str): Device tree filename to use
6442 tee_fname (str): filename containing tee-os
6443
6444 Returns:
6445 bytes: Image contents
6446 """
6447 if not elf.ELF_TOOLS:
6448 self.skipTest('Python elftools not available')
6449 entry_args = {
6450 'of-list': 'test-fdt1 test-fdt2',
6451 'default-dt': 'test-fdt2',
6452 'tee-os-path': tee_fname,
6453 }
6454 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6455 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6456 extra_indirs=[test_subdir])[0]
6457 return data
6458
6459 def testFitTeeOsOptionalFit(self):
6460 """Test an image with a FIT with an optional OP-TEE binary"""
6461 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6462
6463 # There should be only one node, holding the data set up in SetUpClass()
6464 # for tee.bin
6465 dtb = fdt.Fdt.FromData(data)
6466 dtb.Scan()
6467 node = dtb.GetNode('/images/tee-1')
6468 self.assertEqual(TEE_ADDR,
6469 fdt_util.fdt32_to_cpu(node.props['load'].value))
6470 self.assertEqual(TEE_ADDR,
6471 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6472 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6473
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006474 with test_util.capture_sys_output() as (stdout, stderr):
6475 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6476 err = stderr.getvalue()
6477 self.assertRegex(
6478 err,
6479 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6480
Simon Glassad5cfe12023-01-07 14:07:14 -07006481 def testFitTeeOsOptionalFitBad(self):
6482 """Test an image with a FIT with an optional OP-TEE binary"""
6483 with self.assertRaises(ValueError) as exc:
6484 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6485 self.assertIn(
6486 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6487 str(exc.exception))
6488
6489 def testFitTeeOsBad(self):
6490 """Test an OP-TEE binary with wrong formats"""
6491 self.make_tee_bin('tee.bad1', 123)
6492 with self.assertRaises(ValueError) as exc:
6493 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6494 self.assertIn(
6495 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6496 str(exc.exception))
6497
6498 self.make_tee_bin('tee.bad2', 0, b'extra data')
6499 with self.assertRaises(ValueError) as exc:
6500 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6501 self.assertIn(
6502 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6503 str(exc.exception))
6504
Simon Glass63328f12023-01-07 14:07:15 -07006505 def testExtblobOptional(self):
6506 """Test an image with an external blob that is optional"""
6507 with test_util.capture_sys_output() as (stdout, stderr):
6508 data = self._DoReadFile('266_blob_ext_opt.dts')
6509 self.assertEqual(REFCODE_DATA, data)
6510 err = stderr.getvalue()
6511 self.assertRegex(
6512 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006513 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006514
Simon Glass7447a9d2023-01-11 16:10:12 -07006515 def testSectionInner(self):
6516 """Test an inner section with a size"""
6517 data = self._DoReadFile('267_section_inner.dts')
6518 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6519 self.assertEqual(expected, data)
6520
Simon Glassa4948b22023-01-11 16:10:14 -07006521 def testNull(self):
6522 """Test an image with a null entry"""
6523 data = self._DoReadFile('268_null.dts')
6524 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6525
Simon Glassf1ee03b2023-01-11 16:10:16 -07006526 def testOverlap(self):
6527 """Test an image with a overlapping entry"""
6528 data = self._DoReadFile('269_overlap.dts')
6529 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6530
6531 image = control.images['image']
6532 entries = image.GetEntries()
6533
6534 self.assertIn('inset', entries)
6535 inset = entries['inset']
6536 self.assertEqual(1, inset.offset);
6537 self.assertEqual(1, inset.image_pos);
6538 self.assertEqual(2, inset.size);
6539
6540 def testOverlapNull(self):
6541 """Test an image with a null overlap"""
6542 data = self._DoReadFile('270_overlap_null.dts')
6543 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6544
6545 # Check the FMAP
6546 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6547 self.assertEqual(4, fhdr.nareas)
6548 fiter = iter(fentries)
6549
6550 fentry = next(fiter)
6551 self.assertEqual(b'SECTION', fentry.name)
6552 self.assertEqual(0, fentry.offset)
6553 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6554 self.assertEqual(0, fentry.flags)
6555
6556 fentry = next(fiter)
6557 self.assertEqual(b'U_BOOT', fentry.name)
6558 self.assertEqual(0, fentry.offset)
6559 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6560 self.assertEqual(0, fentry.flags)
6561
6562 # Make sure that the NULL entry appears in the FMAP
6563 fentry = next(fiter)
6564 self.assertEqual(b'NULL', fentry.name)
6565 self.assertEqual(1, fentry.offset)
6566 self.assertEqual(2, fentry.size)
6567 self.assertEqual(0, fentry.flags)
6568
6569 fentry = next(fiter)
6570 self.assertEqual(b'FMAP', fentry.name)
6571 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6572
6573 def testOverlapBad(self):
6574 """Test an image with a bad overlapping entry"""
6575 with self.assertRaises(ValueError) as exc:
6576 self._DoReadFile('271_overlap_bad.dts')
6577 self.assertIn(
6578 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6579 str(exc.exception))
6580
6581 def testOverlapNoOffset(self):
6582 """Test an image with a bad overlapping entry"""
6583 with self.assertRaises(ValueError) as exc:
6584 self._DoReadFile('272_overlap_no_size.dts')
6585 self.assertIn(
6586 "Node '/binman/inset': 'fill' entry is missing properties: size",
6587 str(exc.exception))
6588
Simon Glasse0035c92023-01-11 16:10:17 -07006589 def testBlobSymbol(self):
6590 """Test a blob with symbols read from an ELF file"""
6591 elf_fname = self.ElfTestFile('blob_syms')
6592 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6593 TestFunctional._MakeInputFile('blob_syms.bin',
6594 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6595
6596 data = self._DoReadFile('273_blob_symbol.dts')
6597
6598 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6599 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6600 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6601 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6602 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6603
6604 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6605 expected = sym_values
6606 self.assertEqual(expected, data[:len(expected)])
6607
Simon Glass49e9c002023-01-11 16:10:19 -07006608 def testOffsetFromElf(self):
6609 """Test a blob with symbols read from an ELF file"""
6610 elf_fname = self.ElfTestFile('blob_syms')
6611 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6612 TestFunctional._MakeInputFile('blob_syms.bin',
6613 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6614
6615 data = self._DoReadFile('274_offset_from_elf.dts')
6616
6617 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6618 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6619
6620 image = control.images['image']
6621 entries = image.GetEntries()
6622
6623 self.assertIn('inset', entries)
6624 inset = entries['inset']
6625
6626 self.assertEqual(base + 4, inset.offset);
6627 self.assertEqual(base + 4, inset.image_pos);
6628 self.assertEqual(4, inset.size);
6629
6630 self.assertIn('inset2', entries)
6631 inset = entries['inset2']
6632 self.assertEqual(base + 8, inset.offset);
6633 self.assertEqual(base + 8, inset.image_pos);
6634 self.assertEqual(4, inset.size);
6635
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006636 def testFitAlign(self):
6637 """Test an image with an FIT with aligned external data"""
6638 data = self._DoReadFile('275_fit_align.dts')
6639 self.assertEqual(4096, len(data))
6640
6641 dtb = fdt.Fdt.FromData(data)
6642 dtb.Scan()
6643
6644 props = self._GetPropTree(dtb, ['data-position'])
6645 expected = {
6646 'u-boot:data-position': 1024,
6647 'fdt-1:data-position': 2048,
6648 'fdt-2:data-position': 3072,
6649 }
6650 self.assertEqual(expected, props)
6651
Jonas Karlman490f73c2023-01-21 19:02:12 +00006652 def testFitFirmwareLoadables(self):
6653 """Test an image with an FIT that use fit,firmware"""
6654 if not elf.ELF_TOOLS:
6655 self.skipTest('Python elftools not available')
6656 entry_args = {
6657 'of-list': 'test-fdt1',
6658 'default-dt': 'test-fdt1',
6659 'atf-bl31-path': 'bl31.elf',
6660 'tee-os-path': 'missing.bin',
6661 }
6662 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006663 with test_util.capture_sys_output() as (stdout, stderr):
6664 data = self._DoReadFileDtb(
6665 '276_fit_firmware_loadables.dts',
6666 entry_args=entry_args,
6667 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006668
6669 dtb = fdt.Fdt.FromData(data)
6670 dtb.Scan()
6671
6672 node = dtb.GetNode('/configurations/conf-uboot-1')
6673 self.assertEqual('u-boot', node.props['firmware'].value)
6674 self.assertEqual(['atf-1', 'atf-2'],
6675 fdt_util.GetStringList(node, 'loadables'))
6676
6677 node = dtb.GetNode('/configurations/conf-atf-1')
6678 self.assertEqual('atf-1', node.props['firmware'].value)
6679 self.assertEqual(['u-boot', 'atf-2'],
6680 fdt_util.GetStringList(node, 'loadables'))
6681
6682 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6683 self.assertEqual('u-boot', node.props['firmware'].value)
6684 self.assertEqual(['atf-1', 'atf-2'],
6685 fdt_util.GetStringList(node, 'loadables'))
6686
6687 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6688 self.assertEqual('atf-1', node.props['firmware'].value)
6689 self.assertEqual(['u-boot', 'atf-2'],
6690 fdt_util.GetStringList(node, 'loadables'))
6691
6692 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6693 self.assertEqual('atf-1', node.props['firmware'].value)
6694 self.assertEqual(['u-boot', 'atf-2'],
6695 fdt_util.GetStringList(node, 'loadables'))
6696
Simon Glass9a1c7262023-02-22 12:14:49 -07006697 def testTooldir(self):
6698 """Test that we can specify the tooldir"""
6699 with test_util.capture_sys_output() as (stdout, stderr):
6700 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6701 'tool', '-l'))
6702 self.assertEqual('fred', bintool.Bintool.tooldir)
6703
6704 # Check that the toolpath is updated correctly
6705 self.assertEqual(['fred'], tools.tool_search_paths)
6706
6707 # Try with a few toolpaths; the tooldir should be at the end
6708 with test_util.capture_sys_output() as (stdout, stderr):
6709 self.assertEqual(0, self._DoBinman(
6710 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6711 'tool', '-l'))
6712 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6713
Simon Glass49b77e82023-03-02 17:02:44 -07006714 def testReplaceSectionEntry(self):
6715 """Test replacing an entry in a section"""
6716 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6717 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6718 expect_data, dts='241_replace_section_simple.dts')
6719 self.assertEqual(expect_data, entry_data)
6720
6721 entries = image.GetEntries()
6722 self.assertIn('section', entries)
6723 section = entries['section']
6724
6725 sect_entries = section.GetEntries()
6726 self.assertIn('blob', sect_entries)
6727 entry = sect_entries['blob']
6728 self.assertEqual(len(expect_data), entry.size)
6729
6730 fname = tools.get_output_filename('image-updated.bin')
6731 data = tools.read_file(fname)
6732
6733 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6734 self.assertEqual(expect_data, new_blob_data)
6735
6736 self.assertEqual(U_BOOT_DATA,
6737 data[entry.image_pos + len(expect_data):]
6738 [:len(U_BOOT_DATA)])
6739
6740 def testReplaceSectionDeep(self):
6741 """Test replacing an entry in two levels of sections"""
6742 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6743 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6744 'section/section/blob', expect_data,
6745 dts='278_replace_section_deep.dts')
6746 self.assertEqual(expect_data, entry_data)
6747
6748 entries = image.GetEntries()
6749 self.assertIn('section', entries)
6750 section = entries['section']
6751
6752 subentries = section.GetEntries()
6753 self.assertIn('section', subentries)
6754 section = subentries['section']
6755
6756 sect_entries = section.GetEntries()
6757 self.assertIn('blob', sect_entries)
6758 entry = sect_entries['blob']
6759 self.assertEqual(len(expect_data), entry.size)
6760
6761 fname = tools.get_output_filename('image-updated.bin')
6762 data = tools.read_file(fname)
6763
6764 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6765 self.assertEqual(expect_data, new_blob_data)
6766
6767 self.assertEqual(U_BOOT_DATA,
6768 data[entry.image_pos + len(expect_data):]
6769 [:len(U_BOOT_DATA)])
6770
6771 def testReplaceFitSibling(self):
6772 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006773 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006774 fname = TestFunctional._MakeInputFile('once', b'available once')
6775 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6776 os.remove(fname)
6777
6778 try:
6779 tmpdir, updated_fname = self._SetupImageInTmpdir()
6780
6781 fname = os.path.join(tmpdir, 'update-blob')
6782 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6783 tools.write_file(fname, expected)
6784
6785 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6786 data = tools.read_file(updated_fname)
6787 start = len(U_BOOT_DTB_DATA)
6788 self.assertEqual(expected, data[start:start + len(expected)])
6789 map_fname = os.path.join(tmpdir, 'image-updated.map')
6790 self.assertFalse(os.path.exists(map_fname))
6791 finally:
6792 shutil.rmtree(tmpdir)
6793
Simon Glassc3fe97f2023-03-02 17:02:45 -07006794 def testX509Cert(self):
6795 """Test creating an X509 certificate"""
6796 keyfile = self.TestFile('key.key')
6797 entry_args = {
6798 'keyfile': keyfile,
6799 }
6800 data = self._DoReadFileDtb('279_x509_cert.dts',
6801 entry_args=entry_args)[0]
6802 cert = data[:-4]
6803 self.assertEqual(U_BOOT_DATA, data[-4:])
6804
6805 # TODO: verify the signature
6806
6807 def testX509CertMissing(self):
6808 """Test that binman still produces an image if openssl is missing"""
6809 keyfile = self.TestFile('key.key')
6810 entry_args = {
6811 'keyfile': 'keyfile',
6812 }
6813 with test_util.capture_sys_output() as (_, stderr):
6814 self._DoTestFile('279_x509_cert.dts',
6815 force_missing_bintools='openssl',
6816 entry_args=entry_args)
6817 err = stderr.getvalue()
6818 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6819
Jonas Karlman35305492023-02-25 19:01:33 +00006820 def testPackRockchipTpl(self):
6821 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006822 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006823 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6824
Jonas Karlman1016ec72023-02-25 19:01:35 +00006825 def testMkimageMissingBlobMultiple(self):
6826 """Test missing blob with mkimage entry and multiple-data-files"""
6827 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006828 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006829 err = stderr.getvalue()
6830 self.assertIn("is missing external blobs and is non-functional", err)
6831
6832 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006833 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006834 self.assertIn("not found in input path", str(e.exception))
6835
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006836 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6837 """Prepare sign environment
6838
6839 Create private and public keys, add pubkey into dtb.
6840
6841 Returns:
6842 Tuple:
6843 FIT container
6844 Image name
6845 Private key
6846 DTB
6847 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006848 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006849 data = self._DoReadFileRealDtb(dts)
6850 updated_fname = tools.get_output_filename('image-updated.bin')
6851 tools.write_file(updated_fname, data)
6852 dtb = tools.get_output_filename('source.dtb')
6853 private_key = tools.get_output_filename('test_key.key')
6854 public_key = tools.get_output_filename('test_key.crt')
6855 fit = tools.get_output_filename('fit.fit')
6856 key_dir = tools.get_output_dir()
6857
6858 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6859 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6860 private_key, '-out', public_key)
6861 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6862 '-n', 'test_key', '-r', 'conf', dtb)
6863
6864 return fit, updated_fname, private_key, dtb
6865
6866 def testSignSimple(self):
6867 """Test that a FIT container can be signed in image"""
6868 is_signed = False
6869 fit, fname, private_key, dtb = self._PrepareSignEnv()
6870
6871 # do sign with private key
6872 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6873 ['fit'])
6874 is_signed = self._CheckSign(fit, dtb)
6875
6876 self.assertEqual(is_signed, True)
6877
6878 def testSignExactFIT(self):
6879 """Test that a FIT container can be signed and replaced in image"""
6880 is_signed = False
6881 fit, fname, private_key, dtb = self._PrepareSignEnv()
6882
6883 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6884 args = []
6885 if self.toolpath:
6886 for path in self.toolpath:
6887 args += ['--toolpath', path]
6888
6889 # do sign with private key
6890 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6891 'sha256,rsa4096', '-f', fit, 'fit')
6892 is_signed = self._CheckSign(fit, dtb)
6893
6894 self.assertEqual(is_signed, True)
6895
6896 def testSignNonFit(self):
6897 """Test a non-FIT entry cannot be signed"""
6898 is_signed = False
6899 fit, fname, private_key, _ = self._PrepareSignEnv(
6900 '281_sign_non_fit.dts')
6901
6902 # do sign with private key
6903 with self.assertRaises(ValueError) as e:
6904 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6905 'sha256,rsa4096', '-f', fit, 'u-boot')
6906 self.assertIn(
6907 "Node '/u-boot': Updating signatures is not supported with this entry type",
6908 str(e.exception))
6909
6910 def testSignMissingMkimage(self):
6911 """Test that FIT signing handles a missing mkimage tool"""
6912 fit, fname, private_key, _ = self._PrepareSignEnv()
6913
6914 # try to sign with a missing mkimage tool
6915 bintool.Bintool.set_missing_list(['mkimage'])
6916 with self.assertRaises(ValueError) as e:
6917 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6918 ['fit'])
6919 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6920
Simon Glass4abf7842023-07-18 07:23:54 -06006921 def testSymbolNoWrite(self):
6922 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006923 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006924 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6925 no_write_symbols=True)
6926
6927 def testSymbolNoWriteExpanded(self):
6928 """Test disabling of symbol writing in expanded entries"""
6929 entry_args = {
6930 'spl-dtb': '1',
6931 }
6932 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6933 U_BOOT_SPL_DTB_DATA, 0x38,
6934 entry_args=entry_args, use_expanded=True,
6935 no_write_symbols=True)
6936
Marek Vasutf7413f02023-07-18 07:23:58 -06006937 def testMkimageSpecial(self):
6938 """Test mkimage ignores special hash-1 node"""
6939 data = self._DoReadFile('283_mkimage_special.dts')
6940
6941 # Just check that the data appears in the file somewhere
6942 self.assertIn(U_BOOT_DATA, data)
6943
Simon Glass2d94c422023-07-18 07:23:59 -06006944 def testFitFdtList(self):
6945 """Test an image with an FIT with the fit,fdt-list-val option"""
6946 entry_args = {
6947 'default-dt': 'test-fdt2',
6948 }
6949 data = self._DoReadFileDtb(
6950 '284_fit_fdt_list.dts',
6951 entry_args=entry_args,
6952 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6953 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6954 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6955
Simon Glass83b8bfe2023-07-18 07:24:01 -06006956 def testSplEmptyBss(self):
6957 """Test an expanded SPL with a zero-size BSS"""
6958 # ELF file with a '__bss_size' symbol
6959 self._SetupSplElf(src_fname='bss_data_zero')
6960
6961 entry_args = {
6962 'spl-bss-pad': 'y',
6963 'spl-dtb': 'y',
6964 }
6965 data = self._DoReadFileDtb('285_spl_expand.dts',
6966 use_expanded=True, entry_args=entry_args)[0]
6967
Simon Glassfc792842023-07-18 07:24:04 -06006968 def testTemplate(self):
6969 """Test using a template"""
6970 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6971 data = self._DoReadFile('286_template.dts')
6972 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6973 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6974 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6975
Simon Glass09490b02023-07-22 21:43:52 -06006976 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6977 self.assertTrue(os.path.exists(dtb_fname1))
6978 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6979 dtb.Scan()
6980 node1 = dtb.GetNode('/binman/template')
6981 self.assertTrue(node1)
6982 vga = dtb.GetNode('/binman/first/intel-vga')
6983 self.assertTrue(vga)
6984
Simon Glass54825e12023-07-22 21:43:56 -06006985 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6986 self.assertTrue(os.path.exists(dtb_fname2))
6987 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6988 dtb2.Scan()
6989 node2 = dtb2.GetNode('/binman/template')
6990 self.assertFalse(node2)
6991
Simon Glass9909c112023-07-18 07:24:05 -06006992 def testTemplateBlobMulti(self):
6993 """Test using a template with 'multiple-images' enabled"""
6994 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6995 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6996 retcode = self._DoTestFile('287_template_multi.dts')
6997
6998 self.assertEqual(0, retcode)
6999 image = control.images['image']
7000 image_fname = tools.get_output_filename('my-image.bin')
7001 data = tools.read_file(image_fname)
7002 self.assertEqual(b'blob@@@@other', data)
7003
Simon Glass5dc511b2023-07-18 07:24:06 -06007004 def testTemplateFit(self):
7005 """Test using a template in a FIT"""
7006 fit_data = self._DoReadFile('288_template_fit.dts')
7007 fname = os.path.join(self._indir, 'fit_data.fit')
7008 tools.write_file(fname, fit_data)
7009 out = tools.run('dumpimage', '-l', fname)
7010
Simon Glassaa6e0552023-07-18 07:24:07 -06007011 def testTemplateSection(self):
7012 """Test using a template in a section (not at top level)"""
7013 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
7014 data = self._DoReadFile('289_template_section.dts')
7015 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
7016 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
7017 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
7018
Simon Glassf53a7bc2023-07-18 07:24:08 -06007019 def testMkimageSymbols(self):
7020 """Test using mkimage to build an image with symbols in it"""
7021 self._SetupSplElf('u_boot_binman_syms')
7022 data = self._DoReadFile('290_mkimage_sym.dts')
7023
7024 image = control.images['image']
7025 entries = image.GetEntries()
7026 self.assertIn('u-boot', entries)
7027 u_boot = entries['u-boot']
7028
7029 mkim = entries['mkimage']
7030 mkim_entries = mkim.GetEntries()
7031 self.assertIn('u-boot-spl', mkim_entries)
7032 spl = mkim_entries['u-boot-spl']
7033 self.assertIn('u-boot-spl2', mkim_entries)
7034 spl2 = mkim_entries['u-boot-spl2']
7035
7036 # skip the mkimage header and the area sizes
7037 mk_data = data[mkim.offset + 0x40:]
7038 size, term = struct.unpack('>LL', mk_data[:8])
7039
7040 # There should be only one image, so check that the zero terminator is
7041 # present
7042 self.assertEqual(0, term)
7043
7044 content = mk_data[8:8 + size]
7045
7046 # The image should contain the symbols from u_boot_binman_syms.c
7047 # Note that image_pos is adjusted by the base address of the image,
7048 # which is 0x10 in our test image
7049 spl_data = content[:0x18]
7050 content = content[0x1b:]
7051
7052 # After the header is a table of offsets for each image. There should
7053 # only be one image, then a 0 terminator, so figure out the real start
7054 # of the image data
7055 base = 0x40 + 8
7056
7057 # Check symbols in both u-boot-spl and u-boot-spl2
7058 for i in range(2):
7059 vals = struct.unpack('<LLQLL', spl_data)
7060
7061 # The image should contain the symbols from u_boot_binman_syms.c
7062 # Note that image_pos is adjusted by the base address of the image,
7063 # which is 0x10 in our 'u_boot_binman_syms' test image
7064 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
7065 self.assertEqual(base, vals[1])
7066 self.assertEqual(spl2.offset, vals[2])
7067 # figure out the internal positions of its components
7068 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
7069
7070 # Check that spl and spl2 are actually at the indicated positions
7071 self.assertEqual(
7072 elf.BINMAN_SYM_MAGIC_VALUE,
7073 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
7074 self.assertEqual(
7075 elf.BINMAN_SYM_MAGIC_VALUE,
7076 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
7077
7078 self.assertEqual(len(U_BOOT_DATA), vals[4])
7079
7080 # Move to next
7081 spl_data = content[:0x18]
7082
Simon Glass86b3e472023-07-22 21:43:57 -06007083 def testTemplatePhandle(self):
7084 """Test using a template in a node containing a phandle"""
7085 entry_args = {
7086 'atf-bl31-path': 'bl31.elf',
7087 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06007088 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007089 entry_args=entry_args)
7090 fname = tools.get_output_filename('image.bin')
7091 out = tools.run('dumpimage', '-l', fname)
7092
7093 # We should see the FIT description and one for each of the two images
7094 lines = out.splitlines()
7095 descs = [line.split()[-1] for line in lines if 'escription' in line]
7096 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7097
7098 def testTemplatePhandleDup(self):
7099 """Test using a template in a node containing a phandle"""
7100 entry_args = {
7101 'atf-bl31-path': 'bl31.elf',
7102 }
7103 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007104 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007105 entry_args=entry_args)
7106 self.assertIn(
7107 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7108 str(e.exception))
7109
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307110 def testTIBoardConfig(self):
7111 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007112 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307113 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7114
Neha Malcom Francis8cd04512024-01-05 17:09:17 +05307115 def testTIBoardConfigLint(self):
7116 """Test that an incorrectly linted config file would generate error"""
7117 with self.assertRaises(ValueError) as e:
7118 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7119 self.assertIn("Yamllint error", str(e.exception))
7120
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307121 def testTIBoardConfigCombined(self):
7122 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007123 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307124 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7125 self.assertGreater(data, configlen_noheader)
7126
7127 def testTIBoardConfigNoDataType(self):
7128 """Test that error is thrown when data type is not supported"""
7129 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007130 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307131 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007132
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307133 def testPackTiSecure(self):
7134 """Test that an image with a TI secured binary can be created"""
7135 keyfile = self.TestFile('key.key')
7136 entry_args = {
7137 'keyfile': keyfile,
7138 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007139 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307140 entry_args=entry_args)[0]
7141 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7142
Manorit Chawdhry2e523b02023-12-29 16:16:27 +05307143 def testPackTiSecureFirewall(self):
7144 """Test that an image with a TI secured binary can be created"""
7145 keyfile = self.TestFile('key.key')
7146 entry_args = {
7147 'keyfile': keyfile,
7148 }
7149 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7150 entry_args=entry_args)[0]
7151 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7152 entry_args=entry_args)[0]
7153 self.assertGreater(len(data_firewall),len(data_no_firewall))
7154
7155 def testPackTiSecureFirewallMissingProperty(self):
7156 """Test that an image with a TI secured binary can be created"""
7157 keyfile = self.TestFile('key.key')
7158 entry_args = {
7159 'keyfile': keyfile,
7160 }
7161 with self.assertRaises(ValueError) as e:
7162 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7163 entry_args=entry_args)[0]
7164 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7165
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307166 def testPackTiSecureMissingTool(self):
7167 """Test that an image with a TI secured binary (non-functional) can be created
7168 when openssl is missing"""
7169 keyfile = self.TestFile('key.key')
7170 entry_args = {
7171 'keyfile': keyfile,
7172 }
7173 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007174 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307175 force_missing_bintools='openssl',
7176 entry_args=entry_args)
7177 err = stderr.getvalue()
7178 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7179
7180 def testPackTiSecureROM(self):
7181 """Test that a ROM image with a TI secured binary can be created"""
7182 keyfile = self.TestFile('key.key')
7183 entry_args = {
7184 'keyfile': keyfile,
7185 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007186 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307187 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007188 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307189 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007190 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307191 entry_args=entry_args)[0]
7192 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7193 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7194 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7195
7196 def testPackTiSecureROMCombined(self):
7197 """Test that a ROM image with a TI secured binary can be created"""
7198 keyfile = self.TestFile('key.key')
7199 entry_args = {
7200 'keyfile': keyfile,
7201 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007202 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307203 entry_args=entry_args)[0]
7204 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7205
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007206 def testEncryptedNoAlgo(self):
7207 """Test encrypted node with missing required properties"""
7208 with self.assertRaises(ValueError) as e:
7209 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7210 self.assertIn(
7211 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7212 str(e.exception))
7213
7214 def testEncryptedInvalidIvfile(self):
7215 """Test encrypted node with invalid iv file"""
7216 with self.assertRaises(ValueError) as e:
7217 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7218 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7219 str(e.exception))
7220
7221 def testEncryptedMissingKey(self):
7222 """Test encrypted node with missing key properties"""
7223 with self.assertRaises(ValueError) as e:
7224 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7225 self.assertIn(
7226 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7227 str(e.exception))
7228
7229 def testEncryptedKeySource(self):
7230 """Test encrypted node with key-source property"""
7231 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7232
7233 dtb = fdt.Fdt.FromData(data)
7234 dtb.Scan()
7235
7236 node = dtb.GetNode('/images/u-boot/cipher')
7237 self.assertEqual('algo-name', node.props['algo'].value)
7238 self.assertEqual('key-source-value', node.props['key-source'].value)
7239 self.assertEqual(ENCRYPTED_IV_DATA,
7240 tools.to_bytes(''.join(node.props['iv'].value)))
7241 self.assertNotIn('key', node.props)
7242
7243 def testEncryptedKeyFile(self):
7244 """Test encrypted node with key-filename property"""
7245 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7246
7247 dtb = fdt.Fdt.FromData(data)
7248 dtb.Scan()
7249
7250 node = dtb.GetNode('/images/u-boot/cipher')
7251 self.assertEqual('algo-name', node.props['algo'].value)
7252 self.assertEqual(ENCRYPTED_IV_DATA,
7253 tools.to_bytes(''.join(node.props['iv'].value)))
7254 self.assertEqual(ENCRYPTED_KEY_DATA,
7255 tools.to_bytes(''.join(node.props['key'].value)))
7256 self.assertNotIn('key-source', node.props)
7257
Lukas Funkee901faf2023-07-18 13:53:13 +02007258
7259 def testSplPubkeyDtb(self):
Simon Glass4b861272024-07-20 11:49:41 +01007260 """Test u_boot_spl_pubkey_dtb etype"""
7261 data = tools.read_file(self.TestFile("key.pem"))
7262 self._MakeInputFile("key.crt", data)
7263 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7264 image = control.images['image']
7265 entries = image.GetEntries()
7266 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7267 dtb_data = dtb_entry.GetData()
7268 dtb = fdt.Fdt.FromData(dtb_data)
7269 dtb.Scan()
Lukas Funkee901faf2023-07-18 13:53:13 +02007270
Simon Glass4b861272024-07-20 11:49:41 +01007271 signature_node = dtb.GetNode('/signature')
7272 self.assertIsNotNone(signature_node)
7273 key_node = signature_node.FindNode("key-key")
7274 self.assertIsNotNone(key_node)
7275 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7276 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7277 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007278
Lukas Funke712e1062023-08-03 17:22:14 +02007279 def testXilinxBootgenSigning(self):
7280 """Test xilinx-bootgen etype"""
7281 bootgen = bintool.Bintool.create('bootgen')
7282 self._CheckBintool(bootgen)
7283 data = tools.read_file(self.TestFile("key.key"))
7284 self._MakeInputFile("psk.pem", data)
7285 self._MakeInputFile("ssk.pem", data)
7286 self._SetupPmuFwlElf()
7287 self._SetupSplElf()
7288 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7289 image_fname = tools.get_output_filename('image.bin')
7290
7291 # Read partition header table and check if authentication is enabled
7292 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7293 "-read", image_fname, "pht").splitlines()
7294 attributes = {"authentication": None,
7295 "core": None,
7296 "encryption": None}
7297
7298 for l in bootgen_out:
7299 for a in attributes.keys():
7300 if a in l:
7301 m = re.match(fr".*{a} \[([^]]+)\]", l)
7302 attributes[a] = m.group(1)
7303
7304 self.assertTrue(attributes['authentication'] == "rsa")
7305 self.assertTrue(attributes['core'] == "a53-0")
7306 self.assertTrue(attributes['encryption'] == "no")
7307
7308 def testXilinxBootgenSigningEncryption(self):
7309 """Test xilinx-bootgen etype"""
7310 bootgen = bintool.Bintool.create('bootgen')
7311 self._CheckBintool(bootgen)
7312 data = tools.read_file(self.TestFile("key.key"))
7313 self._MakeInputFile("psk.pem", data)
7314 self._MakeInputFile("ssk.pem", data)
7315 self._SetupPmuFwlElf()
7316 self._SetupSplElf()
7317 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7318 image_fname = tools.get_output_filename('image.bin')
7319
7320 # Read boot header in order to verify encryption source and
7321 # encryption parameter
7322 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7323 "-read", image_fname, "bh").splitlines()
7324 attributes = {"auth_only":
7325 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7326 "encryption_keystore":
7327 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7328 "value": None},
7329 }
7330
7331 for l in bootgen_out:
7332 for a in attributes.keys():
7333 if a in l:
7334 m = re.match(attributes[a]['re'], l)
7335 attributes[a] = m.group(1)
7336
7337 # Check if fsbl-attribute is set correctly
7338 self.assertTrue(attributes['auth_only'] == "true")
7339 # Check if key is stored in efuse
7340 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7341
7342 def testXilinxBootgenMissing(self):
7343 """Test that binman still produces an image if bootgen is missing"""
7344 data = tools.read_file(self.TestFile("key.key"))
7345 self._MakeInputFile("psk.pem", data)
7346 self._MakeInputFile("ssk.pem", data)
7347 self._SetupPmuFwlElf()
7348 self._SetupSplElf()
7349 with test_util.capture_sys_output() as (_, stderr):
7350 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7351 force_missing_bintools='bootgen')
7352 err = stderr.getvalue()
7353 self.assertRegex(err,
7354 "Image 'image'.*missing bintools.*: bootgen")
7355
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307356 def _GetCapsuleHeaders(self, data):
7357 """Get the capsule header contents
7358
7359 Args:
7360 data: Capsule file contents
7361
7362 Returns:
7363 Dict:
7364 key: Capsule Header name (str)
7365 value: Header field value (str)
7366 """
7367 capsule_file = os.path.join(self._indir, 'test.capsule')
7368 tools.write_file(capsule_file, data)
7369
7370 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7371 lines = out.splitlines()
7372
7373 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7374 vals = {}
7375 for line in lines:
7376 mat = re_line.match(line)
7377 if mat:
7378 vals[mat.group(1)] = mat.group(2)
7379
7380 return vals
7381
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307382 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7383 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307384 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7385 fmp_size = "00000010"
7386 fmp_fw_version = "00000002"
7387 capsule_image_index = "00000001"
7388 oemflag = "00018000"
7389 auth_hdr_revision = "00000200"
7390 auth_hdr_cert_type = "00000EF1"
7391
7392 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307393
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307394 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307395
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307396 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307397
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307398 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7399 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7400 self.assertEqual(capsule_image_index,
7401 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307402
7403 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307404 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7405
7406 if signed_capsule:
7407 self.assertEqual(auth_hdr_revision,
7408 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7409 self.assertEqual(auth_hdr_cert_type,
7410 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7411 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7412 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7413
7414 if version_check:
7415 self.assertEqual(fmp_signature,
7416 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7417 self.assertEqual(fmp_size,
7418 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7419 self.assertEqual(fmp_fw_version,
7420 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7421
7422 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307423
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307424 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7425 if accept_capsule:
7426 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7427 else:
7428 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7429
7430 hdr = self._GetCapsuleHeaders(data)
7431
7432 self.assertEqual(capsule_hdr_guid.upper(),
7433 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7434
7435 if accept_capsule:
7436 capsule_size = "0000002C"
7437 else:
7438 capsule_size = "0000001C"
7439 self.assertEqual(capsule_size,
7440 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7441
7442 if accept_capsule:
7443 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7444
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307445 def testCapsuleGen(self):
7446 """Test generation of EFI capsule"""
7447 data = self._DoReadFile('311_capsule.dts')
7448
7449 self._CheckCapsule(data)
7450
7451 def testSignedCapsuleGen(self):
7452 """Test generation of EFI capsule"""
7453 data = tools.read_file(self.TestFile("key.key"))
7454 self._MakeInputFile("key.key", data)
7455 data = tools.read_file(self.TestFile("key.pem"))
7456 self._MakeInputFile("key.crt", data)
7457
7458 data = self._DoReadFile('312_capsule_signed.dts')
7459
7460 self._CheckCapsule(data, signed_capsule=True)
7461
7462 def testCapsuleGenVersionSupport(self):
7463 """Test generation of EFI capsule with version support"""
7464 data = self._DoReadFile('313_capsule_version.dts')
7465
7466 self._CheckCapsule(data, version_check=True)
7467
7468 def testCapsuleGenSignedVer(self):
7469 """Test generation of signed EFI capsule with version information"""
7470 data = tools.read_file(self.TestFile("key.key"))
7471 self._MakeInputFile("key.key", data)
7472 data = tools.read_file(self.TestFile("key.pem"))
7473 self._MakeInputFile("key.crt", data)
7474
7475 data = self._DoReadFile('314_capsule_signed_ver.dts')
7476
7477 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7478
7479 def testCapsuleGenCapOemFlags(self):
7480 """Test generation of EFI capsule with OEM Flags set"""
7481 data = self._DoReadFile('315_capsule_oemflags.dts')
7482
7483 self._CheckCapsule(data, capoemflags=True)
7484
7485 def testCapsuleGenKeyMissing(self):
7486 """Test that binman errors out on missing key"""
7487 with self.assertRaises(ValueError) as e:
7488 self._DoReadFile('316_capsule_missing_key.dts')
7489
7490 self.assertIn("Both private key and public key certificate need to be provided",
7491 str(e.exception))
7492
7493 def testCapsuleGenIndexMissing(self):
7494 """Test that binman errors out on missing image index"""
7495 with self.assertRaises(ValueError) as e:
7496 self._DoReadFile('317_capsule_missing_index.dts')
7497
7498 self.assertIn("entry is missing properties: image-index",
7499 str(e.exception))
7500
7501 def testCapsuleGenGuidMissing(self):
7502 """Test that binman errors out on missing image GUID"""
7503 with self.assertRaises(ValueError) as e:
7504 self._DoReadFile('318_capsule_missing_guid.dts')
7505
7506 self.assertIn("entry is missing properties: image-guid",
7507 str(e.exception))
7508
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307509 def testCapsuleGenAcceptCapsule(self):
7510 """Test generationg of accept EFI capsule"""
7511 data = self._DoReadFile('319_capsule_accept.dts')
7512
7513 self._CheckEmptyCapsule(data, accept_capsule=True)
7514
7515 def testCapsuleGenRevertCapsule(self):
7516 """Test generationg of revert EFI capsule"""
7517 data = self._DoReadFile('320_capsule_revert.dts')
7518
7519 self._CheckEmptyCapsule(data)
7520
7521 def testCapsuleGenAcceptGuidMissing(self):
7522 """Test that binman errors out on missing image GUID for accept capsule"""
7523 with self.assertRaises(ValueError) as e:
7524 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7525
7526 self.assertIn("Image GUID needed for generating accept capsule",
7527 str(e.exception))
7528
7529 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7530 """Test that capsule-type is specified"""
7531 with self.assertRaises(ValueError) as e:
7532 self._DoReadFile('322_empty_capsule_type_missing.dts')
7533
7534 self.assertIn("entry is missing properties: capsule-type",
7535 str(e.exception))
7536
7537 def testCapsuleGenAcceptOrRevertMissing(self):
7538 """Test that both accept and revert capsule are not specified"""
7539 with self.assertRaises(ValueError) as e:
7540 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7541
Simon Glassa360b8f2024-06-23 11:55:06 -06007542 def test_assume_size(self):
7543 """Test handling of the assume-size property for external blob"""
7544 with self.assertRaises(ValueError) as e:
7545 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7546 allow_fake_blobs=True)
7547 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7548 str(e.exception))
7549
7550 def test_assume_size_ok(self):
7551 """Test handling of the assume-size where it fits OK"""
7552 with test_util.capture_sys_output() as (stdout, stderr):
7553 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7554 allow_fake_blobs=True)
7555 err = stderr.getvalue()
7556 self.assertRegex(
7557 err,
7558 "Image '.*' has faked external blobs and is non-functional: .*")
7559
7560 def test_assume_size_no_fake(self):
7561 """Test handling of the assume-size where it fits OK"""
7562 with test_util.capture_sys_output() as (stdout, stderr):
7563 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7564 err = stderr.getvalue()
7565 self.assertRegex(
7566 err,
7567 "Image '.*' is missing external blobs and is non-functional: .*")
7568
Simon Glass5f7aadf2024-07-20 11:49:47 +01007569 def SetupAlternateDts(self):
7570 """Compile the .dts test files for alternative-fdt
7571
7572 Returns:
7573 tuple:
7574 str: Test directory created
7575 list of str: '.bin' files which we expect Binman to create
7576 """
7577 testdir = TestFunctional._MakeInputDir('dtb')
7578 dtb_list = []
7579 for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
7580 tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
7581 base = os.path.splitext(os.path.basename(fname))[0]
7582 dtb_list.append(base + '.bin')
7583 shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
7584
7585 return testdir, dtb_list
7586
Simon Glassf3598922024-07-20 11:49:45 +01007587 def CheckAlternates(self, dts, phase, xpl_data):
7588 """Run the test for the alterative-fdt etype
7589
7590 Args:
7591 dts (str): Devicetree file to process
7592 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7593 xpl_data (bytes): Expected data for the phase's binary
7594
7595 Returns:
7596 dict of .dtb files produced
7597 key: str filename
7598 value: Fdt object
7599 """
Simon Glass5f7aadf2024-07-20 11:49:47 +01007600 dtb_list = self.SetupAlternateDts()[1]
Simon Glassf3598922024-07-20 11:49:45 +01007601
7602 entry_args = {
7603 f'{phase}-dtb': '1',
7604 f'{phase}-bss-pad': 'y',
7605 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7606 }
7607 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7608 use_expanded=True, entry_args=entry_args)[0]
7609 self.assertEqual(xpl_data, data[:len(xpl_data)])
7610 rest = data[len(xpl_data):]
7611 pad_len = 10
7612 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7613
7614 # Check the dtb is using the test file
7615 dtb_data = rest[pad_len:]
7616 dtb = fdt.Fdt.FromData(dtb_data)
7617 dtb.Scan()
7618 fdt_size = dtb.GetFdtObj().totalsize()
7619 self.assertEqual('model-not-set',
7620 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7621
7622 pad_len = 10
7623
7624 # Check the other output files
7625 dtbs = {}
7626 for fname in dtb_list:
7627 pathname = tools.get_output_filename(fname)
7628 self.assertTrue(os.path.exists(pathname))
7629
7630 data = tools.read_file(pathname)
7631 self.assertEqual(xpl_data, data[:len(xpl_data)])
7632 rest = data[len(xpl_data):]
7633
7634 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7635 rest = rest[pad_len:]
7636
7637 dtb = fdt.Fdt.FromData(rest)
7638 dtb.Scan()
7639 dtbs[fname] = dtb
7640
7641 expected = 'one' if '1' in fname else 'two'
7642 self.assertEqual(f'u-boot,model-{expected}',
7643 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7644
7645 # Make sure the FDT is the same size as the 'main' one
7646 rest = rest[fdt_size:]
7647
7648 self.assertEqual(b'', rest)
7649 return dtbs
7650
7651 def testAlternatesFdt(self):
7652 """Test handling of alternates-fdt etype"""
7653 self._SetupTplElf()
7654 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7655 U_BOOT_TPL_NODTB_DATA)
7656 for dtb in dtbs.values():
7657 # Check for the node with the tag
7658 node = dtb.GetNode('/node')
7659 self.assertIsNotNone(node)
7660 self.assertEqual(5, len(node.props.keys()))
7661
7662 # Make sure the other node is still there
7663 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7664
7665 def testAlternatesFdtgrep(self):
7666 """Test handling of alternates-fdt etype using fdtgrep"""
7667 self._SetupTplElf()
7668 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7669 U_BOOT_TPL_NODTB_DATA)
7670 for dtb in dtbs.values():
7671 # Check for the node with the tag
7672 node = dtb.GetNode('/node')
7673 self.assertIsNotNone(node)
7674 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7675 node.props.keys())
7676
7677 # Make sure the other node is gone
7678 self.assertIsNone(dtb.GetNode('/node/other-node'))
7679
7680 def testAlternatesFdtgrepVpl(self):
7681 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7682 self._SetupVplElf()
7683 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7684 U_BOOT_VPL_NODTB_DATA)
7685
7686 def testAlternatesFdtgrepSpl(self):
7687 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7688 self._SetupSplElf()
7689 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7690 U_BOOT_SPL_NODTB_DATA)
7691
7692 def testAlternatesFdtgrepInval(self):
7693 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7694 self._SetupSplElf()
7695 with self.assertRaises(ValueError) as e:
7696 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7697 U_BOOT_SPL_NODTB_DATA)
7698 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7699 str(e.exception))
7700
Simon Glasscd2783e2024-07-20 11:49:46 +01007701 def testFitFdtListDir(self):
7702 """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
Simon Glass1bba8942024-08-26 13:11:34 -06007703 old_dir = os.getcwd()
7704 try:
7705 os.chdir(self._indir)
7706 self.CheckFitFdt('333_fit_fdt_dir.dts', False)
7707 finally:
7708 os.chdir(old_dir)
Simon Glasscd2783e2024-07-20 11:49:46 +01007709
Simon Glassd2a9d6e2024-08-26 13:11:37 -06007710 def testFitFdtListDirDefault(self):
7711 """Test an FIT fit,fdt-list-dir where the default DT in is a subdir"""
7712 old_dir = os.getcwd()
7713 try:
7714 os.chdir(self._indir)
7715 self.CheckFitFdt('333_fit_fdt_dir.dts', False,
7716 default_dt='rockchip/test-fdt2')
7717 finally:
7718 os.chdir(old_dir)
7719
Simon Glass5f7aadf2024-07-20 11:49:47 +01007720 def testFitFdtCompat(self):
7721 """Test an image with an FIT with compatible in the config nodes"""
7722 entry_args = {
7723 'of-list': 'model1 model2',
7724 'default-dt': 'model2',
7725 }
7726 testdir, dtb_list = self.SetupAlternateDts()
7727 data = self._DoReadFileDtb(
7728 '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
7729 entry_args=entry_args, extra_indirs=[testdir])[0]
7730
7731 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7732
7733 fit = fdt.Fdt.FromData(fit_data)
7734 fit.Scan()
7735
7736 cnode = fit.GetNode('/configurations')
7737 self.assertIn('default', cnode.props)
7738 self.assertEqual('config-2', cnode.props['default'].value)
7739
7740 for seq in range(1, 2):
7741 name = f'config-{seq}'
7742 fnode = fit.GetNode('/configurations/%s' % name)
7743 self.assertIsNotNone(fnode)
7744 self.assertIn('compatible', fnode.props.keys())
7745 expected = 'one' if seq == 1 else 'two'
7746 self.assertEqual(f'u-boot,model-{expected}',
7747 fnode.props['compatible'].value)
7748
Simon Glassa04b9942024-07-20 11:49:48 +01007749 def testFitFdtPhase(self):
7750 """Test an image with an FIT with fdt-phase in the fdt nodes"""
7751 phase = 'tpl'
7752 entry_args = {
7753 f'{phase}-dtb': '1',
7754 f'{phase}-bss-pad': 'y',
7755 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7756 'of-list': 'model1 model2',
7757 'default-dt': 'model2',
7758 }
7759 testdir, dtb_list = self.SetupAlternateDts()
7760 data = self._DoReadFileDtb(
7761 '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
7762 entry_args=entry_args, extra_indirs=[testdir])[0]
7763 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7764 fit = fdt.Fdt.FromData(fit_data)
7765 fit.Scan()
7766
7767 # Check that each FDT has only the expected properties for the phase
7768 for seq in range(1, 2):
7769 fnode = fit.GetNode(f'/images/fdt-{seq}')
7770 self.assertIsNotNone(fnode)
7771 dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
7772 dtb.Scan()
7773
7774 # Make sure that the 'bootph-pre-sram' tag in /node protects it from
7775 # removal
7776 node = dtb.GetNode('/node')
7777 self.assertIsNotNone(node)
7778 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7779 node.props.keys())
7780
7781 # Make sure the other node is gone
7782 self.assertIsNone(dtb.GetNode('/node/other-node'))
7783
Simon Glassb553e8a2024-08-26 13:11:29 -06007784 def testMkeficapsuleMissing(self):
7785 """Test that binman complains if mkeficapsule is missing"""
7786 with self.assertRaises(ValueError) as e:
7787 self._DoTestFile('311_capsule.dts',
7788 force_missing_bintools='mkeficapsule')
7789 self.assertIn("Node '/binman/efi-capsule': Missing tool: 'mkeficapsule'",
7790 str(e.exception))
7791
7792 def testMkeficapsuleMissingOk(self):
7793 """Test that binman deals with mkeficapsule being missing"""
7794 with test_util.capture_sys_output() as (stdout, stderr):
7795 ret = self._DoTestFile('311_capsule.dts',
7796 force_missing_bintools='mkeficapsule',
7797 allow_missing=True)
7798 self.assertEqual(103, ret)
7799 err = stderr.getvalue()
7800 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkeficapsule")
7801
Simon Glass4b0f4142024-08-26 13:11:40 -06007802 def testSymbolsBase(self):
7803 """Test handling of symbols-base"""
7804 self.checkSymbols('336_symbols_base.dts', U_BOOT_SPL_DATA, 0x1c,
7805 symbols_base=0)
7806
7807 def testSymbolsBaseExpanded(self):
7808 """Test handling of symbols-base with expanded entries"""
7809 entry_args = {
7810 'spl-dtb': '1',
7811 }
7812 self.checkSymbols('337_symbols_base_expand.dts', U_BOOT_SPL_NODTB_DATA +
7813 U_BOOT_SPL_DTB_DATA, 0x38,
7814 entry_args=entry_args, use_expanded=True,
7815 symbols_base=0)
7816
Simon Glass3eb30a42024-08-26 13:11:42 -06007817 def testSymbolsCompressed(self):
7818 """Test binman complains about symbols from a compressed section"""
7819 with test_util.capture_sys_output() as (stdout, stderr):
7820 self.checkSymbols('338_symbols_comp.dts', U_BOOT_SPL_DATA, None)
7821 out = stdout.getvalue()
7822 self.assertIn('Symbol-writing: no value for /binman/section/u-boot',
7823 out)
7824
Simon Glass9c25ef22024-08-26 13:11:43 -06007825 def testNxpImx8Image(self):
7826 """Test that binman can produce an iMX8 image"""
7827 self._DoTestFile('339_nxp_imx8.dts')
7828
Alexander Kochetkova730a282024-09-16 11:24:46 +03007829 def testFitSignSimple(self):
7830 """Test that image with FIT and signature nodes can be signed"""
7831 if not elf.ELF_TOOLS:
7832 self.skipTest('Python elftools not available')
7833 entry_args = {
7834 'of-list': 'test-fdt1',
7835 'default-dt': 'test-fdt1',
7836 'atf-bl31-path': 'bl31.elf',
7837 }
7838 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7839 self._MakeInputFile("keys/rsa2048.key", data)
7840
7841 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7842 keys_subdir = os.path.join(self._indir, "keys")
7843 data = self._DoReadFileDtb(
7844 '340_fit_signature.dts',
7845 entry_args=entry_args,
7846 extra_indirs=[test_subdir, keys_subdir])[0]
7847
7848 dtb = fdt.Fdt.FromData(data)
7849 dtb.Scan()
7850
7851 conf = dtb.GetNode('/configurations/conf-uboot-1')
7852 self.assertIsNotNone(conf)
7853 signature = conf.FindNode('signature')
7854 self.assertIsNotNone(signature)
7855 self.assertIsNotNone(signature.props.get('value'))
7856
7857 images = dtb.GetNode('/images')
7858 self.assertIsNotNone(images)
7859 for subnode in images.subnodes:
7860 signature = subnode.FindNode('signature')
7861 self.assertIsNotNone(signature)
7862 self.assertIsNotNone(signature.props.get('value'))
7863
7864 def testFitSignKeyNotFound(self):
7865 """Test that missing keys raise an error"""
7866 if not elf.ELF_TOOLS:
7867 self.skipTest('Python elftools not available')
7868 entry_args = {
7869 'of-list': 'test-fdt1',
7870 'default-dt': 'test-fdt1',
7871 'atf-bl31-path': 'bl31.elf',
7872 }
7873 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7874 with self.assertRaises(ValueError) as e:
7875 self._DoReadFileDtb(
7876 '340_fit_signature.dts',
7877 entry_args=entry_args,
7878 extra_indirs=[test_subdir])[0]
7879 self.assertIn(
7880 'Filename \'rsa2048.key\' not found in input path',
7881 str(e.exception))
7882
7883 def testFitSignMultipleKeyPaths(self):
7884 """Test that keys found in multiple paths raise an error"""
7885 if not elf.ELF_TOOLS:
7886 self.skipTest('Python elftools not available')
7887 entry_args = {
7888 'of-list': 'test-fdt1',
7889 'default-dt': 'test-fdt1',
7890 'atf-bl31-path': 'bl31.elf',
7891 }
7892 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7893 self._MakeInputFile("keys1/rsa2048.key", data)
7894 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7895 self._MakeInputFile("keys2/conf-rsa2048.key", data)
7896
7897 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7898 keys_subdir1 = os.path.join(self._indir, "keys1")
7899 keys_subdir2 = os.path.join(self._indir, "keys2")
7900 with self.assertRaises(ValueError) as e:
7901 self._DoReadFileDtb(
7902 '341_fit_signature.dts',
7903 entry_args=entry_args,
7904 extra_indirs=[test_subdir, keys_subdir1, keys_subdir2])[0]
7905 self.assertIn(
7906 'Node \'/binman/fit\': multiple key paths found',
7907 str(e.exception))
7908
7909 def testFitSignNoSingatureNodes(self):
7910 """Test that fit,sign doens't raise error if no signature nodes found"""
7911 if not elf.ELF_TOOLS:
7912 self.skipTest('Python elftools not available')
7913 entry_args = {
7914 'of-list': 'test-fdt1',
7915 'default-dt': 'test-fdt1',
7916 'atf-bl31-path': 'bl31.elf',
7917 }
7918 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7919 self._DoReadFileDtb(
7920 '342_fit_signature.dts',
7921 entry_args=entry_args,
7922 extra_indirs=[test_subdir])[0]
7923
Simon Glassa360b8f2024-06-23 11:55:06 -06007924
Paul HENRYSff318462024-11-25 18:47:17 +01007925 def testSimpleFitEncryptedData(self):
7926 """Test an image with a FIT containing data to be encrypted"""
7927 data = tools.read_file(self.TestFile("aes256.bin"))
7928 self._MakeInputFile("keys/aes256.bin", data)
7929
7930 keys_subdir = os.path.join(self._indir, "keys")
7931 data = self._DoReadFileDtb(
7932 '343_fit_encrypt_data.dts',
7933 extra_indirs=[keys_subdir])[0]
7934
7935 fit = fdt.Fdt.FromData(data)
7936 fit.Scan()
7937
7938 # Extract the encrypted data and the Initialization Vector from the FIT
7939 node = fit.GetNode('/images/u-boot')
7940 subnode = fit.GetNode('/images/u-boot/cipher')
7941 data_size_unciphered = int.from_bytes(fit.GetProps(node)['data-size-unciphered'].bytes,
7942 byteorder='big')
7943 self.assertEqual(data_size_unciphered, len(U_BOOT_NODTB_DATA))
7944
7945 # Retrieve the key name from the FIT removing any null byte
7946 key_name = fit.GetProps(subnode)['key-name-hint'].bytes.replace(b'\x00', b'')
7947 with open(self.TestFile(key_name.decode('ascii') + '.bin'), 'rb') as file:
7948 key = file.read()
7949 iv = fit.GetProps(subnode)['iv'].bytes.hex()
7950 enc_data = fit.GetProps(node)['data'].bytes
7951 outdir = tools.get_output_dir()
7952 enc_data_file = os.path.join(outdir, 'encrypted_data.bin')
7953 tools.write_file(enc_data_file, enc_data)
7954 data_file = os.path.join(outdir, 'data.bin')
7955
7956 # Decrypt the encrypted data from the FIT and compare the data
7957 tools.run('openssl', 'enc', '-aes-256-cbc', '-nosalt', '-d', '-in',
7958 enc_data_file, '-out', data_file, '-K', key.hex(), '-iv', iv)
7959 with open(data_file, 'r') as file:
7960 dec_data = file.read()
7961 self.assertEqual(U_BOOT_NODTB_DATA, dec_data.encode('ascii'))
7962
7963 def testSimpleFitEncryptedDataMissingKey(self):
7964 """Test an image with a FIT containing data to be encrypted but with a missing key"""
7965 with self.assertRaises(ValueError) as e:
7966 self._DoReadFile('344_fit_encrypt_data_no_key.dts')
7967
7968 self.assertIn("Filename 'aes256.bin' not found in input path", str(e.exception))
7969
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01007970 def testFitFdtName(self):
7971 """Test an image with an FIT with multiple FDT images using NAME"""
7972 self.CheckFitFdt('345_fit_fdt_name.dts', use_seq_num=False)
7973
Simon Glassac599912017-11-12 21:52:22 -07007974if __name__ == "__main__":
7975 unittest.main()