blob: 9f6688ee7a4c8fcc86cb0f771341494127836c49 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass57454f42016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass57454f42016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glass45d556d2020-07-09 18:39:45 -06009import collections
Simon Glassf3598922024-07-20 11:49:45 +010010import glob
Simon Glassc585dd42020-04-17 18:09:03 -060011import gzip
Simon Glassae7cf032018-09-14 04:57:31 -060012import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070013from optparse import OptionParser
14import os
Simon Glass45d556d2020-07-09 18:39:45 -060015import re
Simon Glass57454f42016-11-25 20:15:52 -070016import shutil
17import struct
18import sys
19import tempfile
20import unittest
Simon Glass162017b2022-01-09 20:13:57 -070021import unittest.mock
22import urllib.error
Simon Glass57454f42016-11-25 20:15:52 -070023
Simon Glass4eae9252022-01-09 20:13:50 -070024from binman import bintool
Simon Glassc585dd42020-04-17 18:09:03 -060025from binman import cbfs_util
26from binman import cmdline
27from binman import control
28from binman import elf
29from binman import elf_test
Simon Glass3efb2972021-11-23 21:08:59 -070030from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060031from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060032from binman import state
33from dtoc import fdt
34from dtoc import fdt_util
35from binman.etype import fdtmap
36from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060037from binman.image import Image
Simon Glass131444f2023-02-23 18:18:04 -070038from u_boot_pylib import command
39from u_boot_pylib import test_util
40from u_boot_pylib import tools
41from u_boot_pylib import tout
Simon Glass57454f42016-11-25 20:15:52 -070042
43# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060044U_BOOT_DATA = b'1234'
45U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +030046U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass56d05412022-02-28 07:16:54 -070048U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glass303f62f2019-05-17 22:00:46 -060049BLOB_DATA = b'89'
50ME_DATA = b'0abcd'
51VGA_DATA = b'vga'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +053052EFI_CAPSULE_DATA = b'efi'
Simon Glass303f62f2019-05-17 22:00:46 -060053U_BOOT_DTB_DATA = b'udtb'
54U_BOOT_SPL_DTB_DATA = b'spldtb'
55U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass56d05412022-02-28 07:16:54 -070056U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glass303f62f2019-05-17 22:00:46 -060057X86_START16_DATA = b'start16'
58X86_START16_SPL_DATA = b'start16spl'
59X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060060X86_RESET16_DATA = b'reset16'
61X86_RESET16_SPL_DATA = b'reset16spl'
62X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060063PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
64U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
65U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
66U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass56d05412022-02-28 07:16:54 -070067U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +030068U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
69U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
70U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glass303f62f2019-05-17 22:00:46 -060071FSP_DATA = b'fsp'
72CMC_DATA = b'cmc'
73VBT_DATA = b'vbt'
74MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060075TEXT_DATA = 'text'
76TEXT_DATA2 = 'text2'
77TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060078CROS_EC_RW_DATA = b'ecrw'
79GBB_DATA = b'gbbd'
80BMPBLK_DATA = b'bmp'
81VBLOCK_DATA = b'vblk'
82FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
83 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060084COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060085COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060086REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060087FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060088FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060089FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060090ATF_BL31_DATA = b'bl31'
Roger Quadros5cdcea02022-02-19 20:50:04 +020091TEE_OS_DATA = b'this is some tee OS data'
Neha Malcom Francis59be2552023-12-05 15:12:18 +053092TI_DM_DATA = b'tidmtidm'
Simon Glass3efb2972021-11-23 21:08:59 -070093ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080094OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050095SCP_DATA = b'scp'
Jonas Karlman35305492023-02-25 19:01:33 +000096ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glassa435cd12020-09-01 05:13:59 -060097TEST_FDT1_DATA = b'fdt1'
98TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060099ENV_DATA = b'var1=1\nvar2="2"'
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200100ENCRYPTED_IV_DATA = b'123456'
101ENCRYPTED_KEY_DATA = b'abcde'
Philippe Reynesebe96cb2022-03-28 22:57:04 +0200102PRE_LOAD_MAGIC = b'UBSH'
103PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
104PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530105TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530106TI_UNSECURE_DATA = b'unsecuredata'
Simon Glassa435cd12020-09-01 05:13:59 -0600107
108# Subdirectory of the input dir to use to put test FDTs
109TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600110
Simon Glass2c6adba2019-07-20 12:23:47 -0600111# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600112EXTRACT_DTB_SIZE = 0x3c9
113
Simon Glass2c6adba2019-07-20 12:23:47 -0600114# Properties expected to be in the device tree when update_dtb is used
115BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
116
Simon Glassfb30e292019-07-20 12:23:51 -0600117# Extra properties expected to be in the device tree when allow-repack is used
118REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
119
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200120# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200121COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700122
Simon Glassad5cfe12023-01-07 14:07:14 -0700123TEE_ADDR = 0x5678
124
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530125# Firmware Management Protocol(FMP) GUID
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530126FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530127# Image GUID specified in the DTS
Caleb Connolly4bdc9602024-08-30 13:34:35 +0100128CAPSULE_IMAGE_GUID = '985F2937-7C2E-5E9A-8A5E-8E063312964B'
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530129# Windows cert GUID
130WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +0530131# Empty capsule GUIDs
132EMPTY_CAPSULE_ACCEPT_GUID = '0c996046-bcc0-4d04-85ec-e1fcedf1c6f8'
133EMPTY_CAPSULE_REVERT_GUID = 'acd58b4b-c0e8-475f-99b5-6b3f7e07aaf0'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530134
Simon Glass57454f42016-11-25 20:15:52 -0700135class TestFunctional(unittest.TestCase):
136 """Functional tests for binman
137
138 Most of these use a sample .dts file to build an image and then check
139 that it looks correct. The sample files are in the test/ subdirectory
140 and are numbered.
141
142 For each entry type a very small test file is created using fixed
143 string contents. This makes it easy to test that things look right, and
144 debug problems.
145
146 In some cases a 'real' file must be used - these are also supplied in
147 the test/ diurectory.
148 """
149 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600150 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700151 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600152 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700153
Simon Glass57454f42016-11-25 20:15:52 -0700154 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600155 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
156 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700157
158 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600159 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700160
161 # Create some test files
162 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
163 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
164 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600165 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700166 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700167 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700168 TestFunctional._MakeInputFile('me.bin', ME_DATA)
169 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600170 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600171
Jagdish Gediya311d4842018-09-03 21:35:08 +0530172 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600173
Simon Glassabab18c2019-08-24 07:22:49 -0600174 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
175 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700176 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600177 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600178 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600179
180 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
181 X86_RESET16_DATA)
182 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
183 X86_RESET16_SPL_DATA)
184 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
185 X86_RESET16_TPL_DATA)
186
Simon Glass57454f42016-11-25 20:15:52 -0700187 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700188 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
189 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600190 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
191 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700192 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
193 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700194 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
195 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700196 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700197 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600198 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600199 TestFunctional._MakeInputDir('devkeys')
200 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600201 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600202 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600203 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600204 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700205
Simon Glassf6290892019-08-24 07:22:53 -0600206 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
207 elf_test.BuildElfTestFiles(cls._elf_testdir)
208
Simon Glass72232452016-11-25 20:15:53 -0700209 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600210 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700211 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700212
213 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600214 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700215
Simon Glass862f8e22019-08-24 07:22:43 -0600216 shutil.copytree(cls.TestFile('files'),
217 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600218
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530219 shutil.copytree(cls.TestFile('yaml'),
220 os.path.join(cls._indir, 'yaml'))
221
Simon Glass7ba33592018-09-14 04:57:26 -0600222 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600223 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600224 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200225 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Neha Malcom Francis59be2552023-12-05 15:12:18 +0530226 TestFunctional._MakeInputFile('dm.bin', TI_DM_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700227 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800228 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500229 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman35305492023-02-25 19:01:33 +0000230 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530231 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530232 TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600233
Simon Glassa435cd12020-09-01 05:13:59 -0600234 # Add a few .dtb files for testing
235 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
236 TEST_FDT1_DATA)
237 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
238 TEST_FDT2_DATA)
239
Simon Glassa0729502020-09-06 10:35:33 -0600240 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
241
Simon Glass5f423422022-03-05 20:19:12 -0700242 # ELF file with two sections in different parts of memory, used for both
243 # ATF and OP_TEE
244 TestFunctional._MakeInputFile('bl31.elf',
245 tools.read_file(cls.ElfTestFile('elf_sections')))
246 TestFunctional._MakeInputFile('tee.elf',
247 tools.read_file(cls.ElfTestFile('elf_sections')))
248
Simon Glassad5cfe12023-01-07 14:07:14 -0700249 # Newer OP_TEE file in v1 binary format
250 cls.make_tee_bin('tee.bin')
251
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200252 # test files for encrypted tests
253 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
254 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
255
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200256 cls.comp_bintools = {}
257 for name in COMP_BINTOOLS:
258 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600259
Simon Glass57454f42016-11-25 20:15:52 -0700260 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600261 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700262 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600263 if cls.preserve_indir:
264 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600265 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600266 if cls._indir:
267 shutil.rmtree(cls._indir)
268 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700269
Simon Glass1c420c92019-07-08 13:18:49 -0600270 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600271 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600272 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600273 """Accept arguments controlling test execution
274
275 Args:
276 preserve_indir: Preserve the shared input directory used by all
277 tests in this class.
278 preserve_outdir: Preserve the output directories used by tests. Each
279 test has its own, so this is normally only useful when running a
280 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600281 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600282 """
283 cls.preserve_indir = preserve_indir
284 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600285 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600286 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600287
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200288 def _CheckBintool(self, bintool):
289 if not bintool.is_present():
290 self.skipTest('%s not available' % bintool.name)
291
Simon Glass1de34482019-07-08 13:18:53 -0600292 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200293 bintool = self.comp_bintools['lz4']
294 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600295
Simon Glassee9d10d2019-07-20 12:24:09 -0600296 def _CleanupOutputDir(self):
297 """Remove the temporary output directory"""
298 if self.preserve_outdirs:
299 print('Preserving output dir: %s' % tools.outdir)
300 else:
Simon Glass80025522022-01-29 14:14:04 -0700301 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600302
Simon Glass57454f42016-11-25 20:15:52 -0700303 def setUp(self):
304 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700305 # tout.init(tout.DEBUG)
Simon Glass5dc22cf2025-02-03 09:26:42 -0700306 command.TEST_RESULT = None
Simon Glass57454f42016-11-25 20:15:52 -0700307
308 def tearDown(self):
309 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600310 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700311
Simon Glassb3d6fc72019-07-20 12:24:10 -0600312 def _SetupImageInTmpdir(self):
313 """Set up the output image in a new temporary directory
314
315 This is used when an image has been generated in the output directory,
316 but we want to run binman again. This will create a new output
317 directory and fail to delete the original one.
318
319 This creates a new temporary directory, copies the image to it (with a
320 new name) and removes the old output directory.
321
322 Returns:
323 Tuple:
324 Temporary directory to use
325 New image filename
326 """
Simon Glass80025522022-01-29 14:14:04 -0700327 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600328 tmpdir = tempfile.mkdtemp(prefix='binman.')
329 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700330 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600331 self._CleanupOutputDir()
332 return tmpdir, updated_fname
333
Simon Glass8425a1f2018-07-17 13:25:48 -0600334 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600335 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600336 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
337 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
338 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700339 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600340
Simon Glass57454f42016-11-25 20:15:52 -0700341 def _RunBinman(self, *args, **kwargs):
342 """Run binman using the command line
343
344 Args:
345 Arguments to pass, as a list of strings
346 kwargs: Arguments to pass to Command.RunPipe()
347 """
Simon Glass51f55182025-02-03 09:26:45 -0700348 all_args = [self._binman_pathname] + list(args)
349 result = command.run_one(*all_args, capture=True, capture_stderr=True,
350 raise_on_error=False)
Simon Glass57454f42016-11-25 20:15:52 -0700351 if result.return_code and kwargs.get('raise_on_error', True):
352 raise Exception("Error running '%s': %s" % (' '.join(args),
353 result.stdout + result.stderr))
354 return result
355
Simon Glassf46732a2019-07-08 14:25:29 -0600356 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700357 """Run binman using directly (in the same process)
358
359 Args:
360 Arguments to pass, as a list of strings
361 Returns:
362 Return value (0 for success)
363 """
Simon Glassf46732a2019-07-08 14:25:29 -0600364 argv = list(argv)
365 args = cmdline.ParseArgs(argv)
366 args.pager = 'binman-invalid-pager'
367 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700368
369 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600370 # args.verbosity = tout.DEBUG
371 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700372
Simon Glass91710b32018-07-17 13:25:32 -0600373 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600374 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300375 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100376 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700377 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis6b463da2023-07-22 00:14:44 +0530378 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass57454f42016-11-25 20:15:52 -0700379 """Run binman with a given test file
380
381 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600382 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600383 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600384 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600385 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600386 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600387 entry_args: Dict of entry args to supply to binman
388 key: arg name
389 value: value of that arg
390 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600391 use_real_dtb: True to use the test file as the contents of
392 the u-boot-dtb entry. Normally this is not needed and the
393 test contents (the U_BOOT_DTB_DATA string) can be used.
394 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300395 use_expanded: True to use expanded entries where available, e.g.
396 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600397 verbosity: Verbosity level to use (0-3, None=don't set it)
398 allow_missing: Set the '--allow-missing' flag so that missing
399 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100400 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600401 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600402 threads: Number of threads to use (None for default, 0 for
403 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600404 test_section_timeout: True to force the first time to timeout, as
405 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600406 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glassb553e8a2024-08-26 13:11:29 -0600407 force_missing_bintools (str): comma-separated list of bintools to
Simon Glass66152ce2022-01-09 20:14:09 -0700408 regard as missing
Simon Glassb553e8a2024-08-26 13:11:29 -0600409 ignore_missing (bool): True to return success even if there are
410 missing blobs or bintools
Andrew Davis6b463da2023-07-22 00:14:44 +0530411 output_dir: Specific output directory to use for image using -O
Simon Glass9a798402021-11-03 21:09:17 -0600412
413 Returns:
414 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700415 """
Simon Glassf46732a2019-07-08 14:25:29 -0600416 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700417 if debug:
418 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600419 if verbosity is not None:
420 args.append('-v%d' % verbosity)
421 elif self.verbosity:
422 args.append('-v%d' % self.verbosity)
423 if self.toolpath:
424 for path in self.toolpath:
425 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600426 if threads is not None:
427 args.append('-T%d' % threads)
428 if test_section_timeout:
429 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600430 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600431 if map:
432 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600433 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600434 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600435 if not use_real_dtb:
436 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300437 if not use_expanded:
438 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600439 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600440 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600441 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600442 if allow_missing:
443 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700444 if ignore_missing:
445 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100446 if allow_fake_blobs:
447 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700448 if force_missing_bintools:
449 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600450 if update_fdt_in_elf:
451 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600452 if images:
453 for image in images:
454 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600455 if extra_indirs:
456 for indir in extra_indirs:
457 args += ['-I', indir]
Andrew Davis6b463da2023-07-22 00:14:44 +0530458 if output_dir:
459 args += ['-O', output_dir]
Simon Glass075a45c2017-11-13 18:55:00 -0700460 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700461
462 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700463 """Set up a new test device-tree file
464
465 The given file is compiled and set up as the device tree to be used
466 for ths test.
467
468 Args:
469 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600470 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700471
472 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600473 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700474 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600475 tmpdir = tempfile.mkdtemp(prefix='binmant.')
476 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600477 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700478 data = fd.read()
479 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600480 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600481 return data
Simon Glass57454f42016-11-25 20:15:52 -0700482
Simon Glass56d05412022-02-28 07:16:54 -0700483 def _GetDtbContentsForSpls(self, dtb_data, name):
484 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600485
486 For testing we don't actually have different versions of the DTB. With
487 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
488 we don't normally have any unwanted nodes.
489
490 We still want the DTBs for SPL and TPL to be different though, since
491 otherwise it is confusing to know which one we are looking at. So add
492 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600493
494 Args:
495 dtb_data: dtb data to modify (this should be a value devicetree)
496 name: Name of a new property to add
497
498 Returns:
499 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600500 """
501 dtb = fdt.Fdt.FromData(dtb_data)
502 dtb.Scan()
503 dtb.GetNode('/binman').AddZeroProp(name)
504 dtb.Sync(auto_resize=True)
505 dtb.Pack()
506 return dtb.GetContents()
507
Simon Glassed930672021-03-18 20:25:05 +1300508 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
Simon Glass3eb30a42024-08-26 13:11:42 -0600509 verbosity=None, map=False, update_dtb=False,
510 entry_args=None, reset_dtbs=True, extra_indirs=None,
511 threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700512 """Run binman and return the resulting image
513
514 This runs binman with a given test file and then reads the resulting
515 output file. It is a shortcut function since most tests need to do
516 these steps.
517
518 Raises an assertion failure if binman returns a non-zero exit code.
519
520 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600521 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700522 use_real_dtb: True to use the test file as the contents of
523 the u-boot-dtb entry. Normally this is not needed and the
524 test contents (the U_BOOT_DTB_DATA string) can be used.
525 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300526 use_expanded: True to use expanded entries where available, e.g.
527 'u-boot-expanded' instead of 'u-boot'
Simon Glass3eb30a42024-08-26 13:11:42 -0600528 verbosity: Verbosity level to use (0-3, None=don't set it)
Simon Glass30732662018-06-01 09:38:20 -0600529 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600530 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600531 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600532 entry_args: Dict of entry args to supply to binman
533 key: arg name
534 value: value of that arg
535 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
536 function. If reset_dtbs is True, then the original test dtb
537 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600538 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600539 threads: Number of threads to use (None for default, 0 for
540 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700541
542 Returns:
543 Tuple:
544 Resulting image contents
545 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600546 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600547 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700548 """
Simon Glass72232452016-11-25 20:15:53 -0700549 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700550 # Use the compiled test file as the u-boot-dtb input
551 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700552 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600553
554 # For testing purposes, make a copy of the DT for SPL and TPL. Add
Simon Glassd9e01d22024-07-20 11:49:40 +0100555 # a node indicating which it is, to aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700556 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600557 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
558 outfile = os.path.join(self._indir, dtb_fname)
559 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700560 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700561
562 try:
Simon Glass91710b32018-07-17 13:25:32 -0600563 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600564 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass3eb30a42024-08-26 13:11:42 -0600565 use_expanded=use_expanded, verbosity=verbosity,
566 extra_indirs=extra_indirs,
Simon Glass76f496d2021-07-06 10:36:37 -0600567 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700568 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700569 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700570
571 # Find the (only) image, read it and return its contents
572 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700573 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600574 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600575 if map:
Simon Glass80025522022-01-29 14:14:04 -0700576 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600577 with open(map_fname) as fd:
578 map_data = fd.read()
579 else:
580 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600581 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600582 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700583 finally:
584 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600585 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600586 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700587
Simon Glass5b4bce32019-07-08 14:25:26 -0600588 def _DoReadFileRealDtb(self, fname):
589 """Run binman with a real .dtb file and return the resulting data
590
591 Args:
592 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
593
594 Returns:
595 Resulting image contents
596 """
597 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
598
Simon Glass72232452016-11-25 20:15:53 -0700599 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600600 """Helper function which discards the device-tree binary
601
602 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600603 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600604 use_real_dtb: True to use the test file as the contents of
605 the u-boot-dtb entry. Normally this is not needed and the
606 test contents (the U_BOOT_DTB_DATA string) can be used.
607 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600608
609 Returns:
610 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600611 """
Simon Glass72232452016-11-25 20:15:53 -0700612 return self._DoReadFileDtb(fname, use_real_dtb)[0]
613
Simon Glass57454f42016-11-25 20:15:52 -0700614 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600615 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700616 """Create a new test input file, creating directories as needed
617
618 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600619 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700620 contents: File contents to write in to the file
621 Returns:
622 Full pathname of file created
623 """
Simon Glass862f8e22019-08-24 07:22:43 -0600624 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700625 dirname = os.path.dirname(pathname)
626 if dirname and not os.path.exists(dirname):
627 os.makedirs(dirname)
628 with open(pathname, 'wb') as fd:
629 fd.write(contents)
630 return pathname
631
632 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600633 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600634 """Create a new test input directory, creating directories as needed
635
636 Args:
637 dirname: Directory name to create
638
639 Returns:
640 Full pathname of directory created
641 """
Simon Glass862f8e22019-08-24 07:22:43 -0600642 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600643 if not os.path.exists(pathname):
644 os.makedirs(pathname)
645 return pathname
646
647 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600648 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600649 """Set up an ELF file with a '_dt_ucode_base_size' symbol
650
651 Args:
652 Filename of ELF file to use as SPL
653 """
Simon Glass93a806f2019-08-24 07:22:59 -0600654 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700655 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600656
657 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600658 def _SetupTplElf(cls, src_fname='bss_data'):
659 """Set up an ELF file with a '_dt_ucode_base_size' symbol
660
661 Args:
662 Filename of ELF file to use as TPL
663 """
664 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700665 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600666
667 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700668 def _SetupVplElf(cls, src_fname='bss_data'):
669 """Set up an ELF file with a '_dt_ucode_base_size' symbol
670
671 Args:
672 Filename of ELF file to use as VPL
673 """
674 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
675 tools.read_file(cls.ElfTestFile(src_fname)))
676
677 @classmethod
Lukas Funkee901faf2023-07-18 13:53:13 +0200678 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
679 """Set up an ELF file with a '_dt_ucode_base_size' symbol
680
681 Args:
682 Filename of ELF file to use as VPL
683 """
684 TestFunctional._MakeInputFile('pmu-firmware.elf',
685 tools.read_file(cls.ElfTestFile(src_fname)))
686
687 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600688 def _SetupDescriptor(cls):
689 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
690 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
691
692 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600693 def TestFile(cls, fname):
694 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700695
Simon Glassf6290892019-08-24 07:22:53 -0600696 @classmethod
697 def ElfTestFile(cls, fname):
698 return os.path.join(cls._elf_testdir, fname)
699
Simon Glassad5cfe12023-01-07 14:07:14 -0700700 @classmethod
701 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
702 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
703 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
704 dummy, paged_sz) + U_BOOT_DATA
705 data += extra_data
706 TestFunctional._MakeInputFile(fname, data)
707
Simon Glass57454f42016-11-25 20:15:52 -0700708 def AssertInList(self, grep_list, target):
709 """Assert that at least one of a list of things is in a target
710
711 Args:
712 grep_list: List of strings to check
713 target: Target string
714 """
715 for grep in grep_list:
716 if grep in target:
717 return
Simon Glass848cdb52019-05-17 22:00:50 -0600718 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700719
720 def CheckNoGaps(self, entries):
721 """Check that all entries fit together without gaps
722
723 Args:
724 entries: List of entries to check
725 """
Simon Glasse8561af2018-08-01 15:22:37 -0600726 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700727 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600728 self.assertEqual(offset, entry.offset)
729 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700730
Simon Glass72232452016-11-25 20:15:53 -0700731 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600732 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700733
734 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600735 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700736
737 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600738 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700739 """
740 return struct.unpack('>L', dtb[4:8])[0]
741
Simon Glass0f621332019-07-08 14:25:27 -0600742 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600743 def AddNode(node, path):
744 if node.name != '/':
745 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600746 for prop in node.props.values():
747 if prop.name in prop_names:
748 prop_path = path + ':' + prop.name
749 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
750 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600751 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600752 AddNode(subnode, path)
753
754 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600755 AddNode(dtb.GetRoot(), '')
756 return tree
757
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000758 def _CheckSign(self, fit, key):
759 try:
760 tools.run('fit_check_sign', '-k', key, '-f', fit)
761 except:
762 self.fail('Expected signed FIT container')
763 return False
764 return True
765
Simon Glass57454f42016-11-25 20:15:52 -0700766 def testRun(self):
767 """Test a basic run with valid args"""
768 result = self._RunBinman('-h')
769
770 def testFullHelp(self):
771 """Test that the full help is displayed with -H"""
772 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300773 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500774 # Remove possible extraneous strings
775 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
776 gothelp = result.stdout.replace(extra, '')
777 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700778 self.assertEqual(0, len(result.stderr))
779 self.assertEqual(0, result.return_code)
780
781 def testFullHelpInternal(self):
782 """Test that the full help is displayed with -H"""
783 try:
Simon Glass5dc22cf2025-02-03 09:26:42 -0700784 command.TEST_RESULT = command.CommandResult()
Simon Glass57454f42016-11-25 20:15:52 -0700785 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300786 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700787 finally:
Simon Glass5dc22cf2025-02-03 09:26:42 -0700788 command.TEST_RESULT = None
Simon Glass57454f42016-11-25 20:15:52 -0700789
790 def testHelp(self):
791 """Test that the basic help is displayed with -h"""
792 result = self._RunBinman('-h')
793 self.assertTrue(len(result.stdout) > 200)
794 self.assertEqual(0, len(result.stderr))
795 self.assertEqual(0, result.return_code)
796
Simon Glass57454f42016-11-25 20:15:52 -0700797 def testBoard(self):
798 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600799 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700800 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300801 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700802 self.assertEqual(0, result)
803
804 def testNeedBoard(self):
805 """Test that we get an error when no board ius supplied"""
806 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600807 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700808 self.assertIn("Must provide a board to process (use -b <board>)",
809 str(e.exception))
810
811 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600812 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700813 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600814 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700815 # We get one error from libfdt, and a different one from fdtget.
816 self.AssertInList(["Couldn't open blob from 'missing_file'",
817 'No such file or directory'], str(e.exception))
818
819 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600820 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700821
822 Since this is a source file it should be compiled and the error
823 will come from the device-tree compiler (dtc).
824 """
825 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600826 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700827 self.assertIn("FATAL ERROR: Unable to parse input tree",
828 str(e.exception))
829
830 def testMissingNode(self):
831 """Test that a device tree without a 'binman' node generates an error"""
832 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600833 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700834 self.assertIn("does not have a 'binman' node", str(e.exception))
835
836 def testEmpty(self):
837 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600838 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700839 self.assertEqual(0, len(result.stderr))
840 self.assertEqual(0, result.return_code)
841
842 def testInvalidEntry(self):
843 """Test that an invalid entry is flagged"""
844 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600845 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600846 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700847 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
848 "'/binman/not-a-valid-type'", str(e.exception))
849
850 def testSimple(self):
851 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600852 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700853 self.assertEqual(U_BOOT_DATA, data)
854
Simon Glass075a45c2017-11-13 18:55:00 -0700855 def testSimpleDebug(self):
856 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600857 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700858
Simon Glass57454f42016-11-25 20:15:52 -0700859 def testDual(self):
860 """Test that we can handle creating two images
861
862 This also tests image padding.
863 """
Simon Glass511f6582018-10-01 12:22:30 -0600864 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700865 self.assertEqual(0, retcode)
866
867 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600868 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700869 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700870 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600871 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700872 data = fd.read()
873 self.assertEqual(U_BOOT_DATA, data)
874
875 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600876 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700877 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700878 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600879 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700880 data = fd.read()
881 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700882 self.assertEqual(tools.get_bytes(0, 3), data[:3])
883 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700884
885 def testBadAlign(self):
886 """Test that an invalid alignment value is detected"""
887 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600888 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700889 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
890 "of two", str(e.exception))
891
892 def testPackSimple(self):
893 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600894 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700895 self.assertEqual(0, retcode)
896 self.assertIn('image', control.images)
897 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600898 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700899 self.assertEqual(5, len(entries))
900
901 # First u-boot
902 self.assertIn('u-boot', entries)
903 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600904 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700905 self.assertEqual(len(U_BOOT_DATA), entry.size)
906
907 # Second u-boot, aligned to 16-byte boundary
908 self.assertIn('u-boot-align', entries)
909 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600910 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700911 self.assertEqual(len(U_BOOT_DATA), entry.size)
912
913 # Third u-boot, size 23 bytes
914 self.assertIn('u-boot-size', entries)
915 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600916 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700917 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
918 self.assertEqual(23, entry.size)
919
920 # Fourth u-boot, placed immediate after the above
921 self.assertIn('u-boot-next', entries)
922 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600923 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700924 self.assertEqual(len(U_BOOT_DATA), entry.size)
925
Simon Glasse8561af2018-08-01 15:22:37 -0600926 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700927 self.assertIn('u-boot-fixed', entries)
928 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600929 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700930 self.assertEqual(len(U_BOOT_DATA), entry.size)
931
Simon Glass39dd2152019-07-08 14:25:47 -0600932 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700933
934 def testPackExtra(self):
935 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600936 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
937 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700938
Simon Glass57454f42016-11-25 20:15:52 -0700939 self.assertIn('image', control.images)
940 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600941 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600942 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700943
Samuel Hollande2574022023-01-21 17:25:16 -0600944 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700945 self.assertIn('u-boot', entries)
946 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600947 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700948 self.assertEqual(3, entry.pad_before)
949 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600950 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700951 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
952 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600953 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700954
955 # Second u-boot has an aligned size, but it has no effect
956 self.assertIn('u-boot-align-size-nop', entries)
957 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600958 self.assertEqual(pos, entry.offset)
959 self.assertEqual(len(U_BOOT_DATA), entry.size)
960 self.assertEqual(U_BOOT_DATA, entry.data)
961 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
962 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700963
964 # Third u-boot has an aligned size too
965 self.assertIn('u-boot-align-size', entries)
966 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600967 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700968 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600969 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700970 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600971 data[pos:pos + entry.size])
972 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700973
974 # Fourth u-boot has an aligned end
975 self.assertIn('u-boot-align-end', entries)
976 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600977 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700978 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600979 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700980 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600981 data[pos:pos + entry.size])
982 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700983
984 # Fifth u-boot immediately afterwards
985 self.assertIn('u-boot-align-both', entries)
986 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600987 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700988 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600989 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700990 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600991 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700992
Samuel Hollande2574022023-01-21 17:25:16 -0600993 # Sixth u-boot with both minimum size and aligned size
994 self.assertIn('u-boot-min-size', entries)
995 entry = entries['u-boot-min-size']
996 self.assertEqual(128, entry.offset)
997 self.assertEqual(32, entry.size)
998 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
999 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
1000 data[pos:pos + entry.size])
1001
Simon Glass57454f42016-11-25 20:15:52 -07001002 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -06001003 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001004
Simon Glassafb9caa2020-10-26 17:40:10 -06001005 dtb = fdt.Fdt(out_dtb_fname)
1006 dtb.Scan()
1007 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
1008 expected = {
1009 'image-pos': 0,
1010 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -06001011 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -06001012
1013 'u-boot:image-pos': 0,
1014 'u-boot:offset': 0,
1015 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1016
1017 'u-boot-align-size-nop:image-pos': 12,
1018 'u-boot-align-size-nop:offset': 12,
1019 'u-boot-align-size-nop:size': 4,
1020
1021 'u-boot-align-size:image-pos': 16,
1022 'u-boot-align-size:offset': 16,
1023 'u-boot-align-size:size': 32,
1024
1025 'u-boot-align-end:image-pos': 48,
1026 'u-boot-align-end:offset': 48,
1027 'u-boot-align-end:size': 16,
1028
1029 'u-boot-align-both:image-pos': 64,
1030 'u-boot-align-both:offset': 64,
1031 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -06001032
1033 'u-boot-min-size:image-pos': 128,
1034 'u-boot-min-size:offset': 128,
1035 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -06001036 }
1037 self.assertEqual(expected, props)
1038
Simon Glass57454f42016-11-25 20:15:52 -07001039 def testPackAlignPowerOf2(self):
1040 """Test that invalid entry alignment is detected"""
1041 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001042 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001043 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1044 "of two", str(e.exception))
1045
1046 def testPackAlignSizePowerOf2(self):
1047 """Test that invalid entry size alignment is detected"""
1048 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001049 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001050 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1051 "power of two", str(e.exception))
1052
1053 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001054 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001055 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001056 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001057 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001058 "align 0x4 (4)", str(e.exception))
1059
1060 def testPackInvalidSizeAlign(self):
1061 """Test that invalid entry size alignment is detected"""
1062 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001063 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001064 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1065 "align-size 0x4 (4)", str(e.exception))
1066
1067 def testPackOverlap(self):
1068 """Test that overlapping regions are detected"""
1069 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001070 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001071 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001072 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1073 str(e.exception))
1074
1075 def testPackEntryOverflow(self):
1076 """Test that entries that overflow their size are detected"""
1077 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001078 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001079 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1080 "but entry size is 0x3 (3)", str(e.exception))
1081
1082 def testPackImageOverflow(self):
1083 """Test that entries which overflow the image size are detected"""
1084 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001085 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001086 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001087 "size 0x3 (3)", str(e.exception))
1088
1089 def testPackImageSize(self):
1090 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001091 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001092 self.assertEqual(0, retcode)
1093 self.assertIn('image', control.images)
1094 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001095 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001096
1097 def testPackImageSizeAlign(self):
1098 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001099 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001100 self.assertEqual(0, retcode)
1101 self.assertIn('image', control.images)
1102 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001103 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001104
1105 def testPackInvalidImageAlign(self):
1106 """Test that invalid image alignment is detected"""
1107 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001108 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001109 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001110 "align-size 0x8 (8)", str(e.exception))
1111
Simon Glass2a0fa982022-02-11 13:23:21 -07001112 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001113 """Test that invalid image alignment is detected"""
1114 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001115 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001116 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001117 "two", str(e.exception))
1118
1119 def testImagePadByte(self):
1120 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001121 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001122 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001123 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001124 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001125
1126 def testImageName(self):
1127 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001128 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001129 self.assertEqual(0, retcode)
1130 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001131 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001132 self.assertTrue(os.path.exists(fname))
1133
1134 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001135 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001136 self.assertTrue(os.path.exists(fname))
1137
1138 def testBlobFilename(self):
1139 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001140 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001141 self.assertEqual(BLOB_DATA, data)
1142
1143 def testPackSorted(self):
1144 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001145 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001146 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001147 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1148 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001149
Simon Glasse8561af2018-08-01 15:22:37 -06001150 def testPackZeroOffset(self):
1151 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001152 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001153 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001154 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001155 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001156 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1157 str(e.exception))
1158
1159 def testPackUbootDtb(self):
1160 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001161 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001162 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001163
1164 def testPackX86RomNoSize(self):
1165 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001166 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001167 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001168 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001169 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001170 "using end-at-4gb", str(e.exception))
1171
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301172 def test4gbAndSkipAtStartTogether(self):
1173 """Test that the end-at-4gb and skip-at-size property can't be used
1174 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001175 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301176 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001177 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001178 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301179 "'skip-at-start'", str(e.exception))
1180
Simon Glass72232452016-11-25 20:15:53 -07001181 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001182 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001183 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001184 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001185 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001186 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1187 "is outside the section '/binman' starting at "
1188 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001189 str(e.exception))
1190
1191 def testPackX86Rom(self):
1192 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001193 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001194 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001195 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1196 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001197
1198 def testPackX86RomMeNoDesc(self):
1199 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001200 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001201 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001202 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001203 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001204 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1205 str(e.exception))
1206 finally:
1207 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001208
1209 def testPackX86RomBadDesc(self):
1210 """Test that the Intel requires a descriptor entry"""
1211 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001212 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001213 self.assertIn("Node '/binman/intel-me': No offset set with "
1214 "offset-unset: should another entry provide this correct "
1215 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001216
1217 def testPackX86RomMe(self):
1218 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001219 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001220 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001221 if data[:0x1000] != expected_desc:
1222 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001223 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1224
1225 def testPackVga(self):
1226 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001227 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001228 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1229
1230 def testPackStart16(self):
1231 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001232 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001233 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1234
Jagdish Gediya311d4842018-09-03 21:35:08 +05301235 def testPackPowerpcMpc85xxBootpgResetvec(self):
1236 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1237 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001238 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301239 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1240
Simon Glass6ba679c2018-07-06 10:27:17 -06001241 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001242 """Handle running a test for insertion of microcode
1243
1244 Args:
1245 dts_fname: Name of test .dts file
1246 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001247 ucode_second: True if the microsecond entry is second instead of
1248 third
Simon Glass820af1d2018-07-06 10:27:16 -06001249
1250 Returns:
1251 Tuple:
1252 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001253 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001254 in the above (two 4-byte words)
1255 """
Simon Glass3d274232017-11-12 21:52:27 -07001256 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001257
1258 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001259 if ucode_second:
1260 ucode_content = data[len(nodtb_data):]
1261 ucode_pos = len(nodtb_data)
1262 dtb_with_ucode = ucode_content[16:]
1263 fdt_len = self.GetFdtLen(dtb_with_ucode)
1264 else:
1265 dtb_with_ucode = data[len(nodtb_data):]
1266 fdt_len = self.GetFdtLen(dtb_with_ucode)
1267 ucode_content = dtb_with_ucode[fdt_len:]
1268 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001269 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001270 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001271 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001272 dtb = fdt.FdtScan(fname)
1273 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001274 self.assertTrue(ucode)
1275 for node in ucode.subnodes:
1276 self.assertFalse(node.props.get('data'))
1277
Simon Glass72232452016-11-25 20:15:53 -07001278 # Check that the microcode appears immediately after the Fdt
1279 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001280 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001281 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1282 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001283 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001284
1285 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001286 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001287 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1288 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001289 u_boot = data[:len(nodtb_data)]
1290 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001291
1292 def testPackUbootMicrocode(self):
1293 """Test that x86 microcode can be handled correctly
1294
1295 We expect to see the following in the image, in order:
1296 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1297 place
1298 u-boot.dtb with the microcode removed
1299 the microcode
1300 """
Simon Glass511f6582018-10-01 12:22:30 -06001301 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001302 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001303 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1304 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001305
Simon Glassbac25c82017-05-27 07:38:26 -06001306 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001307 """Test that x86 microcode can be handled correctly
1308
1309 We expect to see the following in the image, in order:
1310 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1311 place
1312 u-boot.dtb with the microcode
1313 an empty microcode region
1314 """
1315 # We need the libfdt library to run this test since only that allows
1316 # finding the offset of a property. This is required by
1317 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001318 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001319
1320 second = data[len(U_BOOT_NODTB_DATA):]
1321
1322 fdt_len = self.GetFdtLen(second)
1323 third = second[fdt_len:]
1324 second = second[:fdt_len]
1325
Simon Glassbac25c82017-05-27 07:38:26 -06001326 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1327 self.assertIn(ucode_data, second)
1328 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001329
Simon Glassbac25c82017-05-27 07:38:26 -06001330 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001331 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001332 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1333 len(ucode_data))
1334 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001335 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1336 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001337
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001338 def testPackUbootSingleMicrocode(self):
1339 """Test that x86 microcode can be handled correctly with fdt_normal.
1340 """
Simon Glassbac25c82017-05-27 07:38:26 -06001341 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001342
Simon Glass996021e2016-11-25 20:15:54 -07001343 def testUBootImg(self):
1344 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001345 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001346 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001347
1348 def testNoMicrocode(self):
1349 """Test that a missing microcode region is detected"""
1350 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001351 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001352 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1353 "node found in ", str(e.exception))
1354
1355 def testMicrocodeWithoutNode(self):
1356 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1357 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001358 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001359 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1360 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1361
1362 def testMicrocodeWithoutNode2(self):
1363 """Test that a missing u-boot-ucode node is detected"""
1364 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001365 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001366 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1367 "microcode region u-boot-ucode", str(e.exception))
1368
1369 def testMicrocodeWithoutPtrInElf(self):
1370 """Test that a U-Boot binary without the microcode symbol is detected"""
1371 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001372 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001373 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001374 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001375
1376 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001377 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001378 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1379 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1380
1381 finally:
1382 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001383 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001384 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001385
1386 def testMicrocodeNotInImage(self):
1387 """Test that microcode must be placed within the image"""
1388 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001389 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001390 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1391 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001392 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001393
1394 def testWithoutMicrocode(self):
1395 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001396 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001397 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001398 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001399
1400 # Now check the device tree has no microcode
1401 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1402 second = data[len(U_BOOT_NODTB_DATA):]
1403
1404 fdt_len = self.GetFdtLen(second)
1405 self.assertEqual(dtb, second[:fdt_len])
1406
1407 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1408 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001409 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001410
1411 def testUnknownPosSize(self):
1412 """Test that microcode must be placed within the image"""
1413 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001414 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001415 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001416 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001417
1418 def testPackFsp(self):
1419 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001420 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001421 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1422
1423 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001424 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001425 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001426 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001427
1428 def testPackVbt(self):
1429 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001430 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001431 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001432
Simon Glass7f94e832017-11-12 21:52:25 -07001433 def testSplBssPad(self):
1434 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001435 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001436 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001437 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001438 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001439 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001440
Simon Glass04cda032018-10-01 21:12:42 -06001441 def testSplBssPadMissing(self):
1442 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001443 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001444 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001445 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001446 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1447 str(e.exception))
1448
Simon Glasse83679d2017-11-12 21:52:26 -07001449 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001450 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001451 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001452 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1453
Simon Glass6ba679c2018-07-06 10:27:17 -06001454 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1455 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001456
1457 We expect to see the following in the image, in order:
1458 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1459 correct place
1460 u-boot.dtb with the microcode removed
1461 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001462
1463 Args:
1464 dts: Device tree file to use for test
1465 ucode_second: True if the microsecond entry is second instead of
1466 third
Simon Glass3d274232017-11-12 21:52:27 -07001467 """
Simon Glass7057d022018-10-01 21:12:47 -06001468 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001469 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1470 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001471 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1472 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001473
Simon Glass6ba679c2018-07-06 10:27:17 -06001474 def testPackUbootSplMicrocode(self):
1475 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001476 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001477 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001478
1479 def testPackUbootSplMicrocodeReorder(self):
1480 """Test that order doesn't matter for microcode entries
1481
1482 This is the same as testPackUbootSplMicrocode but when we process the
1483 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1484 entry, so we reply on binman to try later.
1485 """
Simon Glass511f6582018-10-01 12:22:30 -06001486 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001487 ucode_second=True)
1488
Simon Glassa409c932017-11-12 21:52:28 -07001489 def testPackMrc(self):
1490 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001491 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001492 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1493
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001494 def testSplDtb(self):
1495 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001496 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001497 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001498 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1499
Simon Glass0a6da312017-11-13 18:54:56 -07001500 def testSplNoDtb(self):
1501 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001502 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001503 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001504 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1505
Simon Glass7098b7f2021-03-21 18:24:30 +13001506 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4b0f4142024-08-26 13:11:40 -06001507 use_expanded=False, no_write_symbols=False,
1508 symbols_base=None):
Simon Glass31e04cb2021-03-18 20:24:56 +13001509 """Check the image contains the expected symbol values
1510
1511 Args:
1512 dts: Device tree file to use for test
1513 base_data: Data before and after 'u-boot' section
Simon Glass3eb30a42024-08-26 13:11:42 -06001514 u_boot_offset (int): Offset of 'u-boot' section in image, or None if
1515 the offset not available due to it being in a compressed section
Simon Glass7098b7f2021-03-21 18:24:30 +13001516 entry_args: Dict of entry args to supply to binman
1517 key: arg name
1518 value: value of that arg
1519 use_expanded: True to use expanded entries where available, e.g.
1520 'u-boot-expanded' instead of 'u-boot'
Simon Glass4b0f4142024-08-26 13:11:40 -06001521 symbols_base (int): Value to expect for symbols-base in u-boot-spl,
1522 None if none
Simon Glass31e04cb2021-03-18 20:24:56 +13001523 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001524 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001525 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1526 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001527 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001528 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001529 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001530
Simon Glass7057d022018-10-01 21:12:47 -06001531 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001532 data = self._DoReadFileDtb(dts, entry_args=entry_args,
Simon Glass3eb30a42024-08-26 13:11:42 -06001533 use_expanded=use_expanded,
1534 verbosity=None if u_boot_offset else 3)[0]
1535
1536 # The lz4-compressed version of the U-Boot data is 19 bytes long
1537 comp_uboot_len = 19
1538
Simon Glass31e04cb2021-03-18 20:24:56 +13001539 # The image should contain the symbols from u_boot_binman_syms.c
1540 # Note that image_pos is adjusted by the base address of the image,
1541 # which is 0x10 in our test image
Simon Glass3eb30a42024-08-26 13:11:42 -06001542 # If u_boot_offset is None, Binman should write -1U into the image
Simon Glass4b0f4142024-08-26 13:11:40 -06001543 vals2 = (elf.BINMAN_SYM_MAGIC_VALUE, 0x00,
Simon Glass3eb30a42024-08-26 13:11:42 -06001544 u_boot_offset + len(U_BOOT_DATA) if u_boot_offset else
1545 len(U_BOOT_SPL_DATA) + 1 + comp_uboot_len,
1546 0x10 + u_boot_offset if u_boot_offset else 0xffffffff, 0x04)
Simon Glass4b0f4142024-08-26 13:11:40 -06001547
1548 # u-boot-spl has a symbols-base property, so take that into account if
1549 # required. The caller must supply the value
1550 vals = list(vals2)
1551 if symbols_base is not None:
1552 vals[3] = symbols_base + u_boot_offset
1553 vals = tuple(vals)
1554
Simon Glass4b4049e2024-08-26 13:11:39 -06001555 sym_values = struct.pack('<LLQLL', *vals)
Simon Glass4b0f4142024-08-26 13:11:40 -06001556 sym_values2 = struct.pack('<LLQLL', *vals2)
Simon Glass4abf7842023-07-18 07:23:54 -06001557 if no_write_symbols:
Simon Glass4b4049e2024-08-26 13:11:39 -06001558 self.assertEqual(
1559 base_data +
1560 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1561 U_BOOT_DATA + base_data, data)
Simon Glass4abf7842023-07-18 07:23:54 -06001562 else:
Simon Glass4b4049e2024-08-26 13:11:39 -06001563 got_vals = struct.unpack('<LLQLL', data[:24])
1564
1565 # For debugging:
1566 #print('expect:', list(f'{v:x}' for v in vals))
1567 #print(' got:', list(f'{v:x}' for v in got_vals))
1568
1569 self.assertEqual(vals, got_vals)
1570 self.assertEqual(sym_values, data[:24])
1571
1572 blen = len(base_data)
1573 self.assertEqual(base_data[24:], data[24:blen])
1574 self.assertEqual(0xff, data[blen])
1575
Simon Glass3eb30a42024-08-26 13:11:42 -06001576 if u_boot_offset:
1577 ofs = blen + 1 + len(U_BOOT_DATA)
1578 self.assertEqual(U_BOOT_DATA, data[blen + 1:ofs])
1579 else:
1580 ofs = blen + 1 + comp_uboot_len
Simon Glass4b4049e2024-08-26 13:11:39 -06001581
Simon Glass4b0f4142024-08-26 13:11:40 -06001582 self.assertEqual(sym_values2, data[ofs:ofs + 24])
Simon Glass4b4049e2024-08-26 13:11:39 -06001583 self.assertEqual(base_data[24:], data[ofs + 24:])
1584
1585 # Just repeating the above asserts all at once, for clarity
Simon Glass3eb30a42024-08-26 13:11:42 -06001586 if u_boot_offset:
1587 expected = (sym_values + base_data[24:] +
1588 tools.get_bytes(0xff, 1) + U_BOOT_DATA +
1589 sym_values2 + base_data[24:])
1590 self.assertEqual(expected, data)
Simon Glass4ca8e042017-11-13 18:55:01 -07001591
Simon Glass31e04cb2021-03-18 20:24:56 +13001592 def testSymbols(self):
1593 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001594 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001595
1596 def testSymbolsNoDtb(self):
1597 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001598 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001599 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1600 0x38)
1601
Simon Glasse76a3e62018-06-01 09:38:11 -06001602 def testPackUnitAddress(self):
1603 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001604 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001605 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1606
Simon Glassa91e1152018-06-01 09:38:16 -06001607 def testSections(self):
1608 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001609 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001610 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1611 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1612 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001613 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001614
Simon Glass30732662018-06-01 09:38:20 -06001615 def testMap(self):
1616 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001617 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001618 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700161900000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600162000000000 00000000 00000010 section@0
162100000000 00000000 00000004 u-boot
162200000010 00000010 00000010 section@1
162300000010 00000000 00000004 u-boot
162400000020 00000020 00000004 section@2
162500000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001626''', map_data)
1627
Simon Glass3b78d532018-06-01 09:38:21 -06001628 def testNamePrefix(self):
1629 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001630 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001631 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700163200000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600163300000000 00000000 00000010 section@0
163400000000 00000000 00000004 ro-u-boot
163500000010 00000010 00000010 section@1
163600000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001637''', map_data)
1638
Simon Glass6ba679c2018-07-06 10:27:17 -06001639 def testUnknownContents(self):
1640 """Test that obtaining the contents works as expected"""
1641 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001642 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001643 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001644 "processing of contents: remaining ["
1645 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001646
Simon Glass2e1169f2018-07-06 10:27:19 -06001647 def testBadChangeSize(self):
1648 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001649 try:
1650 state.SetAllowEntryExpansion(False)
1651 with self.assertRaises(ValueError) as e:
1652 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001653 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001654 str(e.exception))
1655 finally:
1656 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001657
Simon Glassa87014e2018-07-06 10:27:42 -06001658 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001659 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001660 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001661 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001662 dtb = fdt.Fdt(out_dtb_fname)
1663 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001664 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001665 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001666 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001667 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001668 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001669 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001670 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001671 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001672 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001673 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001674 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001675 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001676 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001677
Simon Glasse8561af2018-08-01 15:22:37 -06001678 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001679 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001680 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001681 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001682 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001683 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001684 'size': 40
1685 }, props)
1686
1687 def testUpdateFdtBad(self):
1688 """Test that we detect when ProcessFdt never completes"""
1689 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001690 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001691 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001692 '[<binman.etype._testing.Entry__testing',
1693 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001694
Simon Glass91710b32018-07-17 13:25:32 -06001695 def testEntryArgs(self):
1696 """Test passing arguments to entries from the command line"""
1697 entry_args = {
1698 'test-str-arg': 'test1',
1699 'test-int-arg': '456',
1700 }
Simon Glass511f6582018-10-01 12:22:30 -06001701 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001702 self.assertIn('image', control.images)
1703 entry = control.images['image'].GetEntries()['_testing']
1704 self.assertEqual('test0', entry.test_str_fdt)
1705 self.assertEqual('test1', entry.test_str_arg)
1706 self.assertEqual(123, entry.test_int_fdt)
1707 self.assertEqual(456, entry.test_int_arg)
1708
1709 def testEntryArgsMissing(self):
1710 """Test missing arguments and properties"""
1711 entry_args = {
1712 'test-int-arg': '456',
1713 }
Simon Glass511f6582018-10-01 12:22:30 -06001714 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001715 entry = control.images['image'].GetEntries()['_testing']
1716 self.assertEqual('test0', entry.test_str_fdt)
1717 self.assertEqual(None, entry.test_str_arg)
1718 self.assertEqual(None, entry.test_int_fdt)
1719 self.assertEqual(456, entry.test_int_arg)
1720
1721 def testEntryArgsRequired(self):
1722 """Test missing arguments and properties"""
1723 entry_args = {
1724 'test-int-arg': '456',
1725 }
1726 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001727 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001728 self.assertIn("Node '/binman/_testing': "
1729 'Missing required properties/entry args: test-str-arg, '
1730 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001731 str(e.exception))
1732
1733 def testEntryArgsInvalidFormat(self):
1734 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001735 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1736 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001737 with self.assertRaises(ValueError) as e:
1738 self._DoBinman(*args)
1739 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1740
1741 def testEntryArgsInvalidInteger(self):
1742 """Test that an invalid entry-argument integer is detected"""
1743 entry_args = {
1744 'test-int-arg': 'abc',
1745 }
1746 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001747 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001748 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1749 "'test-int-arg' (value 'abc') to integer",
1750 str(e.exception))
1751
1752 def testEntryArgsInvalidDatatype(self):
1753 """Test that an invalid entry-argument datatype is detected
1754
1755 This test could be written in entry_test.py except that it needs
1756 access to control.entry_args, which seems more than that module should
1757 be able to see.
1758 """
1759 entry_args = {
1760 'test-bad-datatype-arg': '12',
1761 }
1762 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001763 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001764 entry_args=entry_args)
1765 self.assertIn('GetArg() internal error: Unknown data type ',
1766 str(e.exception))
1767
Simon Glass2ca52032018-07-17 13:25:33 -06001768 def testText(self):
1769 """Test for a text entry type"""
1770 entry_args = {
1771 'test-id': TEXT_DATA,
1772 'test-id2': TEXT_DATA2,
1773 'test-id3': TEXT_DATA3,
1774 }
Simon Glass511f6582018-10-01 12:22:30 -06001775 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001776 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001777 expected = (tools.to_bytes(TEXT_DATA) +
1778 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1779 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001780 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001781 self.assertEqual(expected, data)
1782
Simon Glass969616c2018-07-17 13:25:36 -06001783 def testEntryDocs(self):
1784 """Test for creation of entry documentation"""
1785 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001786 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001787 self.assertTrue(len(stdout.getvalue()) > 0)
1788
1789 def testEntryDocsMissing(self):
1790 """Test handling of missing entry documentation"""
1791 with self.assertRaises(ValueError) as e:
1792 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001793 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001794 self.assertIn('Documentation is missing for modules: u_boot',
1795 str(e.exception))
1796
Simon Glass704784b2018-07-17 13:25:38 -06001797 def testFmap(self):
1798 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001799 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001800 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001801 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1802 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001803 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001804 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001805 self.assertEqual(1, fhdr.ver_major)
1806 self.assertEqual(0, fhdr.ver_minor)
1807 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001808 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001809 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001810 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001811 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001812 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001813
Simon Glass82059c22021-04-03 11:05:09 +13001814 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001815 self.assertEqual(b'SECTION0', fentry.name)
1816 self.assertEqual(0, fentry.offset)
1817 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001818 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001819
1820 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001821 self.assertEqual(b'RO_U_BOOT', fentry.name)
1822 self.assertEqual(0, fentry.offset)
1823 self.assertEqual(4, fentry.size)
1824 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001825
Simon Glass82059c22021-04-03 11:05:09 +13001826 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001827 self.assertEqual(b'SECTION1', fentry.name)
1828 self.assertEqual(16, fentry.offset)
1829 self.assertEqual(16, fentry.size)
1830 self.assertEqual(0, fentry.flags)
1831
1832 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001833 self.assertEqual(b'RW_U_BOOT', fentry.name)
1834 self.assertEqual(16, fentry.offset)
1835 self.assertEqual(4, fentry.size)
1836 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001837
Simon Glass82059c22021-04-03 11:05:09 +13001838 fentry = next(fiter)
1839 self.assertEqual(b'FMAP', fentry.name)
1840 self.assertEqual(32, fentry.offset)
1841 self.assertEqual(expect_size, fentry.size)
1842 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001843
Simon Glassdb168d42018-07-17 13:25:39 -06001844 def testBlobNamedByArg(self):
1845 """Test we can add a blob with the filename coming from an entry arg"""
1846 entry_args = {
1847 'cros-ec-rw-path': 'ecrw.bin',
1848 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001849 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001850
Simon Glass53f53992018-07-17 13:25:40 -06001851 def testFill(self):
1852 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001853 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001854 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001855 self.assertEqual(expected, data)
1856
1857 def testFillNoSize(self):
1858 """Test for an fill entry type with no size"""
1859 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001860 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001861 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001862 str(e.exception))
1863
Simon Glassc1ae83c2018-07-17 13:25:44 -06001864 def _HandleGbbCommand(self, pipe_list):
1865 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001866 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001867 fname = pipe_list[0][-1]
1868 # Append our GBB data to the file, which will happen every time the
1869 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001870 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001871 fd.write(GBB_DATA)
1872 return command.CommandResult()
1873
1874 def testGbb(self):
1875 """Test for the Chromium OS Google Binary Block"""
Simon Glass5dc22cf2025-02-03 09:26:42 -07001876 command.TEST_RESULT = self._HandleGbbCommand
Simon Glassc1ae83c2018-07-17 13:25:44 -06001877 entry_args = {
1878 'keydir': 'devkeys',
1879 'bmpblk': 'bmpblk.bin',
1880 }
Simon Glass511f6582018-10-01 12:22:30 -06001881 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001882
1883 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001884 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1885 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001886 self.assertEqual(expected, data)
1887
1888 def testGbbTooSmall(self):
1889 """Test for the Chromium OS Google Binary Block being large enough"""
1890 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001891 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001892 self.assertIn("Node '/binman/gbb': GBB is too small",
1893 str(e.exception))
1894
1895 def testGbbNoSize(self):
1896 """Test for the Chromium OS Google Binary Block having a size"""
1897 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001898 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001899 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1900 str(e.exception))
1901
Simon Glass66152ce2022-01-09 20:14:09 -07001902 def testGbbMissing(self):
1903 """Test that binman still produces an image if futility is missing"""
1904 entry_args = {
1905 'keydir': 'devkeys',
1906 }
1907 with test_util.capture_sys_output() as (_, stderr):
1908 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1909 entry_args=entry_args)
1910 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001911 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001912
Simon Glass5c350162018-07-17 13:25:47 -06001913 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001914 """Fake calls to the futility utility
1915
1916 The expected pipe is:
1917
1918 [('futility', 'vbutil_firmware', '--vblock',
1919 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1920 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1921 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1922 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1923
1924 This writes to the output file (here, 'vblock.vblock'). If
1925 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1926 of the input data (here, 'input.vblock').
1927 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001928 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001929 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001930 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001931 if self._hash_data:
1932 infile = pipe_list[0][11]
1933 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001934 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001935 m.update(data)
1936 fd.write(m.digest())
1937 else:
1938 fd.write(VBLOCK_DATA)
1939
Simon Glass5c350162018-07-17 13:25:47 -06001940 return command.CommandResult()
1941
1942 def testVblock(self):
1943 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001944 self._hash_data = False
Simon Glass5dc22cf2025-02-03 09:26:42 -07001945 command.TEST_RESULT = self._HandleVblockCommand
Simon Glass5c350162018-07-17 13:25:47 -06001946 entry_args = {
1947 'keydir': 'devkeys',
1948 }
Simon Glass511f6582018-10-01 12:22:30 -06001949 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001950 entry_args=entry_args)
1951 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1952 self.assertEqual(expected, data)
1953
1954 def testVblockNoContent(self):
1955 """Test we detect a vblock which has no content to sign"""
1956 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001957 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001958 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001959 'property', str(e.exception))
1960
1961 def testVblockBadPhandle(self):
1962 """Test that we detect a vblock with an invalid phandle in contents"""
1963 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001964 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001965 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1966 '1000', str(e.exception))
1967
1968 def testVblockBadEntry(self):
1969 """Test that we detect an entry that points to a non-entry"""
1970 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001971 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001972 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1973 "'other'", str(e.exception))
1974
Simon Glass220c6222021-01-06 21:35:17 -07001975 def testVblockContent(self):
1976 """Test that the vblock signs the right data"""
1977 self._hash_data = True
Simon Glass5dc22cf2025-02-03 09:26:42 -07001978 command.TEST_RESULT = self._HandleVblockCommand
Simon Glass220c6222021-01-06 21:35:17 -07001979 entry_args = {
1980 'keydir': 'devkeys',
1981 }
1982 data = self._DoReadFileDtb(
1983 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1984 entry_args=entry_args)[0]
1985 hashlen = 32 # SHA256 hash is 32 bytes
1986 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1987 hashval = data[-hashlen:]
1988 dtb = data[len(U_BOOT_DATA):-hashlen]
1989
1990 expected_data = U_BOOT_DATA + dtb
1991
1992 # The hashval should be a hash of the dtb
1993 m = hashlib.sha256()
1994 m.update(expected_data)
1995 expected_hashval = m.digest()
1996 self.assertEqual(expected_hashval, hashval)
1997
Simon Glass66152ce2022-01-09 20:14:09 -07001998 def testVblockMissing(self):
1999 """Test that binman still produces an image if futility is missing"""
2000 entry_args = {
2001 'keydir': 'devkeys',
2002 }
2003 with test_util.capture_sys_output() as (_, stderr):
2004 self._DoTestFile('074_vblock.dts',
2005 force_missing_bintools='futility',
2006 entry_args=entry_args)
2007 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07002008 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07002009
Simon Glass8425a1f2018-07-17 13:25:48 -06002010 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06002011 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06002012 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06002013 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06002014 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06002015 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
2016
Simon Glass24b97442018-07-17 13:25:51 -06002017 def testUsesPos(self):
2018 """Test that the 'pos' property cannot be used anymore"""
2019 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002020 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06002021 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
2022 "'pos'", str(e.exception))
2023
Simon Glass274bf092018-09-14 04:57:08 -06002024 def testFillZero(self):
2025 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06002026 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07002027 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06002028
Simon Glass267de432018-09-14 04:57:09 -06002029 def testTextMissing(self):
2030 """Test for a text entry type where there is no text"""
2031 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002032 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06002033 self.assertIn("Node '/binman/text': No value provided for text label "
2034 "'test-id'", str(e.exception))
2035
Simon Glassed40e962018-09-14 04:57:10 -06002036 def testPackStart16Tpl(self):
2037 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06002038 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06002039 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
2040
Simon Glass3b376c32018-09-14 04:57:12 -06002041 def testSelectImage(self):
2042 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06002043 expected = 'Skipping images: image1'
2044
2045 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06002046 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06002047 with test_util.capture_sys_output() as (stdout, stderr):
2048 retcode = self._DoTestFile('006_dual_image.dts',
2049 verbosity=verbosity,
2050 images=['image2'])
2051 self.assertEqual(0, retcode)
2052 if verbosity:
2053 self.assertIn(expected, stdout.getvalue())
2054 else:
2055 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06002056
Simon Glass80025522022-01-29 14:14:04 -07002057 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2058 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06002059 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06002060
Simon Glasse219aa42018-09-14 04:57:24 -06002061 def testUpdateFdtAll(self):
2062 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06002063 self._SetupSplElf()
2064 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06002065 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06002066
2067 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06002068 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002069 'image-pos': 0,
2070 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06002071 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002072 'section:image-pos': 0,
2073 'section:size': 565,
2074 'section/u-boot-dtb:offset': 0,
2075 'section/u-boot-dtb:image-pos': 0,
2076 'section/u-boot-dtb:size': 565,
2077 'u-boot-spl-dtb:offset': 565,
2078 'u-boot-spl-dtb:image-pos': 565,
2079 'u-boot-spl-dtb:size': 585,
2080 'u-boot-tpl-dtb:offset': 1150,
2081 'u-boot-tpl-dtb:image-pos': 1150,
2082 'u-boot-tpl-dtb:size': 585,
2083 'u-boot-vpl-dtb:image-pos': 1735,
2084 'u-boot-vpl-dtb:offset': 1735,
2085 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002086 }
2087
2088 # We expect three device-tree files in the output, one after the other.
2089 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2090 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2091 # main U-Boot tree. All three should have the same postions and offset.
2092 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002093 self.maxDiff = None
2094 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002095 dtb = fdt.Fdt.FromData(data[start:])
2096 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002097 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002098 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002099 expected = dict(base_expected)
2100 if item:
2101 expected[item] = 0
2102 self.assertEqual(expected, props)
2103 start += dtb._fdt_obj.totalsize()
2104
2105 def testUpdateFdtOutput(self):
2106 """Test that output DTB files are updated"""
2107 try:
Simon Glass511f6582018-10-01 12:22:30 -06002108 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002109 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2110
2111 # Unfortunately, compiling a source file always results in a file
2112 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002113 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002114 # binman as a file called u-boot.dtb. To fix this, copy the file
2115 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002116 start = 0
2117 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002118 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002119 dtb = fdt.Fdt.FromData(data[start:])
2120 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002121 pathname = tools.get_output_filename(os.path.split(fname)[1])
2122 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002123 name = os.path.split(fname)[0]
2124
2125 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002126 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002127 else:
2128 orig_indata = dtb_data
2129 self.assertNotEqual(outdata, orig_indata,
2130 "Expected output file '%s' be updated" % pathname)
2131 self.assertEqual(outdata, data[start:start + size],
2132 "Expected output file '%s' to match output image" %
2133 pathname)
2134 start += size
2135 finally:
2136 self._ResetDtbs()
2137
Simon Glass7ba33592018-09-14 04:57:26 -06002138 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002139 bintool = self.comp_bintools['lz4']
2140 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002141
2142 def testCompress(self):
2143 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002144 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002145 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002146 use_real_dtb=True, update_dtb=True)
2147 dtb = fdt.Fdt(out_dtb_fname)
2148 dtb.Scan()
2149 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2150 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00002151 self.assertEqual(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002152
2153 # Do a sanity check on various fields
2154 image = control.images['image']
2155 entries = image.GetEntries()
2156 self.assertEqual(1, len(entries))
2157
2158 entry = entries['blob']
2159 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2160 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2161 orig = self._decompress(entry.data)
2162 self.assertEqual(orig, entry.uncomp_data)
2163
Simon Glass72eeff12020-10-26 17:40:16 -06002164 self.assertEqual(image.data, entry.data)
2165
Simon Glass7ba33592018-09-14 04:57:26 -06002166 expected = {
2167 'blob:uncomp-size': len(COMPRESS_DATA),
2168 'blob:size': len(data),
2169 'size': len(data),
2170 }
2171 self.assertEqual(expected, props)
2172
Simon Glassac6328c2018-09-14 04:57:28 -06002173 def testFiles(self):
2174 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002175 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002176 self.assertEqual(FILES_DATA, data)
2177
2178 def testFilesCompress(self):
2179 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002180 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002181 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002182
2183 image = control.images['image']
2184 entries = image.GetEntries()
2185 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002186 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002187
Simon Glass303f62f2019-05-17 22:00:46 -06002188 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002189 for i in range(1, 3):
2190 key = '%d.dat' % i
2191 start = entries[key].image_pos
2192 len = entries[key].size
2193 chunk = data[start:start + len]
2194 orig += self._decompress(chunk)
2195
2196 self.assertEqual(FILES_DATA, orig)
2197
2198 def testFilesMissing(self):
2199 """Test missing files"""
2200 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002201 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002202 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2203 'no files', str(e.exception))
2204
2205 def testFilesNoPattern(self):
2206 """Test missing files"""
2207 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002208 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002209 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2210 str(e.exception))
2211
Simon Glassdd156a42022-03-05 20:18:59 -07002212 def testExtendSize(self):
2213 """Test an extending entry"""
2214 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002215 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002216 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2217 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2218 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2219 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002220 self.assertEqual(expect, data)
2221 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700222200000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600222300000000 00000000 00000008 fill
222400000008 00000008 00000004 u-boot
22250000000c 0000000c 00000004 section
22260000000c 00000000 00000003 intel-mrc
222700000010 00000010 00000004 u-boot2
222800000014 00000014 0000000c section2
222900000014 00000000 00000008 fill
22300000001c 00000008 00000004 u-boot
223100000020 00000020 00000008 fill2
2232''', map_data)
2233
Simon Glassdd156a42022-03-05 20:18:59 -07002234 def testExtendSizeBad(self):
2235 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002236 with test_util.capture_sys_output() as (stdout, stderr):
2237 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002238 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002239 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2240 'expanding entry', str(e.exception))
2241
Simon Glassae7cf032018-09-14 04:57:31 -06002242 def testHash(self):
2243 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002244 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002245 use_real_dtb=True, update_dtb=True)
2246 dtb = fdt.Fdt(out_dtb_fname)
2247 dtb.Scan()
2248 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2249 m = hashlib.sha256()
2250 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002251 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002252
2253 def testHashNoAlgo(self):
2254 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002255 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002256 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2257 'hash node', str(e.exception))
2258
2259 def testHashBadAlgo(self):
2260 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002261 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002262 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002263 str(e.exception))
2264
2265 def testHashSection(self):
2266 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002267 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002268 use_real_dtb=True, update_dtb=True)
2269 dtb = fdt.Fdt(out_dtb_fname)
2270 dtb.Scan()
2271 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2272 m = hashlib.sha256()
2273 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002274 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002275 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002276
Simon Glass3fb4f422018-09-14 04:57:32 -06002277 def testPackUBootTplMicrocode(self):
2278 """Test that x86 microcode can be handled correctly in TPL
2279
2280 We expect to see the following in the image, in order:
2281 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2282 place
2283 u-boot-tpl.dtb with the microcode removed
2284 the microcode
2285 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002286 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002287 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002288 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002289 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2290 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002291
Simon Glassc64aea52018-09-14 04:57:34 -06002292 def testFmapX86(self):
2293 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002294 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002295 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002296 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002297 self.assertEqual(expected, data[:32])
2298 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2299
2300 self.assertEqual(0x100, fhdr.image_size)
2301
2302 self.assertEqual(0, fentries[0].offset)
2303 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002304 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002305
2306 self.assertEqual(4, fentries[1].offset)
2307 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002308 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002309
2310 self.assertEqual(32, fentries[2].offset)
2311 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2312 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002313 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002314
2315 def testFmapX86Section(self):
2316 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002317 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002318 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002319 self.assertEqual(expected, data[:32])
2320 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2321
Simon Glassb1d414c2021-04-03 11:05:10 +13002322 self.assertEqual(0x180, fhdr.image_size)
2323 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002324 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002325
Simon Glass82059c22021-04-03 11:05:09 +13002326 fentry = next(fiter)
2327 self.assertEqual(b'U_BOOT', fentry.name)
2328 self.assertEqual(0, fentry.offset)
2329 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002330
Simon Glass82059c22021-04-03 11:05:09 +13002331 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002332 self.assertEqual(b'SECTION', fentry.name)
2333 self.assertEqual(4, fentry.offset)
2334 self.assertEqual(0x20 + expect_size, fentry.size)
2335
2336 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002337 self.assertEqual(b'INTEL_MRC', fentry.name)
2338 self.assertEqual(4, fentry.offset)
2339 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002340
Simon Glass82059c22021-04-03 11:05:09 +13002341 fentry = next(fiter)
2342 self.assertEqual(b'FMAP', fentry.name)
2343 self.assertEqual(36, fentry.offset)
2344 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002345
Simon Glassb1714232018-09-14 04:57:35 -06002346 def testElf(self):
2347 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002348 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002349 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002350 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002351 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002352 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002353
Simon Glass0d673792019-07-08 13:18:25 -06002354 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002355 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002356 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002357 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002358 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002359 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002360
Simon Glasscd817d52018-09-14 04:57:36 -06002361 def testPackOverlapMap(self):
2362 """Test that overlapping regions are detected"""
2363 with test_util.capture_sys_output() as (stdout, stderr):
2364 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002365 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002366 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002367 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2368 stdout.getvalue())
2369
2370 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002371 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002372 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002373 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002374 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002375<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002376<none> 00000000 00000004 u-boot
2377<none> 00000003 00000004 u-boot-align
2378''', map_data)
2379
Simon Glass0d673792019-07-08 13:18:25 -06002380 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002381 """Test that an image with an Intel Reference code binary works"""
2382 data = self._DoReadFile('100_intel_refcode.dts')
2383 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2384
Simon Glasseb023b32019-04-25 21:58:39 -06002385 def testSectionOffset(self):
2386 """Tests use of a section with an offset"""
2387 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2388 map=True)
2389 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700239000000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600239100000004 00000004 00000010 section@0
239200000004 00000000 00000004 u-boot
239300000018 00000018 00000010 section@1
239400000018 00000000 00000004 u-boot
23950000002c 0000002c 00000004 section@2
23960000002c 00000000 00000004 u-boot
2397''', map_data)
2398 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002399 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2400 tools.get_bytes(0x21, 12) +
2401 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2402 tools.get_bytes(0x61, 12) +
2403 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2404 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002405
Simon Glass1de34482019-07-08 13:18:53 -06002406 def testCbfsRaw(self):
2407 """Test base handling of a Coreboot Filesystem (CBFS)
2408
2409 The exact contents of the CBFS is verified by similar tests in
2410 cbfs_util_test.py. The tests here merely check that the files added to
2411 the CBFS can be found in the final image.
2412 """
2413 data = self._DoReadFile('102_cbfs_raw.dts')
2414 size = 0xb0
2415
2416 cbfs = cbfs_util.CbfsReader(data)
2417 self.assertEqual(size, cbfs.rom_size)
2418
2419 self.assertIn('u-boot-dtb', cbfs.files)
2420 cfile = cbfs.files['u-boot-dtb']
2421 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2422
2423 def testCbfsArch(self):
2424 """Test on non-x86 architecture"""
2425 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2426 size = 0x100
2427
2428 cbfs = cbfs_util.CbfsReader(data)
2429 self.assertEqual(size, cbfs.rom_size)
2430
2431 self.assertIn('u-boot-dtb', cbfs.files)
2432 cfile = cbfs.files['u-boot-dtb']
2433 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2434
2435 def testCbfsStage(self):
2436 """Tests handling of a Coreboot Filesystem (CBFS)"""
2437 if not elf.ELF_TOOLS:
2438 self.skipTest('Python elftools not available')
2439 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2440 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2441 size = 0xb0
2442
2443 data = self._DoReadFile('104_cbfs_stage.dts')
2444 cbfs = cbfs_util.CbfsReader(data)
2445 self.assertEqual(size, cbfs.rom_size)
2446
2447 self.assertIn('u-boot', cbfs.files)
2448 cfile = cbfs.files['u-boot']
2449 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2450
2451 def testCbfsRawCompress(self):
2452 """Test handling of compressing raw files"""
2453 self._CheckLz4()
2454 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2455 size = 0x140
2456
2457 cbfs = cbfs_util.CbfsReader(data)
2458 self.assertIn('u-boot', cbfs.files)
2459 cfile = cbfs.files['u-boot']
2460 self.assertEqual(COMPRESS_DATA, cfile.data)
2461
2462 def testCbfsBadArch(self):
2463 """Test handling of a bad architecture"""
2464 with self.assertRaises(ValueError) as e:
2465 self._DoReadFile('106_cbfs_bad_arch.dts')
2466 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2467
2468 def testCbfsNoSize(self):
2469 """Test handling of a missing size property"""
2470 with self.assertRaises(ValueError) as e:
2471 self._DoReadFile('107_cbfs_no_size.dts')
2472 self.assertIn('entry must have a size property', str(e.exception))
2473
Simon Glass3e28f4f2021-11-23 11:03:54 -07002474 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002475 """Test handling of a CBFS entry which does not provide contentsy"""
2476 with self.assertRaises(ValueError) as e:
2477 self._DoReadFile('108_cbfs_no_contents.dts')
2478 self.assertIn('Could not complete processing of contents',
2479 str(e.exception))
2480
2481 def testCbfsBadCompress(self):
2482 """Test handling of a bad architecture"""
2483 with self.assertRaises(ValueError) as e:
2484 self._DoReadFile('109_cbfs_bad_compress.dts')
2485 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2486 str(e.exception))
2487
2488 def testCbfsNamedEntries(self):
2489 """Test handling of named entries"""
2490 data = self._DoReadFile('110_cbfs_name.dts')
2491
2492 cbfs = cbfs_util.CbfsReader(data)
2493 self.assertIn('FRED', cbfs.files)
2494 cfile1 = cbfs.files['FRED']
2495 self.assertEqual(U_BOOT_DATA, cfile1.data)
2496
2497 self.assertIn('hello', cbfs.files)
2498 cfile2 = cbfs.files['hello']
2499 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2500
Simon Glass759af872019-07-08 13:18:54 -06002501 def _SetupIfwi(self, fname):
2502 """Set up to run an IFWI test
2503
2504 Args:
2505 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2506 """
2507 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002508 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002509
2510 # Intel Integrated Firmware Image (IFWI) file
2511 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2512 data = fd.read()
2513 TestFunctional._MakeInputFile(fname,data)
2514
2515 def _CheckIfwi(self, data):
2516 """Check that an image with an IFWI contains the correct output
2517
2518 Args:
2519 data: Conents of output file
2520 """
Simon Glass80025522022-01-29 14:14:04 -07002521 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002522 if data[:0x1000] != expected_desc:
2523 self.fail('Expected descriptor binary at start of image')
2524
2525 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002526 image_fname = tools.get_output_filename('image.bin')
2527 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002528 ifwitool = bintool.Bintool.create('ifwitool')
2529 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002530
Simon Glass80025522022-01-29 14:14:04 -07002531 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002532 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002533
2534 def testPackX86RomIfwi(self):
2535 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2536 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002537 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002538 self._CheckIfwi(data)
2539
2540 def testPackX86RomIfwiNoDesc(self):
2541 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2542 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002543 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002544 self._CheckIfwi(data)
2545
2546 def testPackX86RomIfwiNoData(self):
2547 """Test that an x86 ROM with IFWI handles missing data"""
2548 self._SetupIfwi('ifwi.bin')
2549 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002550 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002551 self.assertIn('Could not complete processing of contents',
2552 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002553
Simon Glass66152ce2022-01-09 20:14:09 -07002554 def testIfwiMissing(self):
2555 """Test that binman still produces an image if ifwitool is missing"""
2556 self._SetupIfwi('fitimage.bin')
2557 with test_util.capture_sys_output() as (_, stderr):
2558 self._DoTestFile('111_x86_rom_ifwi.dts',
2559 force_missing_bintools='ifwitool')
2560 err = stderr.getvalue()
2561 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002562 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002563
Simon Glassc2f1aed2019-07-08 13:18:56 -06002564 def testCbfsOffset(self):
2565 """Test a CBFS with files at particular offsets
2566
2567 Like all CFBS tests, this is just checking the logic that calls
2568 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2569 """
2570 data = self._DoReadFile('114_cbfs_offset.dts')
2571 size = 0x200
2572
2573 cbfs = cbfs_util.CbfsReader(data)
2574 self.assertEqual(size, cbfs.rom_size)
2575
2576 self.assertIn('u-boot', cbfs.files)
2577 cfile = cbfs.files['u-boot']
2578 self.assertEqual(U_BOOT_DATA, cfile.data)
2579 self.assertEqual(0x40, cfile.cbfs_offset)
2580
2581 self.assertIn('u-boot-dtb', cbfs.files)
2582 cfile2 = cbfs.files['u-boot-dtb']
2583 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2584 self.assertEqual(0x140, cfile2.cbfs_offset)
2585
Simon Glass0f621332019-07-08 14:25:27 -06002586 def testFdtmap(self):
2587 """Test an FDT map can be inserted in the image"""
2588 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2589 fdtmap_data = data[len(U_BOOT_DATA):]
2590 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002591 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002592 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002593
2594 fdt_data = fdtmap_data[16:]
2595 dtb = fdt.Fdt.FromData(fdt_data)
2596 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002597 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002598 self.assertEqual({
2599 'image-pos': 0,
2600 'offset': 0,
2601 'u-boot:offset': 0,
2602 'u-boot:size': len(U_BOOT_DATA),
2603 'u-boot:image-pos': 0,
2604 'fdtmap:image-pos': 4,
2605 'fdtmap:offset': 4,
2606 'fdtmap:size': len(fdtmap_data),
2607 'size': len(data),
2608 }, props)
2609
2610 def testFdtmapNoMatch(self):
2611 """Check handling of an FDT map when the section cannot be found"""
2612 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2613
2614 # Mangle the section name, which should cause a mismatch between the
2615 # correct FDT path and the one expected by the section
2616 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002617 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002618 entries = image.GetEntries()
2619 fdtmap = entries['fdtmap']
2620 with self.assertRaises(ValueError) as e:
2621 fdtmap._GetFdtmap()
2622 self.assertIn("Cannot locate node for path '/binman-suffix'",
2623 str(e.exception))
2624
Simon Glasscec34ba2019-07-08 14:25:28 -06002625 def testFdtmapHeader(self):
2626 """Test an FDT map and image header can be inserted in the image"""
2627 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2628 fdtmap_pos = len(U_BOOT_DATA)
2629 fdtmap_data = data[fdtmap_pos:]
2630 fdt_data = fdtmap_data[16:]
2631 dtb = fdt.Fdt.FromData(fdt_data)
2632 fdt_size = dtb.GetFdtObj().totalsize()
2633 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002634 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002635 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2636 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2637
2638 def testFdtmapHeaderStart(self):
2639 """Test an image header can be inserted at the image start"""
2640 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2641 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2642 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002643 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002644 offset = struct.unpack('<I', hdr_data[4:])[0]
2645 self.assertEqual(fdtmap_pos, offset)
2646
2647 def testFdtmapHeaderPos(self):
2648 """Test an image header can be inserted at a chosen position"""
2649 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2650 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2651 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002652 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002653 offset = struct.unpack('<I', hdr_data[4:])[0]
2654 self.assertEqual(fdtmap_pos, offset)
2655
2656 def testHeaderMissingFdtmap(self):
2657 """Test an image header requires an fdtmap"""
2658 with self.assertRaises(ValueError) as e:
2659 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2660 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2661 str(e.exception))
2662
2663 def testHeaderNoLocation(self):
2664 """Test an image header with a no specified location is detected"""
2665 with self.assertRaises(ValueError) as e:
2666 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2667 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2668 str(e.exception))
2669
Simon Glasse61b6f62019-07-08 14:25:37 -06002670 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002671 """Test extending an entry after it is packed"""
2672 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002673 self.assertEqual(b'aaa', data[:3])
2674 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2675 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002676
Simon Glassdd156a42022-03-05 20:18:59 -07002677 def testEntryExtendBad(self):
2678 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002679 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002680 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002681 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002682 str(e.exception))
2683
Simon Glassdd156a42022-03-05 20:18:59 -07002684 def testEntryExtendSection(self):
2685 """Test extending an entry within a section after it is packed"""
2686 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002687 self.assertEqual(b'aaa', data[:3])
2688 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2689 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002690
Simon Glass90d29682019-07-08 14:25:38 -06002691 def testCompressDtb(self):
2692 """Test that compress of device-tree files is supported"""
2693 self._CheckLz4()
2694 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2695 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2696 comp_data = data[len(U_BOOT_DATA):]
2697 orig = self._decompress(comp_data)
2698 dtb = fdt.Fdt.FromData(orig)
2699 dtb.Scan()
2700 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2701 expected = {
2702 'u-boot:size': len(U_BOOT_DATA),
2703 'u-boot-dtb:uncomp-size': len(orig),
2704 'u-boot-dtb:size': len(comp_data),
2705 'size': len(data),
2706 }
2707 self.assertEqual(expected, props)
2708
Simon Glass151bbbf2019-07-08 14:25:41 -06002709 def testCbfsUpdateFdt(self):
2710 """Test that we can update the device tree with CBFS offset/size info"""
2711 self._CheckLz4()
2712 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2713 update_dtb=True)
2714 dtb = fdt.Fdt(out_dtb_fname)
2715 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002716 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002717 del props['cbfs/u-boot:size']
2718 self.assertEqual({
2719 'offset': 0,
2720 'size': len(data),
2721 'image-pos': 0,
2722 'cbfs:offset': 0,
2723 'cbfs:size': len(data),
2724 'cbfs:image-pos': 0,
Simon Glassfa144222023-10-14 14:40:28 -06002725 'cbfs/u-boot:offset': 0x30,
Simon Glass151bbbf2019-07-08 14:25:41 -06002726 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002727 'cbfs/u-boot:image-pos': 0x30,
2728 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002729 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002730 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002731 }, props)
2732
Simon Glass3c9b4f22019-07-08 14:25:42 -06002733 def testCbfsBadType(self):
2734 """Test an image header with a no specified location is detected"""
2735 with self.assertRaises(ValueError) as e:
2736 self._DoReadFile('126_cbfs_bad_type.dts')
2737 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2738
Simon Glass6b156f82019-07-08 14:25:43 -06002739 def testList(self):
2740 """Test listing the files in an image"""
2741 self._CheckLz4()
2742 data = self._DoReadFile('127_list.dts')
2743 image = control.images['image']
2744 entries = image.BuildEntryList()
2745 self.assertEqual(7, len(entries))
2746
2747 ent = entries[0]
2748 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002749 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002750 self.assertEqual('section', ent.etype)
2751 self.assertEqual(len(data), ent.size)
2752 self.assertEqual(0, ent.image_pos)
2753 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002754 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002755
2756 ent = entries[1]
2757 self.assertEqual(1, ent.indent)
2758 self.assertEqual('u-boot', ent.name)
2759 self.assertEqual('u-boot', ent.etype)
2760 self.assertEqual(len(U_BOOT_DATA), ent.size)
2761 self.assertEqual(0, ent.image_pos)
2762 self.assertEqual(None, ent.uncomp_size)
2763 self.assertEqual(0, ent.offset)
2764
2765 ent = entries[2]
2766 self.assertEqual(1, ent.indent)
2767 self.assertEqual('section', ent.name)
2768 self.assertEqual('section', ent.etype)
2769 section_size = ent.size
2770 self.assertEqual(0x100, ent.image_pos)
2771 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002772 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002773
2774 ent = entries[3]
2775 self.assertEqual(2, ent.indent)
2776 self.assertEqual('cbfs', ent.name)
2777 self.assertEqual('cbfs', ent.etype)
2778 self.assertEqual(0x400, ent.size)
2779 self.assertEqual(0x100, ent.image_pos)
2780 self.assertEqual(None, ent.uncomp_size)
2781 self.assertEqual(0, ent.offset)
2782
2783 ent = entries[4]
2784 self.assertEqual(3, ent.indent)
2785 self.assertEqual('u-boot', ent.name)
2786 self.assertEqual('u-boot', ent.etype)
2787 self.assertEqual(len(U_BOOT_DATA), ent.size)
2788 self.assertEqual(0x138, ent.image_pos)
2789 self.assertEqual(None, ent.uncomp_size)
2790 self.assertEqual(0x38, ent.offset)
2791
2792 ent = entries[5]
2793 self.assertEqual(3, ent.indent)
2794 self.assertEqual('u-boot-dtb', ent.name)
2795 self.assertEqual('text', ent.etype)
2796 self.assertGreater(len(COMPRESS_DATA), ent.size)
2797 self.assertEqual(0x178, ent.image_pos)
2798 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2799 self.assertEqual(0x78, ent.offset)
2800
2801 ent = entries[6]
2802 self.assertEqual(2, ent.indent)
2803 self.assertEqual('u-boot-dtb', ent.name)
2804 self.assertEqual('u-boot-dtb', ent.etype)
2805 self.assertEqual(0x500, ent.image_pos)
2806 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2807 dtb_size = ent.size
2808 # Compressing this data expands it since headers are added
2809 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2810 self.assertEqual(0x400, ent.offset)
2811
2812 self.assertEqual(len(data), 0x100 + section_size)
2813 self.assertEqual(section_size, 0x400 + dtb_size)
2814
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002815 def testFindFdtmap(self):
2816 """Test locating an FDT map in an image"""
2817 self._CheckLz4()
2818 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2819 image = control.images['image']
2820 entries = image.GetEntries()
2821 entry = entries['fdtmap']
2822 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2823
2824 def testFindFdtmapMissing(self):
2825 """Test failing to locate an FDP map"""
2826 data = self._DoReadFile('005_simple.dts')
2827 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2828
Simon Glassed39a3c2019-07-08 14:25:45 -06002829 def testFindImageHeader(self):
2830 """Test locating a image header"""
2831 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002832 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002833 image = control.images['image']
2834 entries = image.GetEntries()
2835 entry = entries['fdtmap']
2836 # The header should point to the FDT map
2837 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2838
2839 def testFindImageHeaderStart(self):
2840 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002841 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002842 image = control.images['image']
2843 entries = image.GetEntries()
2844 entry = entries['fdtmap']
2845 # The header should point to the FDT map
2846 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2847
2848 def testFindImageHeaderMissing(self):
2849 """Test failing to locate an image header"""
2850 data = self._DoReadFile('005_simple.dts')
2851 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2852
Simon Glassb8424fa2019-07-08 14:25:46 -06002853 def testReadImage(self):
2854 """Test reading an image and accessing its FDT map"""
2855 self._CheckLz4()
2856 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002857 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002858 orig_image = control.images['image']
2859 image = Image.FromFile(image_fname)
2860 self.assertEqual(orig_image.GetEntries().keys(),
2861 image.GetEntries().keys())
2862
2863 orig_entry = orig_image.GetEntries()['fdtmap']
2864 entry = image.GetEntries()['fdtmap']
Brandon Maiera657bc62024-06-04 16:16:05 +00002865 self.assertEqual(orig_entry.offset, entry.offset)
2866 self.assertEqual(orig_entry.size, entry.size)
2867 self.assertEqual(orig_entry.image_pos, entry.image_pos)
Simon Glassb8424fa2019-07-08 14:25:46 -06002868
2869 def testReadImageNoHeader(self):
2870 """Test accessing an image's FDT map without an image header"""
2871 self._CheckLz4()
2872 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002873 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002874 image = Image.FromFile(image_fname)
2875 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002876 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002877
2878 def testReadImageFail(self):
2879 """Test failing to read an image image's FDT map"""
2880 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002881 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002882 with self.assertRaises(ValueError) as e:
2883 image = Image.FromFile(image_fname)
2884 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002885
Simon Glassb2fd11d2019-07-08 14:25:48 -06002886 def testListCmd(self):
2887 """Test listing the files in an image using an Fdtmap"""
2888 self._CheckLz4()
2889 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2890
2891 # lz4 compression size differs depending on the version
2892 image = control.images['image']
2893 entries = image.GetEntries()
2894 section_size = entries['section'].size
2895 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2896 fdtmap_offset = entries['fdtmap'].offset
2897
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002898 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002899 try:
2900 tmpdir, updated_fname = self._SetupImageInTmpdir()
2901 with test_util.capture_sys_output() as (stdout, stderr):
2902 self._DoBinman('ls', '-i', updated_fname)
2903 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002904 if tmpdir:
2905 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002906 lines = stdout.getvalue().splitlines()
2907 expected = [
2908'Name Image-pos Size Entry-type Offset Uncomp-size',
2909'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002910'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002911' u-boot 0 4 u-boot 0',
2912' section 100 %x section 100' % section_size,
2913' cbfs 100 400 cbfs 0',
Simon Glassfa144222023-10-14 14:40:28 -06002914' u-boot 120 4 u-boot 20',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002915' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002916' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002917' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002918 (fdtmap_offset, fdtmap_offset),
2919' image-header bf8 8 image-header bf8',
2920 ]
2921 self.assertEqual(expected, lines)
2922
2923 def testListCmdFail(self):
2924 """Test failing to list an image"""
2925 self._DoReadFile('005_simple.dts')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002926 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002927 try:
2928 tmpdir, updated_fname = self._SetupImageInTmpdir()
2929 with self.assertRaises(ValueError) as e:
2930 self._DoBinman('ls', '-i', updated_fname)
2931 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002932 if tmpdir:
2933 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002934 self.assertIn("Cannot find FDT map in image", str(e.exception))
2935
2936 def _RunListCmd(self, paths, expected):
2937 """List out entries and check the result
2938
2939 Args:
2940 paths: List of paths to pass to the list command
2941 expected: Expected list of filenames to be returned, in order
2942 """
2943 self._CheckLz4()
2944 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002945 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002946 image = Image.FromFile(image_fname)
2947 lines = image.GetListEntries(paths)[1]
2948 files = [line[0].strip() for line in lines[1:]]
2949 self.assertEqual(expected, files)
2950
2951 def testListCmdSection(self):
2952 """Test listing the files in a section"""
2953 self._RunListCmd(['section'],
2954 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2955
2956 def testListCmdFile(self):
2957 """Test listing a particular file"""
2958 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2959
2960 def testListCmdWildcard(self):
2961 """Test listing a wildcarded file"""
2962 self._RunListCmd(['*boot*'],
2963 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2964
2965 def testListCmdWildcardMulti(self):
2966 """Test listing a wildcarded file"""
2967 self._RunListCmd(['*cb*', '*head*'],
2968 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2969
2970 def testListCmdEmpty(self):
2971 """Test listing a wildcarded file"""
2972 self._RunListCmd(['nothing'], [])
2973
2974 def testListCmdPath(self):
2975 """Test listing the files in a sub-entry of a section"""
2976 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2977
Simon Glass4c613bf2019-07-08 14:25:50 -06002978 def _RunExtractCmd(self, entry_name, decomp=True):
2979 """Extract an entry from an image
2980
2981 Args:
2982 entry_name: Entry name to extract
2983 decomp: True to decompress the data if compressed, False to leave
2984 it in its raw uncompressed format
2985
2986 Returns:
2987 data from entry
2988 """
2989 self._CheckLz4()
2990 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002991 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002992 return control.ReadEntry(image_fname, entry_name, decomp)
2993
2994 def testExtractSimple(self):
2995 """Test extracting a single file"""
2996 data = self._RunExtractCmd('u-boot')
2997 self.assertEqual(U_BOOT_DATA, data)
2998
Simon Glass980a2842019-07-08 14:25:52 -06002999 def testExtractSection(self):
3000 """Test extracting the files in a section"""
3001 data = self._RunExtractCmd('section')
3002 cbfs_data = data[:0x400]
3003 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06003004 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06003005 dtb_data = data[0x400:]
3006 dtb = self._decompress(dtb_data)
3007 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3008
3009 def testExtractCompressed(self):
3010 """Test extracting compressed data"""
3011 data = self._RunExtractCmd('section/u-boot-dtb')
3012 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3013
3014 def testExtractRaw(self):
3015 """Test extracting compressed data without decompressing it"""
3016 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
3017 dtb = self._decompress(data)
3018 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3019
3020 def testExtractCbfs(self):
3021 """Test extracting CBFS data"""
3022 data = self._RunExtractCmd('section/cbfs/u-boot')
3023 self.assertEqual(U_BOOT_DATA, data)
3024
3025 def testExtractCbfsCompressed(self):
3026 """Test extracting CBFS compressed data"""
3027 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
3028 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3029
3030 def testExtractCbfsRaw(self):
3031 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003032 bintool = self.comp_bintools['lzma_alone']
3033 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06003034 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003035 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06003036 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3037
Simon Glass4c613bf2019-07-08 14:25:50 -06003038 def testExtractBadEntry(self):
3039 """Test extracting a bad section path"""
3040 with self.assertRaises(ValueError) as e:
3041 self._RunExtractCmd('section/does-not-exist')
3042 self.assertIn("Entry 'does-not-exist' not found in '/section'",
3043 str(e.exception))
3044
3045 def testExtractMissingFile(self):
3046 """Test extracting file that does not exist"""
3047 with self.assertRaises(IOError) as e:
3048 control.ReadEntry('missing-file', 'name')
3049
3050 def testExtractBadFile(self):
3051 """Test extracting an invalid file"""
3052 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07003053 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06003054 with self.assertRaises(ValueError) as e:
3055 control.ReadEntry(fname, 'name')
3056
Simon Glass980a2842019-07-08 14:25:52 -06003057 def testExtractCmd(self):
3058 """Test extracting a file fron an image on the command line"""
3059 self._CheckLz4()
3060 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06003061 fname = os.path.join(self._indir, 'output.extact')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003062 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06003063 try:
3064 tmpdir, updated_fname = self._SetupImageInTmpdir()
3065 with test_util.capture_sys_output() as (stdout, stderr):
3066 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3067 '-f', fname)
3068 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003069 if tmpdir:
3070 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07003071 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003072 self.assertEqual(U_BOOT_DATA, data)
3073
3074 def testExtractOneEntry(self):
3075 """Test extracting a single entry fron an image """
3076 self._CheckLz4()
3077 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003078 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003079 fname = os.path.join(self._indir, 'output.extact')
3080 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003081 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003082 self.assertEqual(U_BOOT_DATA, data)
3083
3084 def _CheckExtractOutput(self, decomp):
3085 """Helper to test file output with and without decompression
3086
3087 Args:
3088 decomp: True to decompress entry data, False to output it raw
3089 """
3090 def _CheckPresent(entry_path, expect_data, expect_size=None):
3091 """Check and remove expected file
3092
3093 This checks the data/size of a file and removes the file both from
3094 the outfiles set and from the output directory. Once all files are
3095 processed, both the set and directory should be empty.
3096
3097 Args:
3098 entry_path: Entry path
3099 expect_data: Data to expect in file, or None to skip check
3100 expect_size: Size of data to expect in file, or None to skip
3101 """
3102 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003103 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003104 os.remove(path)
3105 if expect_data:
3106 self.assertEqual(expect_data, data)
3107 elif expect_size:
3108 self.assertEqual(expect_size, len(data))
3109 outfiles.remove(path)
3110
3111 def _CheckDirPresent(name):
3112 """Remove expected directory
3113
3114 This gives an error if the directory does not exist as expected
3115
3116 Args:
3117 name: Name of directory to remove
3118 """
3119 path = os.path.join(outdir, name)
3120 os.rmdir(path)
3121
3122 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003123 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003124 outdir = os.path.join(self._indir, 'extract')
3125 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3126
3127 # Create a set of all file that were output (should be 9)
3128 outfiles = set()
3129 for root, dirs, files in os.walk(outdir):
3130 outfiles |= set([os.path.join(root, fname) for fname in files])
3131 self.assertEqual(9, len(outfiles))
3132 self.assertEqual(9, len(einfos))
3133
3134 image = control.images['image']
3135 entries = image.GetEntries()
3136
3137 # Check the 9 files in various ways
3138 section = entries['section']
3139 section_entries = section.GetEntries()
3140 cbfs_entries = section_entries['cbfs'].GetEntries()
3141 _CheckPresent('u-boot', U_BOOT_DATA)
3142 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3143 dtb_len = EXTRACT_DTB_SIZE
3144 if not decomp:
3145 dtb_len = cbfs_entries['u-boot-dtb'].size
3146 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3147 if not decomp:
3148 dtb_len = section_entries['u-boot-dtb'].size
3149 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3150
3151 fdtmap = entries['fdtmap']
3152 _CheckPresent('fdtmap', fdtmap.data)
3153 hdr = entries['image-header']
3154 _CheckPresent('image-header', hdr.data)
3155
3156 _CheckPresent('section/root', section.data)
3157 cbfs = section_entries['cbfs']
3158 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003159 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003160 _CheckPresent('root', data)
3161
3162 # There should be no files left. Remove all the directories to check.
3163 # If there are any files/dirs remaining, one of these checks will fail.
3164 self.assertEqual(0, len(outfiles))
3165 _CheckDirPresent('section/cbfs')
3166 _CheckDirPresent('section')
3167 _CheckDirPresent('')
3168 self.assertFalse(os.path.exists(outdir))
3169
3170 def testExtractAllEntries(self):
3171 """Test extracting all entries"""
3172 self._CheckLz4()
3173 self._CheckExtractOutput(decomp=True)
3174
3175 def testExtractAllEntriesRaw(self):
3176 """Test extracting all entries without decompressing them"""
3177 self._CheckLz4()
3178 self._CheckExtractOutput(decomp=False)
3179
3180 def testExtractSelectedEntries(self):
3181 """Test extracting some entries"""
3182 self._CheckLz4()
3183 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003184 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003185 outdir = os.path.join(self._indir, 'extract')
3186 einfos = control.ExtractEntries(image_fname, None, outdir,
3187 ['*cb*', '*head*'])
3188
3189 # File output is tested by testExtractAllEntries(), so just check that
3190 # the expected entries are selected
3191 names = [einfo.name for einfo in einfos]
3192 self.assertEqual(names,
3193 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3194
3195 def testExtractNoEntryPaths(self):
3196 """Test extracting some entries"""
3197 self._CheckLz4()
3198 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003199 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003200 with self.assertRaises(ValueError) as e:
3201 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003202 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003203 str(e.exception))
3204
3205 def testExtractTooManyEntryPaths(self):
3206 """Test extracting some entries"""
3207 self._CheckLz4()
3208 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003209 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003210 with self.assertRaises(ValueError) as e:
3211 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003212 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003213 str(e.exception))
3214
Simon Glass52d06212019-07-08 14:25:53 -06003215 def testPackAlignSection(self):
3216 """Test that sections can have alignment"""
3217 self._DoReadFile('131_pack_align_section.dts')
3218
3219 self.assertIn('image', control.images)
3220 image = control.images['image']
3221 entries = image.GetEntries()
3222 self.assertEqual(3, len(entries))
3223
3224 # First u-boot
3225 self.assertIn('u-boot', entries)
3226 entry = entries['u-boot']
3227 self.assertEqual(0, entry.offset)
3228 self.assertEqual(0, entry.image_pos)
3229 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3230 self.assertEqual(len(U_BOOT_DATA), entry.size)
3231
3232 # Section0
3233 self.assertIn('section0', entries)
3234 section0 = entries['section0']
3235 self.assertEqual(0x10, section0.offset)
3236 self.assertEqual(0x10, section0.image_pos)
3237 self.assertEqual(len(U_BOOT_DATA), section0.size)
3238
3239 # Second u-boot
3240 section_entries = section0.GetEntries()
3241 self.assertIn('u-boot', section_entries)
3242 entry = section_entries['u-boot']
3243 self.assertEqual(0, entry.offset)
3244 self.assertEqual(0x10, entry.image_pos)
3245 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3246 self.assertEqual(len(U_BOOT_DATA), entry.size)
3247
3248 # Section1
3249 self.assertIn('section1', entries)
3250 section1 = entries['section1']
3251 self.assertEqual(0x14, section1.offset)
3252 self.assertEqual(0x14, section1.image_pos)
3253 self.assertEqual(0x20, section1.size)
3254
3255 # Second u-boot
3256 section_entries = section1.GetEntries()
3257 self.assertIn('u-boot', section_entries)
3258 entry = section_entries['u-boot']
3259 self.assertEqual(0, entry.offset)
3260 self.assertEqual(0x14, entry.image_pos)
3261 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3262 self.assertEqual(len(U_BOOT_DATA), entry.size)
3263
3264 # Section2
3265 self.assertIn('section2', section_entries)
3266 section2 = section_entries['section2']
3267 self.assertEqual(0x4, section2.offset)
3268 self.assertEqual(0x18, section2.image_pos)
3269 self.assertEqual(4, section2.size)
3270
3271 # Third u-boot
3272 section_entries = section2.GetEntries()
3273 self.assertIn('u-boot', section_entries)
3274 entry = section_entries['u-boot']
3275 self.assertEqual(0, entry.offset)
3276 self.assertEqual(0x18, entry.image_pos)
3277 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3278 self.assertEqual(len(U_BOOT_DATA), entry.size)
3279
Simon Glassf8a54bc2019-07-20 12:23:56 -06003280 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3281 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003282 """Replace an entry in an image
3283
3284 This writes the entry data to update it, then opens the updated file and
3285 returns the value that it now finds there.
3286
3287 Args:
3288 entry_name: Entry name to replace
3289 data: Data to replace it with
3290 decomp: True to compress the data if needed, False if data is
3291 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003292 allow_resize: True to allow entries to change size, False to raise
3293 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003294
3295 Returns:
3296 Tuple:
3297 data from entry
3298 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003299 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003300 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003301 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003302 update_dtb=True)[1]
3303
3304 self.assertIn('image', control.images)
3305 image = control.images['image']
3306 entries = image.GetEntries()
3307 orig_dtb_data = entries['u-boot-dtb'].data
3308 orig_fdtmap_data = entries['fdtmap'].data
3309
Simon Glass80025522022-01-29 14:14:04 -07003310 image_fname = tools.get_output_filename('image.bin')
3311 updated_fname = tools.get_output_filename('image-updated.bin')
3312 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003313 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3314 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003315 data = control.ReadEntry(updated_fname, entry_name, decomp)
3316
Simon Glassf8a54bc2019-07-20 12:23:56 -06003317 # The DT data should not change unless resized:
3318 if not allow_resize:
3319 new_dtb_data = entries['u-boot-dtb'].data
3320 self.assertEqual(new_dtb_data, orig_dtb_data)
3321 new_fdtmap_data = entries['fdtmap'].data
3322 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003323
Simon Glassf8a54bc2019-07-20 12:23:56 -06003324 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003325
3326 def testReplaceSimple(self):
3327 """Test replacing a single file"""
3328 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003329 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3330 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003331 self.assertEqual(expected, data)
3332
3333 # Test that the state looks right. There should be an FDT for the fdtmap
3334 # that we jsut read back in, and it should match what we find in the
3335 # 'control' tables. Checking for an FDT that does not exist should
3336 # return None.
3337 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003338 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003339 self.assertEqual(expected_fdtmap, fdtmap)
3340
3341 dtb = state.GetFdtForEtype('fdtmap')
3342 self.assertEqual(dtb.GetContents(), fdtmap)
3343
3344 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3345 self.assertIsNone(missing_path)
3346 self.assertIsNone(missing_fdtmap)
3347
3348 missing_dtb = state.GetFdtForEtype('missing')
3349 self.assertIsNone(missing_dtb)
3350
3351 self.assertEqual('/binman', state.fdt_path_prefix)
3352
3353 def testReplaceResizeFail(self):
3354 """Test replacing a file by something larger"""
3355 expected = U_BOOT_DATA + b'x'
3356 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003357 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3358 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003359 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3360 str(e.exception))
3361
3362 def testReplaceMulti(self):
3363 """Test replacing entry data where multiple images are generated"""
3364 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3365 update_dtb=True)[0]
3366 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003367 updated_fname = tools.get_output_filename('image-updated.bin')
3368 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003369 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003370 control.WriteEntry(updated_fname, entry_name, expected,
3371 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003372 data = control.ReadEntry(updated_fname, entry_name)
3373 self.assertEqual(expected, data)
3374
3375 # Check the state looks right.
3376 self.assertEqual('/binman/image', state.fdt_path_prefix)
3377
3378 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003379 image_fname = tools.get_output_filename('first-image.bin')
3380 updated_fname = tools.get_output_filename('first-updated.bin')
3381 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003382 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003383 control.WriteEntry(updated_fname, entry_name, expected,
3384 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003385 data = control.ReadEntry(updated_fname, entry_name)
3386 self.assertEqual(expected, data)
3387
3388 # Check the state looks right.
3389 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003390
Simon Glassfb30e292019-07-20 12:23:51 -06003391 def testUpdateFdtAllRepack(self):
3392 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003393 self._SetupSplElf()
3394 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003395 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3396 SECTION_SIZE = 0x300
3397 DTB_SIZE = 602
3398 FDTMAP_SIZE = 608
3399 base_expected = {
3400 'offset': 0,
3401 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3402 'image-pos': 0,
3403 'section:offset': 0,
3404 'section:size': SECTION_SIZE,
3405 'section:image-pos': 0,
3406 'section/u-boot-dtb:offset': 4,
3407 'section/u-boot-dtb:size': 636,
3408 'section/u-boot-dtb:image-pos': 4,
3409 'u-boot-spl-dtb:offset': SECTION_SIZE,
3410 'u-boot-spl-dtb:size': DTB_SIZE,
3411 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3412 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3413 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3414 'u-boot-tpl-dtb:size': DTB_SIZE,
3415 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3416 'fdtmap:size': FDTMAP_SIZE,
3417 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3418 }
3419 main_expected = {
3420 'section:orig-size': SECTION_SIZE,
3421 'section/u-boot-dtb:orig-offset': 4,
3422 }
3423
3424 # We expect three device-tree files in the output, with the first one
3425 # within a fixed-size section.
3426 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3427 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3428 # main U-Boot tree. All three should have the same positions and offset
3429 # except that the main tree should include the main_expected properties
3430 start = 4
3431 for item in ['', 'spl', 'tpl', None]:
3432 if item is None:
3433 start += 16 # Move past fdtmap header
3434 dtb = fdt.Fdt.FromData(data[start:])
3435 dtb.Scan()
3436 props = self._GetPropTree(dtb,
3437 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3438 prefix='/' if item is None else '/binman/')
3439 expected = dict(base_expected)
3440 if item:
3441 expected[item] = 0
3442 else:
3443 # Main DTB and fdtdec should include the 'orig-' properties
3444 expected.update(main_expected)
3445 # Helpful for debugging:
3446 #for prop in sorted(props):
3447 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3448 self.assertEqual(expected, props)
3449 if item == '':
3450 start = SECTION_SIZE
3451 else:
3452 start += dtb._fdt_obj.totalsize()
3453
Simon Glass11453762019-07-20 12:23:55 -06003454 def testFdtmapHeaderMiddle(self):
3455 """Test an FDT map in the middle of an image when it should be at end"""
3456 with self.assertRaises(ValueError) as e:
3457 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3458 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3459 str(e.exception))
3460
3461 def testFdtmapHeaderStartBad(self):
3462 """Test an FDT map in middle of an image when it should be at start"""
3463 with self.assertRaises(ValueError) as e:
3464 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3465 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3466 str(e.exception))
3467
3468 def testFdtmapHeaderEndBad(self):
3469 """Test an FDT map at the start of an image when it should be at end"""
3470 with self.assertRaises(ValueError) as e:
3471 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3472 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3473 str(e.exception))
3474
3475 def testFdtmapHeaderNoSize(self):
3476 """Test an image header at the end of an image with undefined size"""
3477 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3478
Simon Glassf8a54bc2019-07-20 12:23:56 -06003479 def testReplaceResize(self):
3480 """Test replacing a single file in an entry with a larger file"""
3481 expected = U_BOOT_DATA + b'x'
3482 data, _, image = self._RunReplaceCmd('u-boot', expected,
3483 dts='139_replace_repack.dts')
3484 self.assertEqual(expected, data)
3485
3486 entries = image.GetEntries()
3487 dtb_data = entries['u-boot-dtb'].data
3488 dtb = fdt.Fdt.FromData(dtb_data)
3489 dtb.Scan()
3490
3491 # The u-boot section should now be larger in the dtb
3492 node = dtb.GetNode('/binman/u-boot')
3493 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3494
3495 # Same for the fdtmap
3496 fdata = entries['fdtmap'].data
3497 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3498 fdtb.Scan()
3499 fnode = fdtb.GetNode('/u-boot')
3500 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3501
3502 def testReplaceResizeNoRepack(self):
3503 """Test replacing an entry with a larger file when not allowed"""
3504 expected = U_BOOT_DATA + b'x'
3505 with self.assertRaises(ValueError) as e:
3506 self._RunReplaceCmd('u-boot', expected)
3507 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3508 str(e.exception))
3509
Simon Glass9d8ee322019-07-20 12:23:58 -06003510 def testEntryShrink(self):
3511 """Test contracting an entry after it is packed"""
3512 try:
3513 state.SetAllowEntryContraction(True)
3514 data = self._DoReadFileDtb('140_entry_shrink.dts',
3515 update_dtb=True)[0]
3516 finally:
3517 state.SetAllowEntryContraction(False)
3518 self.assertEqual(b'a', data[:1])
3519 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3520 self.assertEqual(b'a', data[-1:])
3521
3522 def testEntryShrinkFail(self):
3523 """Test not being allowed to contract an entry after it is packed"""
3524 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3525
3526 # In this case there is a spare byte at the end of the data. The size of
3527 # the contents is only 1 byte but we still have the size before it
3528 # shrunk.
3529 self.assertEqual(b'a\0', data[:2])
3530 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3531 self.assertEqual(b'a\0', data[-2:])
3532
Simon Glass70e32982019-07-20 12:24:01 -06003533 def testDescriptorOffset(self):
3534 """Test that the Intel descriptor is always placed at at the start"""
3535 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3536 image = control.images['image']
3537 entries = image.GetEntries()
3538 desc = entries['intel-descriptor']
3539 self.assertEqual(0xff800000, desc.offset);
3540 self.assertEqual(0xff800000, desc.image_pos);
3541
Simon Glass37fdd142019-07-20 12:24:06 -06003542 def testReplaceCbfs(self):
3543 """Test replacing a single file in CBFS without changing the size"""
3544 self._CheckLz4()
3545 expected = b'x' * len(U_BOOT_DATA)
3546 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003547 updated_fname = tools.get_output_filename('image-updated.bin')
3548 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003549 entry_name = 'section/cbfs/u-boot'
3550 control.WriteEntry(updated_fname, entry_name, expected,
3551 allow_resize=True)
3552 data = control.ReadEntry(updated_fname, entry_name)
3553 self.assertEqual(expected, data)
3554
3555 def testReplaceResizeCbfs(self):
3556 """Test replacing a single file in CBFS with one of a different size"""
3557 self._CheckLz4()
3558 expected = U_BOOT_DATA + b'x'
3559 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003560 updated_fname = tools.get_output_filename('image-updated.bin')
3561 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003562 entry_name = 'section/cbfs/u-boot'
3563 control.WriteEntry(updated_fname, entry_name, expected,
3564 allow_resize=True)
3565 data = control.ReadEntry(updated_fname, entry_name)
3566 self.assertEqual(expected, data)
3567
Simon Glass30033c22019-07-20 12:24:15 -06003568 def _SetupForReplace(self):
3569 """Set up some files to use to replace entries
3570
3571 This generates an image, copies it to a new file, extracts all the files
3572 in it and updates some of them
3573
3574 Returns:
3575 List
3576 Image filename
3577 Output directory
3578 Expected values for updated entries, each a string
3579 """
3580 data = self._DoReadFileRealDtb('143_replace_all.dts')
3581
Simon Glass80025522022-01-29 14:14:04 -07003582 updated_fname = tools.get_output_filename('image-updated.bin')
3583 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003584
3585 outdir = os.path.join(self._indir, 'extract')
3586 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3587
3588 expected1 = b'x' + U_BOOT_DATA + b'y'
3589 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003590 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003591
3592 expected2 = b'a' + U_BOOT_DATA + b'b'
3593 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003594 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003595
3596 expected_text = b'not the same text'
3597 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003598 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003599
3600 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3601 dtb = fdt.FdtScan(dtb_fname)
3602 node = dtb.GetNode('/binman/text')
3603 node.AddString('my-property', 'the value')
3604 dtb.Sync(auto_resize=True)
3605 dtb.Flush()
3606
3607 return updated_fname, outdir, expected1, expected2, expected_text
3608
3609 def _CheckReplaceMultiple(self, entry_paths):
3610 """Handle replacing the contents of multiple entries
3611
3612 Args:
3613 entry_paths: List of entry paths to replace
3614
3615 Returns:
3616 List
3617 Dict of entries in the image:
3618 key: Entry name
3619 Value: Entry object
3620 Expected values for updated entries, each a string
3621 """
3622 updated_fname, outdir, expected1, expected2, expected_text = (
3623 self._SetupForReplace())
3624 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3625
3626 image = Image.FromFile(updated_fname)
3627 image.LoadData()
3628 return image.GetEntries(), expected1, expected2, expected_text
3629
3630 def testReplaceAll(self):
3631 """Test replacing the contents of all entries"""
3632 entries, expected1, expected2, expected_text = (
3633 self._CheckReplaceMultiple([]))
3634 data = entries['u-boot'].data
3635 self.assertEqual(expected1, data)
3636
3637 data = entries['u-boot2'].data
3638 self.assertEqual(expected2, data)
3639
3640 data = entries['text'].data
3641 self.assertEqual(expected_text, data)
3642
3643 # Check that the device tree is updated
3644 data = entries['u-boot-dtb'].data
3645 dtb = fdt.Fdt.FromData(data)
3646 dtb.Scan()
3647 node = dtb.GetNode('/binman/text')
3648 self.assertEqual('the value', node.props['my-property'].value)
3649
3650 def testReplaceSome(self):
3651 """Test replacing the contents of a few entries"""
3652 entries, expected1, expected2, expected_text = (
3653 self._CheckReplaceMultiple(['u-boot2', 'text']))
3654
3655 # This one should not change
3656 data = entries['u-boot'].data
3657 self.assertEqual(U_BOOT_DATA, data)
3658
3659 data = entries['u-boot2'].data
3660 self.assertEqual(expected2, data)
3661
3662 data = entries['text'].data
3663 self.assertEqual(expected_text, data)
3664
3665 def testReplaceCmd(self):
3666 """Test replacing a file fron an image on the command line"""
3667 self._DoReadFileRealDtb('143_replace_all.dts')
3668
3669 try:
3670 tmpdir, updated_fname = self._SetupImageInTmpdir()
3671
3672 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3673 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003674 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003675
3676 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003677 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003678 self.assertEqual(expected, data[:len(expected)])
3679 map_fname = os.path.join(tmpdir, 'image-updated.map')
3680 self.assertFalse(os.path.exists(map_fname))
3681 finally:
3682 shutil.rmtree(tmpdir)
3683
3684 def testReplaceCmdSome(self):
3685 """Test replacing some files fron an image on the command line"""
3686 updated_fname, outdir, expected1, expected2, expected_text = (
3687 self._SetupForReplace())
3688
3689 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3690 'u-boot2', 'text')
3691
Simon Glass80025522022-01-29 14:14:04 -07003692 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003693 image = Image.FromFile(updated_fname)
3694 image.LoadData()
3695 entries = image.GetEntries()
3696
3697 # This one should not change
3698 data = entries['u-boot'].data
3699 self.assertEqual(U_BOOT_DATA, data)
3700
3701 data = entries['u-boot2'].data
3702 self.assertEqual(expected2, data)
3703
3704 data = entries['text'].data
3705 self.assertEqual(expected_text, data)
3706
3707 def testReplaceMissing(self):
3708 """Test replacing entries where the file is missing"""
3709 updated_fname, outdir, expected1, expected2, expected_text = (
3710 self._SetupForReplace())
3711
3712 # Remove one of the files, to generate a warning
3713 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3714 os.remove(u_boot_fname1)
3715
3716 with test_util.capture_sys_output() as (stdout, stderr):
3717 control.ReplaceEntries(updated_fname, None, outdir, [])
3718 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003719 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003720
3721 def testReplaceCmdMap(self):
3722 """Test replacing a file fron an image on the command line"""
3723 self._DoReadFileRealDtb('143_replace_all.dts')
3724
3725 try:
3726 tmpdir, updated_fname = self._SetupImageInTmpdir()
3727
3728 fname = os.path.join(self._indir, 'update-u-boot.bin')
3729 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003730 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003731
3732 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3733 '-f', fname, '-m')
3734 map_fname = os.path.join(tmpdir, 'image-updated.map')
3735 self.assertTrue(os.path.exists(map_fname))
3736 finally:
3737 shutil.rmtree(tmpdir)
3738
3739 def testReplaceNoEntryPaths(self):
3740 """Test replacing an entry without an entry path"""
3741 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003742 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003743 with self.assertRaises(ValueError) as e:
3744 control.ReplaceEntries(image_fname, 'fname', None, [])
3745 self.assertIn('Must specify an entry path to read with -f',
3746 str(e.exception))
3747
3748 def testReplaceTooManyEntryPaths(self):
3749 """Test extracting some entries"""
3750 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003751 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003752 with self.assertRaises(ValueError) as e:
3753 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3754 self.assertIn('Must specify exactly one entry path to write with -f',
3755 str(e.exception))
3756
Simon Glass0b074d62019-08-24 07:22:48 -06003757 def testPackReset16(self):
3758 """Test that an image with an x86 reset16 region can be created"""
3759 data = self._DoReadFile('144_x86_reset16.dts')
3760 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3761
3762 def testPackReset16Spl(self):
3763 """Test that an image with an x86 reset16-spl region can be created"""
3764 data = self._DoReadFile('145_x86_reset16_spl.dts')
3765 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3766
3767 def testPackReset16Tpl(self):
3768 """Test that an image with an x86 reset16-tpl region can be created"""
3769 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3770 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3771
Simon Glass232f90c2019-08-24 07:22:50 -06003772 def testPackIntelFit(self):
3773 """Test that an image with an Intel FIT and pointer can be created"""
3774 data = self._DoReadFile('147_intel_fit.dts')
3775 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3776 fit = data[16:32];
3777 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3778 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3779
3780 image = control.images['image']
3781 entries = image.GetEntries()
3782 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3783 self.assertEqual(expected_ptr, ptr)
3784
3785 def testPackIntelFitMissing(self):
3786 """Test detection of a FIT pointer with not FIT region"""
3787 with self.assertRaises(ValueError) as e:
3788 self._DoReadFile('148_intel_fit_missing.dts')
3789 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3790 str(e.exception))
3791
Simon Glass72555fa2019-11-06 17:22:44 -07003792 def _CheckSymbolsTplSection(self, dts, expected_vals):
3793 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003794 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003795 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003796 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003797 self.assertEqual(expected1, data[:upto1])
3798
3799 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003800 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003801 self.assertEqual(expected2, data[upto1:upto2])
3802
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003803 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003804 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003805 self.assertEqual(expected3, data[upto2:upto3])
3806
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003807 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003808 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3809
3810 def testSymbolsTplSection(self):
3811 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3812 self._SetupSplElf('u_boot_binman_syms')
3813 self._SetupTplElf('u_boot_binman_syms')
3814 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003815 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003816
3817 def testSymbolsTplSectionX86(self):
3818 """Test binman can assign symbols in a section with end-at-4gb"""
3819 self._SetupSplElf('u_boot_binman_syms_x86')
3820 self._SetupTplElf('u_boot_binman_syms_x86')
3821 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003822 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003823 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003824
Simon Glass98c59572019-08-24 07:23:03 -06003825 def testPackX86RomIfwiSectiom(self):
3826 """Test that a section can be placed in an IFWI region"""
3827 self._SetupIfwi('fitimage.bin')
3828 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3829 self._CheckIfwi(data)
3830
Simon Glassba7985d2019-08-24 07:23:07 -06003831 def testPackFspM(self):
3832 """Test that an image with a FSP memory-init binary can be created"""
3833 data = self._DoReadFile('152_intel_fsp_m.dts')
3834 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3835
Simon Glass4d9086d2019-10-20 21:31:35 -06003836 def testPackFspS(self):
3837 """Test that an image with a FSP silicon-init binary can be created"""
3838 data = self._DoReadFile('153_intel_fsp_s.dts')
3839 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003840
Simon Glass9ea87b22019-10-20 21:31:36 -06003841 def testPackFspT(self):
3842 """Test that an image with a FSP temp-ram-init binary can be created"""
3843 data = self._DoReadFile('154_intel_fsp_t.dts')
3844 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3845
Simon Glass48f3aad2020-07-09 18:39:31 -06003846 def testMkimage(self):
3847 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003848 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003849 data = self._DoReadFile('156_mkimage.dts')
3850
3851 # Just check that the data appears in the file somewhere
3852 self.assertIn(U_BOOT_SPL_DATA, data)
3853
Simon Glass66152ce2022-01-09 20:14:09 -07003854 def testMkimageMissing(self):
3855 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003856 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003857 with test_util.capture_sys_output() as (_, stderr):
3858 self._DoTestFile('156_mkimage.dts',
3859 force_missing_bintools='mkimage')
3860 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003861 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003862
Simon Glass5e560182020-07-09 18:39:36 -06003863 def testExtblob(self):
3864 """Test an image with an external blob"""
3865 data = self._DoReadFile('157_blob_ext.dts')
3866 self.assertEqual(REFCODE_DATA, data)
3867
3868 def testExtblobMissing(self):
3869 """Test an image with a missing external blob"""
3870 with self.assertRaises(ValueError) as e:
3871 self._DoReadFile('158_blob_ext_missing.dts')
3872 self.assertIn("Filename 'missing-file' not found in input path",
3873 str(e.exception))
3874
Simon Glass5d94cc62020-07-09 18:39:38 -06003875 def testExtblobMissingOk(self):
3876 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003877 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003878 ret = self._DoTestFile('158_blob_ext_missing.dts',
3879 allow_missing=True)
3880 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003881 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003882 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003883 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003884 self.assertIn('Some images are invalid', err)
3885
3886 def testExtblobMissingOkFlag(self):
3887 """Test an image with an missing external blob allowed with -W"""
3888 with test_util.capture_sys_output() as (stdout, stderr):
3889 ret = self._DoTestFile('158_blob_ext_missing.dts',
3890 allow_missing=True, ignore_missing=True)
3891 self.assertEqual(0, ret)
3892 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003893 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003894 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003895 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003896
3897 def testExtblobMissingOkSect(self):
3898 """Test an image with an missing external blob that is allowed"""
3899 with test_util.capture_sys_output() as (stdout, stderr):
3900 self._DoTestFile('159_blob_ext_missing_sect.dts',
3901 allow_missing=True)
3902 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003903 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003904
Simon Glasse88cef92020-07-09 18:39:41 -06003905 def testPackX86RomMeMissingDesc(self):
3906 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003907 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003908 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003909 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003910 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003911
3912 def testPackX86RomMissingIfwi(self):
3913 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3914 self._SetupIfwi('fitimage.bin')
3915 pathname = os.path.join(self._indir, 'fitimage.bin')
3916 os.remove(pathname)
3917 with test_util.capture_sys_output() as (stdout, stderr):
3918 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3919 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003920 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003921
Simon Glass2a0fa982022-02-11 13:23:21 -07003922 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003923 """Test that zero-size overlapping regions are ignored"""
3924 self._DoTestFile('160_pack_overlap_zero.dts')
3925
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003926 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003927 # The data should be inside the FIT
3928 dtb = fdt.Fdt.FromData(fit_data)
3929 dtb.Scan()
3930 fnode = dtb.GetNode('/images/kernel')
3931 self.assertIn('data', fnode.props)
3932
3933 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003934 tools.write_file(fname, fit_data)
3935 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003936
3937 # Check a few features to make sure the plumbing works. We don't need
3938 # to test the operation of mkimage or dumpimage here. First convert the
3939 # output into a dict where the keys are the fields printed by dumpimage
3940 # and the values are a list of values for each field
3941 lines = out.splitlines()
3942
3943 # Converts "Compression: gzip compressed" into two groups:
3944 # 'Compression' and 'gzip compressed'
3945 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3946 vals = collections.defaultdict(list)
3947 for line in lines:
3948 mat = re_line.match(line)
3949 vals[mat.group(1)].append(mat.group(2))
3950
Brandon Maiera657bc62024-06-04 16:16:05 +00003951 self.assertEqual('FIT description: test-desc', lines[0])
Simon Glass45d556d2020-07-09 18:39:45 -06003952 self.assertIn('Created:', lines[1])
3953 self.assertIn('Image 0 (kernel)', vals)
3954 self.assertIn('Hash value', vals)
3955 data_sizes = vals.get('Data Size')
3956 self.assertIsNotNone(data_sizes)
3957 self.assertEqual(2, len(data_sizes))
3958 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003959 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3960 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3961
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003962 # Check if entry listing correctly omits /images/
3963 image = control.images['image']
3964 fit_entry = image.GetEntries()['fit']
3965 subentries = list(fit_entry.GetEntries().keys())
3966 expected = ['kernel', 'fdt-1']
3967 self.assertEqual(expected, subentries)
3968
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003969 def testSimpleFit(self):
3970 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003971 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003972 data = self._DoReadFile('161_fit.dts')
3973 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3974 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3975 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3976
3977 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3978
3979 def testSimpleFitExpandsSubentries(self):
3980 """Test that FIT images expand their subentries"""
3981 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3982 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3983 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3984 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3985
3986 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003987
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003988 def testSimpleFitImagePos(self):
3989 """Test that we have correct image-pos for FIT subentries"""
3990 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3991 update_dtb=True)
3992 dtb = fdt.Fdt(out_dtb_fname)
3993 dtb.Scan()
3994 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3995
Simon Glassb7bad182022-03-05 20:19:01 -07003996 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003997 self.assertEqual({
3998 'image-pos': 0,
3999 'offset': 0,
4000 'size': 1890,
4001
4002 'u-boot:image-pos': 0,
4003 'u-boot:offset': 0,
4004 'u-boot:size': 4,
4005
4006 'fit:image-pos': 4,
4007 'fit:offset': 4,
4008 'fit:size': 1840,
4009
Simon Glassb7bad182022-03-05 20:19:01 -07004010 'fit/images/kernel:image-pos': 304,
4011 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004012 'fit/images/kernel:size': 4,
4013
Simon Glassb7bad182022-03-05 20:19:01 -07004014 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004015 'fit/images/kernel/u-boot:offset': 0,
4016 'fit/images/kernel/u-boot:size': 4,
4017
Simon Glassb7bad182022-03-05 20:19:01 -07004018 'fit/images/fdt-1:image-pos': 552,
4019 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004020 'fit/images/fdt-1:size': 6,
4021
Simon Glassb7bad182022-03-05 20:19:01 -07004022 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004023 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
4024 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
4025
4026 'u-boot-nodtb:image-pos': 1844,
4027 'u-boot-nodtb:offset': 1844,
4028 'u-boot-nodtb:size': 46,
4029 }, props)
4030
4031 # Actually check the data is where we think it is
4032 for node, expected in [
4033 ("u-boot", U_BOOT_DATA),
4034 ("fit/images/kernel", U_BOOT_DATA),
4035 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4036 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
4037 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
4038 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4039 ]:
4040 image_pos = props[f"{node}:image-pos"]
4041 size = props[f"{node}:size"]
4042 self.assertEqual(len(expected), size)
4043 self.assertEqual(expected, data[image_pos:image_pos+size])
4044
Simon Glass45d556d2020-07-09 18:39:45 -06004045 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06004046 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06004047 data = self._DoReadFile('162_fit_external.dts')
4048 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
4049
Simon Glass7932c882022-01-09 20:13:39 -07004050 # Size of the external-data region as set up by mkimage
4051 external_data_size = len(U_BOOT_DATA) + 2
4052 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07004053 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07004054 len(U_BOOT_NODTB_DATA))
4055
Simon Glass45d556d2020-07-09 18:39:45 -06004056 # The data should be outside the FIT
4057 dtb = fdt.Fdt.FromData(fit_data)
4058 dtb.Scan()
4059 fnode = dtb.GetNode('/images/kernel')
4060 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07004061 self.assertEqual(len(U_BOOT_DATA),
4062 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4063 fit_pos = 0x400;
4064 self.assertEqual(
4065 fit_pos,
4066 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4067
Brandon Maiera657bc62024-06-04 16:16:05 +00004068 self.assertEqual(expected_size, len(data))
Simon Glass7932c882022-01-09 20:13:39 -07004069 actual_pos = len(U_BOOT_DATA) + fit_pos
4070 self.assertEqual(U_BOOT_DATA + b'aa',
4071 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004072
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004073 def testFitExternalImagePos(self):
4074 """Test that we have correct image-pos for external FIT subentries"""
4075 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4076 update_dtb=True)
4077 dtb = fdt.Fdt(out_dtb_fname)
4078 dtb.Scan()
4079 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4080
4081 self.assertEqual({
4082 'image-pos': 0,
4083 'offset': 0,
4084 'size': 1082,
4085
4086 'u-boot:image-pos': 0,
4087 'u-boot:offset': 0,
4088 'u-boot:size': 4,
4089
4090 'fit:size': 1032,
4091 'fit:offset': 4,
4092 'fit:image-pos': 4,
4093
4094 'fit/images/kernel:size': 4,
4095 'fit/images/kernel:offset': 1024,
4096 'fit/images/kernel:image-pos': 1028,
4097
4098 'fit/images/kernel/u-boot:size': 4,
4099 'fit/images/kernel/u-boot:offset': 0,
4100 'fit/images/kernel/u-boot:image-pos': 1028,
4101
4102 'fit/images/fdt-1:size': 2,
4103 'fit/images/fdt-1:offset': 1028,
4104 'fit/images/fdt-1:image-pos': 1032,
4105
4106 'fit/images/fdt-1/_testing:size': 2,
4107 'fit/images/fdt-1/_testing:offset': 0,
4108 'fit/images/fdt-1/_testing:image-pos': 1032,
4109
4110 'u-boot-nodtb:image-pos': 1036,
4111 'u-boot-nodtb:offset': 1036,
4112 'u-boot-nodtb:size': 46,
4113 }, props)
4114
4115 # Actually check the data is where we think it is
4116 for node, expected in [
4117 ("u-boot", U_BOOT_DATA),
4118 ("fit/images/kernel", U_BOOT_DATA),
4119 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4120 ("fit/images/fdt-1", b'aa'),
4121 ("fit/images/fdt-1/_testing", b'aa'),
4122 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4123 ]:
4124 image_pos = props[f"{node}:image-pos"]
4125 size = props[f"{node}:size"]
4126 self.assertEqual(len(expected), size)
4127 self.assertEqual(expected, data[image_pos:image_pos+size])
4128
Simon Glass66152ce2022-01-09 20:14:09 -07004129 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004130 """Test that binman complains if mkimage is missing"""
4131 with self.assertRaises(ValueError) as e:
4132 self._DoTestFile('162_fit_external.dts',
4133 force_missing_bintools='mkimage')
4134 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4135 str(e.exception))
4136
4137 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004138 """Test that binman still produces a FIT image if mkimage is missing"""
4139 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004140 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004141 force_missing_bintools='mkimage')
4142 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004143 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004144
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004145 def testSectionIgnoreHashSignature(self):
4146 """Test that sections ignore hash, signature nodes for its data"""
4147 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4148 expected = (U_BOOT_DATA + U_BOOT_DATA)
4149 self.assertEqual(expected, data)
4150
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004151 def testPadInSections(self):
4152 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004153 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4154 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004155 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4156 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004157 U_BOOT_DATA)
4158 self.assertEqual(expected, data)
4159
Simon Glassd12599d2020-10-26 17:40:09 -06004160 dtb = fdt.Fdt(out_dtb_fname)
4161 dtb.Scan()
4162 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4163 expected = {
4164 'image-pos': 0,
4165 'offset': 0,
4166 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4167
4168 'section:image-pos': 0,
4169 'section:offset': 0,
4170 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4171
4172 'section/before:image-pos': 0,
4173 'section/before:offset': 0,
4174 'section/before:size': len(U_BOOT_DATA),
4175
4176 'section/u-boot:image-pos': 4,
4177 'section/u-boot:offset': 4,
4178 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4179
4180 'section/after:image-pos': 26,
4181 'section/after:offset': 26,
4182 'section/after:size': len(U_BOOT_DATA),
4183 }
4184 self.assertEqual(expected, props)
4185
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004186 def testFitImageSubentryAlignment(self):
4187 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004188 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004189 entry_args = {
4190 'test-id': TEXT_DATA,
4191 }
4192 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4193 entry_args=entry_args)
4194 dtb = fdt.Fdt.FromData(data)
4195 dtb.Scan()
4196
4197 node = dtb.GetNode('/images/kernel')
4198 data = dtb.GetProps(node)["data"].bytes
4199 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004200 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4201 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004202 self.assertEqual(expected, data)
4203
4204 node = dtb.GetNode('/images/fdt-1')
4205 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004206 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4207 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004208 U_BOOT_DTB_DATA)
4209 self.assertEqual(expected, data)
4210
4211 def testFitExtblobMissingOk(self):
4212 """Test a FIT with a missing external blob that is allowed"""
4213 with test_util.capture_sys_output() as (stdout, stderr):
4214 self._DoTestFile('168_fit_missing_blob.dts',
4215 allow_missing=True)
4216 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004217 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004218
Simon Glass21db0ff2020-09-01 05:13:54 -06004219 def testBlobNamedByArgMissing(self):
4220 """Test handling of a missing entry arg"""
4221 with self.assertRaises(ValueError) as e:
4222 self._DoReadFile('068_blob_named_by_arg.dts')
4223 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4224 str(e.exception))
4225
Simon Glass559c4de2020-09-01 05:13:58 -06004226 def testPackBl31(self):
4227 """Test that an image with an ATF BL31 binary can be created"""
4228 data = self._DoReadFile('169_atf_bl31.dts')
4229 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4230
Samuel Holland9d8cc632020-10-21 21:12:15 -05004231 def testPackScp(self):
4232 """Test that an image with an SCP binary can be created"""
4233 data = self._DoReadFile('172_scp.dts')
4234 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4235
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004236 def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True,
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004237 default_dt=None, use_seq_num=True):
Simon Glasscd2783e2024-07-20 11:49:46 +01004238 """Check an image with an FIT with multiple FDT images"""
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004239 def _CheckFdt(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004240 """Check the FDT nodes
4241
4242 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004243 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004244 expected_data: Expected contents of 'data' property
4245 """
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004246 name = 'fdt-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004247 fnode = dtb.GetNode('/images/%s' % name)
4248 self.assertIsNotNone(fnode)
4249 self.assertEqual({'description','type', 'compression', 'data'},
4250 set(fnode.props.keys()))
4251 self.assertEqual(expected_data, fnode.props['data'].bytes)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004252 description = (
4253 'fdt-test-fdt%s.dtb' % val if len(val) == 1 else
4254 'fdt-%s.dtb' % val
4255 )
4256 self.assertEqual(description, fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004257 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004258
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004259 def _CheckConfig(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004260 """Check the configuration nodes
4261
4262 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004263 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004264 expected_data: Expected contents of 'data' property
4265 """
4266 cnode = dtb.GetNode('/configurations')
4267 self.assertIn('default', cnode.props)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004268 default = (
4269 'config-2' if len(val) == 1 else
4270 'config-test-fdt2'
4271 )
4272 self.assertEqual(default, cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004273
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004274 name = 'config-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004275 fnode = dtb.GetNode('/configurations/%s' % name)
4276 self.assertIsNotNone(fnode)
4277 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4278 set(fnode.props.keys()))
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004279 description = (
4280 'conf-test-fdt%s.dtb' % val if len(val) == 1 else
4281 'conf-%s.dtb' % val
4282 )
4283 self.assertEqual(description, fnode.props['description'].value)
4284 self.assertEqual('fdt-%s' % val, fnode.props['fdt'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004285
4286 entry_args = {
Simon Glass1032acc2020-09-06 10:39:08 -06004287 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004288 }
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004289 extra_indirs = None
Simon Glasscd2783e2024-07-20 11:49:46 +01004290 if use_fdt_list:
4291 entry_args['of-list'] = 'test-fdt1 test-fdt2'
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004292 if default_dt:
4293 entry_args['default-dt'] = default_dt
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004294 if use_fdt_list:
4295 extra_indirs = [os.path.join(self._indir, TEST_FDT_SUBDIR)]
Simon Glassa435cd12020-09-01 05:13:59 -06004296 data = self._DoReadFileDtb(
Simon Glasscd2783e2024-07-20 11:49:46 +01004297 dts,
Simon Glassa435cd12020-09-01 05:13:59 -06004298 entry_args=entry_args,
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004299 extra_indirs=extra_indirs)[0]
Simon Glassa435cd12020-09-01 05:13:59 -06004300 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4301 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4302
4303 dtb = fdt.Fdt.FromData(fit_data)
4304 dtb.Scan()
4305 fnode = dtb.GetNode('/images/kernel')
4306 self.assertIn('data', fnode.props)
4307
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004308 if use_seq_num == True:
4309 # Check all the properties in fdt-1 and fdt-2
4310 _CheckFdt('1', TEST_FDT1_DATA)
4311 _CheckFdt('2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004312
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004313 # Check configurations
4314 _CheckConfig('1', TEST_FDT1_DATA)
4315 _CheckConfig('2', TEST_FDT2_DATA)
4316 else:
4317 # Check all the properties in fdt-1 and fdt-2
4318 _CheckFdt('test-fdt1', TEST_FDT1_DATA)
4319 _CheckFdt('test-fdt2', TEST_FDT2_DATA)
4320
4321 # Check configurations
4322 _CheckConfig('test-fdt1', TEST_FDT1_DATA)
4323 _CheckConfig('test-fdt2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004324
Simon Glasscd2783e2024-07-20 11:49:46 +01004325 def testFitFdt(self):
4326 """Test an image with an FIT with multiple FDT images"""
4327 self.CheckFitFdt()
4328
Simon Glassa435cd12020-09-01 05:13:59 -06004329 def testFitFdtMissingList(self):
4330 """Test handling of a missing 'of-list' entry arg"""
4331 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004332 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004333 self.assertIn("Generator node requires 'of-list' entry argument",
4334 str(e.exception))
4335
4336 def testFitFdtEmptyList(self):
4337 """Test handling of an empty 'of-list' entry arg"""
4338 entry_args = {
4339 'of-list': '',
4340 }
4341 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4342
4343 def testFitFdtMissingProp(self):
4344 """Test handling of a missing 'fit,fdt-list' property"""
4345 with self.assertRaises(ValueError) as e:
4346 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4347 self.assertIn("Generator node requires 'fit,fdt-list' property",
4348 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004349
Simon Glass1032acc2020-09-06 10:39:08 -06004350 def testFitFdtMissing(self):
4351 """Test handling of a missing 'default-dt' entry arg"""
4352 entry_args = {
4353 'of-list': 'test-fdt1 test-fdt2',
4354 }
4355 with self.assertRaises(ValueError) as e:
4356 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004357 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004358 entry_args=entry_args,
4359 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4360 self.assertIn("Generated 'default' node requires default-dt entry argument",
4361 str(e.exception))
4362
4363 def testFitFdtNotInList(self):
4364 """Test handling of a default-dt that is not in the of-list"""
4365 entry_args = {
4366 'of-list': 'test-fdt1 test-fdt2',
4367 'default-dt': 'test-fdt3',
4368 }
4369 with self.assertRaises(ValueError) as e:
4370 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004371 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004372 entry_args=entry_args,
4373 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4374 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4375 str(e.exception))
4376
Simon Glassa820af72020-09-06 10:39:09 -06004377 def testFitExtblobMissingHelp(self):
4378 """Test display of help messages when an external blob is missing"""
4379 control.missing_blob_help = control._ReadMissingBlobHelp()
4380 control.missing_blob_help['wibble'] = 'Wibble test'
4381 control.missing_blob_help['another'] = 'Another test'
4382 with test_util.capture_sys_output() as (stdout, stderr):
4383 self._DoTestFile('168_fit_missing_blob.dts',
4384 allow_missing=True)
4385 err = stderr.getvalue()
4386
4387 # We can get the tag from the name, the type or the missing-msg
4388 # property. Check all three.
4389 self.assertIn('You may need to build ARM Trusted', err)
4390 self.assertIn('Wibble test', err)
4391 self.assertIn('Another test', err)
4392
Simon Glass6f1f4d42020-09-06 10:35:32 -06004393 def testMissingBlob(self):
4394 """Test handling of a blob containing a missing file"""
4395 with self.assertRaises(ValueError) as e:
4396 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4397 self.assertIn("Filename 'missing' not found in input path",
4398 str(e.exception))
4399
Simon Glassa0729502020-09-06 10:35:33 -06004400 def testEnvironment(self):
4401 """Test adding a U-Boot environment"""
4402 data = self._DoReadFile('174_env.dts')
4403 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4404 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4405 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4406 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4407 env)
4408
4409 def testEnvironmentNoSize(self):
4410 """Test that a missing 'size' property is detected"""
4411 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004412 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004413 self.assertIn("'u-boot-env' entry must have a size property",
4414 str(e.exception))
4415
4416 def testEnvironmentTooSmall(self):
4417 """Test handling of an environment that does not fit"""
4418 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004419 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004420
4421 # checksum, start byte, environment with \0 terminator, final \0
4422 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4423 short = need - 0x8
4424 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4425 str(e.exception))
4426
Simon Glassd1fdf752020-10-26 17:40:01 -06004427 def testSkipAtStart(self):
4428 """Test handling of skip-at-start section"""
4429 data = self._DoReadFile('177_skip_at_start.dts')
4430 self.assertEqual(U_BOOT_DATA, data)
4431
4432 image = control.images['image']
4433 entries = image.GetEntries()
4434 section = entries['section']
4435 self.assertEqual(0, section.offset)
4436 self.assertEqual(len(U_BOOT_DATA), section.size)
4437 self.assertEqual(U_BOOT_DATA, section.GetData())
4438
4439 entry = section.GetEntries()['u-boot']
4440 self.assertEqual(16, entry.offset)
4441 self.assertEqual(len(U_BOOT_DATA), entry.size)
4442 self.assertEqual(U_BOOT_DATA, entry.data)
4443
4444 def testSkipAtStartPad(self):
4445 """Test handling of skip-at-start section with padded entry"""
4446 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004447 before = tools.get_bytes(0, 8)
4448 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004449 all = before + U_BOOT_DATA + after
4450 self.assertEqual(all, data)
4451
4452 image = control.images['image']
4453 entries = image.GetEntries()
4454 section = entries['section']
4455 self.assertEqual(0, section.offset)
4456 self.assertEqual(len(all), section.size)
4457 self.assertEqual(all, section.GetData())
4458
4459 entry = section.GetEntries()['u-boot']
4460 self.assertEqual(16, entry.offset)
4461 self.assertEqual(len(all), entry.size)
4462 self.assertEqual(U_BOOT_DATA, entry.data)
4463
4464 def testSkipAtStartSectionPad(self):
4465 """Test handling of skip-at-start section with padding"""
4466 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004467 before = tools.get_bytes(0, 8)
4468 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004469 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004470 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004471
4472 image = control.images['image']
4473 entries = image.GetEntries()
4474 section = entries['section']
4475 self.assertEqual(0, section.offset)
4476 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004477 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004478 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004479
4480 entry = section.GetEntries()['u-boot']
4481 self.assertEqual(16, entry.offset)
4482 self.assertEqual(len(U_BOOT_DATA), entry.size)
4483 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004484
Simon Glassbb395742020-10-26 17:40:14 -06004485 def testSectionPad(self):
4486 """Testing padding with sections"""
4487 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004488 expected = (tools.get_bytes(ord('&'), 3) +
4489 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004490 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004491 tools.get_bytes(ord('!'), 1) +
4492 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004493 self.assertEqual(expected, data)
4494
4495 def testSectionAlign(self):
4496 """Testing alignment with sections"""
4497 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4498 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004499 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004500 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004501 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004502 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004503 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4504 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004505 self.assertEqual(expected, data)
4506
Simon Glassd92c8362020-10-26 17:40:25 -06004507 def testCompressImage(self):
4508 """Test compression of the entire image"""
4509 self._CheckLz4()
4510 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4511 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4512 dtb = fdt.Fdt(out_dtb_fname)
4513 dtb.Scan()
4514 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4515 'uncomp-size'])
4516 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004517 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004518
4519 # Do a sanity check on various fields
4520 image = control.images['image']
4521 entries = image.GetEntries()
4522 self.assertEqual(2, len(entries))
4523
4524 entry = entries['blob']
4525 self.assertEqual(COMPRESS_DATA, entry.data)
4526 self.assertEqual(len(COMPRESS_DATA), entry.size)
4527
4528 entry = entries['u-boot']
4529 self.assertEqual(U_BOOT_DATA, entry.data)
4530 self.assertEqual(len(U_BOOT_DATA), entry.size)
4531
4532 self.assertEqual(len(data), image.size)
4533 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4534 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4535 orig = self._decompress(image.data)
4536 self.assertEqual(orig, image.uncomp_data)
4537
4538 expected = {
4539 'blob:offset': 0,
4540 'blob:size': len(COMPRESS_DATA),
4541 'u-boot:offset': len(COMPRESS_DATA),
4542 'u-boot:size': len(U_BOOT_DATA),
4543 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4544 'offset': 0,
4545 'image-pos': 0,
4546 'size': len(data),
4547 }
4548 self.assertEqual(expected, props)
4549
4550 def testCompressImageLess(self):
4551 """Test compression where compression reduces the image size"""
4552 self._CheckLz4()
4553 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4554 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4555 dtb = fdt.Fdt(out_dtb_fname)
4556 dtb.Scan()
4557 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4558 'uncomp-size'])
4559 orig = self._decompress(data)
4560
Brandon Maiera657bc62024-06-04 16:16:05 +00004561 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004562
4563 # Do a sanity check on various fields
4564 image = control.images['image']
4565 entries = image.GetEntries()
4566 self.assertEqual(2, len(entries))
4567
4568 entry = entries['blob']
4569 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4570 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4571
4572 entry = entries['u-boot']
4573 self.assertEqual(U_BOOT_DATA, entry.data)
4574 self.assertEqual(len(U_BOOT_DATA), entry.size)
4575
4576 self.assertEqual(len(data), image.size)
4577 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4578 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4579 image.uncomp_size)
4580 orig = self._decompress(image.data)
4581 self.assertEqual(orig, image.uncomp_data)
4582
4583 expected = {
4584 'blob:offset': 0,
4585 'blob:size': len(COMPRESS_DATA_BIG),
4586 'u-boot:offset': len(COMPRESS_DATA_BIG),
4587 'u-boot:size': len(U_BOOT_DATA),
4588 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4589 'offset': 0,
4590 'image-pos': 0,
4591 'size': len(data),
4592 }
4593 self.assertEqual(expected, props)
4594
4595 def testCompressSectionSize(self):
4596 """Test compression of a section with a fixed size"""
4597 self._CheckLz4()
4598 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4599 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4600 dtb = fdt.Fdt(out_dtb_fname)
4601 dtb.Scan()
4602 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4603 'uncomp-size'])
4604 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004605 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004606 expected = {
4607 'section/blob:offset': 0,
4608 'section/blob:size': len(COMPRESS_DATA),
4609 'section/u-boot:offset': len(COMPRESS_DATA),
4610 'section/u-boot:size': len(U_BOOT_DATA),
4611 'section:offset': 0,
4612 'section:image-pos': 0,
4613 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4614 'section:size': 0x30,
4615 'offset': 0,
4616 'image-pos': 0,
4617 'size': 0x30,
4618 }
4619 self.assertEqual(expected, props)
4620
4621 def testCompressSection(self):
4622 """Test compression of a section with no fixed size"""
4623 self._CheckLz4()
4624 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4625 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4626 dtb = fdt.Fdt(out_dtb_fname)
4627 dtb.Scan()
4628 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4629 'uncomp-size'])
4630 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004631 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004632 expected = {
4633 'section/blob:offset': 0,
4634 'section/blob:size': len(COMPRESS_DATA),
4635 'section/u-boot:offset': len(COMPRESS_DATA),
4636 'section/u-boot:size': len(U_BOOT_DATA),
4637 'section:offset': 0,
4638 'section:image-pos': 0,
4639 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4640 'section:size': len(data),
4641 'offset': 0,
4642 'image-pos': 0,
4643 'size': len(data),
4644 }
4645 self.assertEqual(expected, props)
4646
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004647 def testLz4Missing(self):
4648 """Test that binman still produces an image if lz4 is missing"""
4649 with test_util.capture_sys_output() as (_, stderr):
4650 self._DoTestFile('185_compress_section.dts',
4651 force_missing_bintools='lz4')
4652 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004653 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004654
Simon Glassd92c8362020-10-26 17:40:25 -06004655 def testCompressExtra(self):
4656 """Test compression of a section with no fixed size"""
4657 self._CheckLz4()
4658 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4659 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4660 dtb = fdt.Fdt(out_dtb_fname)
4661 dtb.Scan()
4662 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4663 'uncomp-size'])
4664
4665 base = data[len(U_BOOT_DATA):]
Brandon Maiera657bc62024-06-04 16:16:05 +00004666 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glassd92c8362020-10-26 17:40:25 -06004667 rest = base[len(U_BOOT_DATA):]
4668
4669 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004670 bintool = self.comp_bintools['lz4']
4671 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004672 data1 = rest[:len(expect1)]
4673 section1 = self._decompress(data1)
Brandon Maiera657bc62024-06-04 16:16:05 +00004674 self.assertEqual(expect1, data1)
4675 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glassd92c8362020-10-26 17:40:25 -06004676 rest1 = rest[len(expect1):]
4677
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004678 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004679 data2 = rest1[:len(expect2)]
4680 section2 = self._decompress(data2)
Brandon Maiera657bc62024-06-04 16:16:05 +00004681 self.assertEqual(expect2, data2)
4682 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glassd92c8362020-10-26 17:40:25 -06004683 rest2 = rest1[len(expect2):]
4684
4685 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4686 len(expect2) + len(U_BOOT_DATA))
Brandon Maiera657bc62024-06-04 16:16:05 +00004687 #self.assertEqual(expect_size, len(data))
Simon Glassd92c8362020-10-26 17:40:25 -06004688
Brandon Maiera657bc62024-06-04 16:16:05 +00004689 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glassd92c8362020-10-26 17:40:25 -06004690
4691 self.maxDiff = None
4692 expected = {
4693 'u-boot:offset': 0,
4694 'u-boot:image-pos': 0,
4695 'u-boot:size': len(U_BOOT_DATA),
4696
4697 'base:offset': len(U_BOOT_DATA),
4698 'base:image-pos': len(U_BOOT_DATA),
4699 'base:size': len(data) - len(U_BOOT_DATA),
4700 'base/u-boot:offset': 0,
4701 'base/u-boot:image-pos': len(U_BOOT_DATA),
4702 'base/u-boot:size': len(U_BOOT_DATA),
4703 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4704 len(expect2),
4705 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4706 len(expect2),
4707 'base/u-boot2:size': len(U_BOOT_DATA),
4708
4709 'base/section:offset': len(U_BOOT_DATA),
4710 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4711 'base/section:size': len(expect1),
4712 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4713 'base/section/blob:offset': 0,
4714 'base/section/blob:size': len(COMPRESS_DATA),
4715 'base/section/u-boot:offset': len(COMPRESS_DATA),
4716 'base/section/u-boot:size': len(U_BOOT_DATA),
4717
4718 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4719 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4720 'base/section2:size': len(expect2),
4721 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4722 'base/section2/blob:offset': 0,
4723 'base/section2/blob:size': len(COMPRESS_DATA),
4724 'base/section2/blob2:offset': len(COMPRESS_DATA),
4725 'base/section2/blob2:size': len(COMPRESS_DATA),
4726
4727 'offset': 0,
4728 'image-pos': 0,
4729 'size': len(data),
4730 }
4731 self.assertEqual(expected, props)
4732
Simon Glassecbe4732021-01-06 21:35:15 -07004733 def testSymbolsSubsection(self):
4734 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004735 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004736
Simon Glass3fb25402021-01-06 21:35:16 -07004737 def testReadImageEntryArg(self):
4738 """Test reading an image that would need an entry arg to generate"""
4739 entry_args = {
4740 'cros-ec-rw-path': 'ecrw.bin',
4741 }
4742 data = self.data = self._DoReadFileDtb(
4743 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4744 entry_args=entry_args)
4745
Simon Glass80025522022-01-29 14:14:04 -07004746 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004747 orig_image = control.images['image']
4748
4749 # This should not generate an error about the missing 'cros-ec-rw-path'
4750 # since we are reading the image from a file. Compare with
4751 # testEntryArgsRequired()
4752 image = Image.FromFile(image_fname)
4753 self.assertEqual(orig_image.GetEntries().keys(),
4754 image.GetEntries().keys())
4755
Simon Glassa2af7302021-01-06 21:35:18 -07004756 def testFilesAlign(self):
4757 """Test alignment with files"""
4758 data = self._DoReadFile('190_files_align.dts')
4759
4760 # The first string is 15 bytes so will align to 16
4761 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4762 self.assertEqual(expect, data)
4763
Simon Glassdb84b562021-01-06 21:35:19 -07004764 def testReadImageSkip(self):
4765 """Test reading an image and accessing its FDT map"""
4766 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004767 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004768 orig_image = control.images['image']
4769 image = Image.FromFile(image_fname)
4770 self.assertEqual(orig_image.GetEntries().keys(),
4771 image.GetEntries().keys())
4772
4773 orig_entry = orig_image.GetEntries()['fdtmap']
4774 entry = image.GetEntries()['fdtmap']
4775 self.assertEqual(orig_entry.offset, entry.offset)
4776 self.assertEqual(orig_entry.size, entry.size)
4777 self.assertEqual(16, entry.image_pos)
4778
4779 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4780
Brandon Maiera657bc62024-06-04 16:16:05 +00004781 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glassdb84b562021-01-06 21:35:19 -07004782
Simon Glassc98de972021-03-18 20:24:57 +13004783 def testTplNoDtb(self):
4784 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004785 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004786 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4787 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4788 data[:len(U_BOOT_TPL_NODTB_DATA)])
4789
Simon Glass63f41d42021-03-18 20:24:58 +13004790 def testTplBssPad(self):
4791 """Test that we can pad TPL's BSS with zeros"""
4792 # ELF file with a '__bss_size' symbol
4793 self._SetupTplElf()
4794 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004795 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004796 data)
4797
4798 def testTplBssPadMissing(self):
4799 """Test that a missing symbol is detected"""
4800 self._SetupTplElf('u_boot_ucode_ptr')
4801 with self.assertRaises(ValueError) as e:
4802 self._DoReadFile('193_tpl_bss_pad.dts')
4803 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4804 str(e.exception))
4805
Simon Glass718b5292021-03-18 20:25:07 +13004806 def checkDtbSizes(self, data, pad_len, start):
4807 """Check the size arguments in a dtb embedded in an image
4808
4809 Args:
4810 data: The image data
4811 pad_len: Length of the pad section in the image, in bytes
4812 start: Start offset of the devicetree to examine, within the image
4813
4814 Returns:
4815 Size of the devicetree in bytes
4816 """
4817 dtb_data = data[start:]
4818 dtb = fdt.Fdt.FromData(dtb_data)
4819 fdt_size = dtb.GetFdtObj().totalsize()
4820 dtb.Scan()
4821 props = self._GetPropTree(dtb, 'size')
4822 self.assertEqual({
4823 'size': len(data),
4824 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4825 'u-boot-spl/u-boot-spl-dtb:size': 801,
4826 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4827 'u-boot-spl:size': 860,
4828 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4829 'u-boot/u-boot-dtb:size': 781,
4830 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4831 'u-boot:size': 827,
4832 }, props)
4833 return fdt_size
4834
4835 def testExpanded(self):
4836 """Test that an expanded entry type is selected when needed"""
4837 self._SetupSplElf()
4838 self._SetupTplElf()
4839
4840 # SPL has a devicetree, TPL does not
4841 entry_args = {
4842 'spl-dtb': '1',
4843 'spl-bss-pad': 'y',
4844 'tpl-dtb': '',
4845 }
4846 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4847 entry_args=entry_args)
4848 image = control.images['image']
4849 entries = image.GetEntries()
4850 self.assertEqual(3, len(entries))
4851
4852 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4853 self.assertIn('u-boot', entries)
4854 entry = entries['u-boot']
4855 self.assertEqual('u-boot-expanded', entry.etype)
4856 subent = entry.GetEntries()
4857 self.assertEqual(2, len(subent))
4858 self.assertIn('u-boot-nodtb', subent)
4859 self.assertIn('u-boot-dtb', subent)
4860
4861 # Second, u-boot-spl, which should be expanded into three parts
4862 self.assertIn('u-boot-spl', entries)
4863 entry = entries['u-boot-spl']
4864 self.assertEqual('u-boot-spl-expanded', entry.etype)
4865 subent = entry.GetEntries()
4866 self.assertEqual(3, len(subent))
4867 self.assertIn('u-boot-spl-nodtb', subent)
4868 self.assertIn('u-boot-spl-bss-pad', subent)
4869 self.assertIn('u-boot-spl-dtb', subent)
4870
4871 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4872 # devicetree
4873 self.assertIn('u-boot-tpl', entries)
4874 entry = entries['u-boot-tpl']
4875 self.assertEqual('u-boot-tpl', entry.etype)
4876 self.assertEqual(None, entry.GetEntries())
4877
4878 def testExpandedTpl(self):
4879 """Test that an expanded entry type is selected for TPL when needed"""
4880 self._SetupTplElf()
4881
4882 entry_args = {
4883 'tpl-bss-pad': 'y',
4884 'tpl-dtb': 'y',
4885 }
4886 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4887 entry_args=entry_args)
4888 image = control.images['image']
4889 entries = image.GetEntries()
4890 self.assertEqual(1, len(entries))
4891
4892 # We only have u-boot-tpl, which be expanded
4893 self.assertIn('u-boot-tpl', entries)
4894 entry = entries['u-boot-tpl']
4895 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4896 subent = entry.GetEntries()
4897 self.assertEqual(3, len(subent))
4898 self.assertIn('u-boot-tpl-nodtb', subent)
4899 self.assertIn('u-boot-tpl-bss-pad', subent)
4900 self.assertIn('u-boot-tpl-dtb', subent)
4901
4902 def testExpandedNoPad(self):
4903 """Test an expanded entry without BSS pad enabled"""
4904 self._SetupSplElf()
4905 self._SetupTplElf()
4906
4907 # SPL has a devicetree, TPL does not
4908 entry_args = {
4909 'spl-dtb': 'something',
4910 'spl-bss-pad': 'n',
4911 'tpl-dtb': '',
4912 }
4913 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4914 entry_args=entry_args)
4915 image = control.images['image']
4916 entries = image.GetEntries()
4917
4918 # Just check u-boot-spl, which should be expanded into two parts
4919 self.assertIn('u-boot-spl', entries)
4920 entry = entries['u-boot-spl']
4921 self.assertEqual('u-boot-spl-expanded', entry.etype)
4922 subent = entry.GetEntries()
4923 self.assertEqual(2, len(subent))
4924 self.assertIn('u-boot-spl-nodtb', subent)
4925 self.assertIn('u-boot-spl-dtb', subent)
4926
4927 def testExpandedTplNoPad(self):
4928 """Test that an expanded entry type with padding disabled in TPL"""
4929 self._SetupTplElf()
4930
4931 entry_args = {
4932 'tpl-bss-pad': '',
4933 'tpl-dtb': 'y',
4934 }
4935 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4936 entry_args=entry_args)
4937 image = control.images['image']
4938 entries = image.GetEntries()
4939 self.assertEqual(1, len(entries))
4940
4941 # We only have u-boot-tpl, which be expanded
4942 self.assertIn('u-boot-tpl', entries)
4943 entry = entries['u-boot-tpl']
4944 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4945 subent = entry.GetEntries()
4946 self.assertEqual(2, len(subent))
4947 self.assertIn('u-boot-tpl-nodtb', subent)
4948 self.assertIn('u-boot-tpl-dtb', subent)
4949
4950 def testFdtInclude(self):
4951 """Test that an Fdt is update within all binaries"""
4952 self._SetupSplElf()
4953 self._SetupTplElf()
4954
4955 # SPL has a devicetree, TPL does not
4956 self.maxDiff = None
4957 entry_args = {
4958 'spl-dtb': '1',
4959 'spl-bss-pad': 'y',
4960 'tpl-dtb': '',
4961 }
4962 # Build the image. It includes two separate devicetree binaries, each
4963 # with their own contents, but all contain the binman definition.
4964 data = self._DoReadFileDtb(
4965 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4966 update_dtb=True, entry_args=entry_args)[0]
4967 pad_len = 10
4968
4969 # Check the U-Boot dtb
4970 start = len(U_BOOT_NODTB_DATA)
4971 fdt_size = self.checkDtbSizes(data, pad_len, start)
4972
4973 # Now check SPL
4974 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4975 fdt_size = self.checkDtbSizes(data, pad_len, start)
4976
4977 # TPL has no devicetree
4978 start += fdt_size + len(U_BOOT_TPL_DATA)
4979 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004980
Simon Glass7098b7f2021-03-21 18:24:30 +13004981 def testSymbolsExpanded(self):
4982 """Test binman can assign symbols in expanded entries"""
4983 entry_args = {
4984 'spl-dtb': '1',
4985 }
4986 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4987 U_BOOT_SPL_DTB_DATA, 0x38,
4988 entry_args=entry_args, use_expanded=True)
4989
Simon Glasse1915782021-03-21 18:24:31 +13004990 def testCollection(self):
4991 """Test a collection"""
4992 data = self._DoReadFile('198_collection.dts')
4993 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004994 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4995 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004996 data)
4997
Simon Glass27a7f772021-03-21 18:24:32 +13004998 def testCollectionSection(self):
4999 """Test a collection where a section must be built first"""
5000 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07005001 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13005002 # building the contents, producing an error is anything is still
5003 # missing.
5004 data = self._DoReadFile('199_collection_section.dts')
5005 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07005006 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
5007 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13005008 data)
5009
Simon Glassf427c5f2021-03-21 18:24:33 +13005010 def testAlignDefault(self):
5011 """Test that default alignment works on sections"""
5012 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07005013 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13005014 U_BOOT_DATA)
5015 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07005016 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13005017 # No alignment within the nested section
5018 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
5019 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07005020 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13005021 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13005022
Bin Mengc0b15742021-05-10 20:23:33 +08005023 def testPackOpenSBI(self):
5024 """Test that an image with an OpenSBI binary can be created"""
5025 data = self._DoReadFile('201_opensbi.dts')
5026 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
5027
Simon Glass76f496d2021-07-06 10:36:37 -06005028 def testSectionsSingleThread(self):
5029 """Test sections without multithreading"""
5030 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07005031 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
5032 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
5033 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06005034 self.assertEqual(expected, data)
5035
5036 def testThreadTimeout(self):
5037 """Test handling a thread that takes too long"""
5038 with self.assertRaises(ValueError) as e:
5039 self._DoTestFile('202_section_timeout.dts',
5040 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06005041 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06005042
Simon Glass748a1d42021-07-06 10:36:41 -06005043 def testTiming(self):
5044 """Test output of timing information"""
5045 data = self._DoReadFile('055_sections.dts')
5046 with test_util.capture_sys_output() as (stdout, stderr):
5047 state.TimingShow()
5048 self.assertIn('read:', stdout.getvalue())
5049 self.assertIn('compress:', stdout.getvalue())
5050
Simon Glassadfb8492021-11-03 21:09:18 -06005051 def testUpdateFdtInElf(self):
5052 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005053 if not elf.ELF_TOOLS:
5054 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005055 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5056 outfile = os.path.join(self._indir, 'u-boot.out')
5057 begin_sym = 'dtb_embed_begin'
5058 end_sym = 'dtb_embed_end'
5059 retcode = self._DoTestFile(
5060 '060_fdt_update.dts', update_dtb=True,
5061 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5062 self.assertEqual(0, retcode)
5063
5064 # Check that the output file does in fact contact a dtb with the binman
5065 # definition in the correct place
5066 syms = elf.GetSymbolFileOffset(infile,
5067 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07005068 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06005069 dtb_data = data[syms['dtb_embed_begin'].offset:
5070 syms['dtb_embed_end'].offset]
5071
5072 dtb = fdt.Fdt.FromData(dtb_data)
5073 dtb.Scan()
5074 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
5075 self.assertEqual({
5076 'image-pos': 0,
5077 'offset': 0,
5078 '_testing:offset': 32,
5079 '_testing:size': 2,
5080 '_testing:image-pos': 32,
5081 'section@0/u-boot:offset': 0,
5082 'section@0/u-boot:size': len(U_BOOT_DATA),
5083 'section@0/u-boot:image-pos': 0,
5084 'section@0:offset': 0,
5085 'section@0:size': 16,
5086 'section@0:image-pos': 0,
5087
5088 'section@1/u-boot:offset': 0,
5089 'section@1/u-boot:size': len(U_BOOT_DATA),
5090 'section@1/u-boot:image-pos': 16,
5091 'section@1:offset': 16,
5092 'section@1:size': 16,
5093 'section@1:image-pos': 16,
5094 'size': 40
5095 }, props)
5096
5097 def testUpdateFdtInElfInvalid(self):
5098 """Test that invalid args are detected with --update-fdt-in-elf"""
5099 with self.assertRaises(ValueError) as e:
5100 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5101 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5102 str(e.exception))
5103
5104 def testUpdateFdtInElfNoSyms(self):
5105 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005106 if not elf.ELF_TOOLS:
5107 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005108 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5109 outfile = ''
5110 begin_sym = 'wrong_begin'
5111 end_sym = 'wrong_end'
5112 with self.assertRaises(ValueError) as e:
5113 self._DoTestFile(
5114 '060_fdt_update.dts',
5115 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5116 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5117 str(e.exception))
5118
5119 def testUpdateFdtInElfTooSmall(self):
5120 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005121 if not elf.ELF_TOOLS:
5122 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005123 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5124 outfile = os.path.join(self._indir, 'u-boot.out')
5125 begin_sym = 'dtb_embed_begin'
5126 end_sym = 'dtb_embed_end'
5127 with self.assertRaises(ValueError) as e:
5128 self._DoTestFile(
5129 '060_fdt_update.dts', update_dtb=True,
5130 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5131 self.assertRegex(
5132 str(e.exception),
5133 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5134
Simon Glass88e04da2021-11-23 11:03:42 -07005135 def testVersion(self):
5136 """Test we can get the binman version"""
5137 version = '(unreleased)'
5138 self.assertEqual(version, state.GetVersion(self._indir))
5139
5140 with self.assertRaises(SystemExit):
5141 with test_util.capture_sys_output() as (_, stderr):
5142 self._DoBinman('-V')
5143 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5144
5145 # Try running the tool too, just to be safe
5146 result = self._RunBinman('-V')
5147 self.assertEqual('Binman %s\n' % version, result.stderr)
5148
5149 # Set up a version file to make sure that works
5150 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005151 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005152 binary=False)
5153 self.assertEqual(version, state.GetVersion(self._indir))
5154
Simon Glass637958f2021-11-23 21:09:50 -07005155 def testAltFormat(self):
5156 """Test that alternative formats can be used to extract"""
5157 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5158
5159 try:
5160 tmpdir, updated_fname = self._SetupImageInTmpdir()
5161 with test_util.capture_sys_output() as (stdout, _):
5162 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5163 self.assertEqual(
5164 '''Flag (-F) Entry type Description
5165fdt fdtmap Extract the devicetree blob from the fdtmap
5166''',
5167 stdout.getvalue())
5168
5169 dtb = os.path.join(tmpdir, 'fdt.dtb')
5170 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5171 dtb, 'fdtmap')
5172
5173 # Check that we can read it and it can be scanning, meaning it does
5174 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005175 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005176 dtb = fdt.Fdt.FromData(data)
5177 dtb.Scan()
5178
5179 # Now check u-boot which has no alt_format
5180 fname = os.path.join(tmpdir, 'fdt.dtb')
5181 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5182 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005183 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005184 self.assertEqual(U_BOOT_DATA, data)
5185
5186 finally:
5187 shutil.rmtree(tmpdir)
5188
Simon Glass0b00ae62021-11-23 21:09:52 -07005189 def testExtblobList(self):
5190 """Test an image with an external blob list"""
5191 data = self._DoReadFile('215_blob_ext_list.dts')
5192 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5193
5194 def testExtblobListMissing(self):
5195 """Test an image with a missing external blob"""
5196 with self.assertRaises(ValueError) as e:
5197 self._DoReadFile('216_blob_ext_list_missing.dts')
5198 self.assertIn("Filename 'missing-file' not found in input path",
5199 str(e.exception))
5200
5201 def testExtblobListMissingOk(self):
5202 """Test an image with an missing external blob that is allowed"""
5203 with test_util.capture_sys_output() as (stdout, stderr):
5204 self._DoTestFile('216_blob_ext_list_missing.dts',
5205 allow_missing=True)
5206 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005207 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005208
Simon Glass3efb2972021-11-23 21:08:59 -07005209 def testFip(self):
5210 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5211 data = self._DoReadFile('203_fip.dts')
5212 hdr, fents = fip_util.decode_fip(data)
5213 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5214 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5215 self.assertEqual(0x123, hdr.flags)
5216
5217 self.assertEqual(2, len(fents))
5218
5219 fent = fents[0]
5220 self.assertEqual(
5221 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5222 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5223 self.assertEqual('soc-fw', fent.fip_type)
5224 self.assertEqual(0x88, fent.offset)
5225 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5226 self.assertEqual(0x123456789abcdef, fent.flags)
5227 self.assertEqual(ATF_BL31_DATA, fent.data)
5228 self.assertEqual(True, fent.valid)
5229
5230 fent = fents[1]
5231 self.assertEqual(
5232 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5233 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5234 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5235 self.assertEqual(0x8c, fent.offset)
5236 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5237 self.assertEqual(0, fent.flags)
5238 self.assertEqual(ATF_BL2U_DATA, fent.data)
5239 self.assertEqual(True, fent.valid)
5240
5241 def testFipOther(self):
5242 """Basic FIP with something that isn't a external blob"""
5243 data = self._DoReadFile('204_fip_other.dts')
5244 hdr, fents = fip_util.decode_fip(data)
5245
5246 self.assertEqual(2, len(fents))
5247 fent = fents[1]
5248 self.assertEqual('rot-cert', fent.fip_type)
5249 self.assertEqual(b'aa', fent.data)
5250
Simon Glass3efb2972021-11-23 21:08:59 -07005251 def testFipNoType(self):
5252 """FIP with an entry of an unknown type"""
5253 with self.assertRaises(ValueError) as e:
5254 self._DoReadFile('205_fip_no_type.dts')
5255 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5256 str(e.exception))
5257
5258 def testFipUuid(self):
5259 """Basic FIP with a manual uuid"""
5260 data = self._DoReadFile('206_fip_uuid.dts')
5261 hdr, fents = fip_util.decode_fip(data)
5262
5263 self.assertEqual(2, len(fents))
5264 fent = fents[1]
5265 self.assertEqual(None, fent.fip_type)
5266 self.assertEqual(
5267 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5268 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5269 fent.uuid)
5270 self.assertEqual(U_BOOT_DATA, fent.data)
5271
5272 def testFipLs(self):
5273 """Test listing a FIP"""
5274 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5275 hdr, fents = fip_util.decode_fip(data)
5276
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005277 tmpdir = None
Simon Glass3efb2972021-11-23 21:08:59 -07005278 try:
5279 tmpdir, updated_fname = self._SetupImageInTmpdir()
5280 with test_util.capture_sys_output() as (stdout, stderr):
5281 self._DoBinman('ls', '-i', updated_fname)
5282 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005283 if tmpdir:
5284 shutil.rmtree(tmpdir)
Simon Glass3efb2972021-11-23 21:08:59 -07005285 lines = stdout.getvalue().splitlines()
5286 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005287'Name Image-pos Size Entry-type Offset Uncomp-size',
5288'--------------------------------------------------------------',
5289'image 0 2d3 section 0',
5290' atf-fip 0 90 atf-fip 0',
5291' soc-fw 88 4 blob-ext 88',
5292' u-boot 8c 4 u-boot 8c',
5293' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005294]
5295 self.assertEqual(expected, lines)
5296
5297 image = control.images['image']
5298 entries = image.GetEntries()
5299 fdtmap = entries['fdtmap']
5300
5301 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5302 magic = fdtmap_data[:8]
5303 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005304 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005305
5306 fdt_data = fdtmap_data[16:]
5307 dtb = fdt.Fdt.FromData(fdt_data)
5308 dtb.Scan()
5309 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5310 self.assertEqual({
5311 'atf-fip/soc-fw:image-pos': 136,
5312 'atf-fip/soc-fw:offset': 136,
5313 'atf-fip/soc-fw:size': 4,
5314 'atf-fip/u-boot:image-pos': 140,
5315 'atf-fip/u-boot:offset': 140,
5316 'atf-fip/u-boot:size': 4,
5317 'atf-fip:image-pos': 0,
5318 'atf-fip:offset': 0,
5319 'atf-fip:size': 144,
5320 'image-pos': 0,
5321 'offset': 0,
5322 'fdtmap:image-pos': fdtmap.image_pos,
5323 'fdtmap:offset': fdtmap.offset,
5324 'fdtmap:size': len(fdtmap_data),
5325 'size': len(data),
5326 }, props)
5327
5328 def testFipExtractOneEntry(self):
5329 """Test extracting a single entry fron an FIP"""
5330 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005331 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005332 fname = os.path.join(self._indir, 'output.extact')
5333 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005334 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005335 self.assertEqual(U_BOOT_DATA, data)
5336
5337 def testFipReplace(self):
5338 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005339 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005340 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005341 updated_fname = tools.get_output_filename('image-updated.bin')
5342 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005343 entry_name = 'atf-fip/u-boot'
5344 control.WriteEntry(updated_fname, entry_name, expected,
5345 allow_resize=True)
5346 actual = control.ReadEntry(updated_fname, entry_name)
5347 self.assertEqual(expected, actual)
5348
Simon Glass80025522022-01-29 14:14:04 -07005349 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005350 hdr, fents = fip_util.decode_fip(new_data)
5351
5352 self.assertEqual(2, len(fents))
5353
5354 # Check that the FIP entry is updated
5355 fent = fents[1]
5356 self.assertEqual(0x8c, fent.offset)
5357 self.assertEqual(len(expected), fent.size)
5358 self.assertEqual(0, fent.flags)
5359 self.assertEqual(expected, fent.data)
5360 self.assertEqual(True, fent.valid)
5361
5362 def testFipMissing(self):
5363 with test_util.capture_sys_output() as (stdout, stderr):
5364 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5365 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005366 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005367
5368 def testFipSize(self):
5369 """Test a FIP with a size property"""
5370 data = self._DoReadFile('210_fip_size.dts')
5371 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5372 hdr, fents = fip_util.decode_fip(data)
5373 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5374 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5375
5376 self.assertEqual(1, len(fents))
5377
5378 fent = fents[0]
5379 self.assertEqual('soc-fw', fent.fip_type)
5380 self.assertEqual(0x60, fent.offset)
5381 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5382 self.assertEqual(ATF_BL31_DATA, fent.data)
5383 self.assertEqual(True, fent.valid)
5384
5385 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005386 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005387
5388 def testFipBadAlign(self):
5389 """Test that an invalid alignment value in a FIP is detected"""
5390 with self.assertRaises(ValueError) as e:
5391 self._DoTestFile('211_fip_bad_align.dts')
5392 self.assertIn(
5393 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5394 str(e.exception))
5395
5396 def testFipCollection(self):
5397 """Test using a FIP in a collection"""
5398 data = self._DoReadFile('212_fip_collection.dts')
5399 entry1 = control.images['image'].GetEntries()['collection']
5400 data1 = data[:entry1.size]
5401 hdr1, fents2 = fip_util.decode_fip(data1)
5402
5403 entry2 = control.images['image'].GetEntries()['atf-fip']
5404 data2 = data[entry2.offset:entry2.offset + entry2.size]
5405 hdr1, fents2 = fip_util.decode_fip(data2)
5406
5407 # The 'collection' entry should have U-Boot included at the end
5408 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5409 self.assertEqual(data1, data2 + U_BOOT_DATA)
5410 self.assertEqual(U_BOOT_DATA, data1[-4:])
5411
5412 # There should be a U-Boot after the final FIP
5413 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005414
Simon Glassccae6862022-01-12 13:10:35 -07005415 def testFakeBlob(self):
5416 """Test handling of faking an external blob"""
5417 with test_util.capture_sys_output() as (stdout, stderr):
5418 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5419 allow_fake_blobs=True)
5420 err = stderr.getvalue()
5421 self.assertRegex(
5422 err,
5423 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005424
Simon Glassceb5f912022-01-09 20:13:46 -07005425 def testExtblobListFaked(self):
5426 """Test an extblob with missing external blob that are faked"""
5427 with test_util.capture_sys_output() as (stdout, stderr):
5428 self._DoTestFile('216_blob_ext_list_missing.dts',
5429 allow_fake_blobs=True)
5430 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005431 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005432
Simon Glass162017b2022-01-09 20:13:57 -07005433 def testListBintools(self):
5434 args = ['tool', '--list']
5435 with test_util.capture_sys_output() as (stdout, _):
5436 self._DoBinman(*args)
5437 out = stdout.getvalue().splitlines()
5438 self.assertTrue(len(out) >= 2)
5439
5440 def testFetchBintools(self):
5441 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005442 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005443 raise urllib.error.URLError('my error')
5444
5445 args = ['tool']
5446 with self.assertRaises(ValueError) as e:
5447 self._DoBinman(*args)
5448 self.assertIn("Invalid arguments to 'tool' subcommand",
5449 str(e.exception))
5450
5451 args = ['tool', '--fetch']
5452 with self.assertRaises(ValueError) as e:
5453 self._DoBinman(*args)
5454 self.assertIn('Please specify bintools to fetch', str(e.exception))
5455
5456 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005457 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005458 side_effect=fail_download):
5459 with test_util.capture_sys_output() as (stdout, _):
5460 self._DoBinman(*args)
5461 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5462
Simon Glass620c4462022-01-09 20:14:11 -07005463 def testBintoolDocs(self):
5464 """Test for creation of bintool documentation"""
5465 with test_util.capture_sys_output() as (stdout, stderr):
5466 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5467 self.assertTrue(len(stdout.getvalue()) > 0)
5468
5469 def testBintoolDocsMissing(self):
5470 """Test handling of missing bintool documentation"""
5471 with self.assertRaises(ValueError) as e:
5472 with test_util.capture_sys_output() as (stdout, stderr):
5473 control.write_bintool_docs(
5474 control.bintool.Bintool.get_tool_list(), 'mkimage')
5475 self.assertIn('Documentation is missing for modules: mkimage',
5476 str(e.exception))
5477
Jan Kiszka58c407f2022-01-28 20:37:53 +01005478 def testListWithGenNode(self):
5479 """Check handling of an FDT map when the section cannot be found"""
5480 entry_args = {
5481 'of-list': 'test-fdt1 test-fdt2',
5482 }
5483 data = self._DoReadFileDtb(
5484 '219_fit_gennode.dts',
5485 entry_args=entry_args,
5486 use_real_dtb=True,
5487 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5488
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005489 tmpdir = None
Jan Kiszka58c407f2022-01-28 20:37:53 +01005490 try:
5491 tmpdir, updated_fname = self._SetupImageInTmpdir()
5492 with test_util.capture_sys_output() as (stdout, stderr):
5493 self._RunBinman('ls', '-i', updated_fname)
5494 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005495 if tmpdir:
5496 shutil.rmtree(tmpdir)
Jan Kiszka58c407f2022-01-28 20:37:53 +01005497
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005498 def testFitSubentryUsesBintool(self):
5499 """Test that binman FIT subentries can use bintools"""
Simon Glass5dc22cf2025-02-03 09:26:42 -07005500 command.TEST_RESULT = self._HandleGbbCommand
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005501 entry_args = {
5502 'keydir': 'devkeys',
5503 'bmpblk': 'bmpblk.bin',
5504 }
5505 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5506 entry_args=entry_args)
5507
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005508 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5509 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005510 self.assertIn(expected, data)
5511
5512 def testFitSubentryMissingBintool(self):
5513 """Test that binman reports missing bintools for FIT subentries"""
5514 entry_args = {
5515 'keydir': 'devkeys',
5516 }
5517 with test_util.capture_sys_output() as (_, stderr):
5518 self._DoTestFile('220_fit_subentry_bintool.dts',
5519 force_missing_bintools='futility', entry_args=entry_args)
5520 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005521 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005522
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005523 def testFitSubentryHashSubnode(self):
5524 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005525 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005526 data, _, _, out_dtb_name = self._DoReadFileDtb(
5527 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5528
5529 mkimage_dtb = fdt.Fdt.FromData(data)
5530 mkimage_dtb.Scan()
5531 binman_dtb = fdt.Fdt(out_dtb_name)
5532 binman_dtb.Scan()
5533
5534 # Check that binman didn't add hash values
5535 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5536 self.assertNotIn('value', fnode.props)
5537
5538 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5539 self.assertNotIn('value', fnode.props)
5540
5541 # Check that mkimage added hash values
5542 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5543 self.assertIn('value', fnode.props)
5544
5545 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5546 self.assertIn('value', fnode.props)
5547
Roger Quadros5cdcea02022-02-19 20:50:04 +02005548 def testPackTeeOs(self):
5549 """Test that an image with an TEE binary can be created"""
5550 data = self._DoReadFile('222_tee_os.dts')
5551 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5552
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305553 def testPackTiDm(self):
5554 """Test that an image with a TI DM binary can be created"""
5555 data = self._DoReadFile('225_ti_dm.dts')
5556 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5557
Simon Glass912339f2022-02-08 11:50:03 -07005558 def testFitFdtOper(self):
5559 """Check handling of a specified FIT operation"""
5560 entry_args = {
5561 'of-list': 'test-fdt1 test-fdt2',
5562 'default-dt': 'test-fdt2',
5563 }
5564 self._DoReadFileDtb(
5565 '223_fit_fdt_oper.dts',
5566 entry_args=entry_args,
5567 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5568
5569 def testFitFdtBadOper(self):
5570 """Check handling of an FDT map when the section cannot be found"""
5571 with self.assertRaises(ValueError) as exc:
5572 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005573 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005574 str(exc.exception))
5575
Simon Glassdd156a42022-03-05 20:18:59 -07005576 def test_uses_expand_size(self):
5577 """Test that the 'expand-size' property cannot be used anymore"""
5578 with self.assertRaises(ValueError) as e:
5579 data = self._DoReadFile('225_expand_size_bad.dts')
5580 self.assertIn(
5581 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5582 str(e.exception))
5583
Simon Glass5f423422022-03-05 20:19:12 -07005584 def testFitSplitElf(self):
5585 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005586 if not elf.ELF_TOOLS:
5587 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005588 entry_args = {
5589 'of-list': 'test-fdt1 test-fdt2',
5590 'default-dt': 'test-fdt2',
5591 'atf-bl31-path': 'bl31.elf',
5592 'tee-os-path': 'tee.elf',
5593 }
5594 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5595 data = self._DoReadFileDtb(
5596 '226_fit_split_elf.dts',
5597 entry_args=entry_args,
5598 extra_indirs=[test_subdir])[0]
5599
5600 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5601 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5602
5603 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5604 'data', 'load'}
5605 dtb = fdt.Fdt.FromData(fit_data)
5606 dtb.Scan()
5607
5608 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5609 segments, entry = elf.read_loadable_segments(elf_data)
5610
5611 # We assume there are two segments
Brandon Maiera657bc62024-06-04 16:16:05 +00005612 self.assertEqual(2, len(segments))
Simon Glass5f423422022-03-05 20:19:12 -07005613
5614 atf1 = dtb.GetNode('/images/atf-1')
5615 _, start, data = segments[0]
5616 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5617 self.assertEqual(entry,
5618 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5619 self.assertEqual(start,
5620 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5621 self.assertEqual(data, atf1.props['data'].bytes)
5622
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005623 hash_node = atf1.FindNode('hash')
5624 self.assertIsNotNone(hash_node)
5625 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5626
Simon Glass5f423422022-03-05 20:19:12 -07005627 atf2 = dtb.GetNode('/images/atf-2')
5628 self.assertEqual(base_keys, atf2.props.keys())
5629 _, start, data = segments[1]
5630 self.assertEqual(start,
5631 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5632 self.assertEqual(data, atf2.props['data'].bytes)
5633
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005634 hash_node = atf2.FindNode('hash')
5635 self.assertIsNotNone(hash_node)
5636 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5637
5638 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5639 self.assertIsNotNone(hash_node)
5640 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5641
Simon Glass5f423422022-03-05 20:19:12 -07005642 conf = dtb.GetNode('/configurations')
5643 self.assertEqual({'default'}, conf.props.keys())
5644
5645 for subnode in conf.subnodes:
5646 self.assertEqual({'description', 'fdt', 'loadables'},
5647 subnode.props.keys())
5648 self.assertEqual(
5649 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5650 fdt_util.GetStringList(subnode, 'loadables'))
5651
5652 def _check_bad_fit(self, dts):
5653 """Check a bad FIT
5654
5655 This runs with the given dts and returns the assertion raised
5656
5657 Args:
5658 dts (str): dts filename to use
5659
5660 Returns:
5661 str: Assertion string raised
5662 """
5663 entry_args = {
5664 'of-list': 'test-fdt1 test-fdt2',
5665 'default-dt': 'test-fdt2',
5666 'atf-bl31-path': 'bl31.elf',
5667 'tee-os-path': 'tee.elf',
5668 }
5669 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5670 with self.assertRaises(ValueError) as exc:
5671 self._DoReadFileDtb(dts, entry_args=entry_args,
5672 extra_indirs=[test_subdir])[0]
5673 return str(exc.exception)
5674
5675 def testFitSplitElfBadElf(self):
5676 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005677 if not elf.ELF_TOOLS:
5678 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005679 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5680 entry_args = {
5681 'of-list': 'test-fdt1 test-fdt2',
5682 'default-dt': 'test-fdt2',
5683 'atf-bl31-path': 'bad.elf',
5684 'tee-os-path': 'tee.elf',
5685 }
5686 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5687 with self.assertRaises(ValueError) as exc:
5688 self._DoReadFileDtb(
5689 '226_fit_split_elf.dts',
5690 entry_args=entry_args,
5691 extra_indirs=[test_subdir])[0]
5692 self.assertIn(
5693 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5694 str(exc.exception))
5695
Simon Glass5f423422022-03-05 20:19:12 -07005696 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005697 """Test an split-elf FIT with a missing ELF file
5698
5699 Args:
5700 kwargs (dict of str): Arguments to pass to _DoTestFile()
5701
5702 Returns:
5703 tuple:
5704 str: stdout result
5705 str: stderr result
5706 """
Simon Glass5f423422022-03-05 20:19:12 -07005707 entry_args = {
5708 'of-list': 'test-fdt1 test-fdt2',
5709 'default-dt': 'test-fdt2',
5710 'atf-bl31-path': 'bl31.elf',
5711 'tee-os-path': 'missing.elf',
5712 }
5713 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5714 with test_util.capture_sys_output() as (stdout, stderr):
5715 self._DoTestFile(
5716 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005717 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5718 out = stdout.getvalue()
5719 err = stderr.getvalue()
5720 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005721
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005722 def testFitSplitElfBadDirective(self):
5723 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5724 if not elf.ELF_TOOLS:
5725 self.skipTest('Python elftools not available')
5726 err = self._check_bad_fit('227_fit_bad_dir.dts')
5727 self.assertIn(
5728 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5729 err)
5730
5731 def testFitSplitElfBadDirectiveConfig(self):
5732 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5733 if not elf.ELF_TOOLS:
5734 self.skipTest('Python elftools not available')
5735 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5736 self.assertEqual(
5737 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5738 err)
5739
5740
Simon Glass5f423422022-03-05 20:19:12 -07005741 def testFitSplitElfMissing(self):
5742 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005743 if not elf.ELF_TOOLS:
5744 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005745 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005746 self.assertRegex(
5747 err,
5748 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005749 self.assertNotRegex(out, '.*Faked blob.*')
5750 fname = tools.get_output_filename('binman-fake/missing.elf')
5751 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005752
5753 def testFitSplitElfFaked(self):
5754 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005755 if not elf.ELF_TOOLS:
5756 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005757 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005758 self.assertRegex(
5759 err,
5760 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005761 self.assertRegex(
5762 out,
5763 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5764 fname = tools.get_output_filename('binman-fake/missing.elf')
5765 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005766
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005767 def testMkimageMissingBlob(self):
5768 """Test using mkimage to build an image"""
5769 with test_util.capture_sys_output() as (stdout, stderr):
5770 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5771 allow_fake_blobs=True)
5772 err = stderr.getvalue()
5773 self.assertRegex(
5774 err,
5775 "Image '.*' has faked external blobs and is non-functional: .*")
5776
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005777 def testPreLoad(self):
5778 """Test an image with a pre-load header"""
5779 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005780 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005781 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005782 data = self._DoReadFileDtb(
5783 '230_pre_load.dts', entry_args=entry_args,
5784 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005785 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5786 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5787 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Simon Glasse2dfb962023-07-24 09:19:57 -06005788
5789 def testPreLoadNoKey(self):
5790 """Test an image with a pre-load heade0r with missing key"""
5791 with self.assertRaises(FileNotFoundError) as exc:
5792 self._DoReadFile('230_pre_load.dts')
5793 self.assertIn("No such file or directory: 'dev.key'",
5794 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005795
5796 def testPreLoadPkcs(self):
5797 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005798 entry_args = {
5799 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5800 }
5801 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5802 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005803 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5804 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5805 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5806
5807 def testPreLoadPss(self):
5808 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005809 entry_args = {
5810 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5811 }
5812 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5813 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005814 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5815 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5816 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5817
5818 def testPreLoadInvalidPadding(self):
5819 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005820 entry_args = {
5821 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5822 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005823 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005824 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5825 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005826
5827 def testPreLoadInvalidSha(self):
5828 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005829 entry_args = {
5830 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5831 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005832 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005833 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5834 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005835
5836 def testPreLoadInvalidAlgo(self):
5837 """Test an image with a pre-load header with an invalid algo"""
5838 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005839 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005840
5841 def testPreLoadInvalidKey(self):
5842 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005843 entry_args = {
5844 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5845 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005846 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005847 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5848 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005849
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005850 def _CheckSafeUniqueNames(self, *images):
5851 """Check all entries of given images for unsafe unique names"""
5852 for image in images:
5853 entries = {}
5854 image._CollectEntries(entries, {}, image)
5855 for entry in entries.values():
5856 uniq = entry.GetUniqueName()
5857
5858 # Used as part of a filename, so must not be absolute paths.
5859 self.assertFalse(os.path.isabs(uniq))
5860
5861 def testSafeUniqueNames(self):
5862 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005863 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005864
5865 orig_image = control.images['image']
5866 image_fname = tools.get_output_filename('image.bin')
5867 image = Image.FromFile(image_fname)
5868
5869 self._CheckSafeUniqueNames(orig_image, image)
5870
5871 def testSafeUniqueNamesMulti(self):
5872 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005873 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005874
5875 orig_image = control.images['image']
5876 image_fname = tools.get_output_filename('image.bin')
5877 image = Image.FromFile(image_fname)
5878
5879 self._CheckSafeUniqueNames(orig_image, image)
5880
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005881 def testReplaceCmdWithBintool(self):
5882 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005883 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005884 expected = U_BOOT_DATA + b'aa'
5885 self.assertEqual(expected, data[:len(expected)])
5886
5887 try:
5888 tmpdir, updated_fname = self._SetupImageInTmpdir()
5889 fname = os.path.join(tmpdir, 'update-testing.bin')
5890 tools.write_file(fname, b'zz')
5891 self._DoBinman('replace', '-i', updated_fname,
5892 '_testing', '-f', fname)
5893
5894 data = tools.read_file(updated_fname)
5895 expected = U_BOOT_DATA + b'zz'
5896 self.assertEqual(expected, data[:len(expected)])
5897 finally:
5898 shutil.rmtree(tmpdir)
5899
5900 def testReplaceCmdOtherWithBintool(self):
5901 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005902 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005903 expected = U_BOOT_DATA + b'aa'
5904 self.assertEqual(expected, data[:len(expected)])
5905
5906 try:
5907 tmpdir, updated_fname = self._SetupImageInTmpdir()
5908 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5909 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5910 self._DoBinman('replace', '-i', updated_fname,
5911 'u-boot', '-f', fname)
5912
5913 data = tools.read_file(updated_fname)
5914 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5915 self.assertEqual(expected, data[:len(expected)])
5916 finally:
5917 shutil.rmtree(tmpdir)
5918
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005919 def testReplaceResizeNoRepackSameSize(self):
5920 """Test replacing entries with same-size data without repacking"""
5921 expected = b'x' * len(U_BOOT_DATA)
5922 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5923 self.assertEqual(expected, data)
5924
5925 path, fdtmap = state.GetFdtContents('fdtmap')
5926 self.assertIsNotNone(path)
5927 self.assertEqual(expected_fdtmap, fdtmap)
5928
5929 def testReplaceResizeNoRepackSmallerSize(self):
5930 """Test replacing entries with smaller-size data without repacking"""
5931 new_data = b'x'
5932 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5933 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5934 self.assertEqual(expected, data)
5935
5936 path, fdtmap = state.GetFdtContents('fdtmap')
5937 self.assertIsNotNone(path)
5938 self.assertEqual(expected_fdtmap, fdtmap)
5939
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005940 def testExtractFit(self):
5941 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005942 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005943 image_fname = tools.get_output_filename('image.bin')
5944
5945 fit_data = control.ReadEntry(image_fname, 'fit')
5946 fit = fdt.Fdt.FromData(fit_data)
5947 fit.Scan()
5948
5949 # Check subentry data inside the extracted fit
5950 for node_path, expected in [
5951 ('/images/kernel', U_BOOT_DATA),
5952 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5953 ('/images/scr-1', COMPRESS_DATA),
5954 ]:
5955 node = fit.GetNode(node_path)
5956 data = fit.GetProps(node)['data'].bytes
5957 self.assertEqual(expected, data)
5958
5959 def testExtractFitSubentries(self):
5960 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005961 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005962 image_fname = tools.get_output_filename('image.bin')
5963
5964 for entry_path, expected in [
5965 ('fit/kernel', U_BOOT_DATA),
5966 ('fit/kernel/u-boot', U_BOOT_DATA),
5967 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5968 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5969 ('fit/scr-1', COMPRESS_DATA),
5970 ('fit/scr-1/blob', COMPRESS_DATA),
5971 ]:
5972 data = control.ReadEntry(image_fname, entry_path)
5973 self.assertEqual(expected, data)
5974
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005975 def testReplaceFitSubentryLeafSameSize(self):
5976 """Test replacing a FIT leaf subentry with same-size data"""
5977 new_data = b'x' * len(U_BOOT_DATA)
5978 data, expected_fdtmap, _ = self._RunReplaceCmd(
5979 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005980 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005981 self.assertEqual(new_data, data)
5982
5983 path, fdtmap = state.GetFdtContents('fdtmap')
5984 self.assertIsNotNone(path)
5985 self.assertEqual(expected_fdtmap, fdtmap)
5986
5987 def testReplaceFitSubentryLeafBiggerSize(self):
5988 """Test replacing a FIT leaf subentry with bigger-size data"""
5989 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5990 data, expected_fdtmap, _ = self._RunReplaceCmd(
5991 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005992 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005993 self.assertEqual(new_data, data)
5994
5995 # Will be repacked, so fdtmap must change
5996 path, fdtmap = state.GetFdtContents('fdtmap')
5997 self.assertIsNotNone(path)
5998 self.assertNotEqual(expected_fdtmap, fdtmap)
5999
6000 def testReplaceFitSubentryLeafSmallerSize(self):
6001 """Test replacing a FIT leaf subentry with smaller-size data"""
6002 new_data = b'x'
6003 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
6004 data, expected_fdtmap, _ = self._RunReplaceCmd(
6005 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006006 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006007 self.assertEqual(expected, data)
6008
6009 path, fdtmap = state.GetFdtContents('fdtmap')
6010 self.assertIsNotNone(path)
6011 self.assertEqual(expected_fdtmap, fdtmap)
6012
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006013 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07006014 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006015 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07006016 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6017 new_data, dts='241_replace_section_simple.dts')
6018 self.assertEqual(new_data, data)
6019
6020 entries = image.GetEntries()
6021 self.assertIn('section', entries)
6022 entry = entries['section']
6023 self.assertEqual(len(new_data), entry.size)
6024
6025 def testReplaceSectionLarger(self):
6026 """Test replacing a simple section with larger data"""
6027 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6028 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6029 new_data, dts='241_replace_section_simple.dts')
6030 self.assertEqual(new_data, data)
6031
6032 entries = image.GetEntries()
6033 self.assertIn('section', entries)
6034 entry = entries['section']
6035 self.assertEqual(len(new_data), entry.size)
6036 fentry = entries['fdtmap']
6037 self.assertEqual(entry.offset + entry.size, fentry.offset)
6038
6039 def testReplaceSectionSmaller(self):
6040 """Test replacing a simple section with smaller data"""
6041 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
6042 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6043 new_data, dts='241_replace_section_simple.dts')
6044 self.assertEqual(new_data, data)
6045
6046 # The new size is the same as the old, just with a pad byte at the end
6047 entries = image.GetEntries()
6048 self.assertIn('section', entries)
6049 entry = entries['section']
6050 self.assertEqual(len(new_data), entry.size)
6051
6052 def testReplaceSectionSmallerAllow(self):
6053 """Test failing to replace a simple section with smaller data"""
6054 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
6055 try:
6056 state.SetAllowEntryContraction(True)
6057 with self.assertRaises(ValueError) as exc:
6058 self._RunReplaceCmd('section', new_data,
6059 dts='241_replace_section_simple.dts')
6060 finally:
6061 state.SetAllowEntryContraction(False)
6062
6063 # Since we have no information about the position of things within the
6064 # section, we cannot adjust the position of /section-u-boot so it ends
6065 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06006066 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07006067 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
6068 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06006069 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006070
Simon Glass8fbca772022-08-13 11:40:48 -06006071 def testMkimageImagename(self):
6072 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006073 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006074 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06006075
6076 # Check that the data appears in the file somewhere
6077 self.assertIn(U_BOOT_SPL_DATA, data)
6078
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006079 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06006080 name = data[0x20:0x40]
6081
6082 # Build the filename that we expect to be placed in there, by virtue of
6083 # the -n paraameter
6084 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6085
6086 # Check that the image name is set to the temporary filename used
6087 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6088
Simon Glassb1669752022-08-13 11:40:49 -06006089 def testMkimageImage(self):
6090 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006091 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006092 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006093
6094 # Check that the data appears in the file somewhere
6095 self.assertIn(U_BOOT_SPL_DATA, data)
6096
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006097 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006098 name = data[0x20:0x40]
6099
6100 # Build the filename that we expect to be placed in there, by virtue of
6101 # the -n paraameter
6102 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6103
6104 # Check that the image name is set to the temporary filename used
6105 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6106
6107 # Check the corect data is in the imagename file
6108 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6109
6110 def testMkimageImageNoContent(self):
6111 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006112 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006113 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006114 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006115 self.assertIn('Could not complete processing of contents',
6116 str(exc.exception))
6117
6118 def testMkimageImageBad(self):
6119 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006120 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006121 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006122 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006123 self.assertIn('Cannot use both imagename node and data-to-imagename',
6124 str(exc.exception))
6125
Simon Glassbd5cd882022-08-13 11:40:50 -06006126 def testCollectionOther(self):
6127 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006128 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006129 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6130 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6131 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6132 data)
6133
6134 def testMkimageCollection(self):
6135 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006136 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006137 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006138 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6139 self.assertEqual(expect, data[:len(expect)])
6140
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006141 def testCompressDtbPrependInvalid(self):
6142 """Test that invalid header is detected"""
6143 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006144 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006145 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6146 "'u-boot-dtb': 'invalid'", str(e.exception))
6147
6148 def testCompressDtbPrependLength(self):
6149 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006150 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006151 image = control.images['image']
6152 entries = image.GetEntries()
6153 self.assertIn('u-boot-dtb', entries)
6154 u_boot_dtb = entries['u-boot-dtb']
6155 self.assertIn('fdtmap', entries)
6156 fdtmap = entries['fdtmap']
6157
6158 image_fname = tools.get_output_filename('image.bin')
6159 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6160 dtb = fdt.Fdt.FromData(orig)
6161 dtb.Scan()
6162 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6163 expected = {
6164 'u-boot:size': len(U_BOOT_DATA),
6165 'u-boot-dtb:uncomp-size': len(orig),
6166 'u-boot-dtb:size': u_boot_dtb.size,
6167 'fdtmap:size': fdtmap.size,
6168 'size': len(data),
6169 }
6170 self.assertEqual(expected, props)
6171
6172 # Check implementation
6173 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6174 rest = data[len(U_BOOT_DATA):]
6175 comp_data_len = struct.unpack('<I', rest[:4])[0]
6176 comp_data = rest[4:4 + comp_data_len]
6177 orig2 = self._decompress(comp_data)
6178 self.assertEqual(orig, orig2)
6179
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006180 def testInvalidCompress(self):
6181 """Test that invalid compress algorithm is detected"""
6182 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006183 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006184 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6185
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006186 def testCompUtilCompressions(self):
6187 """Test compression algorithms"""
6188 for bintool in self.comp_bintools.values():
6189 self._CheckBintool(bintool)
6190 data = bintool.compress(COMPRESS_DATA)
6191 self.assertNotEqual(COMPRESS_DATA, data)
6192 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006193 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006194
6195 def testCompUtilVersions(self):
6196 """Test tool version of compression algorithms"""
6197 for bintool in self.comp_bintools.values():
6198 self._CheckBintool(bintool)
6199 version = bintool.version()
6200 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6201
6202 def testCompUtilPadding(self):
6203 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006204 # Skip zstd because it doesn't support padding
6205 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006206 self._CheckBintool(bintool)
6207 data = bintool.compress(COMPRESS_DATA)
6208 self.assertNotEqual(COMPRESS_DATA, data)
6209 data += tools.get_bytes(0, 64)
6210 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006211 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006212
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006213 def testCompressDtbZstd(self):
6214 """Test that zstd compress of device-tree files failed"""
6215 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006216 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006217 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6218 "requires a length header", str(e.exception))
6219
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006220 def testMkimageMultipleDataFiles(self):
6221 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006222 self._SetupSplElf()
6223 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006224 data = self._DoReadFile('252_mkimage_mult_data.dts')
6225 # Size of files are packed in their 4B big-endian format
6226 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6227 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6228 # Size info is always followed by a 4B zero value.
6229 expect += tools.get_bytes(0, 4)
6230 expect += U_BOOT_TPL_DATA
6231 # All but last files are 4B-aligned
6232 align_pad = len(U_BOOT_TPL_DATA) % 4
6233 if align_pad:
6234 expect += tools.get_bytes(0, align_pad)
6235 expect += U_BOOT_SPL_DATA
6236 self.assertEqual(expect, data[-len(expect):])
6237
Marek Vasutf7413f02023-07-18 07:23:58 -06006238 def testMkimageMultipleExpanded(self):
6239 """Test passing multiple files to mkimage in a mkimage entry"""
6240 self._SetupSplElf()
6241 self._SetupTplElf()
6242 entry_args = {
6243 'spl-bss-pad': 'y',
6244 'spl-dtb': 'y',
6245 }
6246 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6247 use_expanded=True, entry_args=entry_args)[0]
6248 pad_len = 10
6249 tpl_expect = U_BOOT_TPL_DATA
6250 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6251 spl_expect += U_BOOT_SPL_DTB_DATA
6252
6253 content = data[0x40:]
6254 lens = struct.unpack('>III', content[:12])
6255
6256 # Size of files are packed in their 4B big-endian format
6257 # Size info is always followed by a 4B zero value.
6258 self.assertEqual(len(tpl_expect), lens[0])
6259 self.assertEqual(len(spl_expect), lens[1])
6260 self.assertEqual(0, lens[2])
6261
6262 rest = content[12:]
6263 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6264
6265 rest = rest[len(tpl_expect):]
6266 align_pad = len(tpl_expect) % 4
6267 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6268 rest = rest[align_pad:]
6269 self.assertEqual(spl_expect, rest)
6270
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006271 def testMkimageMultipleNoContent(self):
6272 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006273 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006274 with self.assertRaises(ValueError) as exc:
6275 self._DoReadFile('253_mkimage_mult_no_content.dts')
6276 self.assertIn('Could not complete processing of contents',
6277 str(exc.exception))
6278
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006279 def testMkimageFilename(self):
6280 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006281 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006282 retcode = self._DoTestFile('254_mkimage_filename.dts')
6283 self.assertEqual(0, retcode)
6284 fname = tools.get_output_filename('mkimage-test.bin')
6285 self.assertTrue(os.path.exists(fname))
6286
Simon Glass56d05412022-02-28 07:16:54 -07006287 def testVpl(self):
6288 """Test that an image with VPL and its device tree can be created"""
6289 # ELF file with a '__bss_size' symbol
6290 self._SetupVplElf()
6291 data = self._DoReadFile('255_u_boot_vpl.dts')
6292 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6293
6294 def testVplNoDtb(self):
6295 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6296 self._SetupVplElf()
6297 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6298 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6299 data[:len(U_BOOT_VPL_NODTB_DATA)])
6300
6301 def testExpandedVpl(self):
6302 """Test that an expanded entry type is selected for TPL when needed"""
6303 self._SetupVplElf()
6304
6305 entry_args = {
6306 'vpl-bss-pad': 'y',
6307 'vpl-dtb': 'y',
6308 }
6309 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6310 entry_args=entry_args)
6311 image = control.images['image']
6312 entries = image.GetEntries()
6313 self.assertEqual(1, len(entries))
6314
6315 # We only have u-boot-vpl, which be expanded
6316 self.assertIn('u-boot-vpl', entries)
6317 entry = entries['u-boot-vpl']
6318 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6319 subent = entry.GetEntries()
6320 self.assertEqual(3, len(subent))
6321 self.assertIn('u-boot-vpl-nodtb', subent)
6322 self.assertIn('u-boot-vpl-bss-pad', subent)
6323 self.assertIn('u-boot-vpl-dtb', subent)
6324
6325 def testVplBssPadMissing(self):
6326 """Test that a missing symbol is detected"""
6327 self._SetupVplElf('u_boot_ucode_ptr')
6328 with self.assertRaises(ValueError) as e:
6329 self._DoReadFile('258_vpl_bss_pad.dts')
6330 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6331 str(e.exception))
6332
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306333 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306334 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306335 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6336 self.assertEqual(0, retcode)
6337 image = control.images['test_image']
6338 fname = tools.get_output_filename('test_image.bin')
6339 sname = tools.get_output_filename('symlink_to_test.bin')
6340 self.assertTrue(os.path.islink(sname))
6341 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006342
Andrew Davis6b463da2023-07-22 00:14:44 +05306343 def testSymlinkOverwrite(self):
6344 """Test that symlinked images can be overwritten"""
6345 testdir = TestFunctional._MakeInputDir('symlinktest')
6346 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6347 # build the same image again in the same directory so that existing symlink is present
6348 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6349 fname = tools.get_output_filename('test_image.bin')
6350 sname = tools.get_output_filename('symlink_to_test.bin')
6351 self.assertTrue(os.path.islink(sname))
6352 self.assertEqual(os.readlink(sname), fname)
6353
Simon Glass37f85de2022-10-20 18:22:47 -06006354 def testSymbolsElf(self):
6355 """Test binman can assign symbols embedded in an ELF file"""
6356 if not elf.ELF_TOOLS:
6357 self.skipTest('Python elftools not available')
6358 self._SetupTplElf('u_boot_binman_syms')
6359 self._SetupVplElf('u_boot_binman_syms')
6360 self._SetupSplElf('u_boot_binman_syms')
6361 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6362 image_fname = tools.get_output_filename('image.bin')
6363
6364 image = control.images['image']
6365 entries = image.GetEntries()
6366
6367 for entry in entries.values():
6368 # No symbols in u-boot and it has faked contents anyway
6369 if entry.name == 'u-boot':
6370 continue
6371 edata = data[entry.image_pos:entry.image_pos + entry.size]
6372 efname = tools.get_output_filename(f'edata-{entry.name}')
6373 tools.write_file(efname, edata)
6374
6375 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6376 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6377 for name, sym in syms.items():
6378 msg = 'test'
6379 val = elf.GetSymbolValue(sym, edata, msg)
6380 entry_m = re_name.match(name)
6381 if entry_m:
6382 ename, prop = entry_m.group(1), entry_m.group(3)
6383 entry, entry_name, prop_name = image.LookupEntry(entries,
6384 name, msg)
6385 if prop_name == 'offset':
6386 expect_val = entry.offset
6387 elif prop_name == 'image_pos':
6388 expect_val = entry.image_pos
6389 elif prop_name == 'size':
6390 expect_val = entry.size
6391 self.assertEqual(expect_val, val)
6392
6393 def testSymbolsElfBad(self):
6394 """Check error when trying to write symbols without the elftools lib"""
6395 if not elf.ELF_TOOLS:
6396 self.skipTest('Python elftools not available')
6397 self._SetupTplElf('u_boot_binman_syms')
6398 self._SetupVplElf('u_boot_binman_syms')
6399 self._SetupSplElf('u_boot_binman_syms')
6400 try:
6401 elf.ELF_TOOLS = False
6402 with self.assertRaises(ValueError) as exc:
6403 self._DoReadFileDtb('260_symbols_elf.dts')
6404 finally:
6405 elf.ELF_TOOLS = True
6406 self.assertIn(
6407 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6408 'Cannot write symbols to an ELF file without Python elftools',
6409 str(exc.exception))
6410
Simon Glassde244162023-01-07 14:07:08 -07006411 def testSectionFilename(self):
6412 """Check writing of section contents to a file"""
6413 data = self._DoReadFile('261_section_fname.dts')
6414 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6415 tools.get_bytes(ord('!'), 7) +
6416 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6417 self.assertEqual(expected, data)
6418
6419 sect_fname = tools.get_output_filename('outfile.bin')
6420 self.assertTrue(os.path.exists(sect_fname))
6421 sect_data = tools.read_file(sect_fname)
6422 self.assertEqual(U_BOOT_DATA, sect_data)
6423
Simon Glass1e9e61c2023-01-07 14:07:12 -07006424 def testAbsent(self):
6425 """Check handling of absent entries"""
6426 data = self._DoReadFile('262_absent.dts')
6427 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6428
Simon Glassad5cfe12023-01-07 14:07:14 -07006429 def testPackTeeOsOptional(self):
6430 """Test that an image with an optional TEE binary can be created"""
6431 entry_args = {
6432 'tee-os-path': 'tee.elf',
6433 }
6434 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6435 entry_args=entry_args)[0]
6436 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6437
6438 def checkFitTee(self, dts, tee_fname):
6439 """Check that a tee-os entry works and returns data
6440
6441 Args:
6442 dts (str): Device tree filename to use
6443 tee_fname (str): filename containing tee-os
6444
6445 Returns:
6446 bytes: Image contents
6447 """
6448 if not elf.ELF_TOOLS:
6449 self.skipTest('Python elftools not available')
6450 entry_args = {
6451 'of-list': 'test-fdt1 test-fdt2',
6452 'default-dt': 'test-fdt2',
6453 'tee-os-path': tee_fname,
6454 }
6455 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6456 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6457 extra_indirs=[test_subdir])[0]
6458 return data
6459
6460 def testFitTeeOsOptionalFit(self):
6461 """Test an image with a FIT with an optional OP-TEE binary"""
6462 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6463
6464 # There should be only one node, holding the data set up in SetUpClass()
6465 # for tee.bin
6466 dtb = fdt.Fdt.FromData(data)
6467 dtb.Scan()
6468 node = dtb.GetNode('/images/tee-1')
6469 self.assertEqual(TEE_ADDR,
6470 fdt_util.fdt32_to_cpu(node.props['load'].value))
6471 self.assertEqual(TEE_ADDR,
6472 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6473 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6474
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006475 with test_util.capture_sys_output() as (stdout, stderr):
6476 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6477 err = stderr.getvalue()
6478 self.assertRegex(
6479 err,
6480 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6481
Simon Glassad5cfe12023-01-07 14:07:14 -07006482 def testFitTeeOsOptionalFitBad(self):
6483 """Test an image with a FIT with an optional OP-TEE binary"""
6484 with self.assertRaises(ValueError) as exc:
6485 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6486 self.assertIn(
6487 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6488 str(exc.exception))
6489
6490 def testFitTeeOsBad(self):
6491 """Test an OP-TEE binary with wrong formats"""
6492 self.make_tee_bin('tee.bad1', 123)
6493 with self.assertRaises(ValueError) as exc:
6494 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6495 self.assertIn(
6496 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6497 str(exc.exception))
6498
6499 self.make_tee_bin('tee.bad2', 0, b'extra data')
6500 with self.assertRaises(ValueError) as exc:
6501 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6502 self.assertIn(
6503 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6504 str(exc.exception))
6505
Simon Glass63328f12023-01-07 14:07:15 -07006506 def testExtblobOptional(self):
6507 """Test an image with an external blob that is optional"""
6508 with test_util.capture_sys_output() as (stdout, stderr):
6509 data = self._DoReadFile('266_blob_ext_opt.dts')
6510 self.assertEqual(REFCODE_DATA, data)
6511 err = stderr.getvalue()
6512 self.assertRegex(
6513 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006514 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006515
Simon Glass7447a9d2023-01-11 16:10:12 -07006516 def testSectionInner(self):
6517 """Test an inner section with a size"""
6518 data = self._DoReadFile('267_section_inner.dts')
6519 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6520 self.assertEqual(expected, data)
6521
Simon Glassa4948b22023-01-11 16:10:14 -07006522 def testNull(self):
6523 """Test an image with a null entry"""
6524 data = self._DoReadFile('268_null.dts')
6525 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6526
Simon Glassf1ee03b2023-01-11 16:10:16 -07006527 def testOverlap(self):
6528 """Test an image with a overlapping entry"""
6529 data = self._DoReadFile('269_overlap.dts')
6530 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6531
6532 image = control.images['image']
6533 entries = image.GetEntries()
6534
6535 self.assertIn('inset', entries)
6536 inset = entries['inset']
6537 self.assertEqual(1, inset.offset);
6538 self.assertEqual(1, inset.image_pos);
6539 self.assertEqual(2, inset.size);
6540
6541 def testOverlapNull(self):
6542 """Test an image with a null overlap"""
6543 data = self._DoReadFile('270_overlap_null.dts')
6544 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6545
6546 # Check the FMAP
6547 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6548 self.assertEqual(4, fhdr.nareas)
6549 fiter = iter(fentries)
6550
6551 fentry = next(fiter)
6552 self.assertEqual(b'SECTION', fentry.name)
6553 self.assertEqual(0, fentry.offset)
6554 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6555 self.assertEqual(0, fentry.flags)
6556
6557 fentry = next(fiter)
6558 self.assertEqual(b'U_BOOT', fentry.name)
6559 self.assertEqual(0, fentry.offset)
6560 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6561 self.assertEqual(0, fentry.flags)
6562
6563 # Make sure that the NULL entry appears in the FMAP
6564 fentry = next(fiter)
6565 self.assertEqual(b'NULL', fentry.name)
6566 self.assertEqual(1, fentry.offset)
6567 self.assertEqual(2, fentry.size)
6568 self.assertEqual(0, fentry.flags)
6569
6570 fentry = next(fiter)
6571 self.assertEqual(b'FMAP', fentry.name)
6572 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6573
6574 def testOverlapBad(self):
6575 """Test an image with a bad overlapping entry"""
6576 with self.assertRaises(ValueError) as exc:
6577 self._DoReadFile('271_overlap_bad.dts')
6578 self.assertIn(
6579 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6580 str(exc.exception))
6581
6582 def testOverlapNoOffset(self):
6583 """Test an image with a bad overlapping entry"""
6584 with self.assertRaises(ValueError) as exc:
6585 self._DoReadFile('272_overlap_no_size.dts')
6586 self.assertIn(
6587 "Node '/binman/inset': 'fill' entry is missing properties: size",
6588 str(exc.exception))
6589
Simon Glasse0035c92023-01-11 16:10:17 -07006590 def testBlobSymbol(self):
6591 """Test a blob with symbols read from an ELF file"""
6592 elf_fname = self.ElfTestFile('blob_syms')
6593 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6594 TestFunctional._MakeInputFile('blob_syms.bin',
6595 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6596
6597 data = self._DoReadFile('273_blob_symbol.dts')
6598
6599 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6600 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6601 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6602 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6603 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6604
6605 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6606 expected = sym_values
6607 self.assertEqual(expected, data[:len(expected)])
6608
Simon Glass49e9c002023-01-11 16:10:19 -07006609 def testOffsetFromElf(self):
6610 """Test a blob with symbols read from an ELF file"""
6611 elf_fname = self.ElfTestFile('blob_syms')
6612 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6613 TestFunctional._MakeInputFile('blob_syms.bin',
6614 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6615
6616 data = self._DoReadFile('274_offset_from_elf.dts')
6617
6618 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6619 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6620
6621 image = control.images['image']
6622 entries = image.GetEntries()
6623
6624 self.assertIn('inset', entries)
6625 inset = entries['inset']
6626
6627 self.assertEqual(base + 4, inset.offset);
6628 self.assertEqual(base + 4, inset.image_pos);
6629 self.assertEqual(4, inset.size);
6630
6631 self.assertIn('inset2', entries)
6632 inset = entries['inset2']
6633 self.assertEqual(base + 8, inset.offset);
6634 self.assertEqual(base + 8, inset.image_pos);
6635 self.assertEqual(4, inset.size);
6636
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006637 def testFitAlign(self):
6638 """Test an image with an FIT with aligned external data"""
6639 data = self._DoReadFile('275_fit_align.dts')
6640 self.assertEqual(4096, len(data))
6641
6642 dtb = fdt.Fdt.FromData(data)
6643 dtb.Scan()
6644
6645 props = self._GetPropTree(dtb, ['data-position'])
6646 expected = {
6647 'u-boot:data-position': 1024,
6648 'fdt-1:data-position': 2048,
6649 'fdt-2:data-position': 3072,
6650 }
6651 self.assertEqual(expected, props)
6652
Jonas Karlman490f73c2023-01-21 19:02:12 +00006653 def testFitFirmwareLoadables(self):
6654 """Test an image with an FIT that use fit,firmware"""
6655 if not elf.ELF_TOOLS:
6656 self.skipTest('Python elftools not available')
6657 entry_args = {
6658 'of-list': 'test-fdt1',
6659 'default-dt': 'test-fdt1',
6660 'atf-bl31-path': 'bl31.elf',
6661 'tee-os-path': 'missing.bin',
6662 }
6663 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006664 with test_util.capture_sys_output() as (stdout, stderr):
6665 data = self._DoReadFileDtb(
6666 '276_fit_firmware_loadables.dts',
6667 entry_args=entry_args,
6668 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006669
6670 dtb = fdt.Fdt.FromData(data)
6671 dtb.Scan()
6672
6673 node = dtb.GetNode('/configurations/conf-uboot-1')
6674 self.assertEqual('u-boot', node.props['firmware'].value)
6675 self.assertEqual(['atf-1', 'atf-2'],
6676 fdt_util.GetStringList(node, 'loadables'))
6677
6678 node = dtb.GetNode('/configurations/conf-atf-1')
6679 self.assertEqual('atf-1', node.props['firmware'].value)
6680 self.assertEqual(['u-boot', 'atf-2'],
6681 fdt_util.GetStringList(node, 'loadables'))
6682
6683 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6684 self.assertEqual('u-boot', node.props['firmware'].value)
6685 self.assertEqual(['atf-1', 'atf-2'],
6686 fdt_util.GetStringList(node, 'loadables'))
6687
6688 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6689 self.assertEqual('atf-1', node.props['firmware'].value)
6690 self.assertEqual(['u-boot', 'atf-2'],
6691 fdt_util.GetStringList(node, 'loadables'))
6692
6693 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6694 self.assertEqual('atf-1', node.props['firmware'].value)
6695 self.assertEqual(['u-boot', 'atf-2'],
6696 fdt_util.GetStringList(node, 'loadables'))
6697
Simon Glass9a1c7262023-02-22 12:14:49 -07006698 def testTooldir(self):
6699 """Test that we can specify the tooldir"""
6700 with test_util.capture_sys_output() as (stdout, stderr):
6701 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6702 'tool', '-l'))
6703 self.assertEqual('fred', bintool.Bintool.tooldir)
6704
6705 # Check that the toolpath is updated correctly
6706 self.assertEqual(['fred'], tools.tool_search_paths)
6707
6708 # Try with a few toolpaths; the tooldir should be at the end
6709 with test_util.capture_sys_output() as (stdout, stderr):
6710 self.assertEqual(0, self._DoBinman(
6711 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6712 'tool', '-l'))
6713 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6714
Simon Glass49b77e82023-03-02 17:02:44 -07006715 def testReplaceSectionEntry(self):
6716 """Test replacing an entry in a section"""
6717 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6718 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6719 expect_data, dts='241_replace_section_simple.dts')
6720 self.assertEqual(expect_data, entry_data)
6721
6722 entries = image.GetEntries()
6723 self.assertIn('section', entries)
6724 section = entries['section']
6725
6726 sect_entries = section.GetEntries()
6727 self.assertIn('blob', sect_entries)
6728 entry = sect_entries['blob']
6729 self.assertEqual(len(expect_data), entry.size)
6730
6731 fname = tools.get_output_filename('image-updated.bin')
6732 data = tools.read_file(fname)
6733
6734 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6735 self.assertEqual(expect_data, new_blob_data)
6736
6737 self.assertEqual(U_BOOT_DATA,
6738 data[entry.image_pos + len(expect_data):]
6739 [:len(U_BOOT_DATA)])
6740
6741 def testReplaceSectionDeep(self):
6742 """Test replacing an entry in two levels of sections"""
6743 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6744 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6745 'section/section/blob', expect_data,
6746 dts='278_replace_section_deep.dts')
6747 self.assertEqual(expect_data, entry_data)
6748
6749 entries = image.GetEntries()
6750 self.assertIn('section', entries)
6751 section = entries['section']
6752
6753 subentries = section.GetEntries()
6754 self.assertIn('section', subentries)
6755 section = subentries['section']
6756
6757 sect_entries = section.GetEntries()
6758 self.assertIn('blob', sect_entries)
6759 entry = sect_entries['blob']
6760 self.assertEqual(len(expect_data), entry.size)
6761
6762 fname = tools.get_output_filename('image-updated.bin')
6763 data = tools.read_file(fname)
6764
6765 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6766 self.assertEqual(expect_data, new_blob_data)
6767
6768 self.assertEqual(U_BOOT_DATA,
6769 data[entry.image_pos + len(expect_data):]
6770 [:len(U_BOOT_DATA)])
6771
6772 def testReplaceFitSibling(self):
6773 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006774 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006775 fname = TestFunctional._MakeInputFile('once', b'available once')
6776 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6777 os.remove(fname)
6778
6779 try:
6780 tmpdir, updated_fname = self._SetupImageInTmpdir()
6781
6782 fname = os.path.join(tmpdir, 'update-blob')
6783 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6784 tools.write_file(fname, expected)
6785
6786 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6787 data = tools.read_file(updated_fname)
6788 start = len(U_BOOT_DTB_DATA)
6789 self.assertEqual(expected, data[start:start + len(expected)])
6790 map_fname = os.path.join(tmpdir, 'image-updated.map')
6791 self.assertFalse(os.path.exists(map_fname))
6792 finally:
6793 shutil.rmtree(tmpdir)
6794
Simon Glassc3fe97f2023-03-02 17:02:45 -07006795 def testX509Cert(self):
6796 """Test creating an X509 certificate"""
6797 keyfile = self.TestFile('key.key')
6798 entry_args = {
6799 'keyfile': keyfile,
6800 }
6801 data = self._DoReadFileDtb('279_x509_cert.dts',
6802 entry_args=entry_args)[0]
6803 cert = data[:-4]
6804 self.assertEqual(U_BOOT_DATA, data[-4:])
6805
6806 # TODO: verify the signature
6807
6808 def testX509CertMissing(self):
6809 """Test that binman still produces an image if openssl is missing"""
6810 keyfile = self.TestFile('key.key')
6811 entry_args = {
6812 'keyfile': 'keyfile',
6813 }
6814 with test_util.capture_sys_output() as (_, stderr):
6815 self._DoTestFile('279_x509_cert.dts',
6816 force_missing_bintools='openssl',
6817 entry_args=entry_args)
6818 err = stderr.getvalue()
6819 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6820
Jonas Karlman35305492023-02-25 19:01:33 +00006821 def testPackRockchipTpl(self):
6822 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006823 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006824 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6825
Jonas Karlman1016ec72023-02-25 19:01:35 +00006826 def testMkimageMissingBlobMultiple(self):
6827 """Test missing blob with mkimage entry and multiple-data-files"""
6828 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006829 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006830 err = stderr.getvalue()
6831 self.assertIn("is missing external blobs and is non-functional", err)
6832
6833 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006834 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006835 self.assertIn("not found in input path", str(e.exception))
6836
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006837 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6838 """Prepare sign environment
6839
6840 Create private and public keys, add pubkey into dtb.
6841
6842 Returns:
6843 Tuple:
6844 FIT container
6845 Image name
6846 Private key
6847 DTB
6848 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006849 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006850 data = self._DoReadFileRealDtb(dts)
6851 updated_fname = tools.get_output_filename('image-updated.bin')
6852 tools.write_file(updated_fname, data)
6853 dtb = tools.get_output_filename('source.dtb')
6854 private_key = tools.get_output_filename('test_key.key')
6855 public_key = tools.get_output_filename('test_key.crt')
6856 fit = tools.get_output_filename('fit.fit')
6857 key_dir = tools.get_output_dir()
6858
6859 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6860 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6861 private_key, '-out', public_key)
6862 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6863 '-n', 'test_key', '-r', 'conf', dtb)
6864
6865 return fit, updated_fname, private_key, dtb
6866
6867 def testSignSimple(self):
6868 """Test that a FIT container can be signed in image"""
6869 is_signed = False
6870 fit, fname, private_key, dtb = self._PrepareSignEnv()
6871
6872 # do sign with private key
6873 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6874 ['fit'])
6875 is_signed = self._CheckSign(fit, dtb)
6876
6877 self.assertEqual(is_signed, True)
6878
6879 def testSignExactFIT(self):
6880 """Test that a FIT container can be signed and replaced in image"""
6881 is_signed = False
6882 fit, fname, private_key, dtb = self._PrepareSignEnv()
6883
6884 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6885 args = []
6886 if self.toolpath:
6887 for path in self.toolpath:
6888 args += ['--toolpath', path]
6889
6890 # do sign with private key
6891 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6892 'sha256,rsa4096', '-f', fit, 'fit')
6893 is_signed = self._CheckSign(fit, dtb)
6894
6895 self.assertEqual(is_signed, True)
6896
6897 def testSignNonFit(self):
6898 """Test a non-FIT entry cannot be signed"""
6899 is_signed = False
6900 fit, fname, private_key, _ = self._PrepareSignEnv(
6901 '281_sign_non_fit.dts')
6902
6903 # do sign with private key
6904 with self.assertRaises(ValueError) as e:
6905 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6906 'sha256,rsa4096', '-f', fit, 'u-boot')
6907 self.assertIn(
6908 "Node '/u-boot': Updating signatures is not supported with this entry type",
6909 str(e.exception))
6910
6911 def testSignMissingMkimage(self):
6912 """Test that FIT signing handles a missing mkimage tool"""
6913 fit, fname, private_key, _ = self._PrepareSignEnv()
6914
6915 # try to sign with a missing mkimage tool
6916 bintool.Bintool.set_missing_list(['mkimage'])
6917 with self.assertRaises(ValueError) as e:
6918 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6919 ['fit'])
6920 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6921
Simon Glass4abf7842023-07-18 07:23:54 -06006922 def testSymbolNoWrite(self):
6923 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006924 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006925 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6926 no_write_symbols=True)
6927
6928 def testSymbolNoWriteExpanded(self):
6929 """Test disabling of symbol writing in expanded entries"""
6930 entry_args = {
6931 'spl-dtb': '1',
6932 }
6933 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6934 U_BOOT_SPL_DTB_DATA, 0x38,
6935 entry_args=entry_args, use_expanded=True,
6936 no_write_symbols=True)
6937
Marek Vasutf7413f02023-07-18 07:23:58 -06006938 def testMkimageSpecial(self):
6939 """Test mkimage ignores special hash-1 node"""
6940 data = self._DoReadFile('283_mkimage_special.dts')
6941
6942 # Just check that the data appears in the file somewhere
6943 self.assertIn(U_BOOT_DATA, data)
6944
Simon Glass2d94c422023-07-18 07:23:59 -06006945 def testFitFdtList(self):
6946 """Test an image with an FIT with the fit,fdt-list-val option"""
6947 entry_args = {
6948 'default-dt': 'test-fdt2',
6949 }
6950 data = self._DoReadFileDtb(
6951 '284_fit_fdt_list.dts',
6952 entry_args=entry_args,
6953 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6954 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6955 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6956
Simon Glass83b8bfe2023-07-18 07:24:01 -06006957 def testSplEmptyBss(self):
6958 """Test an expanded SPL with a zero-size BSS"""
6959 # ELF file with a '__bss_size' symbol
6960 self._SetupSplElf(src_fname='bss_data_zero')
6961
6962 entry_args = {
6963 'spl-bss-pad': 'y',
6964 'spl-dtb': 'y',
6965 }
6966 data = self._DoReadFileDtb('285_spl_expand.dts',
6967 use_expanded=True, entry_args=entry_args)[0]
6968
Simon Glassfc792842023-07-18 07:24:04 -06006969 def testTemplate(self):
6970 """Test using a template"""
6971 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6972 data = self._DoReadFile('286_template.dts')
6973 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6974 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6975 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6976
Simon Glass09490b02023-07-22 21:43:52 -06006977 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6978 self.assertTrue(os.path.exists(dtb_fname1))
6979 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6980 dtb.Scan()
6981 node1 = dtb.GetNode('/binman/template')
6982 self.assertTrue(node1)
6983 vga = dtb.GetNode('/binman/first/intel-vga')
6984 self.assertTrue(vga)
6985
Simon Glass54825e12023-07-22 21:43:56 -06006986 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6987 self.assertTrue(os.path.exists(dtb_fname2))
6988 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6989 dtb2.Scan()
6990 node2 = dtb2.GetNode('/binman/template')
6991 self.assertFalse(node2)
6992
Simon Glass9909c112023-07-18 07:24:05 -06006993 def testTemplateBlobMulti(self):
6994 """Test using a template with 'multiple-images' enabled"""
6995 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6996 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6997 retcode = self._DoTestFile('287_template_multi.dts')
6998
6999 self.assertEqual(0, retcode)
7000 image = control.images['image']
7001 image_fname = tools.get_output_filename('my-image.bin')
7002 data = tools.read_file(image_fname)
7003 self.assertEqual(b'blob@@@@other', data)
7004
Simon Glass5dc511b2023-07-18 07:24:06 -06007005 def testTemplateFit(self):
7006 """Test using a template in a FIT"""
7007 fit_data = self._DoReadFile('288_template_fit.dts')
7008 fname = os.path.join(self._indir, 'fit_data.fit')
7009 tools.write_file(fname, fit_data)
7010 out = tools.run('dumpimage', '-l', fname)
7011
Simon Glassaa6e0552023-07-18 07:24:07 -06007012 def testTemplateSection(self):
7013 """Test using a template in a section (not at top level)"""
7014 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
7015 data = self._DoReadFile('289_template_section.dts')
7016 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
7017 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
7018 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
7019
Simon Glassf53a7bc2023-07-18 07:24:08 -06007020 def testMkimageSymbols(self):
7021 """Test using mkimage to build an image with symbols in it"""
7022 self._SetupSplElf('u_boot_binman_syms')
7023 data = self._DoReadFile('290_mkimage_sym.dts')
7024
7025 image = control.images['image']
7026 entries = image.GetEntries()
7027 self.assertIn('u-boot', entries)
7028 u_boot = entries['u-boot']
7029
7030 mkim = entries['mkimage']
7031 mkim_entries = mkim.GetEntries()
7032 self.assertIn('u-boot-spl', mkim_entries)
7033 spl = mkim_entries['u-boot-spl']
7034 self.assertIn('u-boot-spl2', mkim_entries)
7035 spl2 = mkim_entries['u-boot-spl2']
7036
7037 # skip the mkimage header and the area sizes
7038 mk_data = data[mkim.offset + 0x40:]
7039 size, term = struct.unpack('>LL', mk_data[:8])
7040
7041 # There should be only one image, so check that the zero terminator is
7042 # present
7043 self.assertEqual(0, term)
7044
7045 content = mk_data[8:8 + size]
7046
7047 # The image should contain the symbols from u_boot_binman_syms.c
7048 # Note that image_pos is adjusted by the base address of the image,
7049 # which is 0x10 in our test image
7050 spl_data = content[:0x18]
7051 content = content[0x1b:]
7052
7053 # After the header is a table of offsets for each image. There should
7054 # only be one image, then a 0 terminator, so figure out the real start
7055 # of the image data
7056 base = 0x40 + 8
7057
7058 # Check symbols in both u-boot-spl and u-boot-spl2
7059 for i in range(2):
7060 vals = struct.unpack('<LLQLL', spl_data)
7061
7062 # The image should contain the symbols from u_boot_binman_syms.c
7063 # Note that image_pos is adjusted by the base address of the image,
7064 # which is 0x10 in our 'u_boot_binman_syms' test image
7065 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
7066 self.assertEqual(base, vals[1])
7067 self.assertEqual(spl2.offset, vals[2])
7068 # figure out the internal positions of its components
7069 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
7070
7071 # Check that spl and spl2 are actually at the indicated positions
7072 self.assertEqual(
7073 elf.BINMAN_SYM_MAGIC_VALUE,
7074 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
7075 self.assertEqual(
7076 elf.BINMAN_SYM_MAGIC_VALUE,
7077 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
7078
7079 self.assertEqual(len(U_BOOT_DATA), vals[4])
7080
7081 # Move to next
7082 spl_data = content[:0x18]
7083
Simon Glass86b3e472023-07-22 21:43:57 -06007084 def testTemplatePhandle(self):
7085 """Test using a template in a node containing a phandle"""
7086 entry_args = {
7087 'atf-bl31-path': 'bl31.elf',
7088 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06007089 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007090 entry_args=entry_args)
7091 fname = tools.get_output_filename('image.bin')
7092 out = tools.run('dumpimage', '-l', fname)
7093
7094 # We should see the FIT description and one for each of the two images
7095 lines = out.splitlines()
7096 descs = [line.split()[-1] for line in lines if 'escription' in line]
7097 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7098
7099 def testTemplatePhandleDup(self):
7100 """Test using a template in a node containing a phandle"""
7101 entry_args = {
7102 'atf-bl31-path': 'bl31.elf',
7103 }
7104 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007105 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007106 entry_args=entry_args)
7107 self.assertIn(
7108 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7109 str(e.exception))
7110
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307111 def testTIBoardConfig(self):
7112 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007113 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307114 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7115
Neha Malcom Francis8cd04512024-01-05 17:09:17 +05307116 def testTIBoardConfigLint(self):
7117 """Test that an incorrectly linted config file would generate error"""
7118 with self.assertRaises(ValueError) as e:
7119 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7120 self.assertIn("Yamllint error", str(e.exception))
7121
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307122 def testTIBoardConfigCombined(self):
7123 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007124 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307125 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7126 self.assertGreater(data, configlen_noheader)
7127
7128 def testTIBoardConfigNoDataType(self):
7129 """Test that error is thrown when data type is not supported"""
7130 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007131 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307132 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007133
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307134 def testPackTiSecure(self):
7135 """Test that an image with a TI secured binary can be created"""
7136 keyfile = self.TestFile('key.key')
7137 entry_args = {
7138 'keyfile': keyfile,
7139 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007140 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307141 entry_args=entry_args)[0]
7142 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7143
Manorit Chawdhry2e523b02023-12-29 16:16:27 +05307144 def testPackTiSecureFirewall(self):
7145 """Test that an image with a TI secured binary can be created"""
7146 keyfile = self.TestFile('key.key')
7147 entry_args = {
7148 'keyfile': keyfile,
7149 }
7150 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7151 entry_args=entry_args)[0]
7152 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7153 entry_args=entry_args)[0]
7154 self.assertGreater(len(data_firewall),len(data_no_firewall))
7155
7156 def testPackTiSecureFirewallMissingProperty(self):
7157 """Test that an image with a TI secured binary can be created"""
7158 keyfile = self.TestFile('key.key')
7159 entry_args = {
7160 'keyfile': keyfile,
7161 }
7162 with self.assertRaises(ValueError) as e:
7163 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7164 entry_args=entry_args)[0]
7165 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7166
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307167 def testPackTiSecureMissingTool(self):
7168 """Test that an image with a TI secured binary (non-functional) can be created
7169 when openssl is missing"""
7170 keyfile = self.TestFile('key.key')
7171 entry_args = {
7172 'keyfile': keyfile,
7173 }
7174 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007175 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307176 force_missing_bintools='openssl',
7177 entry_args=entry_args)
7178 err = stderr.getvalue()
7179 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7180
7181 def testPackTiSecureROM(self):
7182 """Test that a ROM image with a TI secured binary can be created"""
7183 keyfile = self.TestFile('key.key')
7184 entry_args = {
7185 'keyfile': keyfile,
7186 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007187 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307188 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007189 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307190 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007191 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307192 entry_args=entry_args)[0]
7193 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7194 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7195 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7196
7197 def testPackTiSecureROMCombined(self):
7198 """Test that a ROM image with a TI secured binary can be created"""
7199 keyfile = self.TestFile('key.key')
7200 entry_args = {
7201 'keyfile': keyfile,
7202 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007203 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307204 entry_args=entry_args)[0]
7205 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7206
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007207 def testEncryptedNoAlgo(self):
7208 """Test encrypted node with missing required properties"""
7209 with self.assertRaises(ValueError) as e:
7210 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7211 self.assertIn(
7212 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7213 str(e.exception))
7214
7215 def testEncryptedInvalidIvfile(self):
7216 """Test encrypted node with invalid iv file"""
7217 with self.assertRaises(ValueError) as e:
7218 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7219 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7220 str(e.exception))
7221
7222 def testEncryptedMissingKey(self):
7223 """Test encrypted node with missing key properties"""
7224 with self.assertRaises(ValueError) as e:
7225 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7226 self.assertIn(
7227 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7228 str(e.exception))
7229
7230 def testEncryptedKeySource(self):
7231 """Test encrypted node with key-source property"""
7232 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7233
7234 dtb = fdt.Fdt.FromData(data)
7235 dtb.Scan()
7236
7237 node = dtb.GetNode('/images/u-boot/cipher')
7238 self.assertEqual('algo-name', node.props['algo'].value)
7239 self.assertEqual('key-source-value', node.props['key-source'].value)
7240 self.assertEqual(ENCRYPTED_IV_DATA,
7241 tools.to_bytes(''.join(node.props['iv'].value)))
7242 self.assertNotIn('key', node.props)
7243
7244 def testEncryptedKeyFile(self):
7245 """Test encrypted node with key-filename property"""
7246 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7247
7248 dtb = fdt.Fdt.FromData(data)
7249 dtb.Scan()
7250
7251 node = dtb.GetNode('/images/u-boot/cipher')
7252 self.assertEqual('algo-name', node.props['algo'].value)
7253 self.assertEqual(ENCRYPTED_IV_DATA,
7254 tools.to_bytes(''.join(node.props['iv'].value)))
7255 self.assertEqual(ENCRYPTED_KEY_DATA,
7256 tools.to_bytes(''.join(node.props['key'].value)))
7257 self.assertNotIn('key-source', node.props)
7258
Lukas Funkee901faf2023-07-18 13:53:13 +02007259
7260 def testSplPubkeyDtb(self):
Simon Glass4b861272024-07-20 11:49:41 +01007261 """Test u_boot_spl_pubkey_dtb etype"""
7262 data = tools.read_file(self.TestFile("key.pem"))
7263 self._MakeInputFile("key.crt", data)
7264 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7265 image = control.images['image']
7266 entries = image.GetEntries()
7267 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7268 dtb_data = dtb_entry.GetData()
7269 dtb = fdt.Fdt.FromData(dtb_data)
7270 dtb.Scan()
Lukas Funkee901faf2023-07-18 13:53:13 +02007271
Simon Glass4b861272024-07-20 11:49:41 +01007272 signature_node = dtb.GetNode('/signature')
7273 self.assertIsNotNone(signature_node)
7274 key_node = signature_node.FindNode("key-key")
7275 self.assertIsNotNone(key_node)
7276 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7277 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7278 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007279
Lukas Funke712e1062023-08-03 17:22:14 +02007280 def testXilinxBootgenSigning(self):
7281 """Test xilinx-bootgen etype"""
7282 bootgen = bintool.Bintool.create('bootgen')
7283 self._CheckBintool(bootgen)
7284 data = tools.read_file(self.TestFile("key.key"))
7285 self._MakeInputFile("psk.pem", data)
7286 self._MakeInputFile("ssk.pem", data)
7287 self._SetupPmuFwlElf()
7288 self._SetupSplElf()
7289 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7290 image_fname = tools.get_output_filename('image.bin')
7291
7292 # Read partition header table and check if authentication is enabled
7293 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7294 "-read", image_fname, "pht").splitlines()
7295 attributes = {"authentication": None,
7296 "core": None,
7297 "encryption": None}
7298
7299 for l in bootgen_out:
7300 for a in attributes.keys():
7301 if a in l:
7302 m = re.match(fr".*{a} \[([^]]+)\]", l)
7303 attributes[a] = m.group(1)
7304
7305 self.assertTrue(attributes['authentication'] == "rsa")
7306 self.assertTrue(attributes['core'] == "a53-0")
7307 self.assertTrue(attributes['encryption'] == "no")
7308
7309 def testXilinxBootgenSigningEncryption(self):
7310 """Test xilinx-bootgen etype"""
7311 bootgen = bintool.Bintool.create('bootgen')
7312 self._CheckBintool(bootgen)
7313 data = tools.read_file(self.TestFile("key.key"))
7314 self._MakeInputFile("psk.pem", data)
7315 self._MakeInputFile("ssk.pem", data)
7316 self._SetupPmuFwlElf()
7317 self._SetupSplElf()
7318 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7319 image_fname = tools.get_output_filename('image.bin')
7320
7321 # Read boot header in order to verify encryption source and
7322 # encryption parameter
7323 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7324 "-read", image_fname, "bh").splitlines()
7325 attributes = {"auth_only":
7326 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7327 "encryption_keystore":
7328 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7329 "value": None},
7330 }
7331
7332 for l in bootgen_out:
7333 for a in attributes.keys():
7334 if a in l:
7335 m = re.match(attributes[a]['re'], l)
7336 attributes[a] = m.group(1)
7337
7338 # Check if fsbl-attribute is set correctly
7339 self.assertTrue(attributes['auth_only'] == "true")
7340 # Check if key is stored in efuse
7341 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7342
7343 def testXilinxBootgenMissing(self):
7344 """Test that binman still produces an image if bootgen is missing"""
7345 data = tools.read_file(self.TestFile("key.key"))
7346 self._MakeInputFile("psk.pem", data)
7347 self._MakeInputFile("ssk.pem", data)
7348 self._SetupPmuFwlElf()
7349 self._SetupSplElf()
7350 with test_util.capture_sys_output() as (_, stderr):
7351 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7352 force_missing_bintools='bootgen')
7353 err = stderr.getvalue()
7354 self.assertRegex(err,
7355 "Image 'image'.*missing bintools.*: bootgen")
7356
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307357 def _GetCapsuleHeaders(self, data):
7358 """Get the capsule header contents
7359
7360 Args:
7361 data: Capsule file contents
7362
7363 Returns:
7364 Dict:
7365 key: Capsule Header name (str)
7366 value: Header field value (str)
7367 """
7368 capsule_file = os.path.join(self._indir, 'test.capsule')
7369 tools.write_file(capsule_file, data)
7370
7371 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7372 lines = out.splitlines()
7373
7374 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7375 vals = {}
7376 for line in lines:
7377 mat = re_line.match(line)
7378 if mat:
7379 vals[mat.group(1)] = mat.group(2)
7380
7381 return vals
7382
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307383 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7384 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307385 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7386 fmp_size = "00000010"
7387 fmp_fw_version = "00000002"
7388 capsule_image_index = "00000001"
7389 oemflag = "00018000"
7390 auth_hdr_revision = "00000200"
7391 auth_hdr_cert_type = "00000EF1"
7392
7393 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307394
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307395 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307396
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307397 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307398
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307399 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7400 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7401 self.assertEqual(capsule_image_index,
7402 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307403
7404 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307405 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7406
7407 if signed_capsule:
7408 self.assertEqual(auth_hdr_revision,
7409 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7410 self.assertEqual(auth_hdr_cert_type,
7411 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7412 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7413 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7414
7415 if version_check:
7416 self.assertEqual(fmp_signature,
7417 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7418 self.assertEqual(fmp_size,
7419 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7420 self.assertEqual(fmp_fw_version,
7421 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7422
7423 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307424
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307425 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7426 if accept_capsule:
7427 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7428 else:
7429 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7430
7431 hdr = self._GetCapsuleHeaders(data)
7432
7433 self.assertEqual(capsule_hdr_guid.upper(),
7434 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7435
7436 if accept_capsule:
7437 capsule_size = "0000002C"
7438 else:
7439 capsule_size = "0000001C"
7440 self.assertEqual(capsule_size,
7441 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7442
7443 if accept_capsule:
7444 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7445
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307446 def testCapsuleGen(self):
7447 """Test generation of EFI capsule"""
7448 data = self._DoReadFile('311_capsule.dts')
7449
7450 self._CheckCapsule(data)
7451
7452 def testSignedCapsuleGen(self):
7453 """Test generation of EFI capsule"""
7454 data = tools.read_file(self.TestFile("key.key"))
7455 self._MakeInputFile("key.key", data)
7456 data = tools.read_file(self.TestFile("key.pem"))
7457 self._MakeInputFile("key.crt", data)
7458
7459 data = self._DoReadFile('312_capsule_signed.dts')
7460
7461 self._CheckCapsule(data, signed_capsule=True)
7462
7463 def testCapsuleGenVersionSupport(self):
7464 """Test generation of EFI capsule with version support"""
7465 data = self._DoReadFile('313_capsule_version.dts')
7466
7467 self._CheckCapsule(data, version_check=True)
7468
7469 def testCapsuleGenSignedVer(self):
7470 """Test generation of signed EFI capsule with version information"""
7471 data = tools.read_file(self.TestFile("key.key"))
7472 self._MakeInputFile("key.key", data)
7473 data = tools.read_file(self.TestFile("key.pem"))
7474 self._MakeInputFile("key.crt", data)
7475
7476 data = self._DoReadFile('314_capsule_signed_ver.dts')
7477
7478 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7479
7480 def testCapsuleGenCapOemFlags(self):
7481 """Test generation of EFI capsule with OEM Flags set"""
7482 data = self._DoReadFile('315_capsule_oemflags.dts')
7483
7484 self._CheckCapsule(data, capoemflags=True)
7485
7486 def testCapsuleGenKeyMissing(self):
7487 """Test that binman errors out on missing key"""
7488 with self.assertRaises(ValueError) as e:
7489 self._DoReadFile('316_capsule_missing_key.dts')
7490
7491 self.assertIn("Both private key and public key certificate need to be provided",
7492 str(e.exception))
7493
7494 def testCapsuleGenIndexMissing(self):
7495 """Test that binman errors out on missing image index"""
7496 with self.assertRaises(ValueError) as e:
7497 self._DoReadFile('317_capsule_missing_index.dts')
7498
7499 self.assertIn("entry is missing properties: image-index",
7500 str(e.exception))
7501
7502 def testCapsuleGenGuidMissing(self):
7503 """Test that binman errors out on missing image GUID"""
7504 with self.assertRaises(ValueError) as e:
7505 self._DoReadFile('318_capsule_missing_guid.dts')
7506
7507 self.assertIn("entry is missing properties: image-guid",
7508 str(e.exception))
7509
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307510 def testCapsuleGenAcceptCapsule(self):
7511 """Test generationg of accept EFI capsule"""
7512 data = self._DoReadFile('319_capsule_accept.dts')
7513
7514 self._CheckEmptyCapsule(data, accept_capsule=True)
7515
7516 def testCapsuleGenRevertCapsule(self):
7517 """Test generationg of revert EFI capsule"""
7518 data = self._DoReadFile('320_capsule_revert.dts')
7519
7520 self._CheckEmptyCapsule(data)
7521
7522 def testCapsuleGenAcceptGuidMissing(self):
7523 """Test that binman errors out on missing image GUID for accept capsule"""
7524 with self.assertRaises(ValueError) as e:
7525 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7526
7527 self.assertIn("Image GUID needed for generating accept capsule",
7528 str(e.exception))
7529
7530 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7531 """Test that capsule-type is specified"""
7532 with self.assertRaises(ValueError) as e:
7533 self._DoReadFile('322_empty_capsule_type_missing.dts')
7534
7535 self.assertIn("entry is missing properties: capsule-type",
7536 str(e.exception))
7537
7538 def testCapsuleGenAcceptOrRevertMissing(self):
7539 """Test that both accept and revert capsule are not specified"""
7540 with self.assertRaises(ValueError) as e:
7541 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7542
Simon Glassa360b8f2024-06-23 11:55:06 -06007543 def test_assume_size(self):
7544 """Test handling of the assume-size property for external blob"""
7545 with self.assertRaises(ValueError) as e:
7546 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7547 allow_fake_blobs=True)
7548 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7549 str(e.exception))
7550
7551 def test_assume_size_ok(self):
7552 """Test handling of the assume-size where it fits OK"""
7553 with test_util.capture_sys_output() as (stdout, stderr):
7554 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7555 allow_fake_blobs=True)
7556 err = stderr.getvalue()
7557 self.assertRegex(
7558 err,
7559 "Image '.*' has faked external blobs and is non-functional: .*")
7560
7561 def test_assume_size_no_fake(self):
7562 """Test handling of the assume-size where it fits OK"""
7563 with test_util.capture_sys_output() as (stdout, stderr):
7564 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7565 err = stderr.getvalue()
7566 self.assertRegex(
7567 err,
7568 "Image '.*' is missing external blobs and is non-functional: .*")
7569
Simon Glass5f7aadf2024-07-20 11:49:47 +01007570 def SetupAlternateDts(self):
7571 """Compile the .dts test files for alternative-fdt
7572
7573 Returns:
7574 tuple:
7575 str: Test directory created
7576 list of str: '.bin' files which we expect Binman to create
7577 """
7578 testdir = TestFunctional._MakeInputDir('dtb')
7579 dtb_list = []
7580 for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
7581 tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
7582 base = os.path.splitext(os.path.basename(fname))[0]
7583 dtb_list.append(base + '.bin')
7584 shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
7585
7586 return testdir, dtb_list
7587
Simon Glassf3598922024-07-20 11:49:45 +01007588 def CheckAlternates(self, dts, phase, xpl_data):
7589 """Run the test for the alterative-fdt etype
7590
7591 Args:
7592 dts (str): Devicetree file to process
7593 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7594 xpl_data (bytes): Expected data for the phase's binary
7595
7596 Returns:
7597 dict of .dtb files produced
7598 key: str filename
7599 value: Fdt object
7600 """
Simon Glass5f7aadf2024-07-20 11:49:47 +01007601 dtb_list = self.SetupAlternateDts()[1]
Simon Glassf3598922024-07-20 11:49:45 +01007602
7603 entry_args = {
7604 f'{phase}-dtb': '1',
7605 f'{phase}-bss-pad': 'y',
7606 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7607 }
7608 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7609 use_expanded=True, entry_args=entry_args)[0]
7610 self.assertEqual(xpl_data, data[:len(xpl_data)])
7611 rest = data[len(xpl_data):]
7612 pad_len = 10
7613 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7614
7615 # Check the dtb is using the test file
7616 dtb_data = rest[pad_len:]
7617 dtb = fdt.Fdt.FromData(dtb_data)
7618 dtb.Scan()
7619 fdt_size = dtb.GetFdtObj().totalsize()
7620 self.assertEqual('model-not-set',
7621 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7622
7623 pad_len = 10
7624
7625 # Check the other output files
7626 dtbs = {}
7627 for fname in dtb_list:
7628 pathname = tools.get_output_filename(fname)
7629 self.assertTrue(os.path.exists(pathname))
7630
7631 data = tools.read_file(pathname)
7632 self.assertEqual(xpl_data, data[:len(xpl_data)])
7633 rest = data[len(xpl_data):]
7634
7635 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7636 rest = rest[pad_len:]
7637
7638 dtb = fdt.Fdt.FromData(rest)
7639 dtb.Scan()
7640 dtbs[fname] = dtb
7641
7642 expected = 'one' if '1' in fname else 'two'
7643 self.assertEqual(f'u-boot,model-{expected}',
7644 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7645
7646 # Make sure the FDT is the same size as the 'main' one
7647 rest = rest[fdt_size:]
7648
7649 self.assertEqual(b'', rest)
7650 return dtbs
7651
7652 def testAlternatesFdt(self):
7653 """Test handling of alternates-fdt etype"""
7654 self._SetupTplElf()
7655 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7656 U_BOOT_TPL_NODTB_DATA)
7657 for dtb in dtbs.values():
7658 # Check for the node with the tag
7659 node = dtb.GetNode('/node')
7660 self.assertIsNotNone(node)
7661 self.assertEqual(5, len(node.props.keys()))
7662
7663 # Make sure the other node is still there
7664 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7665
7666 def testAlternatesFdtgrep(self):
7667 """Test handling of alternates-fdt etype using fdtgrep"""
7668 self._SetupTplElf()
7669 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7670 U_BOOT_TPL_NODTB_DATA)
7671 for dtb in dtbs.values():
7672 # Check for the node with the tag
7673 node = dtb.GetNode('/node')
7674 self.assertIsNotNone(node)
7675 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7676 node.props.keys())
7677
7678 # Make sure the other node is gone
7679 self.assertIsNone(dtb.GetNode('/node/other-node'))
7680
7681 def testAlternatesFdtgrepVpl(self):
7682 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7683 self._SetupVplElf()
7684 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7685 U_BOOT_VPL_NODTB_DATA)
7686
7687 def testAlternatesFdtgrepSpl(self):
7688 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7689 self._SetupSplElf()
7690 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7691 U_BOOT_SPL_NODTB_DATA)
7692
7693 def testAlternatesFdtgrepInval(self):
7694 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7695 self._SetupSplElf()
7696 with self.assertRaises(ValueError) as e:
7697 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7698 U_BOOT_SPL_NODTB_DATA)
7699 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7700 str(e.exception))
7701
Simon Glasscd2783e2024-07-20 11:49:46 +01007702 def testFitFdtListDir(self):
7703 """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
Simon Glass1bba8942024-08-26 13:11:34 -06007704 old_dir = os.getcwd()
7705 try:
7706 os.chdir(self._indir)
7707 self.CheckFitFdt('333_fit_fdt_dir.dts', False)
7708 finally:
7709 os.chdir(old_dir)
Simon Glasscd2783e2024-07-20 11:49:46 +01007710
Simon Glassd2a9d6e2024-08-26 13:11:37 -06007711 def testFitFdtListDirDefault(self):
7712 """Test an FIT fit,fdt-list-dir where the default DT in is a subdir"""
7713 old_dir = os.getcwd()
7714 try:
7715 os.chdir(self._indir)
7716 self.CheckFitFdt('333_fit_fdt_dir.dts', False,
7717 default_dt='rockchip/test-fdt2')
7718 finally:
7719 os.chdir(old_dir)
7720
Simon Glass5f7aadf2024-07-20 11:49:47 +01007721 def testFitFdtCompat(self):
7722 """Test an image with an FIT with compatible in the config nodes"""
7723 entry_args = {
7724 'of-list': 'model1 model2',
7725 'default-dt': 'model2',
7726 }
7727 testdir, dtb_list = self.SetupAlternateDts()
7728 data = self._DoReadFileDtb(
7729 '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
7730 entry_args=entry_args, extra_indirs=[testdir])[0]
7731
7732 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7733
7734 fit = fdt.Fdt.FromData(fit_data)
7735 fit.Scan()
7736
7737 cnode = fit.GetNode('/configurations')
7738 self.assertIn('default', cnode.props)
7739 self.assertEqual('config-2', cnode.props['default'].value)
7740
7741 for seq in range(1, 2):
7742 name = f'config-{seq}'
7743 fnode = fit.GetNode('/configurations/%s' % name)
7744 self.assertIsNotNone(fnode)
7745 self.assertIn('compatible', fnode.props.keys())
7746 expected = 'one' if seq == 1 else 'two'
7747 self.assertEqual(f'u-boot,model-{expected}',
7748 fnode.props['compatible'].value)
7749
Simon Glassa04b9942024-07-20 11:49:48 +01007750 def testFitFdtPhase(self):
7751 """Test an image with an FIT with fdt-phase in the fdt nodes"""
7752 phase = 'tpl'
7753 entry_args = {
7754 f'{phase}-dtb': '1',
7755 f'{phase}-bss-pad': 'y',
7756 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7757 'of-list': 'model1 model2',
7758 'default-dt': 'model2',
7759 }
7760 testdir, dtb_list = self.SetupAlternateDts()
7761 data = self._DoReadFileDtb(
7762 '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
7763 entry_args=entry_args, extra_indirs=[testdir])[0]
7764 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7765 fit = fdt.Fdt.FromData(fit_data)
7766 fit.Scan()
7767
7768 # Check that each FDT has only the expected properties for the phase
7769 for seq in range(1, 2):
7770 fnode = fit.GetNode(f'/images/fdt-{seq}')
7771 self.assertIsNotNone(fnode)
7772 dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
7773 dtb.Scan()
7774
7775 # Make sure that the 'bootph-pre-sram' tag in /node protects it from
7776 # removal
7777 node = dtb.GetNode('/node')
7778 self.assertIsNotNone(node)
7779 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7780 node.props.keys())
7781
7782 # Make sure the other node is gone
7783 self.assertIsNone(dtb.GetNode('/node/other-node'))
7784
Simon Glassb553e8a2024-08-26 13:11:29 -06007785 def testMkeficapsuleMissing(self):
7786 """Test that binman complains if mkeficapsule is missing"""
7787 with self.assertRaises(ValueError) as e:
7788 self._DoTestFile('311_capsule.dts',
7789 force_missing_bintools='mkeficapsule')
7790 self.assertIn("Node '/binman/efi-capsule': Missing tool: 'mkeficapsule'",
7791 str(e.exception))
7792
7793 def testMkeficapsuleMissingOk(self):
7794 """Test that binman deals with mkeficapsule being missing"""
7795 with test_util.capture_sys_output() as (stdout, stderr):
7796 ret = self._DoTestFile('311_capsule.dts',
7797 force_missing_bintools='mkeficapsule',
7798 allow_missing=True)
7799 self.assertEqual(103, ret)
7800 err = stderr.getvalue()
7801 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkeficapsule")
7802
Simon Glass4b0f4142024-08-26 13:11:40 -06007803 def testSymbolsBase(self):
7804 """Test handling of symbols-base"""
7805 self.checkSymbols('336_symbols_base.dts', U_BOOT_SPL_DATA, 0x1c,
7806 symbols_base=0)
7807
7808 def testSymbolsBaseExpanded(self):
7809 """Test handling of symbols-base with expanded entries"""
7810 entry_args = {
7811 'spl-dtb': '1',
7812 }
7813 self.checkSymbols('337_symbols_base_expand.dts', U_BOOT_SPL_NODTB_DATA +
7814 U_BOOT_SPL_DTB_DATA, 0x38,
7815 entry_args=entry_args, use_expanded=True,
7816 symbols_base=0)
7817
Simon Glass3eb30a42024-08-26 13:11:42 -06007818 def testSymbolsCompressed(self):
7819 """Test binman complains about symbols from a compressed section"""
7820 with test_util.capture_sys_output() as (stdout, stderr):
7821 self.checkSymbols('338_symbols_comp.dts', U_BOOT_SPL_DATA, None)
7822 out = stdout.getvalue()
7823 self.assertIn('Symbol-writing: no value for /binman/section/u-boot',
7824 out)
7825
Simon Glass9c25ef22024-08-26 13:11:43 -06007826 def testNxpImx8Image(self):
7827 """Test that binman can produce an iMX8 image"""
7828 self._DoTestFile('339_nxp_imx8.dts')
7829
Alexander Kochetkova730a282024-09-16 11:24:46 +03007830 def testFitSignSimple(self):
7831 """Test that image with FIT and signature nodes can be signed"""
7832 if not elf.ELF_TOOLS:
7833 self.skipTest('Python elftools not available')
7834 entry_args = {
7835 'of-list': 'test-fdt1',
7836 'default-dt': 'test-fdt1',
7837 'atf-bl31-path': 'bl31.elf',
7838 }
7839 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7840 self._MakeInputFile("keys/rsa2048.key", data)
7841
7842 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7843 keys_subdir = os.path.join(self._indir, "keys")
7844 data = self._DoReadFileDtb(
7845 '340_fit_signature.dts',
7846 entry_args=entry_args,
7847 extra_indirs=[test_subdir, keys_subdir])[0]
7848
7849 dtb = fdt.Fdt.FromData(data)
7850 dtb.Scan()
7851
7852 conf = dtb.GetNode('/configurations/conf-uboot-1')
7853 self.assertIsNotNone(conf)
7854 signature = conf.FindNode('signature')
7855 self.assertIsNotNone(signature)
7856 self.assertIsNotNone(signature.props.get('value'))
7857
7858 images = dtb.GetNode('/images')
7859 self.assertIsNotNone(images)
7860 for subnode in images.subnodes:
7861 signature = subnode.FindNode('signature')
7862 self.assertIsNotNone(signature)
7863 self.assertIsNotNone(signature.props.get('value'))
7864
7865 def testFitSignKeyNotFound(self):
7866 """Test that missing keys raise an error"""
7867 if not elf.ELF_TOOLS:
7868 self.skipTest('Python elftools not available')
7869 entry_args = {
7870 'of-list': 'test-fdt1',
7871 'default-dt': 'test-fdt1',
7872 'atf-bl31-path': 'bl31.elf',
7873 }
7874 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7875 with self.assertRaises(ValueError) as e:
7876 self._DoReadFileDtb(
7877 '340_fit_signature.dts',
7878 entry_args=entry_args,
7879 extra_indirs=[test_subdir])[0]
7880 self.assertIn(
7881 'Filename \'rsa2048.key\' not found in input path',
7882 str(e.exception))
7883
7884 def testFitSignMultipleKeyPaths(self):
7885 """Test that keys found in multiple paths raise an error"""
7886 if not elf.ELF_TOOLS:
7887 self.skipTest('Python elftools not available')
7888 entry_args = {
7889 'of-list': 'test-fdt1',
7890 'default-dt': 'test-fdt1',
7891 'atf-bl31-path': 'bl31.elf',
7892 }
7893 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7894 self._MakeInputFile("keys1/rsa2048.key", data)
7895 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7896 self._MakeInputFile("keys2/conf-rsa2048.key", data)
7897
7898 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7899 keys_subdir1 = os.path.join(self._indir, "keys1")
7900 keys_subdir2 = os.path.join(self._indir, "keys2")
7901 with self.assertRaises(ValueError) as e:
7902 self._DoReadFileDtb(
7903 '341_fit_signature.dts',
7904 entry_args=entry_args,
7905 extra_indirs=[test_subdir, keys_subdir1, keys_subdir2])[0]
7906 self.assertIn(
7907 'Node \'/binman/fit\': multiple key paths found',
7908 str(e.exception))
7909
7910 def testFitSignNoSingatureNodes(self):
7911 """Test that fit,sign doens't raise error if no signature nodes found"""
7912 if not elf.ELF_TOOLS:
7913 self.skipTest('Python elftools not available')
7914 entry_args = {
7915 'of-list': 'test-fdt1',
7916 'default-dt': 'test-fdt1',
7917 'atf-bl31-path': 'bl31.elf',
7918 }
7919 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7920 self._DoReadFileDtb(
7921 '342_fit_signature.dts',
7922 entry_args=entry_args,
7923 extra_indirs=[test_subdir])[0]
7924
Simon Glassa360b8f2024-06-23 11:55:06 -06007925
Paul HENRYSff318462024-11-25 18:47:17 +01007926 def testSimpleFitEncryptedData(self):
7927 """Test an image with a FIT containing data to be encrypted"""
7928 data = tools.read_file(self.TestFile("aes256.bin"))
7929 self._MakeInputFile("keys/aes256.bin", data)
7930
7931 keys_subdir = os.path.join(self._indir, "keys")
7932 data = self._DoReadFileDtb(
7933 '343_fit_encrypt_data.dts',
7934 extra_indirs=[keys_subdir])[0]
7935
7936 fit = fdt.Fdt.FromData(data)
7937 fit.Scan()
7938
7939 # Extract the encrypted data and the Initialization Vector from the FIT
7940 node = fit.GetNode('/images/u-boot')
7941 subnode = fit.GetNode('/images/u-boot/cipher')
7942 data_size_unciphered = int.from_bytes(fit.GetProps(node)['data-size-unciphered'].bytes,
7943 byteorder='big')
7944 self.assertEqual(data_size_unciphered, len(U_BOOT_NODTB_DATA))
7945
7946 # Retrieve the key name from the FIT removing any null byte
7947 key_name = fit.GetProps(subnode)['key-name-hint'].bytes.replace(b'\x00', b'')
7948 with open(self.TestFile(key_name.decode('ascii') + '.bin'), 'rb') as file:
7949 key = file.read()
7950 iv = fit.GetProps(subnode)['iv'].bytes.hex()
7951 enc_data = fit.GetProps(node)['data'].bytes
7952 outdir = tools.get_output_dir()
7953 enc_data_file = os.path.join(outdir, 'encrypted_data.bin')
7954 tools.write_file(enc_data_file, enc_data)
7955 data_file = os.path.join(outdir, 'data.bin')
7956
7957 # Decrypt the encrypted data from the FIT and compare the data
7958 tools.run('openssl', 'enc', '-aes-256-cbc', '-nosalt', '-d', '-in',
7959 enc_data_file, '-out', data_file, '-K', key.hex(), '-iv', iv)
7960 with open(data_file, 'r') as file:
7961 dec_data = file.read()
7962 self.assertEqual(U_BOOT_NODTB_DATA, dec_data.encode('ascii'))
7963
7964 def testSimpleFitEncryptedDataMissingKey(self):
7965 """Test an image with a FIT containing data to be encrypted but with a missing key"""
7966 with self.assertRaises(ValueError) as e:
7967 self._DoReadFile('344_fit_encrypt_data_no_key.dts')
7968
7969 self.assertIn("Filename 'aes256.bin' not found in input path", str(e.exception))
7970
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01007971 def testFitFdtName(self):
7972 """Test an image with an FIT with multiple FDT images using NAME"""
7973 self.CheckFitFdt('345_fit_fdt_name.dts', use_seq_num=False)
7974
Simon Glassac599912017-11-12 21:52:22 -07007975if __name__ == "__main__":
7976 unittest.main()