blob: 1bc2fca26ea0a0d23cafae7e2a37c3db639188fd [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass57454f42016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass57454f42016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glass45d556d2020-07-09 18:39:45 -06009import collections
Simon Glassf3598922024-07-20 11:49:45 +010010import glob
Simon Glassc585dd42020-04-17 18:09:03 -060011import gzip
Simon Glassae7cf032018-09-14 04:57:31 -060012import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070013from optparse import OptionParser
14import os
Simon Glass45d556d2020-07-09 18:39:45 -060015import re
Simon Glass57454f42016-11-25 20:15:52 -070016import shutil
17import struct
18import sys
19import tempfile
20import unittest
Simon Glass162017b2022-01-09 20:13:57 -070021import unittest.mock
22import urllib.error
Simon Glass57454f42016-11-25 20:15:52 -070023
Simon Glass4eae9252022-01-09 20:13:50 -070024from binman import bintool
Simon Glassc585dd42020-04-17 18:09:03 -060025from binman import cbfs_util
26from binman import cmdline
27from binman import control
28from binman import elf
29from binman import elf_test
Simon Glass3efb2972021-11-23 21:08:59 -070030from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060031from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060032from binman import state
33from dtoc import fdt
34from dtoc import fdt_util
35from binman.etype import fdtmap
36from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060037from binman.image import Image
Simon Glass131444f2023-02-23 18:18:04 -070038from u_boot_pylib import command
39from u_boot_pylib import test_util
40from u_boot_pylib import tools
41from u_boot_pylib import tout
Simon Glass57454f42016-11-25 20:15:52 -070042
43# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060044U_BOOT_DATA = b'1234'
45U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +030046U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass56d05412022-02-28 07:16:54 -070048U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glass303f62f2019-05-17 22:00:46 -060049BLOB_DATA = b'89'
50ME_DATA = b'0abcd'
51VGA_DATA = b'vga'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +053052EFI_CAPSULE_DATA = b'efi'
Simon Glass303f62f2019-05-17 22:00:46 -060053U_BOOT_DTB_DATA = b'udtb'
54U_BOOT_SPL_DTB_DATA = b'spldtb'
55U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass56d05412022-02-28 07:16:54 -070056U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glass303f62f2019-05-17 22:00:46 -060057X86_START16_DATA = b'start16'
58X86_START16_SPL_DATA = b'start16spl'
59X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060060X86_RESET16_DATA = b'reset16'
61X86_RESET16_SPL_DATA = b'reset16spl'
62X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060063PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
64U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
65U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
66U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass56d05412022-02-28 07:16:54 -070067U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +030068U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
69U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
70U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glass303f62f2019-05-17 22:00:46 -060071FSP_DATA = b'fsp'
72CMC_DATA = b'cmc'
73VBT_DATA = b'vbt'
74MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060075TEXT_DATA = 'text'
76TEXT_DATA2 = 'text2'
77TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060078CROS_EC_RW_DATA = b'ecrw'
79GBB_DATA = b'gbbd'
80BMPBLK_DATA = b'bmp'
81VBLOCK_DATA = b'vblk'
82FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
83 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060084COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060085COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060086REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060087FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060088FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060089FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060090ATF_BL31_DATA = b'bl31'
Roger Quadros5cdcea02022-02-19 20:50:04 +020091TEE_OS_DATA = b'this is some tee OS data'
Neha Malcom Francis59be2552023-12-05 15:12:18 +053092TI_DM_DATA = b'tidmtidm'
Simon Glass3efb2972021-11-23 21:08:59 -070093ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080094OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050095SCP_DATA = b'scp'
Jonas Karlman35305492023-02-25 19:01:33 +000096ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glassa435cd12020-09-01 05:13:59 -060097TEST_FDT1_DATA = b'fdt1'
98TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060099ENV_DATA = b'var1=1\nvar2="2"'
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200100ENCRYPTED_IV_DATA = b'123456'
101ENCRYPTED_KEY_DATA = b'abcde'
Philippe Reynesebe96cb2022-03-28 22:57:04 +0200102PRE_LOAD_MAGIC = b'UBSH'
103PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
104PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530105TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530106TI_UNSECURE_DATA = b'unsecuredata'
Simon Glassa435cd12020-09-01 05:13:59 -0600107
108# Subdirectory of the input dir to use to put test FDTs
109TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600110
Simon Glass2c6adba2019-07-20 12:23:47 -0600111# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600112EXTRACT_DTB_SIZE = 0x3c9
113
Simon Glass2c6adba2019-07-20 12:23:47 -0600114# Properties expected to be in the device tree when update_dtb is used
115BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
116
Simon Glassfb30e292019-07-20 12:23:51 -0600117# Extra properties expected to be in the device tree when allow-repack is used
118REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
119
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200120# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200121COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700122
Simon Glassad5cfe12023-01-07 14:07:14 -0700123TEE_ADDR = 0x5678
124
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530125# Firmware Management Protocol(FMP) GUID
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530126FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530127# Image GUID specified in the DTS
Caleb Connolly4bdc9602024-08-30 13:34:35 +0100128CAPSULE_IMAGE_GUID = '985F2937-7C2E-5E9A-8A5E-8E063312964B'
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530129# Windows cert GUID
130WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +0530131# Empty capsule GUIDs
132EMPTY_CAPSULE_ACCEPT_GUID = '0c996046-bcc0-4d04-85ec-e1fcedf1c6f8'
133EMPTY_CAPSULE_REVERT_GUID = 'acd58b4b-c0e8-475f-99b5-6b3f7e07aaf0'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530134
Simon Glass57454f42016-11-25 20:15:52 -0700135class TestFunctional(unittest.TestCase):
136 """Functional tests for binman
137
138 Most of these use a sample .dts file to build an image and then check
139 that it looks correct. The sample files are in the test/ subdirectory
140 and are numbered.
141
142 For each entry type a very small test file is created using fixed
143 string contents. This makes it easy to test that things look right, and
144 debug problems.
145
146 In some cases a 'real' file must be used - these are also supplied in
147 the test/ diurectory.
148 """
149 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600150 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700151 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600152 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700153
Simon Glass57454f42016-11-25 20:15:52 -0700154 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600155 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
156 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700157
158 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600159 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700160
161 # Create some test files
162 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
163 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
164 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600165 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700166 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700167 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700168 TestFunctional._MakeInputFile('me.bin', ME_DATA)
169 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600170 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600171
Jagdish Gediya311d4842018-09-03 21:35:08 +0530172 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600173
Simon Glassabab18c2019-08-24 07:22:49 -0600174 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
175 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700176 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600177 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600178 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600179
180 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
181 X86_RESET16_DATA)
182 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
183 X86_RESET16_SPL_DATA)
184 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
185 X86_RESET16_TPL_DATA)
186
Simon Glass57454f42016-11-25 20:15:52 -0700187 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700188 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
189 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600190 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
191 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700192 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
193 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700194 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
195 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700196 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700197 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600198 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600199 TestFunctional._MakeInputDir('devkeys')
200 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600201 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600202 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600203 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600204 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700205
Simon Glassf6290892019-08-24 07:22:53 -0600206 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
207 elf_test.BuildElfTestFiles(cls._elf_testdir)
208
Simon Glass72232452016-11-25 20:15:53 -0700209 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600210 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700211 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700212
213 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600214 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700215
Simon Glass862f8e22019-08-24 07:22:43 -0600216 shutil.copytree(cls.TestFile('files'),
217 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600218
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530219 shutil.copytree(cls.TestFile('yaml'),
220 os.path.join(cls._indir, 'yaml'))
221
Simon Glass7ba33592018-09-14 04:57:26 -0600222 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600223 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600224 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200225 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Neha Malcom Francis59be2552023-12-05 15:12:18 +0530226 TestFunctional._MakeInputFile('dm.bin', TI_DM_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700227 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800228 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500229 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman35305492023-02-25 19:01:33 +0000230 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530231 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530232 TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600233
Simon Glassa435cd12020-09-01 05:13:59 -0600234 # Add a few .dtb files for testing
235 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
236 TEST_FDT1_DATA)
237 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
238 TEST_FDT2_DATA)
239
Simon Glassa0729502020-09-06 10:35:33 -0600240 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
241
Simon Glass5f423422022-03-05 20:19:12 -0700242 # ELF file with two sections in different parts of memory, used for both
243 # ATF and OP_TEE
244 TestFunctional._MakeInputFile('bl31.elf',
245 tools.read_file(cls.ElfTestFile('elf_sections')))
246 TestFunctional._MakeInputFile('tee.elf',
247 tools.read_file(cls.ElfTestFile('elf_sections')))
248
Simon Glassad5cfe12023-01-07 14:07:14 -0700249 # Newer OP_TEE file in v1 binary format
250 cls.make_tee_bin('tee.bin')
251
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200252 # test files for encrypted tests
253 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
254 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
255
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200256 cls.comp_bintools = {}
257 for name in COMP_BINTOOLS:
258 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600259
Simon Glass57454f42016-11-25 20:15:52 -0700260 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600261 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700262 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600263 if cls.preserve_indir:
264 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600265 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600266 if cls._indir:
267 shutil.rmtree(cls._indir)
268 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700269
Simon Glass1c420c92019-07-08 13:18:49 -0600270 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600271 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600272 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600273 """Accept arguments controlling test execution
274
275 Args:
276 preserve_indir: Preserve the shared input directory used by all
277 tests in this class.
278 preserve_outdir: Preserve the output directories used by tests. Each
279 test has its own, so this is normally only useful when running a
280 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600281 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600282 """
283 cls.preserve_indir = preserve_indir
284 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600285 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600286 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600287
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200288 def _CheckBintool(self, bintool):
289 if not bintool.is_present():
290 self.skipTest('%s not available' % bintool.name)
291
Simon Glass1de34482019-07-08 13:18:53 -0600292 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200293 bintool = self.comp_bintools['lz4']
294 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600295
Simon Glassee9d10d2019-07-20 12:24:09 -0600296 def _CleanupOutputDir(self):
297 """Remove the temporary output directory"""
298 if self.preserve_outdirs:
299 print('Preserving output dir: %s' % tools.outdir)
300 else:
Simon Glass80025522022-01-29 14:14:04 -0700301 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600302
Simon Glass57454f42016-11-25 20:15:52 -0700303 def setUp(self):
304 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700305 # tout.init(tout.DEBUG)
Simon Glass5dc22cf2025-02-03 09:26:42 -0700306 command.TEST_RESULT = None
Simon Glass57454f42016-11-25 20:15:52 -0700307
308 def tearDown(self):
309 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600310 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700311
Simon Glassb3d6fc72019-07-20 12:24:10 -0600312 def _SetupImageInTmpdir(self):
313 """Set up the output image in a new temporary directory
314
315 This is used when an image has been generated in the output directory,
316 but we want to run binman again. This will create a new output
317 directory and fail to delete the original one.
318
319 This creates a new temporary directory, copies the image to it (with a
320 new name) and removes the old output directory.
321
322 Returns:
323 Tuple:
324 Temporary directory to use
325 New image filename
326 """
Simon Glass80025522022-01-29 14:14:04 -0700327 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600328 tmpdir = tempfile.mkdtemp(prefix='binman.')
329 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700330 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600331 self._CleanupOutputDir()
332 return tmpdir, updated_fname
333
Simon Glass8425a1f2018-07-17 13:25:48 -0600334 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600335 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600336 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
337 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
338 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700339 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600340
Simon Glass57454f42016-11-25 20:15:52 -0700341 def _RunBinman(self, *args, **kwargs):
342 """Run binman using the command line
343
344 Args:
345 Arguments to pass, as a list of strings
346 kwargs: Arguments to pass to Command.RunPipe()
347 """
Simon Glass51f55182025-02-03 09:26:45 -0700348 all_args = [self._binman_pathname] + list(args)
349 result = command.run_one(*all_args, capture=True, capture_stderr=True,
350 raise_on_error=False)
Simon Glass57454f42016-11-25 20:15:52 -0700351 if result.return_code and kwargs.get('raise_on_error', True):
352 raise Exception("Error running '%s': %s" % (' '.join(args),
353 result.stdout + result.stderr))
354 return result
355
Simon Glassf46732a2019-07-08 14:25:29 -0600356 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700357 """Run binman using directly (in the same process)
358
359 Args:
360 Arguments to pass, as a list of strings
361 Returns:
362 Return value (0 for success)
363 """
Simon Glassf46732a2019-07-08 14:25:29 -0600364 argv = list(argv)
365 args = cmdline.ParseArgs(argv)
366 args.pager = 'binman-invalid-pager'
367 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700368
369 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600370 # args.verbosity = tout.DEBUG
371 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700372
Simon Glass91710b32018-07-17 13:25:32 -0600373 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600374 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300375 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100376 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700377 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis6b463da2023-07-22 00:14:44 +0530378 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass57454f42016-11-25 20:15:52 -0700379 """Run binman with a given test file
380
381 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600382 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600383 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600384 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600385 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600386 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600387 entry_args: Dict of entry args to supply to binman
388 key: arg name
389 value: value of that arg
390 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600391 use_real_dtb: True to use the test file as the contents of
392 the u-boot-dtb entry. Normally this is not needed and the
393 test contents (the U_BOOT_DTB_DATA string) can be used.
394 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300395 use_expanded: True to use expanded entries where available, e.g.
396 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600397 verbosity: Verbosity level to use (0-3, None=don't set it)
398 allow_missing: Set the '--allow-missing' flag so that missing
399 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100400 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600401 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600402 threads: Number of threads to use (None for default, 0 for
403 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600404 test_section_timeout: True to force the first time to timeout, as
405 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600406 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glassb553e8a2024-08-26 13:11:29 -0600407 force_missing_bintools (str): comma-separated list of bintools to
Simon Glass66152ce2022-01-09 20:14:09 -0700408 regard as missing
Simon Glassb553e8a2024-08-26 13:11:29 -0600409 ignore_missing (bool): True to return success even if there are
410 missing blobs or bintools
Andrew Davis6b463da2023-07-22 00:14:44 +0530411 output_dir: Specific output directory to use for image using -O
Simon Glass9a798402021-11-03 21:09:17 -0600412
413 Returns:
414 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700415 """
Simon Glassf46732a2019-07-08 14:25:29 -0600416 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700417 if debug:
418 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600419 if verbosity is not None:
420 args.append('-v%d' % verbosity)
421 elif self.verbosity:
422 args.append('-v%d' % self.verbosity)
423 if self.toolpath:
424 for path in self.toolpath:
425 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600426 if threads is not None:
427 args.append('-T%d' % threads)
428 if test_section_timeout:
429 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600430 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600431 if map:
432 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600433 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600434 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600435 if not use_real_dtb:
436 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300437 if not use_expanded:
438 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600439 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600440 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600441 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600442 if allow_missing:
443 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700444 if ignore_missing:
445 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100446 if allow_fake_blobs:
447 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700448 if force_missing_bintools:
449 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600450 if update_fdt_in_elf:
451 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600452 if images:
453 for image in images:
454 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600455 if extra_indirs:
456 for indir in extra_indirs:
457 args += ['-I', indir]
Andrew Davis6b463da2023-07-22 00:14:44 +0530458 if output_dir:
459 args += ['-O', output_dir]
Simon Glass075a45c2017-11-13 18:55:00 -0700460 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700461
462 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700463 """Set up a new test device-tree file
464
465 The given file is compiled and set up as the device tree to be used
466 for ths test.
467
468 Args:
469 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600470 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700471
472 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600473 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700474 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600475 tmpdir = tempfile.mkdtemp(prefix='binmant.')
476 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600477 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700478 data = fd.read()
479 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600480 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600481 return data
Simon Glass57454f42016-11-25 20:15:52 -0700482
Simon Glass56d05412022-02-28 07:16:54 -0700483 def _GetDtbContentsForSpls(self, dtb_data, name):
484 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600485
486 For testing we don't actually have different versions of the DTB. With
487 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
488 we don't normally have any unwanted nodes.
489
490 We still want the DTBs for SPL and TPL to be different though, since
491 otherwise it is confusing to know which one we are looking at. So add
492 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600493
494 Args:
495 dtb_data: dtb data to modify (this should be a value devicetree)
496 name: Name of a new property to add
497
498 Returns:
499 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600500 """
501 dtb = fdt.Fdt.FromData(dtb_data)
502 dtb.Scan()
503 dtb.GetNode('/binman').AddZeroProp(name)
504 dtb.Sync(auto_resize=True)
505 dtb.Pack()
506 return dtb.GetContents()
507
Simon Glassed930672021-03-18 20:25:05 +1300508 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
Simon Glass3eb30a42024-08-26 13:11:42 -0600509 verbosity=None, map=False, update_dtb=False,
510 entry_args=None, reset_dtbs=True, extra_indirs=None,
511 threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700512 """Run binman and return the resulting image
513
514 This runs binman with a given test file and then reads the resulting
515 output file. It is a shortcut function since most tests need to do
516 these steps.
517
518 Raises an assertion failure if binman returns a non-zero exit code.
519
520 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600521 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700522 use_real_dtb: True to use the test file as the contents of
523 the u-boot-dtb entry. Normally this is not needed and the
524 test contents (the U_BOOT_DTB_DATA string) can be used.
525 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300526 use_expanded: True to use expanded entries where available, e.g.
527 'u-boot-expanded' instead of 'u-boot'
Simon Glass3eb30a42024-08-26 13:11:42 -0600528 verbosity: Verbosity level to use (0-3, None=don't set it)
Simon Glass30732662018-06-01 09:38:20 -0600529 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600530 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600531 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600532 entry_args: Dict of entry args to supply to binman
533 key: arg name
534 value: value of that arg
535 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
536 function. If reset_dtbs is True, then the original test dtb
537 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600538 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600539 threads: Number of threads to use (None for default, 0 for
540 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700541
542 Returns:
543 Tuple:
544 Resulting image contents
545 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600546 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600547 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700548 """
Simon Glass72232452016-11-25 20:15:53 -0700549 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700550 # Use the compiled test file as the u-boot-dtb input
551 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700552 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600553
554 # For testing purposes, make a copy of the DT for SPL and TPL. Add
Simon Glassd9e01d22024-07-20 11:49:40 +0100555 # a node indicating which it is, to aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700556 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600557 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
558 outfile = os.path.join(self._indir, dtb_fname)
559 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700560 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700561
562 try:
Simon Glass91710b32018-07-17 13:25:32 -0600563 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600564 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass3eb30a42024-08-26 13:11:42 -0600565 use_expanded=use_expanded, verbosity=verbosity,
566 extra_indirs=extra_indirs,
Simon Glass76f496d2021-07-06 10:36:37 -0600567 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700568 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700569 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700570
571 # Find the (only) image, read it and return its contents
572 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700573 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600574 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600575 if map:
Simon Glass80025522022-01-29 14:14:04 -0700576 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600577 with open(map_fname) as fd:
578 map_data = fd.read()
579 else:
580 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600581 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600582 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700583 finally:
584 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600585 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600586 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700587
Simon Glass5b4bce32019-07-08 14:25:26 -0600588 def _DoReadFileRealDtb(self, fname):
589 """Run binman with a real .dtb file and return the resulting data
590
591 Args:
592 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
593
594 Returns:
595 Resulting image contents
596 """
597 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
598
Simon Glass72232452016-11-25 20:15:53 -0700599 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600600 """Helper function which discards the device-tree binary
601
602 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600603 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600604 use_real_dtb: True to use the test file as the contents of
605 the u-boot-dtb entry. Normally this is not needed and the
606 test contents (the U_BOOT_DTB_DATA string) can be used.
607 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600608
609 Returns:
610 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600611 """
Simon Glass72232452016-11-25 20:15:53 -0700612 return self._DoReadFileDtb(fname, use_real_dtb)[0]
613
Simon Glass57454f42016-11-25 20:15:52 -0700614 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600615 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700616 """Create a new test input file, creating directories as needed
617
618 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600619 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700620 contents: File contents to write in to the file
621 Returns:
622 Full pathname of file created
623 """
Simon Glass862f8e22019-08-24 07:22:43 -0600624 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700625 dirname = os.path.dirname(pathname)
626 if dirname and not os.path.exists(dirname):
627 os.makedirs(dirname)
628 with open(pathname, 'wb') as fd:
629 fd.write(contents)
630 return pathname
631
632 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600633 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600634 """Create a new test input directory, creating directories as needed
635
636 Args:
637 dirname: Directory name to create
638
639 Returns:
640 Full pathname of directory created
641 """
Simon Glass862f8e22019-08-24 07:22:43 -0600642 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600643 if not os.path.exists(pathname):
644 os.makedirs(pathname)
645 return pathname
646
647 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600648 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600649 """Set up an ELF file with a '_dt_ucode_base_size' symbol
650
651 Args:
652 Filename of ELF file to use as SPL
653 """
Simon Glass93a806f2019-08-24 07:22:59 -0600654 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700655 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600656
657 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600658 def _SetupTplElf(cls, src_fname='bss_data'):
659 """Set up an ELF file with a '_dt_ucode_base_size' symbol
660
661 Args:
662 Filename of ELF file to use as TPL
663 """
664 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700665 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600666
667 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700668 def _SetupVplElf(cls, src_fname='bss_data'):
669 """Set up an ELF file with a '_dt_ucode_base_size' symbol
670
671 Args:
672 Filename of ELF file to use as VPL
673 """
674 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
675 tools.read_file(cls.ElfTestFile(src_fname)))
676
677 @classmethod
Lukas Funkee901faf2023-07-18 13:53:13 +0200678 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
679 """Set up an ELF file with a '_dt_ucode_base_size' symbol
680
681 Args:
682 Filename of ELF file to use as VPL
683 """
684 TestFunctional._MakeInputFile('pmu-firmware.elf',
685 tools.read_file(cls.ElfTestFile(src_fname)))
686
687 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600688 def _SetupDescriptor(cls):
689 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
690 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
691
692 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600693 def TestFile(cls, fname):
694 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700695
Simon Glassf6290892019-08-24 07:22:53 -0600696 @classmethod
697 def ElfTestFile(cls, fname):
698 return os.path.join(cls._elf_testdir, fname)
699
Simon Glassad5cfe12023-01-07 14:07:14 -0700700 @classmethod
701 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
702 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
703 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
704 dummy, paged_sz) + U_BOOT_DATA
705 data += extra_data
706 TestFunctional._MakeInputFile(fname, data)
707
Simon Glass57454f42016-11-25 20:15:52 -0700708 def AssertInList(self, grep_list, target):
709 """Assert that at least one of a list of things is in a target
710
711 Args:
712 grep_list: List of strings to check
713 target: Target string
714 """
715 for grep in grep_list:
716 if grep in target:
717 return
Simon Glass848cdb52019-05-17 22:00:50 -0600718 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700719
720 def CheckNoGaps(self, entries):
721 """Check that all entries fit together without gaps
722
723 Args:
724 entries: List of entries to check
725 """
Simon Glasse8561af2018-08-01 15:22:37 -0600726 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700727 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600728 self.assertEqual(offset, entry.offset)
729 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700730
Simon Glass72232452016-11-25 20:15:53 -0700731 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600732 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700733
734 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600735 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700736
737 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600738 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700739 """
740 return struct.unpack('>L', dtb[4:8])[0]
741
Simon Glass0f621332019-07-08 14:25:27 -0600742 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600743 def AddNode(node, path):
744 if node.name != '/':
745 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600746 for prop in node.props.values():
747 if prop.name in prop_names:
748 prop_path = path + ':' + prop.name
749 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
750 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600751 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600752 AddNode(subnode, path)
753
754 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600755 AddNode(dtb.GetRoot(), '')
756 return tree
757
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000758 def _CheckSign(self, fit, key):
759 try:
760 tools.run('fit_check_sign', '-k', key, '-f', fit)
761 except:
762 self.fail('Expected signed FIT container')
763 return False
764 return True
765
Paul HENRYS5cf82892025-02-24 22:20:55 +0100766 def _CheckPreload(self, image, key, algo="sha256,rsa2048",
767 padding="pkcs-1.5"):
768 try:
769 tools.run('preload_check_sign', '-k', key, '-a', algo, '-p',
770 padding, '-f', image)
771 except:
772 self.fail('Expected image signed with a pre-load')
773 return False
774 return True
775
Simon Glass57454f42016-11-25 20:15:52 -0700776 def testRun(self):
777 """Test a basic run with valid args"""
778 result = self._RunBinman('-h')
779
780 def testFullHelp(self):
781 """Test that the full help is displayed with -H"""
782 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300783 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500784 # Remove possible extraneous strings
785 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
786 gothelp = result.stdout.replace(extra, '')
787 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700788 self.assertEqual(0, len(result.stderr))
789 self.assertEqual(0, result.return_code)
790
791 def testFullHelpInternal(self):
792 """Test that the full help is displayed with -H"""
793 try:
Simon Glass5dc22cf2025-02-03 09:26:42 -0700794 command.TEST_RESULT = command.CommandResult()
Simon Glass57454f42016-11-25 20:15:52 -0700795 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300796 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700797 finally:
Simon Glass5dc22cf2025-02-03 09:26:42 -0700798 command.TEST_RESULT = None
Simon Glass57454f42016-11-25 20:15:52 -0700799
800 def testHelp(self):
801 """Test that the basic help is displayed with -h"""
802 result = self._RunBinman('-h')
803 self.assertTrue(len(result.stdout) > 200)
804 self.assertEqual(0, len(result.stderr))
805 self.assertEqual(0, result.return_code)
806
Simon Glass57454f42016-11-25 20:15:52 -0700807 def testBoard(self):
808 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600809 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700810 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300811 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700812 self.assertEqual(0, result)
813
814 def testNeedBoard(self):
815 """Test that we get an error when no board ius supplied"""
816 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600817 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700818 self.assertIn("Must provide a board to process (use -b <board>)",
819 str(e.exception))
820
821 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600822 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700823 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600824 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700825 # We get one error from libfdt, and a different one from fdtget.
826 self.AssertInList(["Couldn't open blob from 'missing_file'",
827 'No such file or directory'], str(e.exception))
828
829 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600830 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700831
832 Since this is a source file it should be compiled and the error
833 will come from the device-tree compiler (dtc).
834 """
835 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600836 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700837 self.assertIn("FATAL ERROR: Unable to parse input tree",
838 str(e.exception))
839
840 def testMissingNode(self):
841 """Test that a device tree without a 'binman' node generates an error"""
842 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600843 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700844 self.assertIn("does not have a 'binman' node", str(e.exception))
845
846 def testEmpty(self):
847 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600848 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700849 self.assertEqual(0, len(result.stderr))
850 self.assertEqual(0, result.return_code)
851
852 def testInvalidEntry(self):
853 """Test that an invalid entry is flagged"""
854 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600855 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600856 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700857 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
858 "'/binman/not-a-valid-type'", str(e.exception))
859
860 def testSimple(self):
861 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600862 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700863 self.assertEqual(U_BOOT_DATA, data)
864
Simon Glass075a45c2017-11-13 18:55:00 -0700865 def testSimpleDebug(self):
866 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600867 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700868
Simon Glass57454f42016-11-25 20:15:52 -0700869 def testDual(self):
870 """Test that we can handle creating two images
871
872 This also tests image padding.
873 """
Simon Glass511f6582018-10-01 12:22:30 -0600874 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700875 self.assertEqual(0, retcode)
876
877 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600878 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700879 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700880 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600881 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700882 data = fd.read()
883 self.assertEqual(U_BOOT_DATA, data)
884
885 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600886 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700887 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700888 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600889 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700890 data = fd.read()
891 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700892 self.assertEqual(tools.get_bytes(0, 3), data[:3])
893 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700894
895 def testBadAlign(self):
896 """Test that an invalid alignment value is detected"""
897 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600898 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700899 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
900 "of two", str(e.exception))
901
902 def testPackSimple(self):
903 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600904 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700905 self.assertEqual(0, retcode)
906 self.assertIn('image', control.images)
907 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600908 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700909 self.assertEqual(5, len(entries))
910
911 # First u-boot
912 self.assertIn('u-boot', entries)
913 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600914 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700915 self.assertEqual(len(U_BOOT_DATA), entry.size)
916
917 # Second u-boot, aligned to 16-byte boundary
918 self.assertIn('u-boot-align', entries)
919 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600920 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700921 self.assertEqual(len(U_BOOT_DATA), entry.size)
922
923 # Third u-boot, size 23 bytes
924 self.assertIn('u-boot-size', entries)
925 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600926 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700927 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
928 self.assertEqual(23, entry.size)
929
930 # Fourth u-boot, placed immediate after the above
931 self.assertIn('u-boot-next', entries)
932 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600933 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700934 self.assertEqual(len(U_BOOT_DATA), entry.size)
935
Simon Glasse8561af2018-08-01 15:22:37 -0600936 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700937 self.assertIn('u-boot-fixed', entries)
938 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600939 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700940 self.assertEqual(len(U_BOOT_DATA), entry.size)
941
Simon Glass39dd2152019-07-08 14:25:47 -0600942 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700943
944 def testPackExtra(self):
945 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600946 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
947 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700948
Simon Glass57454f42016-11-25 20:15:52 -0700949 self.assertIn('image', control.images)
950 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600951 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600952 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700953
Samuel Hollande2574022023-01-21 17:25:16 -0600954 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700955 self.assertIn('u-boot', entries)
956 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600957 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700958 self.assertEqual(3, entry.pad_before)
959 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600960 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700961 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
962 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600963 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700964
965 # Second u-boot has an aligned size, but it has no effect
966 self.assertIn('u-boot-align-size-nop', entries)
967 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600968 self.assertEqual(pos, entry.offset)
969 self.assertEqual(len(U_BOOT_DATA), entry.size)
970 self.assertEqual(U_BOOT_DATA, entry.data)
971 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
972 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700973
974 # Third u-boot has an aligned size too
975 self.assertIn('u-boot-align-size', entries)
976 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600977 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700978 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600979 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700980 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600981 data[pos:pos + entry.size])
982 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700983
984 # Fourth u-boot has an aligned end
985 self.assertIn('u-boot-align-end', entries)
986 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600987 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700988 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600989 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700990 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600991 data[pos:pos + entry.size])
992 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700993
994 # Fifth u-boot immediately afterwards
995 self.assertIn('u-boot-align-both', entries)
996 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600997 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700998 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600999 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -07001000 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -06001001 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -07001002
Samuel Hollande2574022023-01-21 17:25:16 -06001003 # Sixth u-boot with both minimum size and aligned size
1004 self.assertIn('u-boot-min-size', entries)
1005 entry = entries['u-boot-min-size']
1006 self.assertEqual(128, entry.offset)
1007 self.assertEqual(32, entry.size)
1008 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
1009 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
1010 data[pos:pos + entry.size])
1011
Simon Glass57454f42016-11-25 20:15:52 -07001012 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -06001013 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001014
Simon Glassafb9caa2020-10-26 17:40:10 -06001015 dtb = fdt.Fdt(out_dtb_fname)
1016 dtb.Scan()
1017 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
1018 expected = {
1019 'image-pos': 0,
1020 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -06001021 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -06001022
1023 'u-boot:image-pos': 0,
1024 'u-boot:offset': 0,
1025 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1026
1027 'u-boot-align-size-nop:image-pos': 12,
1028 'u-boot-align-size-nop:offset': 12,
1029 'u-boot-align-size-nop:size': 4,
1030
1031 'u-boot-align-size:image-pos': 16,
1032 'u-boot-align-size:offset': 16,
1033 'u-boot-align-size:size': 32,
1034
1035 'u-boot-align-end:image-pos': 48,
1036 'u-boot-align-end:offset': 48,
1037 'u-boot-align-end:size': 16,
1038
1039 'u-boot-align-both:image-pos': 64,
1040 'u-boot-align-both:offset': 64,
1041 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -06001042
1043 'u-boot-min-size:image-pos': 128,
1044 'u-boot-min-size:offset': 128,
1045 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -06001046 }
1047 self.assertEqual(expected, props)
1048
Simon Glass57454f42016-11-25 20:15:52 -07001049 def testPackAlignPowerOf2(self):
1050 """Test that invalid entry alignment is detected"""
1051 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001052 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001053 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1054 "of two", str(e.exception))
1055
1056 def testPackAlignSizePowerOf2(self):
1057 """Test that invalid entry size alignment is detected"""
1058 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001059 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001060 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1061 "power of two", str(e.exception))
1062
1063 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001064 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001065 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001066 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001067 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001068 "align 0x4 (4)", str(e.exception))
1069
1070 def testPackInvalidSizeAlign(self):
1071 """Test that invalid entry size alignment is detected"""
1072 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001073 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001074 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1075 "align-size 0x4 (4)", str(e.exception))
1076
1077 def testPackOverlap(self):
1078 """Test that overlapping regions are detected"""
1079 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001080 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001081 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001082 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1083 str(e.exception))
1084
1085 def testPackEntryOverflow(self):
1086 """Test that entries that overflow their size are detected"""
1087 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001088 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001089 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1090 "but entry size is 0x3 (3)", str(e.exception))
1091
1092 def testPackImageOverflow(self):
1093 """Test that entries which overflow the image size are detected"""
1094 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001095 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001096 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001097 "size 0x3 (3)", str(e.exception))
1098
1099 def testPackImageSize(self):
1100 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001101 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001102 self.assertEqual(0, retcode)
1103 self.assertIn('image', control.images)
1104 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001105 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001106
1107 def testPackImageSizeAlign(self):
1108 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001109 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001110 self.assertEqual(0, retcode)
1111 self.assertIn('image', control.images)
1112 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001113 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001114
1115 def testPackInvalidImageAlign(self):
1116 """Test that invalid image alignment is detected"""
1117 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001118 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001119 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001120 "align-size 0x8 (8)", str(e.exception))
1121
Simon Glass2a0fa982022-02-11 13:23:21 -07001122 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001123 """Test that invalid image alignment is detected"""
1124 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001125 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001126 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001127 "two", str(e.exception))
1128
1129 def testImagePadByte(self):
1130 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001131 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001132 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001133 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001134 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001135
1136 def testImageName(self):
1137 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001138 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001139 self.assertEqual(0, retcode)
1140 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001141 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001142 self.assertTrue(os.path.exists(fname))
1143
1144 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001145 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001146 self.assertTrue(os.path.exists(fname))
1147
1148 def testBlobFilename(self):
1149 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001150 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001151 self.assertEqual(BLOB_DATA, data)
1152
1153 def testPackSorted(self):
1154 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001155 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001156 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001157 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1158 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001159
Simon Glasse8561af2018-08-01 15:22:37 -06001160 def testPackZeroOffset(self):
1161 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001162 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001163 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001164 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001165 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001166 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1167 str(e.exception))
1168
1169 def testPackUbootDtb(self):
1170 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001171 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001172 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001173
1174 def testPackX86RomNoSize(self):
1175 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001176 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001177 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001178 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001179 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001180 "using end-at-4gb", str(e.exception))
1181
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301182 def test4gbAndSkipAtStartTogether(self):
1183 """Test that the end-at-4gb and skip-at-size property can't be used
1184 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001185 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301186 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001187 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001188 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301189 "'skip-at-start'", str(e.exception))
1190
Simon Glass72232452016-11-25 20:15:53 -07001191 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001192 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001193 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001194 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001195 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001196 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1197 "is outside the section '/binman' starting at "
1198 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001199 str(e.exception))
1200
1201 def testPackX86Rom(self):
1202 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001203 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001204 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001205 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1206 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001207
1208 def testPackX86RomMeNoDesc(self):
1209 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001210 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001211 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001212 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001213 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001214 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1215 str(e.exception))
1216 finally:
1217 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001218
1219 def testPackX86RomBadDesc(self):
1220 """Test that the Intel requires a descriptor entry"""
1221 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001222 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001223 self.assertIn("Node '/binman/intel-me': No offset set with "
1224 "offset-unset: should another entry provide this correct "
1225 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001226
1227 def testPackX86RomMe(self):
1228 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001229 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001230 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001231 if data[:0x1000] != expected_desc:
1232 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001233 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1234
1235 def testPackVga(self):
1236 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001237 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001238 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1239
1240 def testPackStart16(self):
1241 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001242 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001243 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1244
Jagdish Gediya311d4842018-09-03 21:35:08 +05301245 def testPackPowerpcMpc85xxBootpgResetvec(self):
1246 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1247 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001248 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301249 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1250
Simon Glass6ba679c2018-07-06 10:27:17 -06001251 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001252 """Handle running a test for insertion of microcode
1253
1254 Args:
1255 dts_fname: Name of test .dts file
1256 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001257 ucode_second: True if the microsecond entry is second instead of
1258 third
Simon Glass820af1d2018-07-06 10:27:16 -06001259
1260 Returns:
1261 Tuple:
1262 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001263 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001264 in the above (two 4-byte words)
1265 """
Simon Glass3d274232017-11-12 21:52:27 -07001266 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001267
1268 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001269 if ucode_second:
1270 ucode_content = data[len(nodtb_data):]
1271 ucode_pos = len(nodtb_data)
1272 dtb_with_ucode = ucode_content[16:]
1273 fdt_len = self.GetFdtLen(dtb_with_ucode)
1274 else:
1275 dtb_with_ucode = data[len(nodtb_data):]
1276 fdt_len = self.GetFdtLen(dtb_with_ucode)
1277 ucode_content = dtb_with_ucode[fdt_len:]
1278 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001279 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001280 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001281 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001282 dtb = fdt.FdtScan(fname)
1283 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001284 self.assertTrue(ucode)
1285 for node in ucode.subnodes:
1286 self.assertFalse(node.props.get('data'))
1287
Simon Glass72232452016-11-25 20:15:53 -07001288 # Check that the microcode appears immediately after the Fdt
1289 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001290 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001291 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1292 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001293 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001294
1295 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001296 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001297 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1298 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001299 u_boot = data[:len(nodtb_data)]
1300 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001301
1302 def testPackUbootMicrocode(self):
1303 """Test that x86 microcode can be handled correctly
1304
1305 We expect to see the following in the image, in order:
1306 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1307 place
1308 u-boot.dtb with the microcode removed
1309 the microcode
1310 """
Simon Glass511f6582018-10-01 12:22:30 -06001311 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001312 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001313 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1314 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001315
Simon Glassbac25c82017-05-27 07:38:26 -06001316 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001317 """Test that x86 microcode can be handled correctly
1318
1319 We expect to see the following in the image, in order:
1320 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1321 place
1322 u-boot.dtb with the microcode
1323 an empty microcode region
1324 """
1325 # We need the libfdt library to run this test since only that allows
1326 # finding the offset of a property. This is required by
1327 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001328 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001329
1330 second = data[len(U_BOOT_NODTB_DATA):]
1331
1332 fdt_len = self.GetFdtLen(second)
1333 third = second[fdt_len:]
1334 second = second[:fdt_len]
1335
Simon Glassbac25c82017-05-27 07:38:26 -06001336 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1337 self.assertIn(ucode_data, second)
1338 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001339
Simon Glassbac25c82017-05-27 07:38:26 -06001340 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001341 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001342 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1343 len(ucode_data))
1344 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001345 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1346 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001347
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001348 def testPackUbootSingleMicrocode(self):
1349 """Test that x86 microcode can be handled correctly with fdt_normal.
1350 """
Simon Glassbac25c82017-05-27 07:38:26 -06001351 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001352
Simon Glass996021e2016-11-25 20:15:54 -07001353 def testUBootImg(self):
1354 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001355 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001356 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001357
1358 def testNoMicrocode(self):
1359 """Test that a missing microcode region is detected"""
1360 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001361 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001362 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1363 "node found in ", str(e.exception))
1364
1365 def testMicrocodeWithoutNode(self):
1366 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1367 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001368 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001369 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1370 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1371
1372 def testMicrocodeWithoutNode2(self):
1373 """Test that a missing u-boot-ucode node is detected"""
1374 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001375 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001376 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1377 "microcode region u-boot-ucode", str(e.exception))
1378
1379 def testMicrocodeWithoutPtrInElf(self):
1380 """Test that a U-Boot binary without the microcode symbol is detected"""
1381 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001382 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001383 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001384 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001385
1386 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001387 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001388 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1389 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1390
1391 finally:
1392 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001393 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001394 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001395
1396 def testMicrocodeNotInImage(self):
1397 """Test that microcode must be placed within the image"""
1398 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001399 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001400 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1401 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001402 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001403
1404 def testWithoutMicrocode(self):
1405 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001406 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001407 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001408 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001409
1410 # Now check the device tree has no microcode
1411 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1412 second = data[len(U_BOOT_NODTB_DATA):]
1413
1414 fdt_len = self.GetFdtLen(second)
1415 self.assertEqual(dtb, second[:fdt_len])
1416
1417 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1418 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001419 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001420
1421 def testUnknownPosSize(self):
1422 """Test that microcode must be placed within the image"""
1423 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001424 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001425 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001426 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001427
1428 def testPackFsp(self):
1429 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001430 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001431 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1432
1433 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001434 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001435 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001436 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001437
1438 def testPackVbt(self):
1439 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001440 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001441 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001442
Simon Glass7f94e832017-11-12 21:52:25 -07001443 def testSplBssPad(self):
1444 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001445 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001446 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001447 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001448 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001449 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001450
Simon Glass04cda032018-10-01 21:12:42 -06001451 def testSplBssPadMissing(self):
1452 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001453 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001454 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001455 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001456 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1457 str(e.exception))
1458
Simon Glasse83679d2017-11-12 21:52:26 -07001459 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001460 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001461 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001462 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1463
Simon Glass6ba679c2018-07-06 10:27:17 -06001464 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1465 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001466
1467 We expect to see the following in the image, in order:
1468 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1469 correct place
1470 u-boot.dtb with the microcode removed
1471 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001472
1473 Args:
1474 dts: Device tree file to use for test
1475 ucode_second: True if the microsecond entry is second instead of
1476 third
Simon Glass3d274232017-11-12 21:52:27 -07001477 """
Simon Glass7057d022018-10-01 21:12:47 -06001478 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001479 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1480 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001481 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1482 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001483
Simon Glass6ba679c2018-07-06 10:27:17 -06001484 def testPackUbootSplMicrocode(self):
1485 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001486 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001487 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001488
1489 def testPackUbootSplMicrocodeReorder(self):
1490 """Test that order doesn't matter for microcode entries
1491
1492 This is the same as testPackUbootSplMicrocode but when we process the
1493 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1494 entry, so we reply on binman to try later.
1495 """
Simon Glass511f6582018-10-01 12:22:30 -06001496 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001497 ucode_second=True)
1498
Simon Glassa409c932017-11-12 21:52:28 -07001499 def testPackMrc(self):
1500 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001501 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001502 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1503
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001504 def testSplDtb(self):
1505 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001506 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001507 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001508 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1509
Simon Glass0a6da312017-11-13 18:54:56 -07001510 def testSplNoDtb(self):
1511 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001512 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001513 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001514 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1515
Simon Glass7098b7f2021-03-21 18:24:30 +13001516 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4b0f4142024-08-26 13:11:40 -06001517 use_expanded=False, no_write_symbols=False,
1518 symbols_base=None):
Simon Glass31e04cb2021-03-18 20:24:56 +13001519 """Check the image contains the expected symbol values
1520
1521 Args:
1522 dts: Device tree file to use for test
1523 base_data: Data before and after 'u-boot' section
Simon Glass3eb30a42024-08-26 13:11:42 -06001524 u_boot_offset (int): Offset of 'u-boot' section in image, or None if
1525 the offset not available due to it being in a compressed section
Simon Glass7098b7f2021-03-21 18:24:30 +13001526 entry_args: Dict of entry args to supply to binman
1527 key: arg name
1528 value: value of that arg
1529 use_expanded: True to use expanded entries where available, e.g.
1530 'u-boot-expanded' instead of 'u-boot'
Simon Glass4b0f4142024-08-26 13:11:40 -06001531 symbols_base (int): Value to expect for symbols-base in u-boot-spl,
1532 None if none
Simon Glass31e04cb2021-03-18 20:24:56 +13001533 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001534 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001535 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1536 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001537 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001538 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001539 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001540
Simon Glass7057d022018-10-01 21:12:47 -06001541 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001542 data = self._DoReadFileDtb(dts, entry_args=entry_args,
Simon Glass3eb30a42024-08-26 13:11:42 -06001543 use_expanded=use_expanded,
1544 verbosity=None if u_boot_offset else 3)[0]
1545
1546 # The lz4-compressed version of the U-Boot data is 19 bytes long
1547 comp_uboot_len = 19
1548
Simon Glass31e04cb2021-03-18 20:24:56 +13001549 # The image should contain the symbols from u_boot_binman_syms.c
1550 # Note that image_pos is adjusted by the base address of the image,
1551 # which is 0x10 in our test image
Simon Glass3eb30a42024-08-26 13:11:42 -06001552 # If u_boot_offset is None, Binman should write -1U into the image
Simon Glass4b0f4142024-08-26 13:11:40 -06001553 vals2 = (elf.BINMAN_SYM_MAGIC_VALUE, 0x00,
Simon Glass3eb30a42024-08-26 13:11:42 -06001554 u_boot_offset + len(U_BOOT_DATA) if u_boot_offset else
1555 len(U_BOOT_SPL_DATA) + 1 + comp_uboot_len,
1556 0x10 + u_boot_offset if u_boot_offset else 0xffffffff, 0x04)
Simon Glass4b0f4142024-08-26 13:11:40 -06001557
1558 # u-boot-spl has a symbols-base property, so take that into account if
1559 # required. The caller must supply the value
1560 vals = list(vals2)
1561 if symbols_base is not None:
1562 vals[3] = symbols_base + u_boot_offset
1563 vals = tuple(vals)
1564
Simon Glass4b4049e2024-08-26 13:11:39 -06001565 sym_values = struct.pack('<LLQLL', *vals)
Simon Glass4b0f4142024-08-26 13:11:40 -06001566 sym_values2 = struct.pack('<LLQLL', *vals2)
Simon Glass4abf7842023-07-18 07:23:54 -06001567 if no_write_symbols:
Simon Glass4b4049e2024-08-26 13:11:39 -06001568 self.assertEqual(
1569 base_data +
1570 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1571 U_BOOT_DATA + base_data, data)
Simon Glass4abf7842023-07-18 07:23:54 -06001572 else:
Simon Glass4b4049e2024-08-26 13:11:39 -06001573 got_vals = struct.unpack('<LLQLL', data[:24])
1574
1575 # For debugging:
1576 #print('expect:', list(f'{v:x}' for v in vals))
1577 #print(' got:', list(f'{v:x}' for v in got_vals))
1578
1579 self.assertEqual(vals, got_vals)
1580 self.assertEqual(sym_values, data[:24])
1581
1582 blen = len(base_data)
1583 self.assertEqual(base_data[24:], data[24:blen])
1584 self.assertEqual(0xff, data[blen])
1585
Simon Glass3eb30a42024-08-26 13:11:42 -06001586 if u_boot_offset:
1587 ofs = blen + 1 + len(U_BOOT_DATA)
1588 self.assertEqual(U_BOOT_DATA, data[blen + 1:ofs])
1589 else:
1590 ofs = blen + 1 + comp_uboot_len
Simon Glass4b4049e2024-08-26 13:11:39 -06001591
Simon Glass4b0f4142024-08-26 13:11:40 -06001592 self.assertEqual(sym_values2, data[ofs:ofs + 24])
Simon Glass4b4049e2024-08-26 13:11:39 -06001593 self.assertEqual(base_data[24:], data[ofs + 24:])
1594
1595 # Just repeating the above asserts all at once, for clarity
Simon Glass3eb30a42024-08-26 13:11:42 -06001596 if u_boot_offset:
1597 expected = (sym_values + base_data[24:] +
1598 tools.get_bytes(0xff, 1) + U_BOOT_DATA +
1599 sym_values2 + base_data[24:])
1600 self.assertEqual(expected, data)
Simon Glass4ca8e042017-11-13 18:55:01 -07001601
Simon Glass31e04cb2021-03-18 20:24:56 +13001602 def testSymbols(self):
1603 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001604 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001605
1606 def testSymbolsNoDtb(self):
1607 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001608 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001609 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1610 0x38)
1611
Simon Glasse76a3e62018-06-01 09:38:11 -06001612 def testPackUnitAddress(self):
1613 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001614 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001615 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1616
Simon Glassa91e1152018-06-01 09:38:16 -06001617 def testSections(self):
1618 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001619 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001620 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1621 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1622 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001623 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001624
Simon Glass30732662018-06-01 09:38:20 -06001625 def testMap(self):
1626 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001627 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001628 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700162900000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600163000000000 00000000 00000010 section@0
163100000000 00000000 00000004 u-boot
163200000010 00000010 00000010 section@1
163300000010 00000000 00000004 u-boot
163400000020 00000020 00000004 section@2
163500000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001636''', map_data)
1637
Simon Glass3b78d532018-06-01 09:38:21 -06001638 def testNamePrefix(self):
1639 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001640 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001641 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700164200000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600164300000000 00000000 00000010 section@0
164400000000 00000000 00000004 ro-u-boot
164500000010 00000010 00000010 section@1
164600000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001647''', map_data)
1648
Simon Glass6ba679c2018-07-06 10:27:17 -06001649 def testUnknownContents(self):
1650 """Test that obtaining the contents works as expected"""
1651 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001652 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001653 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001654 "processing of contents: remaining ["
1655 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001656
Simon Glass2e1169f2018-07-06 10:27:19 -06001657 def testBadChangeSize(self):
1658 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001659 try:
1660 state.SetAllowEntryExpansion(False)
1661 with self.assertRaises(ValueError) as e:
1662 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001663 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001664 str(e.exception))
1665 finally:
1666 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001667
Simon Glassa87014e2018-07-06 10:27:42 -06001668 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001669 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001670 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001671 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001672 dtb = fdt.Fdt(out_dtb_fname)
1673 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001674 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001675 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001676 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001677 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001678 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001679 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001680 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001681 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001682 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001683 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001684 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001685 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001686 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001687
Simon Glasse8561af2018-08-01 15:22:37 -06001688 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001689 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001690 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001691 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001692 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001693 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001694 'size': 40
1695 }, props)
1696
1697 def testUpdateFdtBad(self):
1698 """Test that we detect when ProcessFdt never completes"""
1699 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001700 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001701 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001702 '[<binman.etype._testing.Entry__testing',
1703 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001704
Simon Glass91710b32018-07-17 13:25:32 -06001705 def testEntryArgs(self):
1706 """Test passing arguments to entries from the command line"""
1707 entry_args = {
1708 'test-str-arg': 'test1',
1709 'test-int-arg': '456',
1710 }
Simon Glass511f6582018-10-01 12:22:30 -06001711 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001712 self.assertIn('image', control.images)
1713 entry = control.images['image'].GetEntries()['_testing']
1714 self.assertEqual('test0', entry.test_str_fdt)
1715 self.assertEqual('test1', entry.test_str_arg)
1716 self.assertEqual(123, entry.test_int_fdt)
1717 self.assertEqual(456, entry.test_int_arg)
1718
1719 def testEntryArgsMissing(self):
1720 """Test missing arguments and properties"""
1721 entry_args = {
1722 'test-int-arg': '456',
1723 }
Simon Glass511f6582018-10-01 12:22:30 -06001724 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001725 entry = control.images['image'].GetEntries()['_testing']
1726 self.assertEqual('test0', entry.test_str_fdt)
1727 self.assertEqual(None, entry.test_str_arg)
1728 self.assertEqual(None, entry.test_int_fdt)
1729 self.assertEqual(456, entry.test_int_arg)
1730
1731 def testEntryArgsRequired(self):
1732 """Test missing arguments and properties"""
1733 entry_args = {
1734 'test-int-arg': '456',
1735 }
1736 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001737 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001738 self.assertIn("Node '/binman/_testing': "
1739 'Missing required properties/entry args: test-str-arg, '
1740 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001741 str(e.exception))
1742
1743 def testEntryArgsInvalidFormat(self):
1744 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001745 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1746 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001747 with self.assertRaises(ValueError) as e:
1748 self._DoBinman(*args)
1749 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1750
1751 def testEntryArgsInvalidInteger(self):
1752 """Test that an invalid entry-argument integer is detected"""
1753 entry_args = {
1754 'test-int-arg': 'abc',
1755 }
1756 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001757 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001758 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1759 "'test-int-arg' (value 'abc') to integer",
1760 str(e.exception))
1761
1762 def testEntryArgsInvalidDatatype(self):
1763 """Test that an invalid entry-argument datatype is detected
1764
1765 This test could be written in entry_test.py except that it needs
1766 access to control.entry_args, which seems more than that module should
1767 be able to see.
1768 """
1769 entry_args = {
1770 'test-bad-datatype-arg': '12',
1771 }
1772 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001773 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001774 entry_args=entry_args)
1775 self.assertIn('GetArg() internal error: Unknown data type ',
1776 str(e.exception))
1777
Simon Glass2ca52032018-07-17 13:25:33 -06001778 def testText(self):
1779 """Test for a text entry type"""
1780 entry_args = {
1781 'test-id': TEXT_DATA,
1782 'test-id2': TEXT_DATA2,
1783 'test-id3': TEXT_DATA3,
1784 }
Simon Glass511f6582018-10-01 12:22:30 -06001785 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001786 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001787 expected = (tools.to_bytes(TEXT_DATA) +
1788 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1789 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001790 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001791 self.assertEqual(expected, data)
1792
Simon Glass969616c2018-07-17 13:25:36 -06001793 def testEntryDocs(self):
1794 """Test for creation of entry documentation"""
1795 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001796 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001797 self.assertTrue(len(stdout.getvalue()) > 0)
1798
1799 def testEntryDocsMissing(self):
1800 """Test handling of missing entry documentation"""
1801 with self.assertRaises(ValueError) as e:
1802 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001803 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001804 self.assertIn('Documentation is missing for modules: u_boot',
1805 str(e.exception))
1806
Simon Glass704784b2018-07-17 13:25:38 -06001807 def testFmap(self):
1808 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001809 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001810 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001811 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1812 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001813 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001814 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001815 self.assertEqual(1, fhdr.ver_major)
1816 self.assertEqual(0, fhdr.ver_minor)
1817 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001818 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001819 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001820 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001821 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001822 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001823
Simon Glass82059c22021-04-03 11:05:09 +13001824 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001825 self.assertEqual(b'SECTION0', fentry.name)
1826 self.assertEqual(0, fentry.offset)
1827 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001828 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001829
1830 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001831 self.assertEqual(b'RO_U_BOOT', fentry.name)
1832 self.assertEqual(0, fentry.offset)
1833 self.assertEqual(4, fentry.size)
1834 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001835
Simon Glass82059c22021-04-03 11:05:09 +13001836 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001837 self.assertEqual(b'SECTION1', fentry.name)
1838 self.assertEqual(16, fentry.offset)
1839 self.assertEqual(16, fentry.size)
1840 self.assertEqual(0, fentry.flags)
1841
1842 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001843 self.assertEqual(b'RW_U_BOOT', fentry.name)
1844 self.assertEqual(16, fentry.offset)
1845 self.assertEqual(4, fentry.size)
1846 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001847
Simon Glass82059c22021-04-03 11:05:09 +13001848 fentry = next(fiter)
1849 self.assertEqual(b'FMAP', fentry.name)
1850 self.assertEqual(32, fentry.offset)
1851 self.assertEqual(expect_size, fentry.size)
1852 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001853
Simon Glassdb168d42018-07-17 13:25:39 -06001854 def testBlobNamedByArg(self):
1855 """Test we can add a blob with the filename coming from an entry arg"""
1856 entry_args = {
1857 'cros-ec-rw-path': 'ecrw.bin',
1858 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001859 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001860
Simon Glass53f53992018-07-17 13:25:40 -06001861 def testFill(self):
1862 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001863 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001864 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001865 self.assertEqual(expected, data)
1866
1867 def testFillNoSize(self):
1868 """Test for an fill entry type with no size"""
1869 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001870 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001871 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001872 str(e.exception))
1873
Simon Glassc1ae83c2018-07-17 13:25:44 -06001874 def _HandleGbbCommand(self, pipe_list):
1875 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001876 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001877 fname = pipe_list[0][-1]
1878 # Append our GBB data to the file, which will happen every time the
1879 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001880 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001881 fd.write(GBB_DATA)
1882 return command.CommandResult()
1883
1884 def testGbb(self):
1885 """Test for the Chromium OS Google Binary Block"""
Simon Glass5dc22cf2025-02-03 09:26:42 -07001886 command.TEST_RESULT = self._HandleGbbCommand
Simon Glassc1ae83c2018-07-17 13:25:44 -06001887 entry_args = {
1888 'keydir': 'devkeys',
1889 'bmpblk': 'bmpblk.bin',
1890 }
Simon Glass511f6582018-10-01 12:22:30 -06001891 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001892
1893 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001894 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1895 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001896 self.assertEqual(expected, data)
1897
1898 def testGbbTooSmall(self):
1899 """Test for the Chromium OS Google Binary Block being large enough"""
1900 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001901 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001902 self.assertIn("Node '/binman/gbb': GBB is too small",
1903 str(e.exception))
1904
1905 def testGbbNoSize(self):
1906 """Test for the Chromium OS Google Binary Block having a size"""
1907 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001908 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001909 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1910 str(e.exception))
1911
Simon Glass66152ce2022-01-09 20:14:09 -07001912 def testGbbMissing(self):
1913 """Test that binman still produces an image if futility is missing"""
1914 entry_args = {
1915 'keydir': 'devkeys',
1916 }
1917 with test_util.capture_sys_output() as (_, stderr):
1918 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1919 entry_args=entry_args)
1920 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001921 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001922
Simon Glass5c350162018-07-17 13:25:47 -06001923 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001924 """Fake calls to the futility utility
1925
1926 The expected pipe is:
1927
1928 [('futility', 'vbutil_firmware', '--vblock',
1929 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1930 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1931 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1932 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1933
1934 This writes to the output file (here, 'vblock.vblock'). If
1935 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1936 of the input data (here, 'input.vblock').
1937 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001938 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001939 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001940 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001941 if self._hash_data:
1942 infile = pipe_list[0][11]
1943 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001944 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001945 m.update(data)
1946 fd.write(m.digest())
1947 else:
1948 fd.write(VBLOCK_DATA)
1949
Simon Glass5c350162018-07-17 13:25:47 -06001950 return command.CommandResult()
1951
1952 def testVblock(self):
1953 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001954 self._hash_data = False
Simon Glass5dc22cf2025-02-03 09:26:42 -07001955 command.TEST_RESULT = self._HandleVblockCommand
Simon Glass5c350162018-07-17 13:25:47 -06001956 entry_args = {
1957 'keydir': 'devkeys',
1958 }
Simon Glass511f6582018-10-01 12:22:30 -06001959 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001960 entry_args=entry_args)
1961 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1962 self.assertEqual(expected, data)
1963
1964 def testVblockNoContent(self):
1965 """Test we detect a vblock which has no content to sign"""
1966 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001967 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001968 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001969 'property', str(e.exception))
1970
1971 def testVblockBadPhandle(self):
1972 """Test that we detect a vblock with an invalid phandle in contents"""
1973 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001974 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001975 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1976 '1000', str(e.exception))
1977
1978 def testVblockBadEntry(self):
1979 """Test that we detect an entry that points to a non-entry"""
1980 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001981 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001982 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1983 "'other'", str(e.exception))
1984
Simon Glass220c6222021-01-06 21:35:17 -07001985 def testVblockContent(self):
1986 """Test that the vblock signs the right data"""
1987 self._hash_data = True
Simon Glass5dc22cf2025-02-03 09:26:42 -07001988 command.TEST_RESULT = self._HandleVblockCommand
Simon Glass220c6222021-01-06 21:35:17 -07001989 entry_args = {
1990 'keydir': 'devkeys',
1991 }
1992 data = self._DoReadFileDtb(
1993 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1994 entry_args=entry_args)[0]
1995 hashlen = 32 # SHA256 hash is 32 bytes
1996 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1997 hashval = data[-hashlen:]
1998 dtb = data[len(U_BOOT_DATA):-hashlen]
1999
2000 expected_data = U_BOOT_DATA + dtb
2001
2002 # The hashval should be a hash of the dtb
2003 m = hashlib.sha256()
2004 m.update(expected_data)
2005 expected_hashval = m.digest()
2006 self.assertEqual(expected_hashval, hashval)
2007
Simon Glass66152ce2022-01-09 20:14:09 -07002008 def testVblockMissing(self):
2009 """Test that binman still produces an image if futility is missing"""
2010 entry_args = {
2011 'keydir': 'devkeys',
2012 }
2013 with test_util.capture_sys_output() as (_, stderr):
2014 self._DoTestFile('074_vblock.dts',
2015 force_missing_bintools='futility',
2016 entry_args=entry_args)
2017 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07002018 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07002019
Simon Glass8425a1f2018-07-17 13:25:48 -06002020 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06002021 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06002022 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06002023 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06002024 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06002025 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
2026
Simon Glass24b97442018-07-17 13:25:51 -06002027 def testUsesPos(self):
2028 """Test that the 'pos' property cannot be used anymore"""
2029 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002030 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06002031 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
2032 "'pos'", str(e.exception))
2033
Simon Glass274bf092018-09-14 04:57:08 -06002034 def testFillZero(self):
2035 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06002036 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07002037 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06002038
Simon Glass267de432018-09-14 04:57:09 -06002039 def testTextMissing(self):
2040 """Test for a text entry type where there is no text"""
2041 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002042 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06002043 self.assertIn("Node '/binman/text': No value provided for text label "
2044 "'test-id'", str(e.exception))
2045
Simon Glassed40e962018-09-14 04:57:10 -06002046 def testPackStart16Tpl(self):
2047 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06002048 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06002049 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
2050
Simon Glass3b376c32018-09-14 04:57:12 -06002051 def testSelectImage(self):
2052 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06002053 expected = 'Skipping images: image1'
2054
2055 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06002056 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06002057 with test_util.capture_sys_output() as (stdout, stderr):
2058 retcode = self._DoTestFile('006_dual_image.dts',
2059 verbosity=verbosity,
2060 images=['image2'])
2061 self.assertEqual(0, retcode)
2062 if verbosity:
2063 self.assertIn(expected, stdout.getvalue())
2064 else:
2065 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06002066
Simon Glass80025522022-01-29 14:14:04 -07002067 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2068 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06002069 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06002070
Simon Glasse219aa42018-09-14 04:57:24 -06002071 def testUpdateFdtAll(self):
2072 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06002073 self._SetupSplElf()
2074 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06002075 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06002076
2077 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06002078 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002079 'image-pos': 0,
2080 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06002081 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002082 'section:image-pos': 0,
2083 'section:size': 565,
2084 'section/u-boot-dtb:offset': 0,
2085 'section/u-boot-dtb:image-pos': 0,
2086 'section/u-boot-dtb:size': 565,
2087 'u-boot-spl-dtb:offset': 565,
2088 'u-boot-spl-dtb:image-pos': 565,
2089 'u-boot-spl-dtb:size': 585,
2090 'u-boot-tpl-dtb:offset': 1150,
2091 'u-boot-tpl-dtb:image-pos': 1150,
2092 'u-boot-tpl-dtb:size': 585,
2093 'u-boot-vpl-dtb:image-pos': 1735,
2094 'u-boot-vpl-dtb:offset': 1735,
2095 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002096 }
2097
2098 # We expect three device-tree files in the output, one after the other.
2099 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2100 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2101 # main U-Boot tree. All three should have the same postions and offset.
2102 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002103 self.maxDiff = None
2104 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002105 dtb = fdt.Fdt.FromData(data[start:])
2106 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002107 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002108 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002109 expected = dict(base_expected)
2110 if item:
2111 expected[item] = 0
2112 self.assertEqual(expected, props)
2113 start += dtb._fdt_obj.totalsize()
2114
2115 def testUpdateFdtOutput(self):
2116 """Test that output DTB files are updated"""
2117 try:
Simon Glass511f6582018-10-01 12:22:30 -06002118 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002119 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2120
2121 # Unfortunately, compiling a source file always results in a file
2122 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002123 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002124 # binman as a file called u-boot.dtb. To fix this, copy the file
2125 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002126 start = 0
2127 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002128 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002129 dtb = fdt.Fdt.FromData(data[start:])
2130 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002131 pathname = tools.get_output_filename(os.path.split(fname)[1])
2132 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002133 name = os.path.split(fname)[0]
2134
2135 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002136 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002137 else:
2138 orig_indata = dtb_data
2139 self.assertNotEqual(outdata, orig_indata,
2140 "Expected output file '%s' be updated" % pathname)
2141 self.assertEqual(outdata, data[start:start + size],
2142 "Expected output file '%s' to match output image" %
2143 pathname)
2144 start += size
2145 finally:
2146 self._ResetDtbs()
2147
Simon Glass7ba33592018-09-14 04:57:26 -06002148 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002149 bintool = self.comp_bintools['lz4']
2150 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002151
2152 def testCompress(self):
2153 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002154 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002155 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002156 use_real_dtb=True, update_dtb=True)
2157 dtb = fdt.Fdt(out_dtb_fname)
2158 dtb.Scan()
2159 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2160 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00002161 self.assertEqual(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002162
2163 # Do a sanity check on various fields
2164 image = control.images['image']
2165 entries = image.GetEntries()
2166 self.assertEqual(1, len(entries))
2167
2168 entry = entries['blob']
2169 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2170 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2171 orig = self._decompress(entry.data)
2172 self.assertEqual(orig, entry.uncomp_data)
2173
Simon Glass72eeff12020-10-26 17:40:16 -06002174 self.assertEqual(image.data, entry.data)
2175
Simon Glass7ba33592018-09-14 04:57:26 -06002176 expected = {
2177 'blob:uncomp-size': len(COMPRESS_DATA),
2178 'blob:size': len(data),
2179 'size': len(data),
2180 }
2181 self.assertEqual(expected, props)
2182
Simon Glassac6328c2018-09-14 04:57:28 -06002183 def testFiles(self):
2184 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002185 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002186 self.assertEqual(FILES_DATA, data)
2187
2188 def testFilesCompress(self):
2189 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002190 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002191 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002192
2193 image = control.images['image']
2194 entries = image.GetEntries()
2195 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002196 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002197
Simon Glass303f62f2019-05-17 22:00:46 -06002198 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002199 for i in range(1, 3):
2200 key = '%d.dat' % i
2201 start = entries[key].image_pos
2202 len = entries[key].size
2203 chunk = data[start:start + len]
2204 orig += self._decompress(chunk)
2205
2206 self.assertEqual(FILES_DATA, orig)
2207
2208 def testFilesMissing(self):
2209 """Test missing files"""
2210 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002211 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002212 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2213 'no files', str(e.exception))
2214
2215 def testFilesNoPattern(self):
2216 """Test missing files"""
2217 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002218 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002219 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2220 str(e.exception))
2221
Simon Glassdd156a42022-03-05 20:18:59 -07002222 def testExtendSize(self):
2223 """Test an extending entry"""
2224 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002225 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002226 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2227 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2228 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2229 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002230 self.assertEqual(expect, data)
2231 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700223200000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600223300000000 00000000 00000008 fill
223400000008 00000008 00000004 u-boot
22350000000c 0000000c 00000004 section
22360000000c 00000000 00000003 intel-mrc
223700000010 00000010 00000004 u-boot2
223800000014 00000014 0000000c section2
223900000014 00000000 00000008 fill
22400000001c 00000008 00000004 u-boot
224100000020 00000020 00000008 fill2
2242''', map_data)
2243
Simon Glassdd156a42022-03-05 20:18:59 -07002244 def testExtendSizeBad(self):
2245 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002246 with test_util.capture_sys_output() as (stdout, stderr):
2247 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002248 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002249 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2250 'expanding entry', str(e.exception))
2251
Simon Glassae7cf032018-09-14 04:57:31 -06002252 def testHash(self):
2253 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002254 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002255 use_real_dtb=True, update_dtb=True)
2256 dtb = fdt.Fdt(out_dtb_fname)
2257 dtb.Scan()
2258 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2259 m = hashlib.sha256()
2260 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002261 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002262
2263 def testHashNoAlgo(self):
2264 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002265 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002266 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2267 'hash node', str(e.exception))
2268
2269 def testHashBadAlgo(self):
2270 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002271 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002272 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002273 str(e.exception))
2274
2275 def testHashSection(self):
2276 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002277 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002278 use_real_dtb=True, update_dtb=True)
2279 dtb = fdt.Fdt(out_dtb_fname)
2280 dtb.Scan()
2281 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2282 m = hashlib.sha256()
2283 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002284 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002285 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002286
Simon Glass3fb4f422018-09-14 04:57:32 -06002287 def testPackUBootTplMicrocode(self):
2288 """Test that x86 microcode can be handled correctly in TPL
2289
2290 We expect to see the following in the image, in order:
2291 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2292 place
2293 u-boot-tpl.dtb with the microcode removed
2294 the microcode
2295 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002296 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002297 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002298 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002299 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2300 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002301
Simon Glassc64aea52018-09-14 04:57:34 -06002302 def testFmapX86(self):
2303 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002304 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002305 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002306 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002307 self.assertEqual(expected, data[:32])
2308 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2309
2310 self.assertEqual(0x100, fhdr.image_size)
2311
2312 self.assertEqual(0, fentries[0].offset)
2313 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002314 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002315
2316 self.assertEqual(4, fentries[1].offset)
2317 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002318 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002319
2320 self.assertEqual(32, fentries[2].offset)
2321 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2322 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002323 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002324
2325 def testFmapX86Section(self):
2326 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002327 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002328 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002329 self.assertEqual(expected, data[:32])
2330 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2331
Simon Glassb1d414c2021-04-03 11:05:10 +13002332 self.assertEqual(0x180, fhdr.image_size)
2333 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002334 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002335
Simon Glass82059c22021-04-03 11:05:09 +13002336 fentry = next(fiter)
2337 self.assertEqual(b'U_BOOT', fentry.name)
2338 self.assertEqual(0, fentry.offset)
2339 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002340
Simon Glass82059c22021-04-03 11:05:09 +13002341 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002342 self.assertEqual(b'SECTION', fentry.name)
2343 self.assertEqual(4, fentry.offset)
2344 self.assertEqual(0x20 + expect_size, fentry.size)
2345
2346 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002347 self.assertEqual(b'INTEL_MRC', fentry.name)
2348 self.assertEqual(4, fentry.offset)
2349 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002350
Simon Glass82059c22021-04-03 11:05:09 +13002351 fentry = next(fiter)
2352 self.assertEqual(b'FMAP', fentry.name)
2353 self.assertEqual(36, fentry.offset)
2354 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002355
Simon Glassb1714232018-09-14 04:57:35 -06002356 def testElf(self):
2357 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002358 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002359 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002360 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002361 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002362 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002363
Simon Glass0d673792019-07-08 13:18:25 -06002364 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002365 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002366 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002367 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002368 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002369 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002370
Simon Glasscd817d52018-09-14 04:57:36 -06002371 def testPackOverlapMap(self):
2372 """Test that overlapping regions are detected"""
2373 with test_util.capture_sys_output() as (stdout, stderr):
2374 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002375 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002376 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002377 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2378 stdout.getvalue())
2379
2380 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002381 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002382 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002383 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002384 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002385<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002386<none> 00000000 00000004 u-boot
2387<none> 00000003 00000004 u-boot-align
2388''', map_data)
2389
Simon Glass0d673792019-07-08 13:18:25 -06002390 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002391 """Test that an image with an Intel Reference code binary works"""
2392 data = self._DoReadFile('100_intel_refcode.dts')
2393 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2394
Simon Glasseb023b32019-04-25 21:58:39 -06002395 def testSectionOffset(self):
2396 """Tests use of a section with an offset"""
2397 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2398 map=True)
2399 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700240000000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600240100000004 00000004 00000010 section@0
240200000004 00000000 00000004 u-boot
240300000018 00000018 00000010 section@1
240400000018 00000000 00000004 u-boot
24050000002c 0000002c 00000004 section@2
24060000002c 00000000 00000004 u-boot
2407''', map_data)
2408 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002409 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2410 tools.get_bytes(0x21, 12) +
2411 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2412 tools.get_bytes(0x61, 12) +
2413 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2414 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002415
Simon Glass1de34482019-07-08 13:18:53 -06002416 def testCbfsRaw(self):
2417 """Test base handling of a Coreboot Filesystem (CBFS)
2418
2419 The exact contents of the CBFS is verified by similar tests in
2420 cbfs_util_test.py. The tests here merely check that the files added to
2421 the CBFS can be found in the final image.
2422 """
2423 data = self._DoReadFile('102_cbfs_raw.dts')
2424 size = 0xb0
2425
2426 cbfs = cbfs_util.CbfsReader(data)
2427 self.assertEqual(size, cbfs.rom_size)
2428
2429 self.assertIn('u-boot-dtb', cbfs.files)
2430 cfile = cbfs.files['u-boot-dtb']
2431 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2432
2433 def testCbfsArch(self):
2434 """Test on non-x86 architecture"""
2435 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2436 size = 0x100
2437
2438 cbfs = cbfs_util.CbfsReader(data)
2439 self.assertEqual(size, cbfs.rom_size)
2440
2441 self.assertIn('u-boot-dtb', cbfs.files)
2442 cfile = cbfs.files['u-boot-dtb']
2443 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2444
2445 def testCbfsStage(self):
2446 """Tests handling of a Coreboot Filesystem (CBFS)"""
2447 if not elf.ELF_TOOLS:
2448 self.skipTest('Python elftools not available')
2449 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2450 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2451 size = 0xb0
2452
2453 data = self._DoReadFile('104_cbfs_stage.dts')
2454 cbfs = cbfs_util.CbfsReader(data)
2455 self.assertEqual(size, cbfs.rom_size)
2456
2457 self.assertIn('u-boot', cbfs.files)
2458 cfile = cbfs.files['u-boot']
2459 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2460
2461 def testCbfsRawCompress(self):
2462 """Test handling of compressing raw files"""
2463 self._CheckLz4()
2464 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2465 size = 0x140
2466
2467 cbfs = cbfs_util.CbfsReader(data)
2468 self.assertIn('u-boot', cbfs.files)
2469 cfile = cbfs.files['u-boot']
2470 self.assertEqual(COMPRESS_DATA, cfile.data)
2471
2472 def testCbfsBadArch(self):
2473 """Test handling of a bad architecture"""
2474 with self.assertRaises(ValueError) as e:
2475 self._DoReadFile('106_cbfs_bad_arch.dts')
2476 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2477
2478 def testCbfsNoSize(self):
2479 """Test handling of a missing size property"""
2480 with self.assertRaises(ValueError) as e:
2481 self._DoReadFile('107_cbfs_no_size.dts')
2482 self.assertIn('entry must have a size property', str(e.exception))
2483
Simon Glass3e28f4f2021-11-23 11:03:54 -07002484 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002485 """Test handling of a CBFS entry which does not provide contentsy"""
2486 with self.assertRaises(ValueError) as e:
2487 self._DoReadFile('108_cbfs_no_contents.dts')
2488 self.assertIn('Could not complete processing of contents',
2489 str(e.exception))
2490
2491 def testCbfsBadCompress(self):
2492 """Test handling of a bad architecture"""
2493 with self.assertRaises(ValueError) as e:
2494 self._DoReadFile('109_cbfs_bad_compress.dts')
2495 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2496 str(e.exception))
2497
2498 def testCbfsNamedEntries(self):
2499 """Test handling of named entries"""
2500 data = self._DoReadFile('110_cbfs_name.dts')
2501
2502 cbfs = cbfs_util.CbfsReader(data)
2503 self.assertIn('FRED', cbfs.files)
2504 cfile1 = cbfs.files['FRED']
2505 self.assertEqual(U_BOOT_DATA, cfile1.data)
2506
2507 self.assertIn('hello', cbfs.files)
2508 cfile2 = cbfs.files['hello']
2509 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2510
Simon Glass759af872019-07-08 13:18:54 -06002511 def _SetupIfwi(self, fname):
2512 """Set up to run an IFWI test
2513
2514 Args:
2515 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2516 """
2517 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002518 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002519
2520 # Intel Integrated Firmware Image (IFWI) file
2521 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2522 data = fd.read()
2523 TestFunctional._MakeInputFile(fname,data)
2524
2525 def _CheckIfwi(self, data):
2526 """Check that an image with an IFWI contains the correct output
2527
2528 Args:
2529 data: Conents of output file
2530 """
Simon Glass80025522022-01-29 14:14:04 -07002531 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002532 if data[:0x1000] != expected_desc:
2533 self.fail('Expected descriptor binary at start of image')
2534
2535 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002536 image_fname = tools.get_output_filename('image.bin')
2537 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002538 ifwitool = bintool.Bintool.create('ifwitool')
2539 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002540
Simon Glass80025522022-01-29 14:14:04 -07002541 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002542 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002543
2544 def testPackX86RomIfwi(self):
2545 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2546 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002547 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002548 self._CheckIfwi(data)
2549
2550 def testPackX86RomIfwiNoDesc(self):
2551 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2552 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002553 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002554 self._CheckIfwi(data)
2555
2556 def testPackX86RomIfwiNoData(self):
2557 """Test that an x86 ROM with IFWI handles missing data"""
2558 self._SetupIfwi('ifwi.bin')
2559 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002560 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002561 self.assertIn('Could not complete processing of contents',
2562 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002563
Simon Glass66152ce2022-01-09 20:14:09 -07002564 def testIfwiMissing(self):
2565 """Test that binman still produces an image if ifwitool is missing"""
2566 self._SetupIfwi('fitimage.bin')
2567 with test_util.capture_sys_output() as (_, stderr):
2568 self._DoTestFile('111_x86_rom_ifwi.dts',
2569 force_missing_bintools='ifwitool')
2570 err = stderr.getvalue()
2571 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002572 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002573
Simon Glassc2f1aed2019-07-08 13:18:56 -06002574 def testCbfsOffset(self):
2575 """Test a CBFS with files at particular offsets
2576
2577 Like all CFBS tests, this is just checking the logic that calls
2578 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2579 """
2580 data = self._DoReadFile('114_cbfs_offset.dts')
2581 size = 0x200
2582
2583 cbfs = cbfs_util.CbfsReader(data)
2584 self.assertEqual(size, cbfs.rom_size)
2585
2586 self.assertIn('u-boot', cbfs.files)
2587 cfile = cbfs.files['u-boot']
2588 self.assertEqual(U_BOOT_DATA, cfile.data)
2589 self.assertEqual(0x40, cfile.cbfs_offset)
2590
2591 self.assertIn('u-boot-dtb', cbfs.files)
2592 cfile2 = cbfs.files['u-boot-dtb']
2593 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2594 self.assertEqual(0x140, cfile2.cbfs_offset)
2595
Simon Glass0f621332019-07-08 14:25:27 -06002596 def testFdtmap(self):
2597 """Test an FDT map can be inserted in the image"""
2598 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2599 fdtmap_data = data[len(U_BOOT_DATA):]
2600 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002601 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002602 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002603
2604 fdt_data = fdtmap_data[16:]
2605 dtb = fdt.Fdt.FromData(fdt_data)
2606 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002607 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002608 self.assertEqual({
2609 'image-pos': 0,
2610 'offset': 0,
2611 'u-boot:offset': 0,
2612 'u-boot:size': len(U_BOOT_DATA),
2613 'u-boot:image-pos': 0,
2614 'fdtmap:image-pos': 4,
2615 'fdtmap:offset': 4,
2616 'fdtmap:size': len(fdtmap_data),
2617 'size': len(data),
2618 }, props)
2619
2620 def testFdtmapNoMatch(self):
2621 """Check handling of an FDT map when the section cannot be found"""
2622 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2623
2624 # Mangle the section name, which should cause a mismatch between the
2625 # correct FDT path and the one expected by the section
2626 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002627 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002628 entries = image.GetEntries()
2629 fdtmap = entries['fdtmap']
2630 with self.assertRaises(ValueError) as e:
2631 fdtmap._GetFdtmap()
2632 self.assertIn("Cannot locate node for path '/binman-suffix'",
2633 str(e.exception))
2634
Simon Glasscec34ba2019-07-08 14:25:28 -06002635 def testFdtmapHeader(self):
2636 """Test an FDT map and image header can be inserted in the image"""
2637 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2638 fdtmap_pos = len(U_BOOT_DATA)
2639 fdtmap_data = data[fdtmap_pos:]
2640 fdt_data = fdtmap_data[16:]
2641 dtb = fdt.Fdt.FromData(fdt_data)
2642 fdt_size = dtb.GetFdtObj().totalsize()
2643 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002644 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002645 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2646 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2647
2648 def testFdtmapHeaderStart(self):
2649 """Test an image header can be inserted at the image start"""
2650 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2651 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2652 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002653 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002654 offset = struct.unpack('<I', hdr_data[4:])[0]
2655 self.assertEqual(fdtmap_pos, offset)
2656
2657 def testFdtmapHeaderPos(self):
2658 """Test an image header can be inserted at a chosen position"""
2659 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2660 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2661 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002662 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002663 offset = struct.unpack('<I', hdr_data[4:])[0]
2664 self.assertEqual(fdtmap_pos, offset)
2665
2666 def testHeaderMissingFdtmap(self):
2667 """Test an image header requires an fdtmap"""
2668 with self.assertRaises(ValueError) as e:
2669 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2670 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2671 str(e.exception))
2672
2673 def testHeaderNoLocation(self):
2674 """Test an image header with a no specified location is detected"""
2675 with self.assertRaises(ValueError) as e:
2676 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2677 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2678 str(e.exception))
2679
Simon Glasse61b6f62019-07-08 14:25:37 -06002680 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002681 """Test extending an entry after it is packed"""
2682 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002683 self.assertEqual(b'aaa', data[:3])
2684 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2685 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002686
Simon Glassdd156a42022-03-05 20:18:59 -07002687 def testEntryExtendBad(self):
2688 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002689 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002690 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002691 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002692 str(e.exception))
2693
Simon Glassdd156a42022-03-05 20:18:59 -07002694 def testEntryExtendSection(self):
2695 """Test extending an entry within a section after it is packed"""
2696 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002697 self.assertEqual(b'aaa', data[:3])
2698 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2699 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002700
Simon Glass90d29682019-07-08 14:25:38 -06002701 def testCompressDtb(self):
2702 """Test that compress of device-tree files is supported"""
2703 self._CheckLz4()
2704 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2705 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2706 comp_data = data[len(U_BOOT_DATA):]
2707 orig = self._decompress(comp_data)
2708 dtb = fdt.Fdt.FromData(orig)
2709 dtb.Scan()
2710 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2711 expected = {
2712 'u-boot:size': len(U_BOOT_DATA),
2713 'u-boot-dtb:uncomp-size': len(orig),
2714 'u-boot-dtb:size': len(comp_data),
2715 'size': len(data),
2716 }
2717 self.assertEqual(expected, props)
2718
Simon Glass151bbbf2019-07-08 14:25:41 -06002719 def testCbfsUpdateFdt(self):
2720 """Test that we can update the device tree with CBFS offset/size info"""
2721 self._CheckLz4()
2722 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2723 update_dtb=True)
2724 dtb = fdt.Fdt(out_dtb_fname)
2725 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002726 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002727 del props['cbfs/u-boot:size']
2728 self.assertEqual({
2729 'offset': 0,
2730 'size': len(data),
2731 'image-pos': 0,
2732 'cbfs:offset': 0,
2733 'cbfs:size': len(data),
2734 'cbfs:image-pos': 0,
Simon Glassfa144222023-10-14 14:40:28 -06002735 'cbfs/u-boot:offset': 0x30,
Simon Glass151bbbf2019-07-08 14:25:41 -06002736 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002737 'cbfs/u-boot:image-pos': 0x30,
2738 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002739 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002740 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002741 }, props)
2742
Simon Glass3c9b4f22019-07-08 14:25:42 -06002743 def testCbfsBadType(self):
2744 """Test an image header with a no specified location is detected"""
2745 with self.assertRaises(ValueError) as e:
2746 self._DoReadFile('126_cbfs_bad_type.dts')
2747 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2748
Simon Glass6b156f82019-07-08 14:25:43 -06002749 def testList(self):
2750 """Test listing the files in an image"""
2751 self._CheckLz4()
2752 data = self._DoReadFile('127_list.dts')
2753 image = control.images['image']
2754 entries = image.BuildEntryList()
2755 self.assertEqual(7, len(entries))
2756
2757 ent = entries[0]
2758 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002759 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002760 self.assertEqual('section', ent.etype)
2761 self.assertEqual(len(data), ent.size)
2762 self.assertEqual(0, ent.image_pos)
2763 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002764 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002765
2766 ent = entries[1]
2767 self.assertEqual(1, ent.indent)
2768 self.assertEqual('u-boot', ent.name)
2769 self.assertEqual('u-boot', ent.etype)
2770 self.assertEqual(len(U_BOOT_DATA), ent.size)
2771 self.assertEqual(0, ent.image_pos)
2772 self.assertEqual(None, ent.uncomp_size)
2773 self.assertEqual(0, ent.offset)
2774
2775 ent = entries[2]
2776 self.assertEqual(1, ent.indent)
2777 self.assertEqual('section', ent.name)
2778 self.assertEqual('section', ent.etype)
2779 section_size = ent.size
2780 self.assertEqual(0x100, ent.image_pos)
2781 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002782 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002783
2784 ent = entries[3]
2785 self.assertEqual(2, ent.indent)
2786 self.assertEqual('cbfs', ent.name)
2787 self.assertEqual('cbfs', ent.etype)
2788 self.assertEqual(0x400, ent.size)
2789 self.assertEqual(0x100, ent.image_pos)
2790 self.assertEqual(None, ent.uncomp_size)
2791 self.assertEqual(0, ent.offset)
2792
2793 ent = entries[4]
2794 self.assertEqual(3, ent.indent)
2795 self.assertEqual('u-boot', ent.name)
2796 self.assertEqual('u-boot', ent.etype)
2797 self.assertEqual(len(U_BOOT_DATA), ent.size)
2798 self.assertEqual(0x138, ent.image_pos)
2799 self.assertEqual(None, ent.uncomp_size)
2800 self.assertEqual(0x38, ent.offset)
2801
2802 ent = entries[5]
2803 self.assertEqual(3, ent.indent)
2804 self.assertEqual('u-boot-dtb', ent.name)
2805 self.assertEqual('text', ent.etype)
2806 self.assertGreater(len(COMPRESS_DATA), ent.size)
2807 self.assertEqual(0x178, ent.image_pos)
2808 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2809 self.assertEqual(0x78, ent.offset)
2810
2811 ent = entries[6]
2812 self.assertEqual(2, ent.indent)
2813 self.assertEqual('u-boot-dtb', ent.name)
2814 self.assertEqual('u-boot-dtb', ent.etype)
2815 self.assertEqual(0x500, ent.image_pos)
2816 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2817 dtb_size = ent.size
2818 # Compressing this data expands it since headers are added
2819 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2820 self.assertEqual(0x400, ent.offset)
2821
2822 self.assertEqual(len(data), 0x100 + section_size)
2823 self.assertEqual(section_size, 0x400 + dtb_size)
2824
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002825 def testFindFdtmap(self):
2826 """Test locating an FDT map in an image"""
2827 self._CheckLz4()
2828 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2829 image = control.images['image']
2830 entries = image.GetEntries()
2831 entry = entries['fdtmap']
2832 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2833
2834 def testFindFdtmapMissing(self):
2835 """Test failing to locate an FDP map"""
2836 data = self._DoReadFile('005_simple.dts')
2837 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2838
Simon Glassed39a3c2019-07-08 14:25:45 -06002839 def testFindImageHeader(self):
2840 """Test locating a image header"""
2841 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002842 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002843 image = control.images['image']
2844 entries = image.GetEntries()
2845 entry = entries['fdtmap']
2846 # The header should point to the FDT map
2847 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2848
2849 def testFindImageHeaderStart(self):
2850 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002851 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002852 image = control.images['image']
2853 entries = image.GetEntries()
2854 entry = entries['fdtmap']
2855 # The header should point to the FDT map
2856 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2857
2858 def testFindImageHeaderMissing(self):
2859 """Test failing to locate an image header"""
2860 data = self._DoReadFile('005_simple.dts')
2861 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2862
Simon Glassb8424fa2019-07-08 14:25:46 -06002863 def testReadImage(self):
2864 """Test reading an image and accessing its FDT map"""
2865 self._CheckLz4()
2866 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002867 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002868 orig_image = control.images['image']
2869 image = Image.FromFile(image_fname)
2870 self.assertEqual(orig_image.GetEntries().keys(),
2871 image.GetEntries().keys())
2872
2873 orig_entry = orig_image.GetEntries()['fdtmap']
2874 entry = image.GetEntries()['fdtmap']
Brandon Maiera657bc62024-06-04 16:16:05 +00002875 self.assertEqual(orig_entry.offset, entry.offset)
2876 self.assertEqual(orig_entry.size, entry.size)
2877 self.assertEqual(orig_entry.image_pos, entry.image_pos)
Simon Glassb8424fa2019-07-08 14:25:46 -06002878
2879 def testReadImageNoHeader(self):
2880 """Test accessing an image's FDT map without an image header"""
2881 self._CheckLz4()
2882 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002883 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002884 image = Image.FromFile(image_fname)
2885 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002886 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002887
2888 def testReadImageFail(self):
2889 """Test failing to read an image image's FDT map"""
2890 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002891 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002892 with self.assertRaises(ValueError) as e:
2893 image = Image.FromFile(image_fname)
2894 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002895
Simon Glassb2fd11d2019-07-08 14:25:48 -06002896 def testListCmd(self):
2897 """Test listing the files in an image using an Fdtmap"""
2898 self._CheckLz4()
2899 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2900
2901 # lz4 compression size differs depending on the version
2902 image = control.images['image']
2903 entries = image.GetEntries()
2904 section_size = entries['section'].size
2905 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2906 fdtmap_offset = entries['fdtmap'].offset
2907
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002908 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002909 try:
2910 tmpdir, updated_fname = self._SetupImageInTmpdir()
2911 with test_util.capture_sys_output() as (stdout, stderr):
2912 self._DoBinman('ls', '-i', updated_fname)
2913 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002914 if tmpdir:
2915 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002916 lines = stdout.getvalue().splitlines()
2917 expected = [
2918'Name Image-pos Size Entry-type Offset Uncomp-size',
2919'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002920'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002921' u-boot 0 4 u-boot 0',
2922' section 100 %x section 100' % section_size,
2923' cbfs 100 400 cbfs 0',
Simon Glassfa144222023-10-14 14:40:28 -06002924' u-boot 120 4 u-boot 20',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002925' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002926' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002927' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002928 (fdtmap_offset, fdtmap_offset),
2929' image-header bf8 8 image-header bf8',
2930 ]
2931 self.assertEqual(expected, lines)
2932
2933 def testListCmdFail(self):
2934 """Test failing to list an image"""
2935 self._DoReadFile('005_simple.dts')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002936 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002937 try:
2938 tmpdir, updated_fname = self._SetupImageInTmpdir()
2939 with self.assertRaises(ValueError) as e:
2940 self._DoBinman('ls', '-i', updated_fname)
2941 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002942 if tmpdir:
2943 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002944 self.assertIn("Cannot find FDT map in image", str(e.exception))
2945
2946 def _RunListCmd(self, paths, expected):
2947 """List out entries and check the result
2948
2949 Args:
2950 paths: List of paths to pass to the list command
2951 expected: Expected list of filenames to be returned, in order
2952 """
2953 self._CheckLz4()
2954 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002955 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002956 image = Image.FromFile(image_fname)
2957 lines = image.GetListEntries(paths)[1]
2958 files = [line[0].strip() for line in lines[1:]]
2959 self.assertEqual(expected, files)
2960
2961 def testListCmdSection(self):
2962 """Test listing the files in a section"""
2963 self._RunListCmd(['section'],
2964 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2965
2966 def testListCmdFile(self):
2967 """Test listing a particular file"""
2968 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2969
2970 def testListCmdWildcard(self):
2971 """Test listing a wildcarded file"""
2972 self._RunListCmd(['*boot*'],
2973 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2974
2975 def testListCmdWildcardMulti(self):
2976 """Test listing a wildcarded file"""
2977 self._RunListCmd(['*cb*', '*head*'],
2978 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2979
2980 def testListCmdEmpty(self):
2981 """Test listing a wildcarded file"""
2982 self._RunListCmd(['nothing'], [])
2983
2984 def testListCmdPath(self):
2985 """Test listing the files in a sub-entry of a section"""
2986 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2987
Simon Glass4c613bf2019-07-08 14:25:50 -06002988 def _RunExtractCmd(self, entry_name, decomp=True):
2989 """Extract an entry from an image
2990
2991 Args:
2992 entry_name: Entry name to extract
2993 decomp: True to decompress the data if compressed, False to leave
2994 it in its raw uncompressed format
2995
2996 Returns:
2997 data from entry
2998 """
2999 self._CheckLz4()
3000 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003001 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06003002 return control.ReadEntry(image_fname, entry_name, decomp)
3003
3004 def testExtractSimple(self):
3005 """Test extracting a single file"""
3006 data = self._RunExtractCmd('u-boot')
3007 self.assertEqual(U_BOOT_DATA, data)
3008
Simon Glass980a2842019-07-08 14:25:52 -06003009 def testExtractSection(self):
3010 """Test extracting the files in a section"""
3011 data = self._RunExtractCmd('section')
3012 cbfs_data = data[:0x400]
3013 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06003014 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06003015 dtb_data = data[0x400:]
3016 dtb = self._decompress(dtb_data)
3017 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3018
3019 def testExtractCompressed(self):
3020 """Test extracting compressed data"""
3021 data = self._RunExtractCmd('section/u-boot-dtb')
3022 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3023
3024 def testExtractRaw(self):
3025 """Test extracting compressed data without decompressing it"""
3026 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
3027 dtb = self._decompress(data)
3028 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3029
3030 def testExtractCbfs(self):
3031 """Test extracting CBFS data"""
3032 data = self._RunExtractCmd('section/cbfs/u-boot')
3033 self.assertEqual(U_BOOT_DATA, data)
3034
3035 def testExtractCbfsCompressed(self):
3036 """Test extracting CBFS compressed data"""
3037 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
3038 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3039
3040 def testExtractCbfsRaw(self):
3041 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003042 bintool = self.comp_bintools['lzma_alone']
3043 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06003044 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003045 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06003046 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3047
Simon Glass4c613bf2019-07-08 14:25:50 -06003048 def testExtractBadEntry(self):
3049 """Test extracting a bad section path"""
3050 with self.assertRaises(ValueError) as e:
3051 self._RunExtractCmd('section/does-not-exist')
3052 self.assertIn("Entry 'does-not-exist' not found in '/section'",
3053 str(e.exception))
3054
3055 def testExtractMissingFile(self):
3056 """Test extracting file that does not exist"""
3057 with self.assertRaises(IOError) as e:
3058 control.ReadEntry('missing-file', 'name')
3059
3060 def testExtractBadFile(self):
3061 """Test extracting an invalid file"""
3062 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07003063 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06003064 with self.assertRaises(ValueError) as e:
3065 control.ReadEntry(fname, 'name')
3066
Simon Glass980a2842019-07-08 14:25:52 -06003067 def testExtractCmd(self):
3068 """Test extracting a file fron an image on the command line"""
3069 self._CheckLz4()
3070 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06003071 fname = os.path.join(self._indir, 'output.extact')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003072 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06003073 try:
3074 tmpdir, updated_fname = self._SetupImageInTmpdir()
3075 with test_util.capture_sys_output() as (stdout, stderr):
3076 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3077 '-f', fname)
3078 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003079 if tmpdir:
3080 shutil.rmtree(tmpdir)
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 testExtractOneEntry(self):
3085 """Test extracting a single entry fron an image """
3086 self._CheckLz4()
3087 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003088 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003089 fname = os.path.join(self._indir, 'output.extact')
3090 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003091 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003092 self.assertEqual(U_BOOT_DATA, data)
3093
3094 def _CheckExtractOutput(self, decomp):
3095 """Helper to test file output with and without decompression
3096
3097 Args:
3098 decomp: True to decompress entry data, False to output it raw
3099 """
3100 def _CheckPresent(entry_path, expect_data, expect_size=None):
3101 """Check and remove expected file
3102
3103 This checks the data/size of a file and removes the file both from
3104 the outfiles set and from the output directory. Once all files are
3105 processed, both the set and directory should be empty.
3106
3107 Args:
3108 entry_path: Entry path
3109 expect_data: Data to expect in file, or None to skip check
3110 expect_size: Size of data to expect in file, or None to skip
3111 """
3112 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003113 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003114 os.remove(path)
3115 if expect_data:
3116 self.assertEqual(expect_data, data)
3117 elif expect_size:
3118 self.assertEqual(expect_size, len(data))
3119 outfiles.remove(path)
3120
3121 def _CheckDirPresent(name):
3122 """Remove expected directory
3123
3124 This gives an error if the directory does not exist as expected
3125
3126 Args:
3127 name: Name of directory to remove
3128 """
3129 path = os.path.join(outdir, name)
3130 os.rmdir(path)
3131
3132 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003133 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003134 outdir = os.path.join(self._indir, 'extract')
3135 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3136
3137 # Create a set of all file that were output (should be 9)
3138 outfiles = set()
3139 for root, dirs, files in os.walk(outdir):
3140 outfiles |= set([os.path.join(root, fname) for fname in files])
3141 self.assertEqual(9, len(outfiles))
3142 self.assertEqual(9, len(einfos))
3143
3144 image = control.images['image']
3145 entries = image.GetEntries()
3146
3147 # Check the 9 files in various ways
3148 section = entries['section']
3149 section_entries = section.GetEntries()
3150 cbfs_entries = section_entries['cbfs'].GetEntries()
3151 _CheckPresent('u-boot', U_BOOT_DATA)
3152 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3153 dtb_len = EXTRACT_DTB_SIZE
3154 if not decomp:
3155 dtb_len = cbfs_entries['u-boot-dtb'].size
3156 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3157 if not decomp:
3158 dtb_len = section_entries['u-boot-dtb'].size
3159 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3160
3161 fdtmap = entries['fdtmap']
3162 _CheckPresent('fdtmap', fdtmap.data)
3163 hdr = entries['image-header']
3164 _CheckPresent('image-header', hdr.data)
3165
3166 _CheckPresent('section/root', section.data)
3167 cbfs = section_entries['cbfs']
3168 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003169 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003170 _CheckPresent('root', data)
3171
3172 # There should be no files left. Remove all the directories to check.
3173 # If there are any files/dirs remaining, one of these checks will fail.
3174 self.assertEqual(0, len(outfiles))
3175 _CheckDirPresent('section/cbfs')
3176 _CheckDirPresent('section')
3177 _CheckDirPresent('')
3178 self.assertFalse(os.path.exists(outdir))
3179
3180 def testExtractAllEntries(self):
3181 """Test extracting all entries"""
3182 self._CheckLz4()
3183 self._CheckExtractOutput(decomp=True)
3184
3185 def testExtractAllEntriesRaw(self):
3186 """Test extracting all entries without decompressing them"""
3187 self._CheckLz4()
3188 self._CheckExtractOutput(decomp=False)
3189
3190 def testExtractSelectedEntries(self):
3191 """Test extracting some entries"""
3192 self._CheckLz4()
3193 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003194 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003195 outdir = os.path.join(self._indir, 'extract')
3196 einfos = control.ExtractEntries(image_fname, None, outdir,
3197 ['*cb*', '*head*'])
3198
3199 # File output is tested by testExtractAllEntries(), so just check that
3200 # the expected entries are selected
3201 names = [einfo.name for einfo in einfos]
3202 self.assertEqual(names,
3203 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3204
3205 def testExtractNoEntryPaths(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, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003212 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003213 str(e.exception))
3214
3215 def testExtractTooManyEntryPaths(self):
3216 """Test extracting some entries"""
3217 self._CheckLz4()
3218 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003219 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003220 with self.assertRaises(ValueError) as e:
3221 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003222 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003223 str(e.exception))
3224
Simon Glass52d06212019-07-08 14:25:53 -06003225 def testPackAlignSection(self):
3226 """Test that sections can have alignment"""
3227 self._DoReadFile('131_pack_align_section.dts')
3228
3229 self.assertIn('image', control.images)
3230 image = control.images['image']
3231 entries = image.GetEntries()
3232 self.assertEqual(3, len(entries))
3233
3234 # First u-boot
3235 self.assertIn('u-boot', entries)
3236 entry = entries['u-boot']
3237 self.assertEqual(0, entry.offset)
3238 self.assertEqual(0, entry.image_pos)
3239 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3240 self.assertEqual(len(U_BOOT_DATA), entry.size)
3241
3242 # Section0
3243 self.assertIn('section0', entries)
3244 section0 = entries['section0']
3245 self.assertEqual(0x10, section0.offset)
3246 self.assertEqual(0x10, section0.image_pos)
3247 self.assertEqual(len(U_BOOT_DATA), section0.size)
3248
3249 # Second u-boot
3250 section_entries = section0.GetEntries()
3251 self.assertIn('u-boot', section_entries)
3252 entry = section_entries['u-boot']
3253 self.assertEqual(0, entry.offset)
3254 self.assertEqual(0x10, entry.image_pos)
3255 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3256 self.assertEqual(len(U_BOOT_DATA), entry.size)
3257
3258 # Section1
3259 self.assertIn('section1', entries)
3260 section1 = entries['section1']
3261 self.assertEqual(0x14, section1.offset)
3262 self.assertEqual(0x14, section1.image_pos)
3263 self.assertEqual(0x20, section1.size)
3264
3265 # Second u-boot
3266 section_entries = section1.GetEntries()
3267 self.assertIn('u-boot', section_entries)
3268 entry = section_entries['u-boot']
3269 self.assertEqual(0, entry.offset)
3270 self.assertEqual(0x14, entry.image_pos)
3271 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3272 self.assertEqual(len(U_BOOT_DATA), entry.size)
3273
3274 # Section2
3275 self.assertIn('section2', section_entries)
3276 section2 = section_entries['section2']
3277 self.assertEqual(0x4, section2.offset)
3278 self.assertEqual(0x18, section2.image_pos)
3279 self.assertEqual(4, section2.size)
3280
3281 # Third u-boot
3282 section_entries = section2.GetEntries()
3283 self.assertIn('u-boot', section_entries)
3284 entry = section_entries['u-boot']
3285 self.assertEqual(0, entry.offset)
3286 self.assertEqual(0x18, entry.image_pos)
3287 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3288 self.assertEqual(len(U_BOOT_DATA), entry.size)
3289
Simon Glassf8a54bc2019-07-20 12:23:56 -06003290 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3291 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003292 """Replace an entry in an image
3293
3294 This writes the entry data to update it, then opens the updated file and
3295 returns the value that it now finds there.
3296
3297 Args:
3298 entry_name: Entry name to replace
3299 data: Data to replace it with
3300 decomp: True to compress the data if needed, False if data is
3301 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003302 allow_resize: True to allow entries to change size, False to raise
3303 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003304
3305 Returns:
3306 Tuple:
3307 data from entry
3308 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003309 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003310 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003311 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003312 update_dtb=True)[1]
3313
3314 self.assertIn('image', control.images)
3315 image = control.images['image']
3316 entries = image.GetEntries()
3317 orig_dtb_data = entries['u-boot-dtb'].data
3318 orig_fdtmap_data = entries['fdtmap'].data
3319
Simon Glass80025522022-01-29 14:14:04 -07003320 image_fname = tools.get_output_filename('image.bin')
3321 updated_fname = tools.get_output_filename('image-updated.bin')
3322 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003323 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3324 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003325 data = control.ReadEntry(updated_fname, entry_name, decomp)
3326
Simon Glassf8a54bc2019-07-20 12:23:56 -06003327 # The DT data should not change unless resized:
3328 if not allow_resize:
3329 new_dtb_data = entries['u-boot-dtb'].data
3330 self.assertEqual(new_dtb_data, orig_dtb_data)
3331 new_fdtmap_data = entries['fdtmap'].data
3332 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003333
Simon Glassf8a54bc2019-07-20 12:23:56 -06003334 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003335
3336 def testReplaceSimple(self):
3337 """Test replacing a single file"""
3338 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003339 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3340 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003341 self.assertEqual(expected, data)
3342
3343 # Test that the state looks right. There should be an FDT for the fdtmap
3344 # that we jsut read back in, and it should match what we find in the
3345 # 'control' tables. Checking for an FDT that does not exist should
3346 # return None.
3347 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003348 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003349 self.assertEqual(expected_fdtmap, fdtmap)
3350
3351 dtb = state.GetFdtForEtype('fdtmap')
3352 self.assertEqual(dtb.GetContents(), fdtmap)
3353
3354 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3355 self.assertIsNone(missing_path)
3356 self.assertIsNone(missing_fdtmap)
3357
3358 missing_dtb = state.GetFdtForEtype('missing')
3359 self.assertIsNone(missing_dtb)
3360
3361 self.assertEqual('/binman', state.fdt_path_prefix)
3362
3363 def testReplaceResizeFail(self):
3364 """Test replacing a file by something larger"""
3365 expected = U_BOOT_DATA + b'x'
3366 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003367 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3368 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003369 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3370 str(e.exception))
3371
3372 def testReplaceMulti(self):
3373 """Test replacing entry data where multiple images are generated"""
3374 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3375 update_dtb=True)[0]
3376 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003377 updated_fname = tools.get_output_filename('image-updated.bin')
3378 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003379 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003380 control.WriteEntry(updated_fname, entry_name, expected,
3381 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003382 data = control.ReadEntry(updated_fname, entry_name)
3383 self.assertEqual(expected, data)
3384
3385 # Check the state looks right.
3386 self.assertEqual('/binman/image', state.fdt_path_prefix)
3387
3388 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003389 image_fname = tools.get_output_filename('first-image.bin')
3390 updated_fname = tools.get_output_filename('first-updated.bin')
3391 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003392 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003393 control.WriteEntry(updated_fname, entry_name, expected,
3394 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003395 data = control.ReadEntry(updated_fname, entry_name)
3396 self.assertEqual(expected, data)
3397
3398 # Check the state looks right.
3399 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003400
Simon Glassfb30e292019-07-20 12:23:51 -06003401 def testUpdateFdtAllRepack(self):
3402 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003403 self._SetupSplElf()
3404 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003405 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3406 SECTION_SIZE = 0x300
3407 DTB_SIZE = 602
3408 FDTMAP_SIZE = 608
3409 base_expected = {
3410 'offset': 0,
3411 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3412 'image-pos': 0,
3413 'section:offset': 0,
3414 'section:size': SECTION_SIZE,
3415 'section:image-pos': 0,
3416 'section/u-boot-dtb:offset': 4,
3417 'section/u-boot-dtb:size': 636,
3418 'section/u-boot-dtb:image-pos': 4,
3419 'u-boot-spl-dtb:offset': SECTION_SIZE,
3420 'u-boot-spl-dtb:size': DTB_SIZE,
3421 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3422 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3423 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3424 'u-boot-tpl-dtb:size': DTB_SIZE,
3425 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3426 'fdtmap:size': FDTMAP_SIZE,
3427 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3428 }
3429 main_expected = {
3430 'section:orig-size': SECTION_SIZE,
3431 'section/u-boot-dtb:orig-offset': 4,
3432 }
3433
3434 # We expect three device-tree files in the output, with the first one
3435 # within a fixed-size section.
3436 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3437 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3438 # main U-Boot tree. All three should have the same positions and offset
3439 # except that the main tree should include the main_expected properties
3440 start = 4
3441 for item in ['', 'spl', 'tpl', None]:
3442 if item is None:
3443 start += 16 # Move past fdtmap header
3444 dtb = fdt.Fdt.FromData(data[start:])
3445 dtb.Scan()
3446 props = self._GetPropTree(dtb,
3447 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3448 prefix='/' if item is None else '/binman/')
3449 expected = dict(base_expected)
3450 if item:
3451 expected[item] = 0
3452 else:
3453 # Main DTB and fdtdec should include the 'orig-' properties
3454 expected.update(main_expected)
3455 # Helpful for debugging:
3456 #for prop in sorted(props):
3457 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3458 self.assertEqual(expected, props)
3459 if item == '':
3460 start = SECTION_SIZE
3461 else:
3462 start += dtb._fdt_obj.totalsize()
3463
Simon Glass11453762019-07-20 12:23:55 -06003464 def testFdtmapHeaderMiddle(self):
3465 """Test an FDT map in the middle of an image when it should be at end"""
3466 with self.assertRaises(ValueError) as e:
3467 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3468 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3469 str(e.exception))
3470
3471 def testFdtmapHeaderStartBad(self):
3472 """Test an FDT map in middle of an image when it should be at start"""
3473 with self.assertRaises(ValueError) as e:
3474 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3475 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3476 str(e.exception))
3477
3478 def testFdtmapHeaderEndBad(self):
3479 """Test an FDT map at the start of an image when it should be at end"""
3480 with self.assertRaises(ValueError) as e:
3481 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3482 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3483 str(e.exception))
3484
3485 def testFdtmapHeaderNoSize(self):
3486 """Test an image header at the end of an image with undefined size"""
3487 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3488
Simon Glassf8a54bc2019-07-20 12:23:56 -06003489 def testReplaceResize(self):
3490 """Test replacing a single file in an entry with a larger file"""
3491 expected = U_BOOT_DATA + b'x'
3492 data, _, image = self._RunReplaceCmd('u-boot', expected,
3493 dts='139_replace_repack.dts')
3494 self.assertEqual(expected, data)
3495
3496 entries = image.GetEntries()
3497 dtb_data = entries['u-boot-dtb'].data
3498 dtb = fdt.Fdt.FromData(dtb_data)
3499 dtb.Scan()
3500
3501 # The u-boot section should now be larger in the dtb
3502 node = dtb.GetNode('/binman/u-boot')
3503 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3504
3505 # Same for the fdtmap
3506 fdata = entries['fdtmap'].data
3507 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3508 fdtb.Scan()
3509 fnode = fdtb.GetNode('/u-boot')
3510 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3511
3512 def testReplaceResizeNoRepack(self):
3513 """Test replacing an entry with a larger file when not allowed"""
3514 expected = U_BOOT_DATA + b'x'
3515 with self.assertRaises(ValueError) as e:
3516 self._RunReplaceCmd('u-boot', expected)
3517 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3518 str(e.exception))
3519
Simon Glass9d8ee322019-07-20 12:23:58 -06003520 def testEntryShrink(self):
3521 """Test contracting an entry after it is packed"""
3522 try:
3523 state.SetAllowEntryContraction(True)
3524 data = self._DoReadFileDtb('140_entry_shrink.dts',
3525 update_dtb=True)[0]
3526 finally:
3527 state.SetAllowEntryContraction(False)
3528 self.assertEqual(b'a', data[:1])
3529 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3530 self.assertEqual(b'a', data[-1:])
3531
3532 def testEntryShrinkFail(self):
3533 """Test not being allowed to contract an entry after it is packed"""
3534 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3535
3536 # In this case there is a spare byte at the end of the data. The size of
3537 # the contents is only 1 byte but we still have the size before it
3538 # shrunk.
3539 self.assertEqual(b'a\0', data[:2])
3540 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3541 self.assertEqual(b'a\0', data[-2:])
3542
Simon Glass70e32982019-07-20 12:24:01 -06003543 def testDescriptorOffset(self):
3544 """Test that the Intel descriptor is always placed at at the start"""
3545 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3546 image = control.images['image']
3547 entries = image.GetEntries()
3548 desc = entries['intel-descriptor']
3549 self.assertEqual(0xff800000, desc.offset);
3550 self.assertEqual(0xff800000, desc.image_pos);
3551
Simon Glass37fdd142019-07-20 12:24:06 -06003552 def testReplaceCbfs(self):
3553 """Test replacing a single file in CBFS without changing the size"""
3554 self._CheckLz4()
3555 expected = b'x' * len(U_BOOT_DATA)
3556 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003557 updated_fname = tools.get_output_filename('image-updated.bin')
3558 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003559 entry_name = 'section/cbfs/u-boot'
3560 control.WriteEntry(updated_fname, entry_name, expected,
3561 allow_resize=True)
3562 data = control.ReadEntry(updated_fname, entry_name)
3563 self.assertEqual(expected, data)
3564
3565 def testReplaceResizeCbfs(self):
3566 """Test replacing a single file in CBFS with one of a different size"""
3567 self._CheckLz4()
3568 expected = U_BOOT_DATA + b'x'
3569 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003570 updated_fname = tools.get_output_filename('image-updated.bin')
3571 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003572 entry_name = 'section/cbfs/u-boot'
3573 control.WriteEntry(updated_fname, entry_name, expected,
3574 allow_resize=True)
3575 data = control.ReadEntry(updated_fname, entry_name)
3576 self.assertEqual(expected, data)
3577
Simon Glass30033c22019-07-20 12:24:15 -06003578 def _SetupForReplace(self):
3579 """Set up some files to use to replace entries
3580
3581 This generates an image, copies it to a new file, extracts all the files
3582 in it and updates some of them
3583
3584 Returns:
3585 List
3586 Image filename
3587 Output directory
3588 Expected values for updated entries, each a string
3589 """
3590 data = self._DoReadFileRealDtb('143_replace_all.dts')
3591
Simon Glass80025522022-01-29 14:14:04 -07003592 updated_fname = tools.get_output_filename('image-updated.bin')
3593 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003594
3595 outdir = os.path.join(self._indir, 'extract')
3596 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3597
3598 expected1 = b'x' + U_BOOT_DATA + b'y'
3599 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003600 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003601
3602 expected2 = b'a' + U_BOOT_DATA + b'b'
3603 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003604 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003605
3606 expected_text = b'not the same text'
3607 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003608 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003609
3610 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3611 dtb = fdt.FdtScan(dtb_fname)
3612 node = dtb.GetNode('/binman/text')
3613 node.AddString('my-property', 'the value')
3614 dtb.Sync(auto_resize=True)
3615 dtb.Flush()
3616
3617 return updated_fname, outdir, expected1, expected2, expected_text
3618
3619 def _CheckReplaceMultiple(self, entry_paths):
3620 """Handle replacing the contents of multiple entries
3621
3622 Args:
3623 entry_paths: List of entry paths to replace
3624
3625 Returns:
3626 List
3627 Dict of entries in the image:
3628 key: Entry name
3629 Value: Entry object
3630 Expected values for updated entries, each a string
3631 """
3632 updated_fname, outdir, expected1, expected2, expected_text = (
3633 self._SetupForReplace())
3634 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3635
3636 image = Image.FromFile(updated_fname)
3637 image.LoadData()
3638 return image.GetEntries(), expected1, expected2, expected_text
3639
3640 def testReplaceAll(self):
3641 """Test replacing the contents of all entries"""
3642 entries, expected1, expected2, expected_text = (
3643 self._CheckReplaceMultiple([]))
3644 data = entries['u-boot'].data
3645 self.assertEqual(expected1, data)
3646
3647 data = entries['u-boot2'].data
3648 self.assertEqual(expected2, data)
3649
3650 data = entries['text'].data
3651 self.assertEqual(expected_text, data)
3652
3653 # Check that the device tree is updated
3654 data = entries['u-boot-dtb'].data
3655 dtb = fdt.Fdt.FromData(data)
3656 dtb.Scan()
3657 node = dtb.GetNode('/binman/text')
3658 self.assertEqual('the value', node.props['my-property'].value)
3659
3660 def testReplaceSome(self):
3661 """Test replacing the contents of a few entries"""
3662 entries, expected1, expected2, expected_text = (
3663 self._CheckReplaceMultiple(['u-boot2', 'text']))
3664
3665 # This one should not change
3666 data = entries['u-boot'].data
3667 self.assertEqual(U_BOOT_DATA, data)
3668
3669 data = entries['u-boot2'].data
3670 self.assertEqual(expected2, data)
3671
3672 data = entries['text'].data
3673 self.assertEqual(expected_text, data)
3674
3675 def testReplaceCmd(self):
3676 """Test replacing a file fron an image on the command line"""
3677 self._DoReadFileRealDtb('143_replace_all.dts')
3678
3679 try:
3680 tmpdir, updated_fname = self._SetupImageInTmpdir()
3681
3682 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3683 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003684 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003685
3686 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003687 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003688 self.assertEqual(expected, data[:len(expected)])
3689 map_fname = os.path.join(tmpdir, 'image-updated.map')
3690 self.assertFalse(os.path.exists(map_fname))
3691 finally:
3692 shutil.rmtree(tmpdir)
3693
3694 def testReplaceCmdSome(self):
3695 """Test replacing some files fron an image on the command line"""
3696 updated_fname, outdir, expected1, expected2, expected_text = (
3697 self._SetupForReplace())
3698
3699 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3700 'u-boot2', 'text')
3701
Simon Glass80025522022-01-29 14:14:04 -07003702 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003703 image = Image.FromFile(updated_fname)
3704 image.LoadData()
3705 entries = image.GetEntries()
3706
3707 # This one should not change
3708 data = entries['u-boot'].data
3709 self.assertEqual(U_BOOT_DATA, data)
3710
3711 data = entries['u-boot2'].data
3712 self.assertEqual(expected2, data)
3713
3714 data = entries['text'].data
3715 self.assertEqual(expected_text, data)
3716
3717 def testReplaceMissing(self):
3718 """Test replacing entries where the file is missing"""
3719 updated_fname, outdir, expected1, expected2, expected_text = (
3720 self._SetupForReplace())
3721
3722 # Remove one of the files, to generate a warning
3723 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3724 os.remove(u_boot_fname1)
3725
3726 with test_util.capture_sys_output() as (stdout, stderr):
3727 control.ReplaceEntries(updated_fname, None, outdir, [])
3728 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003729 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003730
3731 def testReplaceCmdMap(self):
3732 """Test replacing a file fron an image on the command line"""
3733 self._DoReadFileRealDtb('143_replace_all.dts')
3734
3735 try:
3736 tmpdir, updated_fname = self._SetupImageInTmpdir()
3737
3738 fname = os.path.join(self._indir, 'update-u-boot.bin')
3739 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003740 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003741
3742 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3743 '-f', fname, '-m')
3744 map_fname = os.path.join(tmpdir, 'image-updated.map')
3745 self.assertTrue(os.path.exists(map_fname))
3746 finally:
3747 shutil.rmtree(tmpdir)
3748
3749 def testReplaceNoEntryPaths(self):
3750 """Test replacing an entry without an entry path"""
3751 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003752 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003753 with self.assertRaises(ValueError) as e:
3754 control.ReplaceEntries(image_fname, 'fname', None, [])
3755 self.assertIn('Must specify an entry path to read with -f',
3756 str(e.exception))
3757
3758 def testReplaceTooManyEntryPaths(self):
3759 """Test extracting some entries"""
3760 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003761 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003762 with self.assertRaises(ValueError) as e:
3763 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3764 self.assertIn('Must specify exactly one entry path to write with -f',
3765 str(e.exception))
3766
Simon Glass0b074d62019-08-24 07:22:48 -06003767 def testPackReset16(self):
3768 """Test that an image with an x86 reset16 region can be created"""
3769 data = self._DoReadFile('144_x86_reset16.dts')
3770 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3771
3772 def testPackReset16Spl(self):
3773 """Test that an image with an x86 reset16-spl region can be created"""
3774 data = self._DoReadFile('145_x86_reset16_spl.dts')
3775 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3776
3777 def testPackReset16Tpl(self):
3778 """Test that an image with an x86 reset16-tpl region can be created"""
3779 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3780 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3781
Simon Glass232f90c2019-08-24 07:22:50 -06003782 def testPackIntelFit(self):
3783 """Test that an image with an Intel FIT and pointer can be created"""
3784 data = self._DoReadFile('147_intel_fit.dts')
3785 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3786 fit = data[16:32];
3787 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3788 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3789
3790 image = control.images['image']
3791 entries = image.GetEntries()
3792 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3793 self.assertEqual(expected_ptr, ptr)
3794
3795 def testPackIntelFitMissing(self):
3796 """Test detection of a FIT pointer with not FIT region"""
3797 with self.assertRaises(ValueError) as e:
3798 self._DoReadFile('148_intel_fit_missing.dts')
3799 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3800 str(e.exception))
3801
Simon Glass72555fa2019-11-06 17:22:44 -07003802 def _CheckSymbolsTplSection(self, dts, expected_vals):
3803 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003804 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003805 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003806 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003807 self.assertEqual(expected1, data[:upto1])
3808
3809 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003810 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003811 self.assertEqual(expected2, data[upto1:upto2])
3812
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003813 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003814 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003815 self.assertEqual(expected3, data[upto2:upto3])
3816
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003817 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003818 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3819
3820 def testSymbolsTplSection(self):
3821 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3822 self._SetupSplElf('u_boot_binman_syms')
3823 self._SetupTplElf('u_boot_binman_syms')
3824 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003825 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003826
3827 def testSymbolsTplSectionX86(self):
3828 """Test binman can assign symbols in a section with end-at-4gb"""
3829 self._SetupSplElf('u_boot_binman_syms_x86')
3830 self._SetupTplElf('u_boot_binman_syms_x86')
3831 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003832 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003833 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003834
Simon Glass98c59572019-08-24 07:23:03 -06003835 def testPackX86RomIfwiSectiom(self):
3836 """Test that a section can be placed in an IFWI region"""
3837 self._SetupIfwi('fitimage.bin')
3838 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3839 self._CheckIfwi(data)
3840
Simon Glassba7985d2019-08-24 07:23:07 -06003841 def testPackFspM(self):
3842 """Test that an image with a FSP memory-init binary can be created"""
3843 data = self._DoReadFile('152_intel_fsp_m.dts')
3844 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3845
Simon Glass4d9086d2019-10-20 21:31:35 -06003846 def testPackFspS(self):
3847 """Test that an image with a FSP silicon-init binary can be created"""
3848 data = self._DoReadFile('153_intel_fsp_s.dts')
3849 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003850
Simon Glass9ea87b22019-10-20 21:31:36 -06003851 def testPackFspT(self):
3852 """Test that an image with a FSP temp-ram-init binary can be created"""
3853 data = self._DoReadFile('154_intel_fsp_t.dts')
3854 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3855
Simon Glass48f3aad2020-07-09 18:39:31 -06003856 def testMkimage(self):
3857 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003858 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003859 data = self._DoReadFile('156_mkimage.dts')
3860
3861 # Just check that the data appears in the file somewhere
3862 self.assertIn(U_BOOT_SPL_DATA, data)
3863
Simon Glass66152ce2022-01-09 20:14:09 -07003864 def testMkimageMissing(self):
3865 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003866 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003867 with test_util.capture_sys_output() as (_, stderr):
3868 self._DoTestFile('156_mkimage.dts',
3869 force_missing_bintools='mkimage')
3870 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003871 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003872
Simon Glass5e560182020-07-09 18:39:36 -06003873 def testExtblob(self):
3874 """Test an image with an external blob"""
3875 data = self._DoReadFile('157_blob_ext.dts')
3876 self.assertEqual(REFCODE_DATA, data)
3877
3878 def testExtblobMissing(self):
3879 """Test an image with a missing external blob"""
3880 with self.assertRaises(ValueError) as e:
3881 self._DoReadFile('158_blob_ext_missing.dts')
3882 self.assertIn("Filename 'missing-file' not found in input path",
3883 str(e.exception))
3884
Simon Glass5d94cc62020-07-09 18:39:38 -06003885 def testExtblobMissingOk(self):
3886 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003887 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003888 ret = self._DoTestFile('158_blob_ext_missing.dts',
3889 allow_missing=True)
3890 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003891 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003892 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003893 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003894 self.assertIn('Some images are invalid', err)
3895
3896 def testExtblobMissingOkFlag(self):
3897 """Test an image with an missing external blob allowed with -W"""
3898 with test_util.capture_sys_output() as (stdout, stderr):
3899 ret = self._DoTestFile('158_blob_ext_missing.dts',
3900 allow_missing=True, ignore_missing=True)
3901 self.assertEqual(0, ret)
3902 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003903 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003904 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003905 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003906
3907 def testExtblobMissingOkSect(self):
3908 """Test an image with an missing external blob that is allowed"""
3909 with test_util.capture_sys_output() as (stdout, stderr):
3910 self._DoTestFile('159_blob_ext_missing_sect.dts',
3911 allow_missing=True)
3912 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003913 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003914
Simon Glasse88cef92020-07-09 18:39:41 -06003915 def testPackX86RomMeMissingDesc(self):
3916 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003917 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003918 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003919 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003920 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003921
3922 def testPackX86RomMissingIfwi(self):
3923 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3924 self._SetupIfwi('fitimage.bin')
3925 pathname = os.path.join(self._indir, 'fitimage.bin')
3926 os.remove(pathname)
3927 with test_util.capture_sys_output() as (stdout, stderr):
3928 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3929 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003930 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003931
Simon Glass2a0fa982022-02-11 13:23:21 -07003932 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003933 """Test that zero-size overlapping regions are ignored"""
3934 self._DoTestFile('160_pack_overlap_zero.dts')
3935
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003936 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003937 # The data should be inside the FIT
3938 dtb = fdt.Fdt.FromData(fit_data)
3939 dtb.Scan()
3940 fnode = dtb.GetNode('/images/kernel')
3941 self.assertIn('data', fnode.props)
3942
3943 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003944 tools.write_file(fname, fit_data)
3945 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003946
3947 # Check a few features to make sure the plumbing works. We don't need
3948 # to test the operation of mkimage or dumpimage here. First convert the
3949 # output into a dict where the keys are the fields printed by dumpimage
3950 # and the values are a list of values for each field
3951 lines = out.splitlines()
3952
3953 # Converts "Compression: gzip compressed" into two groups:
3954 # 'Compression' and 'gzip compressed'
3955 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3956 vals = collections.defaultdict(list)
3957 for line in lines:
3958 mat = re_line.match(line)
3959 vals[mat.group(1)].append(mat.group(2))
3960
Brandon Maiera657bc62024-06-04 16:16:05 +00003961 self.assertEqual('FIT description: test-desc', lines[0])
Simon Glass45d556d2020-07-09 18:39:45 -06003962 self.assertIn('Created:', lines[1])
3963 self.assertIn('Image 0 (kernel)', vals)
3964 self.assertIn('Hash value', vals)
3965 data_sizes = vals.get('Data Size')
3966 self.assertIsNotNone(data_sizes)
3967 self.assertEqual(2, len(data_sizes))
3968 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003969 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3970 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3971
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003972 # Check if entry listing correctly omits /images/
3973 image = control.images['image']
3974 fit_entry = image.GetEntries()['fit']
3975 subentries = list(fit_entry.GetEntries().keys())
3976 expected = ['kernel', 'fdt-1']
3977 self.assertEqual(expected, subentries)
3978
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003979 def testSimpleFit(self):
3980 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003981 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003982 data = self._DoReadFile('161_fit.dts')
3983 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3984 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3985 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3986
3987 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3988
3989 def testSimpleFitExpandsSubentries(self):
3990 """Test that FIT images expand their subentries"""
3991 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3992 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3993 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3994 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3995
3996 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003997
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003998 def testSimpleFitImagePos(self):
3999 """Test that we have correct image-pos for FIT subentries"""
4000 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
4001 update_dtb=True)
4002 dtb = fdt.Fdt(out_dtb_fname)
4003 dtb.Scan()
4004 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4005
Simon Glassb7bad182022-03-05 20:19:01 -07004006 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004007 self.assertEqual({
4008 'image-pos': 0,
4009 'offset': 0,
4010 'size': 1890,
4011
4012 'u-boot:image-pos': 0,
4013 'u-boot:offset': 0,
4014 'u-boot:size': 4,
4015
4016 'fit:image-pos': 4,
4017 'fit:offset': 4,
4018 'fit:size': 1840,
4019
Simon Glassb7bad182022-03-05 20:19:01 -07004020 'fit/images/kernel:image-pos': 304,
4021 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004022 'fit/images/kernel:size': 4,
4023
Simon Glassb7bad182022-03-05 20:19:01 -07004024 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004025 'fit/images/kernel/u-boot:offset': 0,
4026 'fit/images/kernel/u-boot:size': 4,
4027
Simon Glassb7bad182022-03-05 20:19:01 -07004028 'fit/images/fdt-1:image-pos': 552,
4029 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004030 'fit/images/fdt-1:size': 6,
4031
Simon Glassb7bad182022-03-05 20:19:01 -07004032 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004033 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
4034 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
4035
4036 'u-boot-nodtb:image-pos': 1844,
4037 'u-boot-nodtb:offset': 1844,
4038 'u-boot-nodtb:size': 46,
4039 }, props)
4040
4041 # Actually check the data is where we think it is
4042 for node, expected in [
4043 ("u-boot", U_BOOT_DATA),
4044 ("fit/images/kernel", U_BOOT_DATA),
4045 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4046 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
4047 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
4048 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4049 ]:
4050 image_pos = props[f"{node}:image-pos"]
4051 size = props[f"{node}:size"]
4052 self.assertEqual(len(expected), size)
4053 self.assertEqual(expected, data[image_pos:image_pos+size])
4054
Simon Glass45d556d2020-07-09 18:39:45 -06004055 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06004056 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06004057 data = self._DoReadFile('162_fit_external.dts')
4058 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
4059
Simon Glass7932c882022-01-09 20:13:39 -07004060 # Size of the external-data region as set up by mkimage
4061 external_data_size = len(U_BOOT_DATA) + 2
4062 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07004063 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07004064 len(U_BOOT_NODTB_DATA))
4065
Simon Glass45d556d2020-07-09 18:39:45 -06004066 # The data should be outside the FIT
4067 dtb = fdt.Fdt.FromData(fit_data)
4068 dtb.Scan()
4069 fnode = dtb.GetNode('/images/kernel')
4070 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07004071 self.assertEqual(len(U_BOOT_DATA),
4072 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4073 fit_pos = 0x400;
4074 self.assertEqual(
4075 fit_pos,
4076 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4077
Brandon Maiera657bc62024-06-04 16:16:05 +00004078 self.assertEqual(expected_size, len(data))
Simon Glass7932c882022-01-09 20:13:39 -07004079 actual_pos = len(U_BOOT_DATA) + fit_pos
4080 self.assertEqual(U_BOOT_DATA + b'aa',
4081 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004082
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004083 def testFitExternalImagePos(self):
4084 """Test that we have correct image-pos for external FIT subentries"""
4085 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4086 update_dtb=True)
4087 dtb = fdt.Fdt(out_dtb_fname)
4088 dtb.Scan()
4089 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4090
4091 self.assertEqual({
4092 'image-pos': 0,
4093 'offset': 0,
4094 'size': 1082,
4095
4096 'u-boot:image-pos': 0,
4097 'u-boot:offset': 0,
4098 'u-boot:size': 4,
4099
4100 'fit:size': 1032,
4101 'fit:offset': 4,
4102 'fit:image-pos': 4,
4103
4104 'fit/images/kernel:size': 4,
4105 'fit/images/kernel:offset': 1024,
4106 'fit/images/kernel:image-pos': 1028,
4107
4108 'fit/images/kernel/u-boot:size': 4,
4109 'fit/images/kernel/u-boot:offset': 0,
4110 'fit/images/kernel/u-boot:image-pos': 1028,
4111
4112 'fit/images/fdt-1:size': 2,
4113 'fit/images/fdt-1:offset': 1028,
4114 'fit/images/fdt-1:image-pos': 1032,
4115
4116 'fit/images/fdt-1/_testing:size': 2,
4117 'fit/images/fdt-1/_testing:offset': 0,
4118 'fit/images/fdt-1/_testing:image-pos': 1032,
4119
4120 'u-boot-nodtb:image-pos': 1036,
4121 'u-boot-nodtb:offset': 1036,
4122 'u-boot-nodtb:size': 46,
4123 }, props)
4124
4125 # Actually check the data is where we think it is
4126 for node, expected in [
4127 ("u-boot", U_BOOT_DATA),
4128 ("fit/images/kernel", U_BOOT_DATA),
4129 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4130 ("fit/images/fdt-1", b'aa'),
4131 ("fit/images/fdt-1/_testing", b'aa'),
4132 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4133 ]:
4134 image_pos = props[f"{node}:image-pos"]
4135 size = props[f"{node}:size"]
4136 self.assertEqual(len(expected), size)
4137 self.assertEqual(expected, data[image_pos:image_pos+size])
4138
Simon Glass66152ce2022-01-09 20:14:09 -07004139 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004140 """Test that binman complains if mkimage is missing"""
4141 with self.assertRaises(ValueError) as e:
4142 self._DoTestFile('162_fit_external.dts',
4143 force_missing_bintools='mkimage')
4144 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4145 str(e.exception))
4146
4147 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004148 """Test that binman still produces a FIT image if mkimage is missing"""
4149 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004150 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004151 force_missing_bintools='mkimage')
4152 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004153 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004154
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004155 def testSectionIgnoreHashSignature(self):
4156 """Test that sections ignore hash, signature nodes for its data"""
4157 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4158 expected = (U_BOOT_DATA + U_BOOT_DATA)
4159 self.assertEqual(expected, data)
4160
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004161 def testPadInSections(self):
4162 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004163 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4164 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004165 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4166 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004167 U_BOOT_DATA)
4168 self.assertEqual(expected, data)
4169
Simon Glassd12599d2020-10-26 17:40:09 -06004170 dtb = fdt.Fdt(out_dtb_fname)
4171 dtb.Scan()
4172 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4173 expected = {
4174 'image-pos': 0,
4175 'offset': 0,
4176 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4177
4178 'section:image-pos': 0,
4179 'section:offset': 0,
4180 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4181
4182 'section/before:image-pos': 0,
4183 'section/before:offset': 0,
4184 'section/before:size': len(U_BOOT_DATA),
4185
4186 'section/u-boot:image-pos': 4,
4187 'section/u-boot:offset': 4,
4188 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4189
4190 'section/after:image-pos': 26,
4191 'section/after:offset': 26,
4192 'section/after:size': len(U_BOOT_DATA),
4193 }
4194 self.assertEqual(expected, props)
4195
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004196 def testFitImageSubentryAlignment(self):
4197 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004198 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004199 entry_args = {
4200 'test-id': TEXT_DATA,
4201 }
4202 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4203 entry_args=entry_args)
4204 dtb = fdt.Fdt.FromData(data)
4205 dtb.Scan()
4206
4207 node = dtb.GetNode('/images/kernel')
4208 data = dtb.GetProps(node)["data"].bytes
4209 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004210 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4211 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004212 self.assertEqual(expected, data)
4213
4214 node = dtb.GetNode('/images/fdt-1')
4215 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004216 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4217 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004218 U_BOOT_DTB_DATA)
4219 self.assertEqual(expected, data)
4220
4221 def testFitExtblobMissingOk(self):
4222 """Test a FIT with a missing external blob that is allowed"""
4223 with test_util.capture_sys_output() as (stdout, stderr):
4224 self._DoTestFile('168_fit_missing_blob.dts',
4225 allow_missing=True)
4226 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004227 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004228
Simon Glass21db0ff2020-09-01 05:13:54 -06004229 def testBlobNamedByArgMissing(self):
4230 """Test handling of a missing entry arg"""
4231 with self.assertRaises(ValueError) as e:
4232 self._DoReadFile('068_blob_named_by_arg.dts')
4233 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4234 str(e.exception))
4235
Simon Glass559c4de2020-09-01 05:13:58 -06004236 def testPackBl31(self):
4237 """Test that an image with an ATF BL31 binary can be created"""
4238 data = self._DoReadFile('169_atf_bl31.dts')
4239 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4240
Samuel Holland9d8cc632020-10-21 21:12:15 -05004241 def testPackScp(self):
4242 """Test that an image with an SCP binary can be created"""
4243 data = self._DoReadFile('172_scp.dts')
4244 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4245
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004246 def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True,
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004247 default_dt=None, use_seq_num=True):
Simon Glasscd2783e2024-07-20 11:49:46 +01004248 """Check an image with an FIT with multiple FDT images"""
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004249 def _CheckFdt(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004250 """Check the FDT nodes
4251
4252 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004253 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004254 expected_data: Expected contents of 'data' property
4255 """
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004256 name = 'fdt-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004257 fnode = dtb.GetNode('/images/%s' % name)
4258 self.assertIsNotNone(fnode)
4259 self.assertEqual({'description','type', 'compression', 'data'},
4260 set(fnode.props.keys()))
4261 self.assertEqual(expected_data, fnode.props['data'].bytes)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004262 description = (
4263 'fdt-test-fdt%s.dtb' % val if len(val) == 1 else
4264 'fdt-%s.dtb' % val
4265 )
4266 self.assertEqual(description, fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004267 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004268
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004269 def _CheckConfig(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004270 """Check the configuration nodes
4271
4272 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004273 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004274 expected_data: Expected contents of 'data' property
4275 """
4276 cnode = dtb.GetNode('/configurations')
4277 self.assertIn('default', cnode.props)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004278 default = (
4279 'config-2' if len(val) == 1 else
4280 'config-test-fdt2'
4281 )
4282 self.assertEqual(default, cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004283
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004284 name = 'config-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004285 fnode = dtb.GetNode('/configurations/%s' % name)
4286 self.assertIsNotNone(fnode)
4287 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4288 set(fnode.props.keys()))
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004289 description = (
4290 'conf-test-fdt%s.dtb' % val if len(val) == 1 else
4291 'conf-%s.dtb' % val
4292 )
4293 self.assertEqual(description, fnode.props['description'].value)
4294 self.assertEqual('fdt-%s' % val, fnode.props['fdt'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004295
4296 entry_args = {
Simon Glass1032acc2020-09-06 10:39:08 -06004297 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004298 }
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004299 extra_indirs = None
Simon Glasscd2783e2024-07-20 11:49:46 +01004300 if use_fdt_list:
4301 entry_args['of-list'] = 'test-fdt1 test-fdt2'
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004302 if default_dt:
4303 entry_args['default-dt'] = default_dt
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004304 if use_fdt_list:
4305 extra_indirs = [os.path.join(self._indir, TEST_FDT_SUBDIR)]
Simon Glassa435cd12020-09-01 05:13:59 -06004306 data = self._DoReadFileDtb(
Simon Glasscd2783e2024-07-20 11:49:46 +01004307 dts,
Simon Glassa435cd12020-09-01 05:13:59 -06004308 entry_args=entry_args,
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004309 extra_indirs=extra_indirs)[0]
Simon Glassa435cd12020-09-01 05:13:59 -06004310 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4311 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4312
4313 dtb = fdt.Fdt.FromData(fit_data)
4314 dtb.Scan()
4315 fnode = dtb.GetNode('/images/kernel')
4316 self.assertIn('data', fnode.props)
4317
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004318 if use_seq_num == True:
4319 # Check all the properties in fdt-1 and fdt-2
4320 _CheckFdt('1', TEST_FDT1_DATA)
4321 _CheckFdt('2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004322
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004323 # Check configurations
4324 _CheckConfig('1', TEST_FDT1_DATA)
4325 _CheckConfig('2', TEST_FDT2_DATA)
4326 else:
4327 # Check all the properties in fdt-1 and fdt-2
4328 _CheckFdt('test-fdt1', TEST_FDT1_DATA)
4329 _CheckFdt('test-fdt2', TEST_FDT2_DATA)
4330
4331 # Check configurations
4332 _CheckConfig('test-fdt1', TEST_FDT1_DATA)
4333 _CheckConfig('test-fdt2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004334
Simon Glasscd2783e2024-07-20 11:49:46 +01004335 def testFitFdt(self):
4336 """Test an image with an FIT with multiple FDT images"""
4337 self.CheckFitFdt()
4338
Simon Glassa435cd12020-09-01 05:13:59 -06004339 def testFitFdtMissingList(self):
4340 """Test handling of a missing 'of-list' entry arg"""
4341 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004342 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004343 self.assertIn("Generator node requires 'of-list' entry argument",
4344 str(e.exception))
4345
4346 def testFitFdtEmptyList(self):
4347 """Test handling of an empty 'of-list' entry arg"""
4348 entry_args = {
4349 'of-list': '',
4350 }
4351 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4352
4353 def testFitFdtMissingProp(self):
4354 """Test handling of a missing 'fit,fdt-list' property"""
4355 with self.assertRaises(ValueError) as e:
4356 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4357 self.assertIn("Generator node requires 'fit,fdt-list' property",
4358 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004359
Simon Glass1032acc2020-09-06 10:39:08 -06004360 def testFitFdtMissing(self):
4361 """Test handling of a missing 'default-dt' entry arg"""
4362 entry_args = {
4363 'of-list': 'test-fdt1 test-fdt2',
4364 }
4365 with self.assertRaises(ValueError) as e:
4366 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004367 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004368 entry_args=entry_args,
4369 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4370 self.assertIn("Generated 'default' node requires default-dt entry argument",
4371 str(e.exception))
4372
4373 def testFitFdtNotInList(self):
4374 """Test handling of a default-dt that is not in the of-list"""
4375 entry_args = {
4376 'of-list': 'test-fdt1 test-fdt2',
4377 'default-dt': 'test-fdt3',
4378 }
4379 with self.assertRaises(ValueError) as e:
4380 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004381 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004382 entry_args=entry_args,
4383 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4384 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4385 str(e.exception))
4386
Simon Glassa820af72020-09-06 10:39:09 -06004387 def testFitExtblobMissingHelp(self):
4388 """Test display of help messages when an external blob is missing"""
4389 control.missing_blob_help = control._ReadMissingBlobHelp()
4390 control.missing_blob_help['wibble'] = 'Wibble test'
4391 control.missing_blob_help['another'] = 'Another test'
4392 with test_util.capture_sys_output() as (stdout, stderr):
4393 self._DoTestFile('168_fit_missing_blob.dts',
4394 allow_missing=True)
4395 err = stderr.getvalue()
4396
4397 # We can get the tag from the name, the type or the missing-msg
4398 # property. Check all three.
4399 self.assertIn('You may need to build ARM Trusted', err)
4400 self.assertIn('Wibble test', err)
4401 self.assertIn('Another test', err)
4402
Simon Glass6f1f4d42020-09-06 10:35:32 -06004403 def testMissingBlob(self):
4404 """Test handling of a blob containing a missing file"""
4405 with self.assertRaises(ValueError) as e:
4406 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4407 self.assertIn("Filename 'missing' not found in input path",
4408 str(e.exception))
4409
Simon Glassa0729502020-09-06 10:35:33 -06004410 def testEnvironment(self):
4411 """Test adding a U-Boot environment"""
4412 data = self._DoReadFile('174_env.dts')
4413 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4414 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4415 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4416 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4417 env)
4418
4419 def testEnvironmentNoSize(self):
4420 """Test that a missing 'size' property is detected"""
4421 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004422 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004423 self.assertIn("'u-boot-env' entry must have a size property",
4424 str(e.exception))
4425
4426 def testEnvironmentTooSmall(self):
4427 """Test handling of an environment that does not fit"""
4428 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004429 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004430
4431 # checksum, start byte, environment with \0 terminator, final \0
4432 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4433 short = need - 0x8
4434 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4435 str(e.exception))
4436
Simon Glassd1fdf752020-10-26 17:40:01 -06004437 def testSkipAtStart(self):
4438 """Test handling of skip-at-start section"""
4439 data = self._DoReadFile('177_skip_at_start.dts')
4440 self.assertEqual(U_BOOT_DATA, data)
4441
4442 image = control.images['image']
4443 entries = image.GetEntries()
4444 section = entries['section']
4445 self.assertEqual(0, section.offset)
4446 self.assertEqual(len(U_BOOT_DATA), section.size)
4447 self.assertEqual(U_BOOT_DATA, section.GetData())
4448
4449 entry = section.GetEntries()['u-boot']
4450 self.assertEqual(16, entry.offset)
4451 self.assertEqual(len(U_BOOT_DATA), entry.size)
4452 self.assertEqual(U_BOOT_DATA, entry.data)
4453
4454 def testSkipAtStartPad(self):
4455 """Test handling of skip-at-start section with padded entry"""
4456 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004457 before = tools.get_bytes(0, 8)
4458 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004459 all = before + U_BOOT_DATA + after
4460 self.assertEqual(all, data)
4461
4462 image = control.images['image']
4463 entries = image.GetEntries()
4464 section = entries['section']
4465 self.assertEqual(0, section.offset)
4466 self.assertEqual(len(all), section.size)
4467 self.assertEqual(all, section.GetData())
4468
4469 entry = section.GetEntries()['u-boot']
4470 self.assertEqual(16, entry.offset)
4471 self.assertEqual(len(all), entry.size)
4472 self.assertEqual(U_BOOT_DATA, entry.data)
4473
4474 def testSkipAtStartSectionPad(self):
4475 """Test handling of skip-at-start section with padding"""
4476 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004477 before = tools.get_bytes(0, 8)
4478 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004479 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004480 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004481
4482 image = control.images['image']
4483 entries = image.GetEntries()
4484 section = entries['section']
4485 self.assertEqual(0, section.offset)
4486 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004487 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004488 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004489
4490 entry = section.GetEntries()['u-boot']
4491 self.assertEqual(16, entry.offset)
4492 self.assertEqual(len(U_BOOT_DATA), entry.size)
4493 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004494
Simon Glassbb395742020-10-26 17:40:14 -06004495 def testSectionPad(self):
4496 """Testing padding with sections"""
4497 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004498 expected = (tools.get_bytes(ord('&'), 3) +
4499 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004500 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004501 tools.get_bytes(ord('!'), 1) +
4502 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004503 self.assertEqual(expected, data)
4504
4505 def testSectionAlign(self):
4506 """Testing alignment with sections"""
4507 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4508 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004509 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004510 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004511 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004512 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004513 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4514 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004515 self.assertEqual(expected, data)
4516
Simon Glassd92c8362020-10-26 17:40:25 -06004517 def testCompressImage(self):
4518 """Test compression of the entire image"""
4519 self._CheckLz4()
4520 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4521 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4522 dtb = fdt.Fdt(out_dtb_fname)
4523 dtb.Scan()
4524 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4525 'uncomp-size'])
4526 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004527 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004528
4529 # Do a sanity check on various fields
4530 image = control.images['image']
4531 entries = image.GetEntries()
4532 self.assertEqual(2, len(entries))
4533
4534 entry = entries['blob']
4535 self.assertEqual(COMPRESS_DATA, entry.data)
4536 self.assertEqual(len(COMPRESS_DATA), entry.size)
4537
4538 entry = entries['u-boot']
4539 self.assertEqual(U_BOOT_DATA, entry.data)
4540 self.assertEqual(len(U_BOOT_DATA), entry.size)
4541
4542 self.assertEqual(len(data), image.size)
4543 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4544 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4545 orig = self._decompress(image.data)
4546 self.assertEqual(orig, image.uncomp_data)
4547
4548 expected = {
4549 'blob:offset': 0,
4550 'blob:size': len(COMPRESS_DATA),
4551 'u-boot:offset': len(COMPRESS_DATA),
4552 'u-boot:size': len(U_BOOT_DATA),
4553 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4554 'offset': 0,
4555 'image-pos': 0,
4556 'size': len(data),
4557 }
4558 self.assertEqual(expected, props)
4559
4560 def testCompressImageLess(self):
4561 """Test compression where compression reduces the image size"""
4562 self._CheckLz4()
4563 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4564 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4565 dtb = fdt.Fdt(out_dtb_fname)
4566 dtb.Scan()
4567 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4568 'uncomp-size'])
4569 orig = self._decompress(data)
4570
Brandon Maiera657bc62024-06-04 16:16:05 +00004571 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004572
4573 # Do a sanity check on various fields
4574 image = control.images['image']
4575 entries = image.GetEntries()
4576 self.assertEqual(2, len(entries))
4577
4578 entry = entries['blob']
4579 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4580 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4581
4582 entry = entries['u-boot']
4583 self.assertEqual(U_BOOT_DATA, entry.data)
4584 self.assertEqual(len(U_BOOT_DATA), entry.size)
4585
4586 self.assertEqual(len(data), image.size)
4587 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4588 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4589 image.uncomp_size)
4590 orig = self._decompress(image.data)
4591 self.assertEqual(orig, image.uncomp_data)
4592
4593 expected = {
4594 'blob:offset': 0,
4595 'blob:size': len(COMPRESS_DATA_BIG),
4596 'u-boot:offset': len(COMPRESS_DATA_BIG),
4597 'u-boot:size': len(U_BOOT_DATA),
4598 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4599 'offset': 0,
4600 'image-pos': 0,
4601 'size': len(data),
4602 }
4603 self.assertEqual(expected, props)
4604
4605 def testCompressSectionSize(self):
4606 """Test compression of a section with a fixed size"""
4607 self._CheckLz4()
4608 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4609 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4610 dtb = fdt.Fdt(out_dtb_fname)
4611 dtb.Scan()
4612 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4613 'uncomp-size'])
4614 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004615 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004616 expected = {
4617 'section/blob:offset': 0,
4618 'section/blob:size': len(COMPRESS_DATA),
4619 'section/u-boot:offset': len(COMPRESS_DATA),
4620 'section/u-boot:size': len(U_BOOT_DATA),
4621 'section:offset': 0,
4622 'section:image-pos': 0,
4623 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4624 'section:size': 0x30,
4625 'offset': 0,
4626 'image-pos': 0,
4627 'size': 0x30,
4628 }
4629 self.assertEqual(expected, props)
4630
4631 def testCompressSection(self):
4632 """Test compression of a section with no fixed size"""
4633 self._CheckLz4()
4634 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4635 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4636 dtb = fdt.Fdt(out_dtb_fname)
4637 dtb.Scan()
4638 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4639 'uncomp-size'])
4640 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004641 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004642 expected = {
4643 'section/blob:offset': 0,
4644 'section/blob:size': len(COMPRESS_DATA),
4645 'section/u-boot:offset': len(COMPRESS_DATA),
4646 'section/u-boot:size': len(U_BOOT_DATA),
4647 'section:offset': 0,
4648 'section:image-pos': 0,
4649 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4650 'section:size': len(data),
4651 'offset': 0,
4652 'image-pos': 0,
4653 'size': len(data),
4654 }
4655 self.assertEqual(expected, props)
4656
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004657 def testLz4Missing(self):
4658 """Test that binman still produces an image if lz4 is missing"""
4659 with test_util.capture_sys_output() as (_, stderr):
4660 self._DoTestFile('185_compress_section.dts',
4661 force_missing_bintools='lz4')
4662 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004663 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004664
Simon Glassd92c8362020-10-26 17:40:25 -06004665 def testCompressExtra(self):
4666 """Test compression of a section with no fixed size"""
4667 self._CheckLz4()
4668 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4669 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4670 dtb = fdt.Fdt(out_dtb_fname)
4671 dtb.Scan()
4672 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4673 'uncomp-size'])
4674
4675 base = data[len(U_BOOT_DATA):]
Brandon Maiera657bc62024-06-04 16:16:05 +00004676 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glassd92c8362020-10-26 17:40:25 -06004677 rest = base[len(U_BOOT_DATA):]
4678
4679 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004680 bintool = self.comp_bintools['lz4']
4681 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004682 data1 = rest[:len(expect1)]
4683 section1 = self._decompress(data1)
Brandon Maiera657bc62024-06-04 16:16:05 +00004684 self.assertEqual(expect1, data1)
4685 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glassd92c8362020-10-26 17:40:25 -06004686 rest1 = rest[len(expect1):]
4687
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004688 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004689 data2 = rest1[:len(expect2)]
4690 section2 = self._decompress(data2)
Brandon Maiera657bc62024-06-04 16:16:05 +00004691 self.assertEqual(expect2, data2)
4692 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glassd92c8362020-10-26 17:40:25 -06004693 rest2 = rest1[len(expect2):]
4694
4695 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4696 len(expect2) + len(U_BOOT_DATA))
Brandon Maiera657bc62024-06-04 16:16:05 +00004697 #self.assertEqual(expect_size, len(data))
Simon Glassd92c8362020-10-26 17:40:25 -06004698
Brandon Maiera657bc62024-06-04 16:16:05 +00004699 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glassd92c8362020-10-26 17:40:25 -06004700
4701 self.maxDiff = None
4702 expected = {
4703 'u-boot:offset': 0,
4704 'u-boot:image-pos': 0,
4705 'u-boot:size': len(U_BOOT_DATA),
4706
4707 'base:offset': len(U_BOOT_DATA),
4708 'base:image-pos': len(U_BOOT_DATA),
4709 'base:size': len(data) - len(U_BOOT_DATA),
4710 'base/u-boot:offset': 0,
4711 'base/u-boot:image-pos': len(U_BOOT_DATA),
4712 'base/u-boot:size': len(U_BOOT_DATA),
4713 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4714 len(expect2),
4715 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4716 len(expect2),
4717 'base/u-boot2:size': len(U_BOOT_DATA),
4718
4719 'base/section:offset': len(U_BOOT_DATA),
4720 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4721 'base/section:size': len(expect1),
4722 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4723 'base/section/blob:offset': 0,
4724 'base/section/blob:size': len(COMPRESS_DATA),
4725 'base/section/u-boot:offset': len(COMPRESS_DATA),
4726 'base/section/u-boot:size': len(U_BOOT_DATA),
4727
4728 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4729 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4730 'base/section2:size': len(expect2),
4731 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4732 'base/section2/blob:offset': 0,
4733 'base/section2/blob:size': len(COMPRESS_DATA),
4734 'base/section2/blob2:offset': len(COMPRESS_DATA),
4735 'base/section2/blob2:size': len(COMPRESS_DATA),
4736
4737 'offset': 0,
4738 'image-pos': 0,
4739 'size': len(data),
4740 }
4741 self.assertEqual(expected, props)
4742
Simon Glassecbe4732021-01-06 21:35:15 -07004743 def testSymbolsSubsection(self):
4744 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004745 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004746
Simon Glass3fb25402021-01-06 21:35:16 -07004747 def testReadImageEntryArg(self):
4748 """Test reading an image that would need an entry arg to generate"""
4749 entry_args = {
4750 'cros-ec-rw-path': 'ecrw.bin',
4751 }
4752 data = self.data = self._DoReadFileDtb(
4753 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4754 entry_args=entry_args)
4755
Simon Glass80025522022-01-29 14:14:04 -07004756 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004757 orig_image = control.images['image']
4758
4759 # This should not generate an error about the missing 'cros-ec-rw-path'
4760 # since we are reading the image from a file. Compare with
4761 # testEntryArgsRequired()
4762 image = Image.FromFile(image_fname)
4763 self.assertEqual(orig_image.GetEntries().keys(),
4764 image.GetEntries().keys())
4765
Simon Glassa2af7302021-01-06 21:35:18 -07004766 def testFilesAlign(self):
4767 """Test alignment with files"""
4768 data = self._DoReadFile('190_files_align.dts')
4769
4770 # The first string is 15 bytes so will align to 16
4771 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4772 self.assertEqual(expect, data)
4773
Simon Glassdb84b562021-01-06 21:35:19 -07004774 def testReadImageSkip(self):
4775 """Test reading an image and accessing its FDT map"""
4776 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004777 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004778 orig_image = control.images['image']
4779 image = Image.FromFile(image_fname)
4780 self.assertEqual(orig_image.GetEntries().keys(),
4781 image.GetEntries().keys())
4782
4783 orig_entry = orig_image.GetEntries()['fdtmap']
4784 entry = image.GetEntries()['fdtmap']
4785 self.assertEqual(orig_entry.offset, entry.offset)
4786 self.assertEqual(orig_entry.size, entry.size)
4787 self.assertEqual(16, entry.image_pos)
4788
4789 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4790
Brandon Maiera657bc62024-06-04 16:16:05 +00004791 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glassdb84b562021-01-06 21:35:19 -07004792
Simon Glassc98de972021-03-18 20:24:57 +13004793 def testTplNoDtb(self):
4794 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004795 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004796 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4797 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4798 data[:len(U_BOOT_TPL_NODTB_DATA)])
4799
Simon Glass63f41d42021-03-18 20:24:58 +13004800 def testTplBssPad(self):
4801 """Test that we can pad TPL's BSS with zeros"""
4802 # ELF file with a '__bss_size' symbol
4803 self._SetupTplElf()
4804 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004805 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004806 data)
4807
4808 def testTplBssPadMissing(self):
4809 """Test that a missing symbol is detected"""
4810 self._SetupTplElf('u_boot_ucode_ptr')
4811 with self.assertRaises(ValueError) as e:
4812 self._DoReadFile('193_tpl_bss_pad.dts')
4813 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4814 str(e.exception))
4815
Simon Glass718b5292021-03-18 20:25:07 +13004816 def checkDtbSizes(self, data, pad_len, start):
4817 """Check the size arguments in a dtb embedded in an image
4818
4819 Args:
4820 data: The image data
4821 pad_len: Length of the pad section in the image, in bytes
4822 start: Start offset of the devicetree to examine, within the image
4823
4824 Returns:
4825 Size of the devicetree in bytes
4826 """
4827 dtb_data = data[start:]
4828 dtb = fdt.Fdt.FromData(dtb_data)
4829 fdt_size = dtb.GetFdtObj().totalsize()
4830 dtb.Scan()
4831 props = self._GetPropTree(dtb, 'size')
4832 self.assertEqual({
4833 'size': len(data),
4834 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4835 'u-boot-spl/u-boot-spl-dtb:size': 801,
4836 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4837 'u-boot-spl:size': 860,
4838 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4839 'u-boot/u-boot-dtb:size': 781,
4840 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4841 'u-boot:size': 827,
4842 }, props)
4843 return fdt_size
4844
4845 def testExpanded(self):
4846 """Test that an expanded entry type is selected when needed"""
4847 self._SetupSplElf()
4848 self._SetupTplElf()
4849
4850 # SPL has a devicetree, TPL does not
4851 entry_args = {
4852 'spl-dtb': '1',
4853 'spl-bss-pad': 'y',
4854 'tpl-dtb': '',
4855 }
4856 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4857 entry_args=entry_args)
4858 image = control.images['image']
4859 entries = image.GetEntries()
4860 self.assertEqual(3, len(entries))
4861
4862 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4863 self.assertIn('u-boot', entries)
4864 entry = entries['u-boot']
4865 self.assertEqual('u-boot-expanded', entry.etype)
4866 subent = entry.GetEntries()
4867 self.assertEqual(2, len(subent))
4868 self.assertIn('u-boot-nodtb', subent)
4869 self.assertIn('u-boot-dtb', subent)
4870
4871 # Second, u-boot-spl, which should be expanded into three parts
4872 self.assertIn('u-boot-spl', entries)
4873 entry = entries['u-boot-spl']
4874 self.assertEqual('u-boot-spl-expanded', entry.etype)
4875 subent = entry.GetEntries()
4876 self.assertEqual(3, len(subent))
4877 self.assertIn('u-boot-spl-nodtb', subent)
4878 self.assertIn('u-boot-spl-bss-pad', subent)
4879 self.assertIn('u-boot-spl-dtb', subent)
4880
4881 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4882 # devicetree
4883 self.assertIn('u-boot-tpl', entries)
4884 entry = entries['u-boot-tpl']
4885 self.assertEqual('u-boot-tpl', entry.etype)
4886 self.assertEqual(None, entry.GetEntries())
4887
4888 def testExpandedTpl(self):
4889 """Test that an expanded entry type is selected for TPL when needed"""
4890 self._SetupTplElf()
4891
4892 entry_args = {
4893 'tpl-bss-pad': 'y',
4894 'tpl-dtb': 'y',
4895 }
4896 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4897 entry_args=entry_args)
4898 image = control.images['image']
4899 entries = image.GetEntries()
4900 self.assertEqual(1, len(entries))
4901
4902 # We only have u-boot-tpl, which be expanded
4903 self.assertIn('u-boot-tpl', entries)
4904 entry = entries['u-boot-tpl']
4905 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4906 subent = entry.GetEntries()
4907 self.assertEqual(3, len(subent))
4908 self.assertIn('u-boot-tpl-nodtb', subent)
4909 self.assertIn('u-boot-tpl-bss-pad', subent)
4910 self.assertIn('u-boot-tpl-dtb', subent)
4911
4912 def testExpandedNoPad(self):
4913 """Test an expanded entry without BSS pad enabled"""
4914 self._SetupSplElf()
4915 self._SetupTplElf()
4916
4917 # SPL has a devicetree, TPL does not
4918 entry_args = {
4919 'spl-dtb': 'something',
4920 'spl-bss-pad': 'n',
4921 'tpl-dtb': '',
4922 }
4923 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4924 entry_args=entry_args)
4925 image = control.images['image']
4926 entries = image.GetEntries()
4927
4928 # Just check u-boot-spl, which should be expanded into two parts
4929 self.assertIn('u-boot-spl', entries)
4930 entry = entries['u-boot-spl']
4931 self.assertEqual('u-boot-spl-expanded', entry.etype)
4932 subent = entry.GetEntries()
4933 self.assertEqual(2, len(subent))
4934 self.assertIn('u-boot-spl-nodtb', subent)
4935 self.assertIn('u-boot-spl-dtb', subent)
4936
4937 def testExpandedTplNoPad(self):
4938 """Test that an expanded entry type with padding disabled in TPL"""
4939 self._SetupTplElf()
4940
4941 entry_args = {
4942 'tpl-bss-pad': '',
4943 'tpl-dtb': 'y',
4944 }
4945 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4946 entry_args=entry_args)
4947 image = control.images['image']
4948 entries = image.GetEntries()
4949 self.assertEqual(1, len(entries))
4950
4951 # We only have u-boot-tpl, which be expanded
4952 self.assertIn('u-boot-tpl', entries)
4953 entry = entries['u-boot-tpl']
4954 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4955 subent = entry.GetEntries()
4956 self.assertEqual(2, len(subent))
4957 self.assertIn('u-boot-tpl-nodtb', subent)
4958 self.assertIn('u-boot-tpl-dtb', subent)
4959
4960 def testFdtInclude(self):
4961 """Test that an Fdt is update within all binaries"""
4962 self._SetupSplElf()
4963 self._SetupTplElf()
4964
4965 # SPL has a devicetree, TPL does not
4966 self.maxDiff = None
4967 entry_args = {
4968 'spl-dtb': '1',
4969 'spl-bss-pad': 'y',
4970 'tpl-dtb': '',
4971 }
4972 # Build the image. It includes two separate devicetree binaries, each
4973 # with their own contents, but all contain the binman definition.
4974 data = self._DoReadFileDtb(
4975 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4976 update_dtb=True, entry_args=entry_args)[0]
4977 pad_len = 10
4978
4979 # Check the U-Boot dtb
4980 start = len(U_BOOT_NODTB_DATA)
4981 fdt_size = self.checkDtbSizes(data, pad_len, start)
4982
4983 # Now check SPL
4984 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4985 fdt_size = self.checkDtbSizes(data, pad_len, start)
4986
4987 # TPL has no devicetree
4988 start += fdt_size + len(U_BOOT_TPL_DATA)
4989 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004990
Simon Glass7098b7f2021-03-21 18:24:30 +13004991 def testSymbolsExpanded(self):
4992 """Test binman can assign symbols in expanded entries"""
4993 entry_args = {
4994 'spl-dtb': '1',
4995 }
4996 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4997 U_BOOT_SPL_DTB_DATA, 0x38,
4998 entry_args=entry_args, use_expanded=True)
4999
Simon Glasse1915782021-03-21 18:24:31 +13005000 def testCollection(self):
5001 """Test a collection"""
5002 data = self._DoReadFile('198_collection.dts')
5003 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07005004 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5005 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13005006 data)
5007
Simon Glass27a7f772021-03-21 18:24:32 +13005008 def testCollectionSection(self):
5009 """Test a collection where a section must be built first"""
5010 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07005011 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13005012 # building the contents, producing an error is anything is still
5013 # missing.
5014 data = self._DoReadFile('199_collection_section.dts')
5015 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07005016 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
5017 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13005018 data)
5019
Simon Glassf427c5f2021-03-21 18:24:33 +13005020 def testAlignDefault(self):
5021 """Test that default alignment works on sections"""
5022 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07005023 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13005024 U_BOOT_DATA)
5025 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07005026 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13005027 # No alignment within the nested section
5028 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
5029 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07005030 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13005031 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13005032
Bin Mengc0b15742021-05-10 20:23:33 +08005033 def testPackOpenSBI(self):
5034 """Test that an image with an OpenSBI binary can be created"""
5035 data = self._DoReadFile('201_opensbi.dts')
5036 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
5037
Simon Glass76f496d2021-07-06 10:36:37 -06005038 def testSectionsSingleThread(self):
5039 """Test sections without multithreading"""
5040 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07005041 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
5042 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
5043 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06005044 self.assertEqual(expected, data)
5045
5046 def testThreadTimeout(self):
5047 """Test handling a thread that takes too long"""
5048 with self.assertRaises(ValueError) as e:
5049 self._DoTestFile('202_section_timeout.dts',
5050 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06005051 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06005052
Simon Glass748a1d42021-07-06 10:36:41 -06005053 def testTiming(self):
5054 """Test output of timing information"""
5055 data = self._DoReadFile('055_sections.dts')
5056 with test_util.capture_sys_output() as (stdout, stderr):
5057 state.TimingShow()
5058 self.assertIn('read:', stdout.getvalue())
5059 self.assertIn('compress:', stdout.getvalue())
5060
Simon Glassadfb8492021-11-03 21:09:18 -06005061 def testUpdateFdtInElf(self):
5062 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005063 if not elf.ELF_TOOLS:
5064 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005065 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5066 outfile = os.path.join(self._indir, 'u-boot.out')
5067 begin_sym = 'dtb_embed_begin'
5068 end_sym = 'dtb_embed_end'
5069 retcode = self._DoTestFile(
5070 '060_fdt_update.dts', update_dtb=True,
5071 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5072 self.assertEqual(0, retcode)
5073
5074 # Check that the output file does in fact contact a dtb with the binman
5075 # definition in the correct place
5076 syms = elf.GetSymbolFileOffset(infile,
5077 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07005078 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06005079 dtb_data = data[syms['dtb_embed_begin'].offset:
5080 syms['dtb_embed_end'].offset]
5081
5082 dtb = fdt.Fdt.FromData(dtb_data)
5083 dtb.Scan()
5084 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
5085 self.assertEqual({
5086 'image-pos': 0,
5087 'offset': 0,
5088 '_testing:offset': 32,
5089 '_testing:size': 2,
5090 '_testing:image-pos': 32,
5091 'section@0/u-boot:offset': 0,
5092 'section@0/u-boot:size': len(U_BOOT_DATA),
5093 'section@0/u-boot:image-pos': 0,
5094 'section@0:offset': 0,
5095 'section@0:size': 16,
5096 'section@0:image-pos': 0,
5097
5098 'section@1/u-boot:offset': 0,
5099 'section@1/u-boot:size': len(U_BOOT_DATA),
5100 'section@1/u-boot:image-pos': 16,
5101 'section@1:offset': 16,
5102 'section@1:size': 16,
5103 'section@1:image-pos': 16,
5104 'size': 40
5105 }, props)
5106
5107 def testUpdateFdtInElfInvalid(self):
5108 """Test that invalid args are detected with --update-fdt-in-elf"""
5109 with self.assertRaises(ValueError) as e:
5110 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5111 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5112 str(e.exception))
5113
5114 def testUpdateFdtInElfNoSyms(self):
5115 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005116 if not elf.ELF_TOOLS:
5117 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005118 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5119 outfile = ''
5120 begin_sym = 'wrong_begin'
5121 end_sym = 'wrong_end'
5122 with self.assertRaises(ValueError) as e:
5123 self._DoTestFile(
5124 '060_fdt_update.dts',
5125 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5126 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5127 str(e.exception))
5128
5129 def testUpdateFdtInElfTooSmall(self):
5130 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005131 if not elf.ELF_TOOLS:
5132 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005133 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5134 outfile = os.path.join(self._indir, 'u-boot.out')
5135 begin_sym = 'dtb_embed_begin'
5136 end_sym = 'dtb_embed_end'
5137 with self.assertRaises(ValueError) as e:
5138 self._DoTestFile(
5139 '060_fdt_update.dts', update_dtb=True,
5140 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5141 self.assertRegex(
5142 str(e.exception),
5143 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5144
Simon Glass88e04da2021-11-23 11:03:42 -07005145 def testVersion(self):
5146 """Test we can get the binman version"""
5147 version = '(unreleased)'
5148 self.assertEqual(version, state.GetVersion(self._indir))
5149
5150 with self.assertRaises(SystemExit):
5151 with test_util.capture_sys_output() as (_, stderr):
5152 self._DoBinman('-V')
5153 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5154
5155 # Try running the tool too, just to be safe
5156 result = self._RunBinman('-V')
5157 self.assertEqual('Binman %s\n' % version, result.stderr)
5158
5159 # Set up a version file to make sure that works
5160 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005161 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005162 binary=False)
5163 self.assertEqual(version, state.GetVersion(self._indir))
5164
Simon Glass637958f2021-11-23 21:09:50 -07005165 def testAltFormat(self):
5166 """Test that alternative formats can be used to extract"""
5167 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5168
5169 try:
5170 tmpdir, updated_fname = self._SetupImageInTmpdir()
5171 with test_util.capture_sys_output() as (stdout, _):
5172 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5173 self.assertEqual(
5174 '''Flag (-F) Entry type Description
5175fdt fdtmap Extract the devicetree blob from the fdtmap
5176''',
5177 stdout.getvalue())
5178
5179 dtb = os.path.join(tmpdir, 'fdt.dtb')
5180 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5181 dtb, 'fdtmap')
5182
5183 # Check that we can read it and it can be scanning, meaning it does
5184 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005185 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005186 dtb = fdt.Fdt.FromData(data)
5187 dtb.Scan()
5188
5189 # Now check u-boot which has no alt_format
5190 fname = os.path.join(tmpdir, 'fdt.dtb')
5191 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5192 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005193 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005194 self.assertEqual(U_BOOT_DATA, data)
5195
5196 finally:
5197 shutil.rmtree(tmpdir)
5198
Simon Glass0b00ae62021-11-23 21:09:52 -07005199 def testExtblobList(self):
5200 """Test an image with an external blob list"""
5201 data = self._DoReadFile('215_blob_ext_list.dts')
5202 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5203
5204 def testExtblobListMissing(self):
5205 """Test an image with a missing external blob"""
5206 with self.assertRaises(ValueError) as e:
5207 self._DoReadFile('216_blob_ext_list_missing.dts')
5208 self.assertIn("Filename 'missing-file' not found in input path",
5209 str(e.exception))
5210
5211 def testExtblobListMissingOk(self):
5212 """Test an image with an missing external blob that is allowed"""
5213 with test_util.capture_sys_output() as (stdout, stderr):
5214 self._DoTestFile('216_blob_ext_list_missing.dts',
5215 allow_missing=True)
5216 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005217 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005218
Simon Glass3efb2972021-11-23 21:08:59 -07005219 def testFip(self):
5220 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5221 data = self._DoReadFile('203_fip.dts')
5222 hdr, fents = fip_util.decode_fip(data)
5223 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5224 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5225 self.assertEqual(0x123, hdr.flags)
5226
5227 self.assertEqual(2, len(fents))
5228
5229 fent = fents[0]
5230 self.assertEqual(
5231 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5232 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5233 self.assertEqual('soc-fw', fent.fip_type)
5234 self.assertEqual(0x88, fent.offset)
5235 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5236 self.assertEqual(0x123456789abcdef, fent.flags)
5237 self.assertEqual(ATF_BL31_DATA, fent.data)
5238 self.assertEqual(True, fent.valid)
5239
5240 fent = fents[1]
5241 self.assertEqual(
5242 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5243 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5244 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5245 self.assertEqual(0x8c, fent.offset)
5246 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5247 self.assertEqual(0, fent.flags)
5248 self.assertEqual(ATF_BL2U_DATA, fent.data)
5249 self.assertEqual(True, fent.valid)
5250
5251 def testFipOther(self):
5252 """Basic FIP with something that isn't a external blob"""
5253 data = self._DoReadFile('204_fip_other.dts')
5254 hdr, fents = fip_util.decode_fip(data)
5255
5256 self.assertEqual(2, len(fents))
5257 fent = fents[1]
5258 self.assertEqual('rot-cert', fent.fip_type)
5259 self.assertEqual(b'aa', fent.data)
5260
Simon Glass3efb2972021-11-23 21:08:59 -07005261 def testFipNoType(self):
5262 """FIP with an entry of an unknown type"""
5263 with self.assertRaises(ValueError) as e:
5264 self._DoReadFile('205_fip_no_type.dts')
5265 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5266 str(e.exception))
5267
5268 def testFipUuid(self):
5269 """Basic FIP with a manual uuid"""
5270 data = self._DoReadFile('206_fip_uuid.dts')
5271 hdr, fents = fip_util.decode_fip(data)
5272
5273 self.assertEqual(2, len(fents))
5274 fent = fents[1]
5275 self.assertEqual(None, fent.fip_type)
5276 self.assertEqual(
5277 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5278 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5279 fent.uuid)
5280 self.assertEqual(U_BOOT_DATA, fent.data)
5281
5282 def testFipLs(self):
5283 """Test listing a FIP"""
5284 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5285 hdr, fents = fip_util.decode_fip(data)
5286
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005287 tmpdir = None
Simon Glass3efb2972021-11-23 21:08:59 -07005288 try:
5289 tmpdir, updated_fname = self._SetupImageInTmpdir()
5290 with test_util.capture_sys_output() as (stdout, stderr):
5291 self._DoBinman('ls', '-i', updated_fname)
5292 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005293 if tmpdir:
5294 shutil.rmtree(tmpdir)
Simon Glass3efb2972021-11-23 21:08:59 -07005295 lines = stdout.getvalue().splitlines()
5296 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005297'Name Image-pos Size Entry-type Offset Uncomp-size',
5298'--------------------------------------------------------------',
5299'image 0 2d3 section 0',
5300' atf-fip 0 90 atf-fip 0',
5301' soc-fw 88 4 blob-ext 88',
5302' u-boot 8c 4 u-boot 8c',
5303' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005304]
5305 self.assertEqual(expected, lines)
5306
5307 image = control.images['image']
5308 entries = image.GetEntries()
5309 fdtmap = entries['fdtmap']
5310
5311 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5312 magic = fdtmap_data[:8]
5313 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005314 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005315
5316 fdt_data = fdtmap_data[16:]
5317 dtb = fdt.Fdt.FromData(fdt_data)
5318 dtb.Scan()
5319 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5320 self.assertEqual({
5321 'atf-fip/soc-fw:image-pos': 136,
5322 'atf-fip/soc-fw:offset': 136,
5323 'atf-fip/soc-fw:size': 4,
5324 'atf-fip/u-boot:image-pos': 140,
5325 'atf-fip/u-boot:offset': 140,
5326 'atf-fip/u-boot:size': 4,
5327 'atf-fip:image-pos': 0,
5328 'atf-fip:offset': 0,
5329 'atf-fip:size': 144,
5330 'image-pos': 0,
5331 'offset': 0,
5332 'fdtmap:image-pos': fdtmap.image_pos,
5333 'fdtmap:offset': fdtmap.offset,
5334 'fdtmap:size': len(fdtmap_data),
5335 'size': len(data),
5336 }, props)
5337
5338 def testFipExtractOneEntry(self):
5339 """Test extracting a single entry fron an FIP"""
5340 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005341 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005342 fname = os.path.join(self._indir, 'output.extact')
5343 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005344 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005345 self.assertEqual(U_BOOT_DATA, data)
5346
5347 def testFipReplace(self):
5348 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005349 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005350 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005351 updated_fname = tools.get_output_filename('image-updated.bin')
5352 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005353 entry_name = 'atf-fip/u-boot'
5354 control.WriteEntry(updated_fname, entry_name, expected,
5355 allow_resize=True)
5356 actual = control.ReadEntry(updated_fname, entry_name)
5357 self.assertEqual(expected, actual)
5358
Simon Glass80025522022-01-29 14:14:04 -07005359 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005360 hdr, fents = fip_util.decode_fip(new_data)
5361
5362 self.assertEqual(2, len(fents))
5363
5364 # Check that the FIP entry is updated
5365 fent = fents[1]
5366 self.assertEqual(0x8c, fent.offset)
5367 self.assertEqual(len(expected), fent.size)
5368 self.assertEqual(0, fent.flags)
5369 self.assertEqual(expected, fent.data)
5370 self.assertEqual(True, fent.valid)
5371
5372 def testFipMissing(self):
5373 with test_util.capture_sys_output() as (stdout, stderr):
5374 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5375 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005376 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005377
5378 def testFipSize(self):
5379 """Test a FIP with a size property"""
5380 data = self._DoReadFile('210_fip_size.dts')
5381 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5382 hdr, fents = fip_util.decode_fip(data)
5383 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5384 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5385
5386 self.assertEqual(1, len(fents))
5387
5388 fent = fents[0]
5389 self.assertEqual('soc-fw', fent.fip_type)
5390 self.assertEqual(0x60, fent.offset)
5391 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5392 self.assertEqual(ATF_BL31_DATA, fent.data)
5393 self.assertEqual(True, fent.valid)
5394
5395 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005396 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005397
5398 def testFipBadAlign(self):
5399 """Test that an invalid alignment value in a FIP is detected"""
5400 with self.assertRaises(ValueError) as e:
5401 self._DoTestFile('211_fip_bad_align.dts')
5402 self.assertIn(
5403 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5404 str(e.exception))
5405
5406 def testFipCollection(self):
5407 """Test using a FIP in a collection"""
5408 data = self._DoReadFile('212_fip_collection.dts')
5409 entry1 = control.images['image'].GetEntries()['collection']
5410 data1 = data[:entry1.size]
5411 hdr1, fents2 = fip_util.decode_fip(data1)
5412
5413 entry2 = control.images['image'].GetEntries()['atf-fip']
5414 data2 = data[entry2.offset:entry2.offset + entry2.size]
5415 hdr1, fents2 = fip_util.decode_fip(data2)
5416
5417 # The 'collection' entry should have U-Boot included at the end
5418 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5419 self.assertEqual(data1, data2 + U_BOOT_DATA)
5420 self.assertEqual(U_BOOT_DATA, data1[-4:])
5421
5422 # There should be a U-Boot after the final FIP
5423 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005424
Simon Glassccae6862022-01-12 13:10:35 -07005425 def testFakeBlob(self):
5426 """Test handling of faking an external blob"""
5427 with test_util.capture_sys_output() as (stdout, stderr):
5428 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5429 allow_fake_blobs=True)
5430 err = stderr.getvalue()
5431 self.assertRegex(
5432 err,
5433 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005434
Simon Glassceb5f912022-01-09 20:13:46 -07005435 def testExtblobListFaked(self):
5436 """Test an extblob with missing external blob that are faked"""
5437 with test_util.capture_sys_output() as (stdout, stderr):
5438 self._DoTestFile('216_blob_ext_list_missing.dts',
5439 allow_fake_blobs=True)
5440 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005441 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005442
Simon Glass162017b2022-01-09 20:13:57 -07005443 def testListBintools(self):
5444 args = ['tool', '--list']
5445 with test_util.capture_sys_output() as (stdout, _):
5446 self._DoBinman(*args)
5447 out = stdout.getvalue().splitlines()
5448 self.assertTrue(len(out) >= 2)
5449
5450 def testFetchBintools(self):
5451 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005452 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005453 raise urllib.error.URLError('my error')
5454
5455 args = ['tool']
5456 with self.assertRaises(ValueError) as e:
5457 self._DoBinman(*args)
5458 self.assertIn("Invalid arguments to 'tool' subcommand",
5459 str(e.exception))
5460
5461 args = ['tool', '--fetch']
5462 with self.assertRaises(ValueError) as e:
5463 self._DoBinman(*args)
5464 self.assertIn('Please specify bintools to fetch', str(e.exception))
5465
5466 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005467 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005468 side_effect=fail_download):
5469 with test_util.capture_sys_output() as (stdout, _):
5470 self._DoBinman(*args)
5471 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5472
Simon Glass620c4462022-01-09 20:14:11 -07005473 def testBintoolDocs(self):
5474 """Test for creation of bintool documentation"""
5475 with test_util.capture_sys_output() as (stdout, stderr):
5476 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5477 self.assertTrue(len(stdout.getvalue()) > 0)
5478
5479 def testBintoolDocsMissing(self):
5480 """Test handling of missing bintool documentation"""
5481 with self.assertRaises(ValueError) as e:
5482 with test_util.capture_sys_output() as (stdout, stderr):
5483 control.write_bintool_docs(
5484 control.bintool.Bintool.get_tool_list(), 'mkimage')
5485 self.assertIn('Documentation is missing for modules: mkimage',
5486 str(e.exception))
5487
Jan Kiszka58c407f2022-01-28 20:37:53 +01005488 def testListWithGenNode(self):
5489 """Check handling of an FDT map when the section cannot be found"""
5490 entry_args = {
5491 'of-list': 'test-fdt1 test-fdt2',
5492 }
5493 data = self._DoReadFileDtb(
5494 '219_fit_gennode.dts',
5495 entry_args=entry_args,
5496 use_real_dtb=True,
5497 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5498
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005499 tmpdir = None
Jan Kiszka58c407f2022-01-28 20:37:53 +01005500 try:
5501 tmpdir, updated_fname = self._SetupImageInTmpdir()
5502 with test_util.capture_sys_output() as (stdout, stderr):
5503 self._RunBinman('ls', '-i', updated_fname)
5504 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005505 if tmpdir:
5506 shutil.rmtree(tmpdir)
Jan Kiszka58c407f2022-01-28 20:37:53 +01005507
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005508 def testFitSubentryUsesBintool(self):
5509 """Test that binman FIT subentries can use bintools"""
Simon Glass5dc22cf2025-02-03 09:26:42 -07005510 command.TEST_RESULT = self._HandleGbbCommand
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005511 entry_args = {
5512 'keydir': 'devkeys',
5513 'bmpblk': 'bmpblk.bin',
5514 }
5515 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5516 entry_args=entry_args)
5517
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005518 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5519 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005520 self.assertIn(expected, data)
5521
5522 def testFitSubentryMissingBintool(self):
5523 """Test that binman reports missing bintools for FIT subentries"""
5524 entry_args = {
5525 'keydir': 'devkeys',
5526 }
5527 with test_util.capture_sys_output() as (_, stderr):
5528 self._DoTestFile('220_fit_subentry_bintool.dts',
5529 force_missing_bintools='futility', entry_args=entry_args)
5530 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005531 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005532
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005533 def testFitSubentryHashSubnode(self):
5534 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005535 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005536 data, _, _, out_dtb_name = self._DoReadFileDtb(
5537 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5538
5539 mkimage_dtb = fdt.Fdt.FromData(data)
5540 mkimage_dtb.Scan()
5541 binman_dtb = fdt.Fdt(out_dtb_name)
5542 binman_dtb.Scan()
5543
5544 # Check that binman didn't add hash values
5545 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5546 self.assertNotIn('value', fnode.props)
5547
5548 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5549 self.assertNotIn('value', fnode.props)
5550
5551 # Check that mkimage added hash values
5552 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5553 self.assertIn('value', fnode.props)
5554
5555 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5556 self.assertIn('value', fnode.props)
5557
Roger Quadros5cdcea02022-02-19 20:50:04 +02005558 def testPackTeeOs(self):
5559 """Test that an image with an TEE binary can be created"""
5560 data = self._DoReadFile('222_tee_os.dts')
5561 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5562
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305563 def testPackTiDm(self):
5564 """Test that an image with a TI DM binary can be created"""
5565 data = self._DoReadFile('225_ti_dm.dts')
5566 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5567
Simon Glass912339f2022-02-08 11:50:03 -07005568 def testFitFdtOper(self):
5569 """Check handling of a specified FIT operation"""
5570 entry_args = {
5571 'of-list': 'test-fdt1 test-fdt2',
5572 'default-dt': 'test-fdt2',
5573 }
5574 self._DoReadFileDtb(
5575 '223_fit_fdt_oper.dts',
5576 entry_args=entry_args,
5577 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5578
5579 def testFitFdtBadOper(self):
5580 """Check handling of an FDT map when the section cannot be found"""
5581 with self.assertRaises(ValueError) as exc:
5582 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005583 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005584 str(exc.exception))
5585
Simon Glassdd156a42022-03-05 20:18:59 -07005586 def test_uses_expand_size(self):
5587 """Test that the 'expand-size' property cannot be used anymore"""
5588 with self.assertRaises(ValueError) as e:
5589 data = self._DoReadFile('225_expand_size_bad.dts')
5590 self.assertIn(
5591 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5592 str(e.exception))
5593
Simon Glass5f423422022-03-05 20:19:12 -07005594 def testFitSplitElf(self):
5595 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005596 if not elf.ELF_TOOLS:
5597 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005598 entry_args = {
5599 'of-list': 'test-fdt1 test-fdt2',
5600 'default-dt': 'test-fdt2',
5601 'atf-bl31-path': 'bl31.elf',
5602 'tee-os-path': 'tee.elf',
5603 }
5604 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5605 data = self._DoReadFileDtb(
5606 '226_fit_split_elf.dts',
5607 entry_args=entry_args,
5608 extra_indirs=[test_subdir])[0]
5609
5610 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5611 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5612
5613 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5614 'data', 'load'}
5615 dtb = fdt.Fdt.FromData(fit_data)
5616 dtb.Scan()
5617
5618 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5619 segments, entry = elf.read_loadable_segments(elf_data)
5620
5621 # We assume there are two segments
Brandon Maiera657bc62024-06-04 16:16:05 +00005622 self.assertEqual(2, len(segments))
Simon Glass5f423422022-03-05 20:19:12 -07005623
5624 atf1 = dtb.GetNode('/images/atf-1')
5625 _, start, data = segments[0]
5626 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5627 self.assertEqual(entry,
5628 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5629 self.assertEqual(start,
5630 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5631 self.assertEqual(data, atf1.props['data'].bytes)
5632
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005633 hash_node = atf1.FindNode('hash')
5634 self.assertIsNotNone(hash_node)
5635 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5636
Simon Glass5f423422022-03-05 20:19:12 -07005637 atf2 = dtb.GetNode('/images/atf-2')
5638 self.assertEqual(base_keys, atf2.props.keys())
5639 _, start, data = segments[1]
5640 self.assertEqual(start,
5641 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5642 self.assertEqual(data, atf2.props['data'].bytes)
5643
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005644 hash_node = atf2.FindNode('hash')
5645 self.assertIsNotNone(hash_node)
5646 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5647
5648 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5649 self.assertIsNotNone(hash_node)
5650 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5651
Simon Glass5f423422022-03-05 20:19:12 -07005652 conf = dtb.GetNode('/configurations')
5653 self.assertEqual({'default'}, conf.props.keys())
5654
5655 for subnode in conf.subnodes:
5656 self.assertEqual({'description', 'fdt', 'loadables'},
5657 subnode.props.keys())
5658 self.assertEqual(
5659 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5660 fdt_util.GetStringList(subnode, 'loadables'))
5661
5662 def _check_bad_fit(self, dts):
5663 """Check a bad FIT
5664
5665 This runs with the given dts and returns the assertion raised
5666
5667 Args:
5668 dts (str): dts filename to use
5669
5670 Returns:
5671 str: Assertion string raised
5672 """
5673 entry_args = {
5674 'of-list': 'test-fdt1 test-fdt2',
5675 'default-dt': 'test-fdt2',
5676 'atf-bl31-path': 'bl31.elf',
5677 'tee-os-path': 'tee.elf',
5678 }
5679 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5680 with self.assertRaises(ValueError) as exc:
5681 self._DoReadFileDtb(dts, entry_args=entry_args,
5682 extra_indirs=[test_subdir])[0]
5683 return str(exc.exception)
5684
5685 def testFitSplitElfBadElf(self):
5686 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005687 if not elf.ELF_TOOLS:
5688 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005689 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5690 entry_args = {
5691 'of-list': 'test-fdt1 test-fdt2',
5692 'default-dt': 'test-fdt2',
5693 'atf-bl31-path': 'bad.elf',
5694 'tee-os-path': 'tee.elf',
5695 }
5696 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5697 with self.assertRaises(ValueError) as exc:
5698 self._DoReadFileDtb(
5699 '226_fit_split_elf.dts',
5700 entry_args=entry_args,
5701 extra_indirs=[test_subdir])[0]
5702 self.assertIn(
5703 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5704 str(exc.exception))
5705
Simon Glass5f423422022-03-05 20:19:12 -07005706 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005707 """Test an split-elf FIT with a missing ELF file
5708
5709 Args:
5710 kwargs (dict of str): Arguments to pass to _DoTestFile()
5711
5712 Returns:
5713 tuple:
5714 str: stdout result
5715 str: stderr result
5716 """
Simon Glass5f423422022-03-05 20:19:12 -07005717 entry_args = {
5718 'of-list': 'test-fdt1 test-fdt2',
5719 'default-dt': 'test-fdt2',
5720 'atf-bl31-path': 'bl31.elf',
5721 'tee-os-path': 'missing.elf',
5722 }
5723 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5724 with test_util.capture_sys_output() as (stdout, stderr):
5725 self._DoTestFile(
5726 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005727 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5728 out = stdout.getvalue()
5729 err = stderr.getvalue()
5730 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005731
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005732 def testFitSplitElfBadDirective(self):
5733 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5734 if not elf.ELF_TOOLS:
5735 self.skipTest('Python elftools not available')
5736 err = self._check_bad_fit('227_fit_bad_dir.dts')
5737 self.assertIn(
5738 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5739 err)
5740
5741 def testFitSplitElfBadDirectiveConfig(self):
5742 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5743 if not elf.ELF_TOOLS:
5744 self.skipTest('Python elftools not available')
5745 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5746 self.assertEqual(
5747 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5748 err)
5749
5750
Simon Glass5f423422022-03-05 20:19:12 -07005751 def testFitSplitElfMissing(self):
5752 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005753 if not elf.ELF_TOOLS:
5754 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005755 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005756 self.assertRegex(
5757 err,
5758 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005759 self.assertNotRegex(out, '.*Faked blob.*')
5760 fname = tools.get_output_filename('binman-fake/missing.elf')
5761 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005762
5763 def testFitSplitElfFaked(self):
5764 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005765 if not elf.ELF_TOOLS:
5766 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005767 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005768 self.assertRegex(
5769 err,
5770 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005771 self.assertRegex(
5772 out,
5773 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5774 fname = tools.get_output_filename('binman-fake/missing.elf')
5775 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005776
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005777 def testMkimageMissingBlob(self):
5778 """Test using mkimage to build an image"""
5779 with test_util.capture_sys_output() as (stdout, stderr):
5780 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5781 allow_fake_blobs=True)
5782 err = stderr.getvalue()
5783 self.assertRegex(
5784 err,
5785 "Image '.*' has faked external blobs and is non-functional: .*")
5786
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005787 def testPreLoad(self):
5788 """Test an image with a pre-load header"""
5789 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005790 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005791 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005792 data = self._DoReadFileDtb(
5793 '230_pre_load.dts', entry_args=entry_args,
5794 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Paul HENRYS5cf82892025-02-24 22:20:55 +01005795
5796 image_fname = tools.get_output_filename('image.bin')
5797 is_signed = self._CheckPreload(image_fname, self.TestFile("dev.key"))
5798
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005799 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5800 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5801 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Paul HENRYS5cf82892025-02-24 22:20:55 +01005802 self.assertEqual(is_signed, True)
Simon Glasse2dfb962023-07-24 09:19:57 -06005803
5804 def testPreLoadNoKey(self):
5805 """Test an image with a pre-load heade0r with missing key"""
5806 with self.assertRaises(FileNotFoundError) as exc:
5807 self._DoReadFile('230_pre_load.dts')
5808 self.assertIn("No such file or directory: 'dev.key'",
5809 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005810
5811 def testPreLoadPkcs(self):
5812 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005813 entry_args = {
5814 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5815 }
5816 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5817 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005818 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5819 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5820 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5821
5822 def testPreLoadPss(self):
5823 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005824 entry_args = {
5825 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5826 }
5827 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5828 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005829 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5830 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5831 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5832
5833 def testPreLoadInvalidPadding(self):
5834 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005835 entry_args = {
5836 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5837 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005838 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005839 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5840 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005841
5842 def testPreLoadInvalidSha(self):
5843 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005844 entry_args = {
5845 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5846 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005847 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005848 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5849 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005850
5851 def testPreLoadInvalidAlgo(self):
5852 """Test an image with a pre-load header with an invalid algo"""
5853 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005854 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005855
5856 def testPreLoadInvalidKey(self):
5857 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005858 entry_args = {
5859 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5860 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005861 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005862 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5863 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005864
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005865 def _CheckSafeUniqueNames(self, *images):
5866 """Check all entries of given images for unsafe unique names"""
5867 for image in images:
5868 entries = {}
5869 image._CollectEntries(entries, {}, image)
5870 for entry in entries.values():
5871 uniq = entry.GetUniqueName()
5872
5873 # Used as part of a filename, so must not be absolute paths.
5874 self.assertFalse(os.path.isabs(uniq))
5875
5876 def testSafeUniqueNames(self):
5877 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005878 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005879
5880 orig_image = control.images['image']
5881 image_fname = tools.get_output_filename('image.bin')
5882 image = Image.FromFile(image_fname)
5883
5884 self._CheckSafeUniqueNames(orig_image, image)
5885
5886 def testSafeUniqueNamesMulti(self):
5887 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005888 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005889
5890 orig_image = control.images['image']
5891 image_fname = tools.get_output_filename('image.bin')
5892 image = Image.FromFile(image_fname)
5893
5894 self._CheckSafeUniqueNames(orig_image, image)
5895
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005896 def testReplaceCmdWithBintool(self):
5897 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005898 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005899 expected = U_BOOT_DATA + b'aa'
5900 self.assertEqual(expected, data[:len(expected)])
5901
5902 try:
5903 tmpdir, updated_fname = self._SetupImageInTmpdir()
5904 fname = os.path.join(tmpdir, 'update-testing.bin')
5905 tools.write_file(fname, b'zz')
5906 self._DoBinman('replace', '-i', updated_fname,
5907 '_testing', '-f', fname)
5908
5909 data = tools.read_file(updated_fname)
5910 expected = U_BOOT_DATA + b'zz'
5911 self.assertEqual(expected, data[:len(expected)])
5912 finally:
5913 shutil.rmtree(tmpdir)
5914
5915 def testReplaceCmdOtherWithBintool(self):
5916 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005917 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005918 expected = U_BOOT_DATA + b'aa'
5919 self.assertEqual(expected, data[:len(expected)])
5920
5921 try:
5922 tmpdir, updated_fname = self._SetupImageInTmpdir()
5923 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5924 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5925 self._DoBinman('replace', '-i', updated_fname,
5926 'u-boot', '-f', fname)
5927
5928 data = tools.read_file(updated_fname)
5929 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5930 self.assertEqual(expected, data[:len(expected)])
5931 finally:
5932 shutil.rmtree(tmpdir)
5933
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005934 def testReplaceResizeNoRepackSameSize(self):
5935 """Test replacing entries with same-size data without repacking"""
5936 expected = b'x' * len(U_BOOT_DATA)
5937 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5938 self.assertEqual(expected, data)
5939
5940 path, fdtmap = state.GetFdtContents('fdtmap')
5941 self.assertIsNotNone(path)
5942 self.assertEqual(expected_fdtmap, fdtmap)
5943
5944 def testReplaceResizeNoRepackSmallerSize(self):
5945 """Test replacing entries with smaller-size data without repacking"""
5946 new_data = b'x'
5947 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5948 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5949 self.assertEqual(expected, data)
5950
5951 path, fdtmap = state.GetFdtContents('fdtmap')
5952 self.assertIsNotNone(path)
5953 self.assertEqual(expected_fdtmap, fdtmap)
5954
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005955 def testExtractFit(self):
5956 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005957 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005958 image_fname = tools.get_output_filename('image.bin')
5959
5960 fit_data = control.ReadEntry(image_fname, 'fit')
5961 fit = fdt.Fdt.FromData(fit_data)
5962 fit.Scan()
5963
5964 # Check subentry data inside the extracted fit
5965 for node_path, expected in [
5966 ('/images/kernel', U_BOOT_DATA),
5967 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5968 ('/images/scr-1', COMPRESS_DATA),
5969 ]:
5970 node = fit.GetNode(node_path)
5971 data = fit.GetProps(node)['data'].bytes
5972 self.assertEqual(expected, data)
5973
5974 def testExtractFitSubentries(self):
5975 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005976 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005977 image_fname = tools.get_output_filename('image.bin')
5978
5979 for entry_path, expected in [
5980 ('fit/kernel', U_BOOT_DATA),
5981 ('fit/kernel/u-boot', U_BOOT_DATA),
5982 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5983 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5984 ('fit/scr-1', COMPRESS_DATA),
5985 ('fit/scr-1/blob', COMPRESS_DATA),
5986 ]:
5987 data = control.ReadEntry(image_fname, entry_path)
5988 self.assertEqual(expected, data)
5989
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005990 def testReplaceFitSubentryLeafSameSize(self):
5991 """Test replacing a FIT leaf subentry with same-size data"""
5992 new_data = b'x' * len(U_BOOT_DATA)
5993 data, expected_fdtmap, _ = self._RunReplaceCmd(
5994 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005995 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005996 self.assertEqual(new_data, data)
5997
5998 path, fdtmap = state.GetFdtContents('fdtmap')
5999 self.assertIsNotNone(path)
6000 self.assertEqual(expected_fdtmap, fdtmap)
6001
6002 def testReplaceFitSubentryLeafBiggerSize(self):
6003 """Test replacing a FIT leaf subentry with bigger-size data"""
6004 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
6005 data, expected_fdtmap, _ = self._RunReplaceCmd(
6006 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006007 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006008 self.assertEqual(new_data, data)
6009
6010 # Will be repacked, so fdtmap must change
6011 path, fdtmap = state.GetFdtContents('fdtmap')
6012 self.assertIsNotNone(path)
6013 self.assertNotEqual(expected_fdtmap, fdtmap)
6014
6015 def testReplaceFitSubentryLeafSmallerSize(self):
6016 """Test replacing a FIT leaf subentry with smaller-size data"""
6017 new_data = b'x'
6018 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
6019 data, expected_fdtmap, _ = self._RunReplaceCmd(
6020 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006021 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006022 self.assertEqual(expected, data)
6023
6024 path, fdtmap = state.GetFdtContents('fdtmap')
6025 self.assertIsNotNone(path)
6026 self.assertEqual(expected_fdtmap, fdtmap)
6027
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006028 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07006029 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006030 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07006031 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6032 new_data, dts='241_replace_section_simple.dts')
6033 self.assertEqual(new_data, data)
6034
6035 entries = image.GetEntries()
6036 self.assertIn('section', entries)
6037 entry = entries['section']
6038 self.assertEqual(len(new_data), entry.size)
6039
6040 def testReplaceSectionLarger(self):
6041 """Test replacing a simple section with larger data"""
6042 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6043 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6044 new_data, dts='241_replace_section_simple.dts')
6045 self.assertEqual(new_data, data)
6046
6047 entries = image.GetEntries()
6048 self.assertIn('section', entries)
6049 entry = entries['section']
6050 self.assertEqual(len(new_data), entry.size)
6051 fentry = entries['fdtmap']
6052 self.assertEqual(entry.offset + entry.size, fentry.offset)
6053
6054 def testReplaceSectionSmaller(self):
6055 """Test replacing a simple section with smaller data"""
6056 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
6057 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6058 new_data, dts='241_replace_section_simple.dts')
6059 self.assertEqual(new_data, data)
6060
6061 # The new size is the same as the old, just with a pad byte at the end
6062 entries = image.GetEntries()
6063 self.assertIn('section', entries)
6064 entry = entries['section']
6065 self.assertEqual(len(new_data), entry.size)
6066
6067 def testReplaceSectionSmallerAllow(self):
6068 """Test failing to replace a simple section with smaller data"""
6069 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
6070 try:
6071 state.SetAllowEntryContraction(True)
6072 with self.assertRaises(ValueError) as exc:
6073 self._RunReplaceCmd('section', new_data,
6074 dts='241_replace_section_simple.dts')
6075 finally:
6076 state.SetAllowEntryContraction(False)
6077
6078 # Since we have no information about the position of things within the
6079 # section, we cannot adjust the position of /section-u-boot so it ends
6080 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06006081 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07006082 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
6083 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06006084 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006085
Simon Glass8fbca772022-08-13 11:40:48 -06006086 def testMkimageImagename(self):
6087 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006088 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006089 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06006090
6091 # Check that the data appears in the file somewhere
6092 self.assertIn(U_BOOT_SPL_DATA, data)
6093
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006094 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06006095 name = data[0x20:0x40]
6096
6097 # Build the filename that we expect to be placed in there, by virtue of
6098 # the -n paraameter
6099 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6100
6101 # Check that the image name is set to the temporary filename used
6102 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6103
Simon Glassb1669752022-08-13 11:40:49 -06006104 def testMkimageImage(self):
6105 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006106 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006107 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006108
6109 # Check that the data appears in the file somewhere
6110 self.assertIn(U_BOOT_SPL_DATA, data)
6111
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006112 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006113 name = data[0x20:0x40]
6114
6115 # Build the filename that we expect to be placed in there, by virtue of
6116 # the -n paraameter
6117 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6118
6119 # Check that the image name is set to the temporary filename used
6120 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6121
6122 # Check the corect data is in the imagename file
6123 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6124
6125 def testMkimageImageNoContent(self):
6126 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006127 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006128 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006129 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006130 self.assertIn('Could not complete processing of contents',
6131 str(exc.exception))
6132
6133 def testMkimageImageBad(self):
6134 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006135 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006136 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006137 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006138 self.assertIn('Cannot use both imagename node and data-to-imagename',
6139 str(exc.exception))
6140
Simon Glassbd5cd882022-08-13 11:40:50 -06006141 def testCollectionOther(self):
6142 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006143 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006144 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6145 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6146 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6147 data)
6148
6149 def testMkimageCollection(self):
6150 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006151 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006152 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006153 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6154 self.assertEqual(expect, data[:len(expect)])
6155
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006156 def testCompressDtbPrependInvalid(self):
6157 """Test that invalid header is detected"""
6158 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006159 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006160 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6161 "'u-boot-dtb': 'invalid'", str(e.exception))
6162
6163 def testCompressDtbPrependLength(self):
6164 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006165 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006166 image = control.images['image']
6167 entries = image.GetEntries()
6168 self.assertIn('u-boot-dtb', entries)
6169 u_boot_dtb = entries['u-boot-dtb']
6170 self.assertIn('fdtmap', entries)
6171 fdtmap = entries['fdtmap']
6172
6173 image_fname = tools.get_output_filename('image.bin')
6174 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6175 dtb = fdt.Fdt.FromData(orig)
6176 dtb.Scan()
6177 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6178 expected = {
6179 'u-boot:size': len(U_BOOT_DATA),
6180 'u-boot-dtb:uncomp-size': len(orig),
6181 'u-boot-dtb:size': u_boot_dtb.size,
6182 'fdtmap:size': fdtmap.size,
6183 'size': len(data),
6184 }
6185 self.assertEqual(expected, props)
6186
6187 # Check implementation
6188 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6189 rest = data[len(U_BOOT_DATA):]
6190 comp_data_len = struct.unpack('<I', rest[:4])[0]
6191 comp_data = rest[4:4 + comp_data_len]
6192 orig2 = self._decompress(comp_data)
6193 self.assertEqual(orig, orig2)
6194
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006195 def testInvalidCompress(self):
6196 """Test that invalid compress algorithm is detected"""
6197 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006198 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006199 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6200
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006201 def testCompUtilCompressions(self):
6202 """Test compression algorithms"""
6203 for bintool in self.comp_bintools.values():
6204 self._CheckBintool(bintool)
6205 data = bintool.compress(COMPRESS_DATA)
6206 self.assertNotEqual(COMPRESS_DATA, data)
6207 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006208 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006209
6210 def testCompUtilVersions(self):
6211 """Test tool version of compression algorithms"""
6212 for bintool in self.comp_bintools.values():
6213 self._CheckBintool(bintool)
6214 version = bintool.version()
6215 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6216
6217 def testCompUtilPadding(self):
6218 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006219 # Skip zstd because it doesn't support padding
6220 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006221 self._CheckBintool(bintool)
6222 data = bintool.compress(COMPRESS_DATA)
6223 self.assertNotEqual(COMPRESS_DATA, data)
6224 data += tools.get_bytes(0, 64)
6225 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006226 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006227
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006228 def testCompressDtbZstd(self):
6229 """Test that zstd compress of device-tree files failed"""
6230 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006231 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006232 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6233 "requires a length header", str(e.exception))
6234
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006235 def testMkimageMultipleDataFiles(self):
6236 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006237 self._SetupSplElf()
6238 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006239 data = self._DoReadFile('252_mkimage_mult_data.dts')
6240 # Size of files are packed in their 4B big-endian format
6241 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6242 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6243 # Size info is always followed by a 4B zero value.
6244 expect += tools.get_bytes(0, 4)
6245 expect += U_BOOT_TPL_DATA
6246 # All but last files are 4B-aligned
6247 align_pad = len(U_BOOT_TPL_DATA) % 4
6248 if align_pad:
6249 expect += tools.get_bytes(0, align_pad)
6250 expect += U_BOOT_SPL_DATA
6251 self.assertEqual(expect, data[-len(expect):])
6252
Marek Vasutf7413f02023-07-18 07:23:58 -06006253 def testMkimageMultipleExpanded(self):
6254 """Test passing multiple files to mkimage in a mkimage entry"""
6255 self._SetupSplElf()
6256 self._SetupTplElf()
6257 entry_args = {
6258 'spl-bss-pad': 'y',
6259 'spl-dtb': 'y',
6260 }
6261 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6262 use_expanded=True, entry_args=entry_args)[0]
6263 pad_len = 10
6264 tpl_expect = U_BOOT_TPL_DATA
6265 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6266 spl_expect += U_BOOT_SPL_DTB_DATA
6267
6268 content = data[0x40:]
6269 lens = struct.unpack('>III', content[:12])
6270
6271 # Size of files are packed in their 4B big-endian format
6272 # Size info is always followed by a 4B zero value.
6273 self.assertEqual(len(tpl_expect), lens[0])
6274 self.assertEqual(len(spl_expect), lens[1])
6275 self.assertEqual(0, lens[2])
6276
6277 rest = content[12:]
6278 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6279
6280 rest = rest[len(tpl_expect):]
6281 align_pad = len(tpl_expect) % 4
6282 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6283 rest = rest[align_pad:]
6284 self.assertEqual(spl_expect, rest)
6285
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006286 def testMkimageMultipleNoContent(self):
6287 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006288 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006289 with self.assertRaises(ValueError) as exc:
6290 self._DoReadFile('253_mkimage_mult_no_content.dts')
6291 self.assertIn('Could not complete processing of contents',
6292 str(exc.exception))
6293
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006294 def testMkimageFilename(self):
6295 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006296 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006297 retcode = self._DoTestFile('254_mkimage_filename.dts')
6298 self.assertEqual(0, retcode)
6299 fname = tools.get_output_filename('mkimage-test.bin')
6300 self.assertTrue(os.path.exists(fname))
6301
Simon Glass56d05412022-02-28 07:16:54 -07006302 def testVpl(self):
6303 """Test that an image with VPL and its device tree can be created"""
6304 # ELF file with a '__bss_size' symbol
6305 self._SetupVplElf()
6306 data = self._DoReadFile('255_u_boot_vpl.dts')
6307 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6308
6309 def testVplNoDtb(self):
6310 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6311 self._SetupVplElf()
6312 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6313 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6314 data[:len(U_BOOT_VPL_NODTB_DATA)])
6315
6316 def testExpandedVpl(self):
6317 """Test that an expanded entry type is selected for TPL when needed"""
6318 self._SetupVplElf()
6319
6320 entry_args = {
6321 'vpl-bss-pad': 'y',
6322 'vpl-dtb': 'y',
6323 }
6324 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6325 entry_args=entry_args)
6326 image = control.images['image']
6327 entries = image.GetEntries()
6328 self.assertEqual(1, len(entries))
6329
6330 # We only have u-boot-vpl, which be expanded
6331 self.assertIn('u-boot-vpl', entries)
6332 entry = entries['u-boot-vpl']
6333 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6334 subent = entry.GetEntries()
6335 self.assertEqual(3, len(subent))
6336 self.assertIn('u-boot-vpl-nodtb', subent)
6337 self.assertIn('u-boot-vpl-bss-pad', subent)
6338 self.assertIn('u-boot-vpl-dtb', subent)
6339
6340 def testVplBssPadMissing(self):
6341 """Test that a missing symbol is detected"""
6342 self._SetupVplElf('u_boot_ucode_ptr')
6343 with self.assertRaises(ValueError) as e:
6344 self._DoReadFile('258_vpl_bss_pad.dts')
6345 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6346 str(e.exception))
6347
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306348 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306349 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306350 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6351 self.assertEqual(0, retcode)
6352 image = control.images['test_image']
6353 fname = tools.get_output_filename('test_image.bin')
6354 sname = tools.get_output_filename('symlink_to_test.bin')
6355 self.assertTrue(os.path.islink(sname))
6356 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006357
Andrew Davis6b463da2023-07-22 00:14:44 +05306358 def testSymlinkOverwrite(self):
6359 """Test that symlinked images can be overwritten"""
6360 testdir = TestFunctional._MakeInputDir('symlinktest')
6361 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6362 # build the same image again in the same directory so that existing symlink is present
6363 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6364 fname = tools.get_output_filename('test_image.bin')
6365 sname = tools.get_output_filename('symlink_to_test.bin')
6366 self.assertTrue(os.path.islink(sname))
6367 self.assertEqual(os.readlink(sname), fname)
6368
Simon Glass37f85de2022-10-20 18:22:47 -06006369 def testSymbolsElf(self):
6370 """Test binman can assign symbols embedded in an ELF file"""
6371 if not elf.ELF_TOOLS:
6372 self.skipTest('Python elftools not available')
6373 self._SetupTplElf('u_boot_binman_syms')
6374 self._SetupVplElf('u_boot_binman_syms')
6375 self._SetupSplElf('u_boot_binman_syms')
6376 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6377 image_fname = tools.get_output_filename('image.bin')
6378
6379 image = control.images['image']
6380 entries = image.GetEntries()
6381
6382 for entry in entries.values():
6383 # No symbols in u-boot and it has faked contents anyway
6384 if entry.name == 'u-boot':
6385 continue
6386 edata = data[entry.image_pos:entry.image_pos + entry.size]
6387 efname = tools.get_output_filename(f'edata-{entry.name}')
6388 tools.write_file(efname, edata)
6389
6390 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6391 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6392 for name, sym in syms.items():
6393 msg = 'test'
6394 val = elf.GetSymbolValue(sym, edata, msg)
6395 entry_m = re_name.match(name)
6396 if entry_m:
6397 ename, prop = entry_m.group(1), entry_m.group(3)
6398 entry, entry_name, prop_name = image.LookupEntry(entries,
6399 name, msg)
Simon Glassd3d3a102025-02-19 08:11:16 -07006400 expect_val = None
Simon Glass37f85de2022-10-20 18:22:47 -06006401 if prop_name == 'offset':
6402 expect_val = entry.offset
6403 elif prop_name == 'image_pos':
6404 expect_val = entry.image_pos
6405 elif prop_name == 'size':
6406 expect_val = entry.size
6407 self.assertEqual(expect_val, val)
6408
6409 def testSymbolsElfBad(self):
6410 """Check error when trying to write symbols without the elftools lib"""
6411 if not elf.ELF_TOOLS:
6412 self.skipTest('Python elftools not available')
6413 self._SetupTplElf('u_boot_binman_syms')
6414 self._SetupVplElf('u_boot_binman_syms')
6415 self._SetupSplElf('u_boot_binman_syms')
6416 try:
6417 elf.ELF_TOOLS = False
6418 with self.assertRaises(ValueError) as exc:
6419 self._DoReadFileDtb('260_symbols_elf.dts')
6420 finally:
6421 elf.ELF_TOOLS = True
6422 self.assertIn(
6423 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6424 'Cannot write symbols to an ELF file without Python elftools',
6425 str(exc.exception))
6426
Simon Glassde244162023-01-07 14:07:08 -07006427 def testSectionFilename(self):
6428 """Check writing of section contents to a file"""
6429 data = self._DoReadFile('261_section_fname.dts')
6430 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6431 tools.get_bytes(ord('!'), 7) +
6432 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6433 self.assertEqual(expected, data)
6434
6435 sect_fname = tools.get_output_filename('outfile.bin')
6436 self.assertTrue(os.path.exists(sect_fname))
6437 sect_data = tools.read_file(sect_fname)
6438 self.assertEqual(U_BOOT_DATA, sect_data)
6439
Simon Glass1e9e61c2023-01-07 14:07:12 -07006440 def testAbsent(self):
6441 """Check handling of absent entries"""
6442 data = self._DoReadFile('262_absent.dts')
6443 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6444
Simon Glassad5cfe12023-01-07 14:07:14 -07006445 def testPackTeeOsOptional(self):
6446 """Test that an image with an optional TEE binary can be created"""
6447 entry_args = {
6448 'tee-os-path': 'tee.elf',
6449 }
6450 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6451 entry_args=entry_args)[0]
6452 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6453
6454 def checkFitTee(self, dts, tee_fname):
6455 """Check that a tee-os entry works and returns data
6456
6457 Args:
6458 dts (str): Device tree filename to use
6459 tee_fname (str): filename containing tee-os
6460
6461 Returns:
6462 bytes: Image contents
6463 """
6464 if not elf.ELF_TOOLS:
6465 self.skipTest('Python elftools not available')
6466 entry_args = {
6467 'of-list': 'test-fdt1 test-fdt2',
6468 'default-dt': 'test-fdt2',
6469 'tee-os-path': tee_fname,
6470 }
6471 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6472 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6473 extra_indirs=[test_subdir])[0]
6474 return data
6475
6476 def testFitTeeOsOptionalFit(self):
6477 """Test an image with a FIT with an optional OP-TEE binary"""
6478 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6479
6480 # There should be only one node, holding the data set up in SetUpClass()
6481 # for tee.bin
6482 dtb = fdt.Fdt.FromData(data)
6483 dtb.Scan()
6484 node = dtb.GetNode('/images/tee-1')
6485 self.assertEqual(TEE_ADDR,
6486 fdt_util.fdt32_to_cpu(node.props['load'].value))
6487 self.assertEqual(TEE_ADDR,
6488 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6489 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6490
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006491 with test_util.capture_sys_output() as (stdout, stderr):
6492 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6493 err = stderr.getvalue()
6494 self.assertRegex(
6495 err,
6496 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6497
Simon Glassad5cfe12023-01-07 14:07:14 -07006498 def testFitTeeOsOptionalFitBad(self):
6499 """Test an image with a FIT with an optional OP-TEE binary"""
6500 with self.assertRaises(ValueError) as exc:
6501 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6502 self.assertIn(
6503 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6504 str(exc.exception))
6505
6506 def testFitTeeOsBad(self):
6507 """Test an OP-TEE binary with wrong formats"""
6508 self.make_tee_bin('tee.bad1', 123)
6509 with self.assertRaises(ValueError) as exc:
6510 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6511 self.assertIn(
6512 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6513 str(exc.exception))
6514
6515 self.make_tee_bin('tee.bad2', 0, b'extra data')
6516 with self.assertRaises(ValueError) as exc:
6517 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6518 self.assertIn(
6519 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6520 str(exc.exception))
6521
Simon Glass63328f12023-01-07 14:07:15 -07006522 def testExtblobOptional(self):
6523 """Test an image with an external blob that is optional"""
6524 with test_util.capture_sys_output() as (stdout, stderr):
6525 data = self._DoReadFile('266_blob_ext_opt.dts')
6526 self.assertEqual(REFCODE_DATA, data)
6527 err = stderr.getvalue()
6528 self.assertRegex(
6529 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006530 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006531
Simon Glass7447a9d2023-01-11 16:10:12 -07006532 def testSectionInner(self):
6533 """Test an inner section with a size"""
6534 data = self._DoReadFile('267_section_inner.dts')
6535 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6536 self.assertEqual(expected, data)
6537
Simon Glassa4948b22023-01-11 16:10:14 -07006538 def testNull(self):
6539 """Test an image with a null entry"""
6540 data = self._DoReadFile('268_null.dts')
6541 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6542
Simon Glassf1ee03b2023-01-11 16:10:16 -07006543 def testOverlap(self):
6544 """Test an image with a overlapping entry"""
6545 data = self._DoReadFile('269_overlap.dts')
6546 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6547
6548 image = control.images['image']
6549 entries = image.GetEntries()
6550
6551 self.assertIn('inset', entries)
6552 inset = entries['inset']
6553 self.assertEqual(1, inset.offset);
6554 self.assertEqual(1, inset.image_pos);
6555 self.assertEqual(2, inset.size);
6556
6557 def testOverlapNull(self):
6558 """Test an image with a null overlap"""
6559 data = self._DoReadFile('270_overlap_null.dts')
6560 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6561
6562 # Check the FMAP
6563 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6564 self.assertEqual(4, fhdr.nareas)
6565 fiter = iter(fentries)
6566
6567 fentry = next(fiter)
6568 self.assertEqual(b'SECTION', fentry.name)
6569 self.assertEqual(0, fentry.offset)
6570 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6571 self.assertEqual(0, fentry.flags)
6572
6573 fentry = next(fiter)
6574 self.assertEqual(b'U_BOOT', fentry.name)
6575 self.assertEqual(0, fentry.offset)
6576 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6577 self.assertEqual(0, fentry.flags)
6578
6579 # Make sure that the NULL entry appears in the FMAP
6580 fentry = next(fiter)
6581 self.assertEqual(b'NULL', fentry.name)
6582 self.assertEqual(1, fentry.offset)
6583 self.assertEqual(2, fentry.size)
6584 self.assertEqual(0, fentry.flags)
6585
6586 fentry = next(fiter)
6587 self.assertEqual(b'FMAP', fentry.name)
6588 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6589
6590 def testOverlapBad(self):
6591 """Test an image with a bad overlapping entry"""
6592 with self.assertRaises(ValueError) as exc:
6593 self._DoReadFile('271_overlap_bad.dts')
6594 self.assertIn(
6595 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6596 str(exc.exception))
6597
6598 def testOverlapNoOffset(self):
6599 """Test an image with a bad overlapping entry"""
6600 with self.assertRaises(ValueError) as exc:
6601 self._DoReadFile('272_overlap_no_size.dts')
6602 self.assertIn(
6603 "Node '/binman/inset': 'fill' entry is missing properties: size",
6604 str(exc.exception))
6605
Simon Glasse0035c92023-01-11 16:10:17 -07006606 def testBlobSymbol(self):
6607 """Test a blob with symbols read from an ELF file"""
6608 elf_fname = self.ElfTestFile('blob_syms')
6609 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6610 TestFunctional._MakeInputFile('blob_syms.bin',
6611 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6612
6613 data = self._DoReadFile('273_blob_symbol.dts')
6614
6615 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6616 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6617 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6618 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6619 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6620
6621 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6622 expected = sym_values
6623 self.assertEqual(expected, data[:len(expected)])
6624
Simon Glass49e9c002023-01-11 16:10:19 -07006625 def testOffsetFromElf(self):
6626 """Test a blob with symbols read from an ELF file"""
6627 elf_fname = self.ElfTestFile('blob_syms')
6628 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6629 TestFunctional._MakeInputFile('blob_syms.bin',
6630 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6631
6632 data = self._DoReadFile('274_offset_from_elf.dts')
6633
6634 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6635 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6636
6637 image = control.images['image']
6638 entries = image.GetEntries()
6639
6640 self.assertIn('inset', entries)
6641 inset = entries['inset']
6642
6643 self.assertEqual(base + 4, inset.offset);
6644 self.assertEqual(base + 4, inset.image_pos);
6645 self.assertEqual(4, inset.size);
6646
6647 self.assertIn('inset2', entries)
6648 inset = entries['inset2']
6649 self.assertEqual(base + 8, inset.offset);
6650 self.assertEqual(base + 8, inset.image_pos);
6651 self.assertEqual(4, inset.size);
6652
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006653 def testFitAlign(self):
6654 """Test an image with an FIT with aligned external data"""
6655 data = self._DoReadFile('275_fit_align.dts')
6656 self.assertEqual(4096, len(data))
6657
6658 dtb = fdt.Fdt.FromData(data)
6659 dtb.Scan()
6660
6661 props = self._GetPropTree(dtb, ['data-position'])
6662 expected = {
6663 'u-boot:data-position': 1024,
6664 'fdt-1:data-position': 2048,
6665 'fdt-2:data-position': 3072,
6666 }
6667 self.assertEqual(expected, props)
6668
Jonas Karlman490f73c2023-01-21 19:02:12 +00006669 def testFitFirmwareLoadables(self):
6670 """Test an image with an FIT that use fit,firmware"""
6671 if not elf.ELF_TOOLS:
6672 self.skipTest('Python elftools not available')
6673 entry_args = {
6674 'of-list': 'test-fdt1',
6675 'default-dt': 'test-fdt1',
6676 'atf-bl31-path': 'bl31.elf',
6677 'tee-os-path': 'missing.bin',
6678 }
6679 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006680 with test_util.capture_sys_output() as (stdout, stderr):
6681 data = self._DoReadFileDtb(
6682 '276_fit_firmware_loadables.dts',
6683 entry_args=entry_args,
6684 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006685
6686 dtb = fdt.Fdt.FromData(data)
6687 dtb.Scan()
6688
6689 node = dtb.GetNode('/configurations/conf-uboot-1')
6690 self.assertEqual('u-boot', node.props['firmware'].value)
6691 self.assertEqual(['atf-1', 'atf-2'],
6692 fdt_util.GetStringList(node, 'loadables'))
6693
6694 node = dtb.GetNode('/configurations/conf-atf-1')
6695 self.assertEqual('atf-1', node.props['firmware'].value)
6696 self.assertEqual(['u-boot', 'atf-2'],
6697 fdt_util.GetStringList(node, 'loadables'))
6698
6699 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6700 self.assertEqual('u-boot', node.props['firmware'].value)
6701 self.assertEqual(['atf-1', 'atf-2'],
6702 fdt_util.GetStringList(node, 'loadables'))
6703
6704 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6705 self.assertEqual('atf-1', node.props['firmware'].value)
6706 self.assertEqual(['u-boot', 'atf-2'],
6707 fdt_util.GetStringList(node, 'loadables'))
6708
6709 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6710 self.assertEqual('atf-1', node.props['firmware'].value)
6711 self.assertEqual(['u-boot', 'atf-2'],
6712 fdt_util.GetStringList(node, 'loadables'))
6713
Simon Glass9a1c7262023-02-22 12:14:49 -07006714 def testTooldir(self):
6715 """Test that we can specify the tooldir"""
6716 with test_util.capture_sys_output() as (stdout, stderr):
6717 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6718 'tool', '-l'))
6719 self.assertEqual('fred', bintool.Bintool.tooldir)
6720
6721 # Check that the toolpath is updated correctly
6722 self.assertEqual(['fred'], tools.tool_search_paths)
6723
6724 # Try with a few toolpaths; the tooldir should be at the end
6725 with test_util.capture_sys_output() as (stdout, stderr):
6726 self.assertEqual(0, self._DoBinman(
6727 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6728 'tool', '-l'))
6729 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6730
Simon Glass49b77e82023-03-02 17:02:44 -07006731 def testReplaceSectionEntry(self):
6732 """Test replacing an entry in a section"""
6733 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6734 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6735 expect_data, dts='241_replace_section_simple.dts')
6736 self.assertEqual(expect_data, entry_data)
6737
6738 entries = image.GetEntries()
6739 self.assertIn('section', entries)
6740 section = entries['section']
6741
6742 sect_entries = section.GetEntries()
6743 self.assertIn('blob', sect_entries)
6744 entry = sect_entries['blob']
6745 self.assertEqual(len(expect_data), entry.size)
6746
6747 fname = tools.get_output_filename('image-updated.bin')
6748 data = tools.read_file(fname)
6749
6750 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6751 self.assertEqual(expect_data, new_blob_data)
6752
6753 self.assertEqual(U_BOOT_DATA,
6754 data[entry.image_pos + len(expect_data):]
6755 [:len(U_BOOT_DATA)])
6756
6757 def testReplaceSectionDeep(self):
6758 """Test replacing an entry in two levels of sections"""
6759 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6760 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6761 'section/section/blob', expect_data,
6762 dts='278_replace_section_deep.dts')
6763 self.assertEqual(expect_data, entry_data)
6764
6765 entries = image.GetEntries()
6766 self.assertIn('section', entries)
6767 section = entries['section']
6768
6769 subentries = section.GetEntries()
6770 self.assertIn('section', subentries)
6771 section = subentries['section']
6772
6773 sect_entries = section.GetEntries()
6774 self.assertIn('blob', sect_entries)
6775 entry = sect_entries['blob']
6776 self.assertEqual(len(expect_data), entry.size)
6777
6778 fname = tools.get_output_filename('image-updated.bin')
6779 data = tools.read_file(fname)
6780
6781 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6782 self.assertEqual(expect_data, new_blob_data)
6783
6784 self.assertEqual(U_BOOT_DATA,
6785 data[entry.image_pos + len(expect_data):]
6786 [:len(U_BOOT_DATA)])
6787
6788 def testReplaceFitSibling(self):
6789 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006790 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006791 fname = TestFunctional._MakeInputFile('once', b'available once')
6792 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6793 os.remove(fname)
6794
6795 try:
6796 tmpdir, updated_fname = self._SetupImageInTmpdir()
6797
6798 fname = os.path.join(tmpdir, 'update-blob')
6799 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6800 tools.write_file(fname, expected)
6801
6802 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6803 data = tools.read_file(updated_fname)
6804 start = len(U_BOOT_DTB_DATA)
6805 self.assertEqual(expected, data[start:start + len(expected)])
6806 map_fname = os.path.join(tmpdir, 'image-updated.map')
6807 self.assertFalse(os.path.exists(map_fname))
6808 finally:
6809 shutil.rmtree(tmpdir)
6810
Simon Glassc3fe97f2023-03-02 17:02:45 -07006811 def testX509Cert(self):
6812 """Test creating an X509 certificate"""
6813 keyfile = self.TestFile('key.key')
6814 entry_args = {
6815 'keyfile': keyfile,
6816 }
6817 data = self._DoReadFileDtb('279_x509_cert.dts',
6818 entry_args=entry_args)[0]
6819 cert = data[:-4]
6820 self.assertEqual(U_BOOT_DATA, data[-4:])
6821
6822 # TODO: verify the signature
6823
6824 def testX509CertMissing(self):
6825 """Test that binman still produces an image if openssl is missing"""
6826 keyfile = self.TestFile('key.key')
6827 entry_args = {
6828 'keyfile': 'keyfile',
6829 }
6830 with test_util.capture_sys_output() as (_, stderr):
6831 self._DoTestFile('279_x509_cert.dts',
6832 force_missing_bintools='openssl',
6833 entry_args=entry_args)
6834 err = stderr.getvalue()
6835 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6836
Jonas Karlman35305492023-02-25 19:01:33 +00006837 def testPackRockchipTpl(self):
6838 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006839 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006840 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6841
Jonas Karlman1016ec72023-02-25 19:01:35 +00006842 def testMkimageMissingBlobMultiple(self):
6843 """Test missing blob with mkimage entry and multiple-data-files"""
6844 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006845 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006846 err = stderr.getvalue()
6847 self.assertIn("is missing external blobs and is non-functional", err)
6848
6849 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006850 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006851 self.assertIn("not found in input path", str(e.exception))
6852
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006853 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6854 """Prepare sign environment
6855
6856 Create private and public keys, add pubkey into dtb.
6857
6858 Returns:
6859 Tuple:
6860 FIT container
6861 Image name
6862 Private key
6863 DTB
6864 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006865 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006866 data = self._DoReadFileRealDtb(dts)
6867 updated_fname = tools.get_output_filename('image-updated.bin')
6868 tools.write_file(updated_fname, data)
6869 dtb = tools.get_output_filename('source.dtb')
6870 private_key = tools.get_output_filename('test_key.key')
6871 public_key = tools.get_output_filename('test_key.crt')
6872 fit = tools.get_output_filename('fit.fit')
6873 key_dir = tools.get_output_dir()
6874
6875 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6876 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6877 private_key, '-out', public_key)
6878 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6879 '-n', 'test_key', '-r', 'conf', dtb)
6880
6881 return fit, updated_fname, private_key, dtb
6882
6883 def testSignSimple(self):
6884 """Test that a FIT container can be signed in image"""
6885 is_signed = False
6886 fit, fname, private_key, dtb = self._PrepareSignEnv()
6887
6888 # do sign with private key
6889 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6890 ['fit'])
6891 is_signed = self._CheckSign(fit, dtb)
6892
6893 self.assertEqual(is_signed, True)
6894
6895 def testSignExactFIT(self):
6896 """Test that a FIT container can be signed and replaced in image"""
6897 is_signed = False
6898 fit, fname, private_key, dtb = self._PrepareSignEnv()
6899
6900 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6901 args = []
6902 if self.toolpath:
6903 for path in self.toolpath:
6904 args += ['--toolpath', path]
6905
6906 # do sign with private key
6907 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6908 'sha256,rsa4096', '-f', fit, 'fit')
6909 is_signed = self._CheckSign(fit, dtb)
6910
6911 self.assertEqual(is_signed, True)
6912
6913 def testSignNonFit(self):
6914 """Test a non-FIT entry cannot be signed"""
6915 is_signed = False
6916 fit, fname, private_key, _ = self._PrepareSignEnv(
6917 '281_sign_non_fit.dts')
6918
6919 # do sign with private key
6920 with self.assertRaises(ValueError) as e:
6921 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6922 'sha256,rsa4096', '-f', fit, 'u-boot')
6923 self.assertIn(
6924 "Node '/u-boot': Updating signatures is not supported with this entry type",
6925 str(e.exception))
6926
6927 def testSignMissingMkimage(self):
6928 """Test that FIT signing handles a missing mkimage tool"""
6929 fit, fname, private_key, _ = self._PrepareSignEnv()
6930
6931 # try to sign with a missing mkimage tool
6932 bintool.Bintool.set_missing_list(['mkimage'])
6933 with self.assertRaises(ValueError) as e:
6934 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6935 ['fit'])
6936 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6937
Simon Glass4abf7842023-07-18 07:23:54 -06006938 def testSymbolNoWrite(self):
6939 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006940 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006941 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6942 no_write_symbols=True)
6943
6944 def testSymbolNoWriteExpanded(self):
6945 """Test disabling of symbol writing in expanded entries"""
6946 entry_args = {
6947 'spl-dtb': '1',
6948 }
6949 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6950 U_BOOT_SPL_DTB_DATA, 0x38,
6951 entry_args=entry_args, use_expanded=True,
6952 no_write_symbols=True)
6953
Marek Vasutf7413f02023-07-18 07:23:58 -06006954 def testMkimageSpecial(self):
6955 """Test mkimage ignores special hash-1 node"""
6956 data = self._DoReadFile('283_mkimage_special.dts')
6957
6958 # Just check that the data appears in the file somewhere
6959 self.assertIn(U_BOOT_DATA, data)
6960
Simon Glass2d94c422023-07-18 07:23:59 -06006961 def testFitFdtList(self):
6962 """Test an image with an FIT with the fit,fdt-list-val option"""
6963 entry_args = {
6964 'default-dt': 'test-fdt2',
6965 }
6966 data = self._DoReadFileDtb(
6967 '284_fit_fdt_list.dts',
6968 entry_args=entry_args,
6969 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6970 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6971 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6972
Simon Glass83b8bfe2023-07-18 07:24:01 -06006973 def testSplEmptyBss(self):
6974 """Test an expanded SPL with a zero-size BSS"""
6975 # ELF file with a '__bss_size' symbol
6976 self._SetupSplElf(src_fname='bss_data_zero')
6977
6978 entry_args = {
6979 'spl-bss-pad': 'y',
6980 'spl-dtb': 'y',
6981 }
6982 data = self._DoReadFileDtb('285_spl_expand.dts',
6983 use_expanded=True, entry_args=entry_args)[0]
6984
Simon Glassfc792842023-07-18 07:24:04 -06006985 def testTemplate(self):
6986 """Test using a template"""
6987 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6988 data = self._DoReadFile('286_template.dts')
6989 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6990 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6991 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6992
Simon Glass09490b02023-07-22 21:43:52 -06006993 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6994 self.assertTrue(os.path.exists(dtb_fname1))
6995 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6996 dtb.Scan()
6997 node1 = dtb.GetNode('/binman/template')
6998 self.assertTrue(node1)
6999 vga = dtb.GetNode('/binman/first/intel-vga')
7000 self.assertTrue(vga)
7001
Simon Glass54825e12023-07-22 21:43:56 -06007002 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
7003 self.assertTrue(os.path.exists(dtb_fname2))
7004 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
7005 dtb2.Scan()
7006 node2 = dtb2.GetNode('/binman/template')
7007 self.assertFalse(node2)
7008
Simon Glass9909c112023-07-18 07:24:05 -06007009 def testTemplateBlobMulti(self):
7010 """Test using a template with 'multiple-images' enabled"""
7011 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
7012 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
7013 retcode = self._DoTestFile('287_template_multi.dts')
7014
7015 self.assertEqual(0, retcode)
7016 image = control.images['image']
7017 image_fname = tools.get_output_filename('my-image.bin')
7018 data = tools.read_file(image_fname)
7019 self.assertEqual(b'blob@@@@other', data)
7020
Simon Glass5dc511b2023-07-18 07:24:06 -06007021 def testTemplateFit(self):
7022 """Test using a template in a FIT"""
7023 fit_data = self._DoReadFile('288_template_fit.dts')
7024 fname = os.path.join(self._indir, 'fit_data.fit')
7025 tools.write_file(fname, fit_data)
7026 out = tools.run('dumpimage', '-l', fname)
7027
Simon Glassaa6e0552023-07-18 07:24:07 -06007028 def testTemplateSection(self):
7029 """Test using a template in a section (not at top level)"""
7030 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
7031 data = self._DoReadFile('289_template_section.dts')
7032 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
7033 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
7034 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
7035
Simon Glassf53a7bc2023-07-18 07:24:08 -06007036 def testMkimageSymbols(self):
7037 """Test using mkimage to build an image with symbols in it"""
7038 self._SetupSplElf('u_boot_binman_syms')
7039 data = self._DoReadFile('290_mkimage_sym.dts')
7040
7041 image = control.images['image']
7042 entries = image.GetEntries()
7043 self.assertIn('u-boot', entries)
7044 u_boot = entries['u-boot']
7045
7046 mkim = entries['mkimage']
7047 mkim_entries = mkim.GetEntries()
7048 self.assertIn('u-boot-spl', mkim_entries)
7049 spl = mkim_entries['u-boot-spl']
7050 self.assertIn('u-boot-spl2', mkim_entries)
7051 spl2 = mkim_entries['u-boot-spl2']
7052
7053 # skip the mkimage header and the area sizes
7054 mk_data = data[mkim.offset + 0x40:]
7055 size, term = struct.unpack('>LL', mk_data[:8])
7056
7057 # There should be only one image, so check that the zero terminator is
7058 # present
7059 self.assertEqual(0, term)
7060
7061 content = mk_data[8:8 + size]
7062
7063 # The image should contain the symbols from u_boot_binman_syms.c
7064 # Note that image_pos is adjusted by the base address of the image,
7065 # which is 0x10 in our test image
7066 spl_data = content[:0x18]
7067 content = content[0x1b:]
7068
7069 # After the header is a table of offsets for each image. There should
7070 # only be one image, then a 0 terminator, so figure out the real start
7071 # of the image data
7072 base = 0x40 + 8
7073
7074 # Check symbols in both u-boot-spl and u-boot-spl2
7075 for i in range(2):
7076 vals = struct.unpack('<LLQLL', spl_data)
7077
7078 # The image should contain the symbols from u_boot_binman_syms.c
7079 # Note that image_pos is adjusted by the base address of the image,
7080 # which is 0x10 in our 'u_boot_binman_syms' test image
7081 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
7082 self.assertEqual(base, vals[1])
7083 self.assertEqual(spl2.offset, vals[2])
7084 # figure out the internal positions of its components
7085 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
7086
7087 # Check that spl and spl2 are actually at the indicated positions
7088 self.assertEqual(
7089 elf.BINMAN_SYM_MAGIC_VALUE,
7090 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
7091 self.assertEqual(
7092 elf.BINMAN_SYM_MAGIC_VALUE,
7093 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
7094
7095 self.assertEqual(len(U_BOOT_DATA), vals[4])
7096
7097 # Move to next
7098 spl_data = content[:0x18]
7099
Simon Glass86b3e472023-07-22 21:43:57 -06007100 def testTemplatePhandle(self):
7101 """Test using a template in a node containing a phandle"""
7102 entry_args = {
7103 'atf-bl31-path': 'bl31.elf',
7104 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06007105 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007106 entry_args=entry_args)
7107 fname = tools.get_output_filename('image.bin')
7108 out = tools.run('dumpimage', '-l', fname)
7109
7110 # We should see the FIT description and one for each of the two images
7111 lines = out.splitlines()
7112 descs = [line.split()[-1] for line in lines if 'escription' in line]
7113 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7114
7115 def testTemplatePhandleDup(self):
7116 """Test using a template in a node containing a phandle"""
7117 entry_args = {
7118 'atf-bl31-path': 'bl31.elf',
7119 }
7120 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007121 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007122 entry_args=entry_args)
7123 self.assertIn(
7124 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7125 str(e.exception))
7126
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307127 def testTIBoardConfig(self):
7128 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007129 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307130 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7131
Neha Malcom Francis8cd04512024-01-05 17:09:17 +05307132 def testTIBoardConfigLint(self):
7133 """Test that an incorrectly linted config file would generate error"""
7134 with self.assertRaises(ValueError) as e:
7135 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7136 self.assertIn("Yamllint error", str(e.exception))
7137
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307138 def testTIBoardConfigCombined(self):
7139 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007140 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307141 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7142 self.assertGreater(data, configlen_noheader)
7143
7144 def testTIBoardConfigNoDataType(self):
7145 """Test that error is thrown when data type is not supported"""
7146 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007147 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307148 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007149
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307150 def testPackTiSecure(self):
7151 """Test that an image with a TI secured binary can be created"""
7152 keyfile = self.TestFile('key.key')
7153 entry_args = {
7154 'keyfile': keyfile,
7155 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007156 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307157 entry_args=entry_args)[0]
7158 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7159
Manorit Chawdhry2e523b02023-12-29 16:16:27 +05307160 def testPackTiSecureFirewall(self):
7161 """Test that an image with a TI secured binary can be created"""
7162 keyfile = self.TestFile('key.key')
7163 entry_args = {
7164 'keyfile': keyfile,
7165 }
7166 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7167 entry_args=entry_args)[0]
7168 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7169 entry_args=entry_args)[0]
7170 self.assertGreater(len(data_firewall),len(data_no_firewall))
7171
7172 def testPackTiSecureFirewallMissingProperty(self):
7173 """Test that an image with a TI secured binary can be created"""
7174 keyfile = self.TestFile('key.key')
7175 entry_args = {
7176 'keyfile': keyfile,
7177 }
7178 with self.assertRaises(ValueError) as e:
7179 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7180 entry_args=entry_args)[0]
7181 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7182
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307183 def testPackTiSecureMissingTool(self):
7184 """Test that an image with a TI secured binary (non-functional) can be created
7185 when openssl is missing"""
7186 keyfile = self.TestFile('key.key')
7187 entry_args = {
7188 'keyfile': keyfile,
7189 }
7190 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007191 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307192 force_missing_bintools='openssl',
7193 entry_args=entry_args)
7194 err = stderr.getvalue()
7195 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7196
7197 def testPackTiSecureROM(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('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307204 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007205 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307206 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007207 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307208 entry_args=entry_args)[0]
7209 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7210 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7211 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7212
7213 def testPackTiSecureROMCombined(self):
7214 """Test that a ROM image with a TI secured binary can be created"""
7215 keyfile = self.TestFile('key.key')
7216 entry_args = {
7217 'keyfile': keyfile,
7218 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007219 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307220 entry_args=entry_args)[0]
7221 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7222
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007223 def testEncryptedNoAlgo(self):
7224 """Test encrypted node with missing required properties"""
7225 with self.assertRaises(ValueError) as e:
7226 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7227 self.assertIn(
7228 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7229 str(e.exception))
7230
7231 def testEncryptedInvalidIvfile(self):
7232 """Test encrypted node with invalid iv file"""
7233 with self.assertRaises(ValueError) as e:
7234 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7235 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7236 str(e.exception))
7237
7238 def testEncryptedMissingKey(self):
7239 """Test encrypted node with missing key properties"""
7240 with self.assertRaises(ValueError) as e:
7241 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7242 self.assertIn(
7243 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7244 str(e.exception))
7245
7246 def testEncryptedKeySource(self):
7247 """Test encrypted node with key-source property"""
7248 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7249
7250 dtb = fdt.Fdt.FromData(data)
7251 dtb.Scan()
7252
7253 node = dtb.GetNode('/images/u-boot/cipher')
7254 self.assertEqual('algo-name', node.props['algo'].value)
7255 self.assertEqual('key-source-value', node.props['key-source'].value)
7256 self.assertEqual(ENCRYPTED_IV_DATA,
7257 tools.to_bytes(''.join(node.props['iv'].value)))
7258 self.assertNotIn('key', node.props)
7259
7260 def testEncryptedKeyFile(self):
7261 """Test encrypted node with key-filename property"""
7262 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7263
7264 dtb = fdt.Fdt.FromData(data)
7265 dtb.Scan()
7266
7267 node = dtb.GetNode('/images/u-boot/cipher')
7268 self.assertEqual('algo-name', node.props['algo'].value)
7269 self.assertEqual(ENCRYPTED_IV_DATA,
7270 tools.to_bytes(''.join(node.props['iv'].value)))
7271 self.assertEqual(ENCRYPTED_KEY_DATA,
7272 tools.to_bytes(''.join(node.props['key'].value)))
7273 self.assertNotIn('key-source', node.props)
7274
Lukas Funkee901faf2023-07-18 13:53:13 +02007275
7276 def testSplPubkeyDtb(self):
Simon Glass4b861272024-07-20 11:49:41 +01007277 """Test u_boot_spl_pubkey_dtb etype"""
7278 data = tools.read_file(self.TestFile("key.pem"))
7279 self._MakeInputFile("key.crt", data)
7280 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7281 image = control.images['image']
7282 entries = image.GetEntries()
7283 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7284 dtb_data = dtb_entry.GetData()
7285 dtb = fdt.Fdt.FromData(dtb_data)
7286 dtb.Scan()
Lukas Funkee901faf2023-07-18 13:53:13 +02007287
Simon Glass4b861272024-07-20 11:49:41 +01007288 signature_node = dtb.GetNode('/signature')
7289 self.assertIsNotNone(signature_node)
7290 key_node = signature_node.FindNode("key-key")
7291 self.assertIsNotNone(key_node)
7292 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7293 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7294 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007295
Lukas Funke712e1062023-08-03 17:22:14 +02007296 def testXilinxBootgenSigning(self):
7297 """Test xilinx-bootgen etype"""
7298 bootgen = bintool.Bintool.create('bootgen')
7299 self._CheckBintool(bootgen)
7300 data = tools.read_file(self.TestFile("key.key"))
7301 self._MakeInputFile("psk.pem", data)
7302 self._MakeInputFile("ssk.pem", data)
7303 self._SetupPmuFwlElf()
7304 self._SetupSplElf()
7305 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7306 image_fname = tools.get_output_filename('image.bin')
7307
7308 # Read partition header table and check if authentication is enabled
7309 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7310 "-read", image_fname, "pht").splitlines()
7311 attributes = {"authentication": None,
7312 "core": None,
7313 "encryption": None}
7314
7315 for l in bootgen_out:
7316 for a in attributes.keys():
7317 if a in l:
7318 m = re.match(fr".*{a} \[([^]]+)\]", l)
7319 attributes[a] = m.group(1)
7320
7321 self.assertTrue(attributes['authentication'] == "rsa")
7322 self.assertTrue(attributes['core'] == "a53-0")
7323 self.assertTrue(attributes['encryption'] == "no")
7324
7325 def testXilinxBootgenSigningEncryption(self):
7326 """Test xilinx-bootgen etype"""
7327 bootgen = bintool.Bintool.create('bootgen')
7328 self._CheckBintool(bootgen)
7329 data = tools.read_file(self.TestFile("key.key"))
7330 self._MakeInputFile("psk.pem", data)
7331 self._MakeInputFile("ssk.pem", data)
7332 self._SetupPmuFwlElf()
7333 self._SetupSplElf()
7334 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7335 image_fname = tools.get_output_filename('image.bin')
7336
7337 # Read boot header in order to verify encryption source and
7338 # encryption parameter
7339 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7340 "-read", image_fname, "bh").splitlines()
7341 attributes = {"auth_only":
7342 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7343 "encryption_keystore":
7344 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7345 "value": None},
7346 }
7347
7348 for l in bootgen_out:
7349 for a in attributes.keys():
7350 if a in l:
7351 m = re.match(attributes[a]['re'], l)
7352 attributes[a] = m.group(1)
7353
7354 # Check if fsbl-attribute is set correctly
7355 self.assertTrue(attributes['auth_only'] == "true")
7356 # Check if key is stored in efuse
7357 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7358
7359 def testXilinxBootgenMissing(self):
7360 """Test that binman still produces an image if bootgen is missing"""
7361 data = tools.read_file(self.TestFile("key.key"))
7362 self._MakeInputFile("psk.pem", data)
7363 self._MakeInputFile("ssk.pem", data)
7364 self._SetupPmuFwlElf()
7365 self._SetupSplElf()
7366 with test_util.capture_sys_output() as (_, stderr):
7367 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7368 force_missing_bintools='bootgen')
7369 err = stderr.getvalue()
7370 self.assertRegex(err,
7371 "Image 'image'.*missing bintools.*: bootgen")
7372
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307373 def _GetCapsuleHeaders(self, data):
7374 """Get the capsule header contents
7375
7376 Args:
7377 data: Capsule file contents
7378
7379 Returns:
7380 Dict:
7381 key: Capsule Header name (str)
7382 value: Header field value (str)
7383 """
7384 capsule_file = os.path.join(self._indir, 'test.capsule')
7385 tools.write_file(capsule_file, data)
7386
7387 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7388 lines = out.splitlines()
7389
7390 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7391 vals = {}
7392 for line in lines:
7393 mat = re_line.match(line)
7394 if mat:
7395 vals[mat.group(1)] = mat.group(2)
7396
7397 return vals
7398
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307399 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7400 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307401 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7402 fmp_size = "00000010"
7403 fmp_fw_version = "00000002"
7404 capsule_image_index = "00000001"
7405 oemflag = "00018000"
7406 auth_hdr_revision = "00000200"
7407 auth_hdr_cert_type = "00000EF1"
7408
7409 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307410
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307411 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307412
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307413 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307414
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307415 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7416 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7417 self.assertEqual(capsule_image_index,
7418 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307419
7420 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307421 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7422
7423 if signed_capsule:
7424 self.assertEqual(auth_hdr_revision,
7425 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7426 self.assertEqual(auth_hdr_cert_type,
7427 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7428 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7429 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7430
7431 if version_check:
7432 self.assertEqual(fmp_signature,
7433 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7434 self.assertEqual(fmp_size,
7435 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7436 self.assertEqual(fmp_fw_version,
7437 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7438
7439 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307440
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307441 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7442 if accept_capsule:
7443 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7444 else:
7445 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7446
7447 hdr = self._GetCapsuleHeaders(data)
7448
7449 self.assertEqual(capsule_hdr_guid.upper(),
7450 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7451
7452 if accept_capsule:
7453 capsule_size = "0000002C"
7454 else:
7455 capsule_size = "0000001C"
7456 self.assertEqual(capsule_size,
7457 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7458
7459 if accept_capsule:
7460 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7461
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307462 def testCapsuleGen(self):
7463 """Test generation of EFI capsule"""
7464 data = self._DoReadFile('311_capsule.dts')
7465
7466 self._CheckCapsule(data)
7467
7468 def testSignedCapsuleGen(self):
7469 """Test generation of EFI capsule"""
7470 data = tools.read_file(self.TestFile("key.key"))
7471 self._MakeInputFile("key.key", data)
7472 data = tools.read_file(self.TestFile("key.pem"))
7473 self._MakeInputFile("key.crt", data)
7474
7475 data = self._DoReadFile('312_capsule_signed.dts')
7476
7477 self._CheckCapsule(data, signed_capsule=True)
7478
7479 def testCapsuleGenVersionSupport(self):
7480 """Test generation of EFI capsule with version support"""
7481 data = self._DoReadFile('313_capsule_version.dts')
7482
7483 self._CheckCapsule(data, version_check=True)
7484
7485 def testCapsuleGenSignedVer(self):
7486 """Test generation of signed EFI capsule with version information"""
7487 data = tools.read_file(self.TestFile("key.key"))
7488 self._MakeInputFile("key.key", data)
7489 data = tools.read_file(self.TestFile("key.pem"))
7490 self._MakeInputFile("key.crt", data)
7491
7492 data = self._DoReadFile('314_capsule_signed_ver.dts')
7493
7494 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7495
7496 def testCapsuleGenCapOemFlags(self):
7497 """Test generation of EFI capsule with OEM Flags set"""
7498 data = self._DoReadFile('315_capsule_oemflags.dts')
7499
7500 self._CheckCapsule(data, capoemflags=True)
7501
7502 def testCapsuleGenKeyMissing(self):
7503 """Test that binman errors out on missing key"""
7504 with self.assertRaises(ValueError) as e:
7505 self._DoReadFile('316_capsule_missing_key.dts')
7506
7507 self.assertIn("Both private key and public key certificate need to be provided",
7508 str(e.exception))
7509
7510 def testCapsuleGenIndexMissing(self):
7511 """Test that binman errors out on missing image index"""
7512 with self.assertRaises(ValueError) as e:
7513 self._DoReadFile('317_capsule_missing_index.dts')
7514
7515 self.assertIn("entry is missing properties: image-index",
7516 str(e.exception))
7517
7518 def testCapsuleGenGuidMissing(self):
7519 """Test that binman errors out on missing image GUID"""
7520 with self.assertRaises(ValueError) as e:
7521 self._DoReadFile('318_capsule_missing_guid.dts')
7522
7523 self.assertIn("entry is missing properties: image-guid",
7524 str(e.exception))
7525
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307526 def testCapsuleGenAcceptCapsule(self):
7527 """Test generationg of accept EFI capsule"""
7528 data = self._DoReadFile('319_capsule_accept.dts')
7529
7530 self._CheckEmptyCapsule(data, accept_capsule=True)
7531
7532 def testCapsuleGenRevertCapsule(self):
7533 """Test generationg of revert EFI capsule"""
7534 data = self._DoReadFile('320_capsule_revert.dts')
7535
7536 self._CheckEmptyCapsule(data)
7537
7538 def testCapsuleGenAcceptGuidMissing(self):
7539 """Test that binman errors out on missing image GUID for accept capsule"""
7540 with self.assertRaises(ValueError) as e:
7541 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7542
7543 self.assertIn("Image GUID needed for generating accept capsule",
7544 str(e.exception))
7545
7546 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7547 """Test that capsule-type is specified"""
7548 with self.assertRaises(ValueError) as e:
7549 self._DoReadFile('322_empty_capsule_type_missing.dts')
7550
7551 self.assertIn("entry is missing properties: capsule-type",
7552 str(e.exception))
7553
7554 def testCapsuleGenAcceptOrRevertMissing(self):
7555 """Test that both accept and revert capsule are not specified"""
7556 with self.assertRaises(ValueError) as e:
7557 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7558
Simon Glassa360b8f2024-06-23 11:55:06 -06007559 def test_assume_size(self):
7560 """Test handling of the assume-size property for external blob"""
7561 with self.assertRaises(ValueError) as e:
7562 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7563 allow_fake_blobs=True)
7564 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7565 str(e.exception))
7566
7567 def test_assume_size_ok(self):
7568 """Test handling of the assume-size where it fits OK"""
7569 with test_util.capture_sys_output() as (stdout, stderr):
7570 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7571 allow_fake_blobs=True)
7572 err = stderr.getvalue()
7573 self.assertRegex(
7574 err,
7575 "Image '.*' has faked external blobs and is non-functional: .*")
7576
7577 def test_assume_size_no_fake(self):
7578 """Test handling of the assume-size where it fits OK"""
7579 with test_util.capture_sys_output() as (stdout, stderr):
7580 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7581 err = stderr.getvalue()
7582 self.assertRegex(
7583 err,
7584 "Image '.*' is missing external blobs and is non-functional: .*")
7585
Simon Glass5f7aadf2024-07-20 11:49:47 +01007586 def SetupAlternateDts(self):
7587 """Compile the .dts test files for alternative-fdt
7588
7589 Returns:
7590 tuple:
7591 str: Test directory created
7592 list of str: '.bin' files which we expect Binman to create
7593 """
7594 testdir = TestFunctional._MakeInputDir('dtb')
7595 dtb_list = []
7596 for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
7597 tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
7598 base = os.path.splitext(os.path.basename(fname))[0]
7599 dtb_list.append(base + '.bin')
7600 shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
7601
7602 return testdir, dtb_list
7603
Simon Glassf3598922024-07-20 11:49:45 +01007604 def CheckAlternates(self, dts, phase, xpl_data):
7605 """Run the test for the alterative-fdt etype
7606
7607 Args:
7608 dts (str): Devicetree file to process
7609 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7610 xpl_data (bytes): Expected data for the phase's binary
7611
7612 Returns:
7613 dict of .dtb files produced
7614 key: str filename
7615 value: Fdt object
7616 """
Simon Glass5f7aadf2024-07-20 11:49:47 +01007617 dtb_list = self.SetupAlternateDts()[1]
Simon Glassf3598922024-07-20 11:49:45 +01007618
7619 entry_args = {
7620 f'{phase}-dtb': '1',
7621 f'{phase}-bss-pad': 'y',
7622 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7623 }
7624 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7625 use_expanded=True, entry_args=entry_args)[0]
7626 self.assertEqual(xpl_data, data[:len(xpl_data)])
7627 rest = data[len(xpl_data):]
7628 pad_len = 10
7629 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7630
7631 # Check the dtb is using the test file
7632 dtb_data = rest[pad_len:]
7633 dtb = fdt.Fdt.FromData(dtb_data)
7634 dtb.Scan()
7635 fdt_size = dtb.GetFdtObj().totalsize()
7636 self.assertEqual('model-not-set',
7637 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7638
7639 pad_len = 10
7640
7641 # Check the other output files
7642 dtbs = {}
7643 for fname in dtb_list:
7644 pathname = tools.get_output_filename(fname)
7645 self.assertTrue(os.path.exists(pathname))
7646
7647 data = tools.read_file(pathname)
7648 self.assertEqual(xpl_data, data[:len(xpl_data)])
7649 rest = data[len(xpl_data):]
7650
7651 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7652 rest = rest[pad_len:]
7653
7654 dtb = fdt.Fdt.FromData(rest)
7655 dtb.Scan()
7656 dtbs[fname] = dtb
7657
7658 expected = 'one' if '1' in fname else 'two'
7659 self.assertEqual(f'u-boot,model-{expected}',
7660 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7661
7662 # Make sure the FDT is the same size as the 'main' one
7663 rest = rest[fdt_size:]
7664
7665 self.assertEqual(b'', rest)
7666 return dtbs
7667
7668 def testAlternatesFdt(self):
7669 """Test handling of alternates-fdt etype"""
7670 self._SetupTplElf()
7671 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7672 U_BOOT_TPL_NODTB_DATA)
7673 for dtb in dtbs.values():
7674 # Check for the node with the tag
7675 node = dtb.GetNode('/node')
7676 self.assertIsNotNone(node)
7677 self.assertEqual(5, len(node.props.keys()))
7678
7679 # Make sure the other node is still there
7680 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7681
7682 def testAlternatesFdtgrep(self):
7683 """Test handling of alternates-fdt etype using fdtgrep"""
7684 self._SetupTplElf()
7685 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7686 U_BOOT_TPL_NODTB_DATA)
7687 for dtb in dtbs.values():
7688 # Check for the node with the tag
7689 node = dtb.GetNode('/node')
7690 self.assertIsNotNone(node)
7691 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7692 node.props.keys())
7693
7694 # Make sure the other node is gone
7695 self.assertIsNone(dtb.GetNode('/node/other-node'))
7696
7697 def testAlternatesFdtgrepVpl(self):
7698 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7699 self._SetupVplElf()
7700 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7701 U_BOOT_VPL_NODTB_DATA)
7702
7703 def testAlternatesFdtgrepSpl(self):
7704 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7705 self._SetupSplElf()
7706 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7707 U_BOOT_SPL_NODTB_DATA)
7708
7709 def testAlternatesFdtgrepInval(self):
7710 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7711 self._SetupSplElf()
7712 with self.assertRaises(ValueError) as e:
7713 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7714 U_BOOT_SPL_NODTB_DATA)
7715 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7716 str(e.exception))
7717
Simon Glasscd2783e2024-07-20 11:49:46 +01007718 def testFitFdtListDir(self):
7719 """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
Simon Glass1bba8942024-08-26 13:11:34 -06007720 old_dir = os.getcwd()
7721 try:
7722 os.chdir(self._indir)
7723 self.CheckFitFdt('333_fit_fdt_dir.dts', False)
7724 finally:
7725 os.chdir(old_dir)
Simon Glasscd2783e2024-07-20 11:49:46 +01007726
Simon Glassd2a9d6e2024-08-26 13:11:37 -06007727 def testFitFdtListDirDefault(self):
7728 """Test an FIT fit,fdt-list-dir where the default DT in is a subdir"""
7729 old_dir = os.getcwd()
7730 try:
7731 os.chdir(self._indir)
7732 self.CheckFitFdt('333_fit_fdt_dir.dts', False,
7733 default_dt='rockchip/test-fdt2')
7734 finally:
7735 os.chdir(old_dir)
7736
Simon Glass5f7aadf2024-07-20 11:49:47 +01007737 def testFitFdtCompat(self):
7738 """Test an image with an FIT with compatible in the config nodes"""
7739 entry_args = {
7740 'of-list': 'model1 model2',
7741 'default-dt': 'model2',
7742 }
7743 testdir, dtb_list = self.SetupAlternateDts()
7744 data = self._DoReadFileDtb(
7745 '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
7746 entry_args=entry_args, extra_indirs=[testdir])[0]
7747
7748 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7749
7750 fit = fdt.Fdt.FromData(fit_data)
7751 fit.Scan()
7752
7753 cnode = fit.GetNode('/configurations')
7754 self.assertIn('default', cnode.props)
7755 self.assertEqual('config-2', cnode.props['default'].value)
7756
7757 for seq in range(1, 2):
7758 name = f'config-{seq}'
7759 fnode = fit.GetNode('/configurations/%s' % name)
7760 self.assertIsNotNone(fnode)
7761 self.assertIn('compatible', fnode.props.keys())
7762 expected = 'one' if seq == 1 else 'two'
7763 self.assertEqual(f'u-boot,model-{expected}',
7764 fnode.props['compatible'].value)
7765
Simon Glassa04b9942024-07-20 11:49:48 +01007766 def testFitFdtPhase(self):
7767 """Test an image with an FIT with fdt-phase in the fdt nodes"""
7768 phase = 'tpl'
7769 entry_args = {
7770 f'{phase}-dtb': '1',
7771 f'{phase}-bss-pad': 'y',
7772 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7773 'of-list': 'model1 model2',
7774 'default-dt': 'model2',
7775 }
7776 testdir, dtb_list = self.SetupAlternateDts()
7777 data = self._DoReadFileDtb(
7778 '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
7779 entry_args=entry_args, extra_indirs=[testdir])[0]
7780 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7781 fit = fdt.Fdt.FromData(fit_data)
7782 fit.Scan()
7783
7784 # Check that each FDT has only the expected properties for the phase
7785 for seq in range(1, 2):
7786 fnode = fit.GetNode(f'/images/fdt-{seq}')
7787 self.assertIsNotNone(fnode)
7788 dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
7789 dtb.Scan()
7790
7791 # Make sure that the 'bootph-pre-sram' tag in /node protects it from
7792 # removal
7793 node = dtb.GetNode('/node')
7794 self.assertIsNotNone(node)
7795 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7796 node.props.keys())
7797
7798 # Make sure the other node is gone
7799 self.assertIsNone(dtb.GetNode('/node/other-node'))
7800
Simon Glassb553e8a2024-08-26 13:11:29 -06007801 def testMkeficapsuleMissing(self):
7802 """Test that binman complains if mkeficapsule is missing"""
7803 with self.assertRaises(ValueError) as e:
7804 self._DoTestFile('311_capsule.dts',
7805 force_missing_bintools='mkeficapsule')
7806 self.assertIn("Node '/binman/efi-capsule': Missing tool: 'mkeficapsule'",
7807 str(e.exception))
7808
7809 def testMkeficapsuleMissingOk(self):
7810 """Test that binman deals with mkeficapsule being missing"""
7811 with test_util.capture_sys_output() as (stdout, stderr):
7812 ret = self._DoTestFile('311_capsule.dts',
7813 force_missing_bintools='mkeficapsule',
7814 allow_missing=True)
7815 self.assertEqual(103, ret)
7816 err = stderr.getvalue()
7817 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkeficapsule")
7818
Simon Glass4b0f4142024-08-26 13:11:40 -06007819 def testSymbolsBase(self):
7820 """Test handling of symbols-base"""
7821 self.checkSymbols('336_symbols_base.dts', U_BOOT_SPL_DATA, 0x1c,
7822 symbols_base=0)
7823
7824 def testSymbolsBaseExpanded(self):
7825 """Test handling of symbols-base with expanded entries"""
7826 entry_args = {
7827 'spl-dtb': '1',
7828 }
7829 self.checkSymbols('337_symbols_base_expand.dts', U_BOOT_SPL_NODTB_DATA +
7830 U_BOOT_SPL_DTB_DATA, 0x38,
7831 entry_args=entry_args, use_expanded=True,
7832 symbols_base=0)
7833
Simon Glass3eb30a42024-08-26 13:11:42 -06007834 def testSymbolsCompressed(self):
7835 """Test binman complains about symbols from a compressed section"""
7836 with test_util.capture_sys_output() as (stdout, stderr):
7837 self.checkSymbols('338_symbols_comp.dts', U_BOOT_SPL_DATA, None)
7838 out = stdout.getvalue()
7839 self.assertIn('Symbol-writing: no value for /binman/section/u-boot',
7840 out)
7841
Simon Glass9c25ef22024-08-26 13:11:43 -06007842 def testNxpImx8Image(self):
7843 """Test that binman can produce an iMX8 image"""
7844 self._DoTestFile('339_nxp_imx8.dts')
7845
Alexander Kochetkova730a282024-09-16 11:24:46 +03007846 def testFitSignSimple(self):
7847 """Test that image with FIT and signature nodes can be signed"""
7848 if not elf.ELF_TOOLS:
7849 self.skipTest('Python elftools not available')
7850 entry_args = {
7851 'of-list': 'test-fdt1',
7852 'default-dt': 'test-fdt1',
7853 'atf-bl31-path': 'bl31.elf',
7854 }
7855 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7856 self._MakeInputFile("keys/rsa2048.key", data)
7857
7858 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7859 keys_subdir = os.path.join(self._indir, "keys")
7860 data = self._DoReadFileDtb(
7861 '340_fit_signature.dts',
7862 entry_args=entry_args,
7863 extra_indirs=[test_subdir, keys_subdir])[0]
7864
7865 dtb = fdt.Fdt.FromData(data)
7866 dtb.Scan()
7867
7868 conf = dtb.GetNode('/configurations/conf-uboot-1')
7869 self.assertIsNotNone(conf)
7870 signature = conf.FindNode('signature')
7871 self.assertIsNotNone(signature)
7872 self.assertIsNotNone(signature.props.get('value'))
7873
7874 images = dtb.GetNode('/images')
7875 self.assertIsNotNone(images)
7876 for subnode in images.subnodes:
7877 signature = subnode.FindNode('signature')
7878 self.assertIsNotNone(signature)
7879 self.assertIsNotNone(signature.props.get('value'))
7880
7881 def testFitSignKeyNotFound(self):
7882 """Test that missing keys raise an error"""
7883 if not elf.ELF_TOOLS:
7884 self.skipTest('Python elftools not available')
7885 entry_args = {
7886 'of-list': 'test-fdt1',
7887 'default-dt': 'test-fdt1',
7888 'atf-bl31-path': 'bl31.elf',
7889 }
7890 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7891 with self.assertRaises(ValueError) as e:
7892 self._DoReadFileDtb(
7893 '340_fit_signature.dts',
7894 entry_args=entry_args,
7895 extra_indirs=[test_subdir])[0]
7896 self.assertIn(
7897 'Filename \'rsa2048.key\' not found in input path',
7898 str(e.exception))
7899
7900 def testFitSignMultipleKeyPaths(self):
7901 """Test that keys found in multiple paths raise an error"""
7902 if not elf.ELF_TOOLS:
7903 self.skipTest('Python elftools not available')
7904 entry_args = {
7905 'of-list': 'test-fdt1',
7906 'default-dt': 'test-fdt1',
7907 'atf-bl31-path': 'bl31.elf',
7908 }
7909 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7910 self._MakeInputFile("keys1/rsa2048.key", data)
7911 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7912 self._MakeInputFile("keys2/conf-rsa2048.key", data)
7913
7914 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7915 keys_subdir1 = os.path.join(self._indir, "keys1")
7916 keys_subdir2 = os.path.join(self._indir, "keys2")
7917 with self.assertRaises(ValueError) as e:
7918 self._DoReadFileDtb(
7919 '341_fit_signature.dts',
7920 entry_args=entry_args,
7921 extra_indirs=[test_subdir, keys_subdir1, keys_subdir2])[0]
7922 self.assertIn(
7923 'Node \'/binman/fit\': multiple key paths found',
7924 str(e.exception))
7925
7926 def testFitSignNoSingatureNodes(self):
7927 """Test that fit,sign doens't raise error if no signature nodes found"""
7928 if not elf.ELF_TOOLS:
7929 self.skipTest('Python elftools not available')
7930 entry_args = {
7931 'of-list': 'test-fdt1',
7932 'default-dt': 'test-fdt1',
7933 'atf-bl31-path': 'bl31.elf',
7934 }
7935 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7936 self._DoReadFileDtb(
7937 '342_fit_signature.dts',
7938 entry_args=entry_args,
7939 extra_indirs=[test_subdir])[0]
7940
Simon Glassa360b8f2024-06-23 11:55:06 -06007941
Paul HENRYSff318462024-11-25 18:47:17 +01007942 def testSimpleFitEncryptedData(self):
7943 """Test an image with a FIT containing data to be encrypted"""
7944 data = tools.read_file(self.TestFile("aes256.bin"))
7945 self._MakeInputFile("keys/aes256.bin", data)
7946
7947 keys_subdir = os.path.join(self._indir, "keys")
7948 data = self._DoReadFileDtb(
7949 '343_fit_encrypt_data.dts',
7950 extra_indirs=[keys_subdir])[0]
7951
7952 fit = fdt.Fdt.FromData(data)
7953 fit.Scan()
7954
7955 # Extract the encrypted data and the Initialization Vector from the FIT
7956 node = fit.GetNode('/images/u-boot')
7957 subnode = fit.GetNode('/images/u-boot/cipher')
7958 data_size_unciphered = int.from_bytes(fit.GetProps(node)['data-size-unciphered'].bytes,
7959 byteorder='big')
7960 self.assertEqual(data_size_unciphered, len(U_BOOT_NODTB_DATA))
7961
7962 # Retrieve the key name from the FIT removing any null byte
7963 key_name = fit.GetProps(subnode)['key-name-hint'].bytes.replace(b'\x00', b'')
7964 with open(self.TestFile(key_name.decode('ascii') + '.bin'), 'rb') as file:
7965 key = file.read()
7966 iv = fit.GetProps(subnode)['iv'].bytes.hex()
7967 enc_data = fit.GetProps(node)['data'].bytes
7968 outdir = tools.get_output_dir()
7969 enc_data_file = os.path.join(outdir, 'encrypted_data.bin')
7970 tools.write_file(enc_data_file, enc_data)
7971 data_file = os.path.join(outdir, 'data.bin')
7972
7973 # Decrypt the encrypted data from the FIT and compare the data
7974 tools.run('openssl', 'enc', '-aes-256-cbc', '-nosalt', '-d', '-in',
7975 enc_data_file, '-out', data_file, '-K', key.hex(), '-iv', iv)
7976 with open(data_file, 'r') as file:
7977 dec_data = file.read()
7978 self.assertEqual(U_BOOT_NODTB_DATA, dec_data.encode('ascii'))
7979
7980 def testSimpleFitEncryptedDataMissingKey(self):
7981 """Test an image with a FIT containing data to be encrypted but with a missing key"""
7982 with self.assertRaises(ValueError) as e:
7983 self._DoReadFile('344_fit_encrypt_data_no_key.dts')
7984
7985 self.assertIn("Filename 'aes256.bin' not found in input path", str(e.exception))
7986
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01007987 def testFitFdtName(self):
7988 """Test an image with an FIT with multiple FDT images using NAME"""
7989 self.CheckFitFdt('345_fit_fdt_name.dts', use_seq_num=False)
7990
Simon Glassac599912017-11-12 21:52:22 -07007991if __name__ == "__main__":
7992 unittest.main()