blob: 948fcc02259ae61d8f7ff8d4ec8b867c7f513bbf [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)
Simon Glassed836ac2025-02-26 09:26:17 -07002311 base = (1 << 32) - 0x100
Simon Glassc64aea52018-09-14 04:57:34 -06002312
Simon Glassed836ac2025-02-26 09:26:17 -07002313 self.assertEqual(base, fentries[0].offset)
Simon Glassc64aea52018-09-14 04:57:34 -06002314 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002315 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002316
Simon Glassed836ac2025-02-26 09:26:17 -07002317 self.assertEqual(base + 4, fentries[1].offset)
Simon Glassc64aea52018-09-14 04:57:34 -06002318 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002319 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002320
Simon Glassed836ac2025-02-26 09:26:17 -07002321 self.assertEqual(base + 32, fentries[2].offset)
Simon Glassc64aea52018-09-14 04:57:34 -06002322 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2323 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002324 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002325
2326 def testFmapX86Section(self):
2327 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002328 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002329 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002330 self.assertEqual(expected, data[:32])
2331 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2332
Simon Glassb1d414c2021-04-03 11:05:10 +13002333 self.assertEqual(0x180, fhdr.image_size)
Simon Glassed836ac2025-02-26 09:26:17 -07002334 base = (1 << 32) - 0x180
Simon Glassb1d414c2021-04-03 11:05:10 +13002335 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002336 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002337
Simon Glass82059c22021-04-03 11:05:09 +13002338 fentry = next(fiter)
2339 self.assertEqual(b'U_BOOT', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002340 self.assertEqual(base, fentry.offset)
Simon Glass82059c22021-04-03 11:05:09 +13002341 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002342
Simon Glass82059c22021-04-03 11:05:09 +13002343 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002344 self.assertEqual(b'SECTION', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002345 self.assertEqual(base + 4, fentry.offset)
Simon Glassb1d414c2021-04-03 11:05:10 +13002346 self.assertEqual(0x20 + expect_size, fentry.size)
2347
2348 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002349 self.assertEqual(b'INTEL_MRC', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002350 self.assertEqual(base + 4, fentry.offset)
Simon Glass82059c22021-04-03 11:05:09 +13002351 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002352
Simon Glass82059c22021-04-03 11:05:09 +13002353 fentry = next(fiter)
2354 self.assertEqual(b'FMAP', fentry.name)
Simon Glassed836ac2025-02-26 09:26:17 -07002355 self.assertEqual(base + 36, fentry.offset)
Simon Glass82059c22021-04-03 11:05:09 +13002356 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002357
Simon Glassb1714232018-09-14 04:57:35 -06002358 def testElf(self):
2359 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002360 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002361 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002362 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002363 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002364 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002365
Simon Glass0d673792019-07-08 13:18:25 -06002366 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002367 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002368 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002369 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002370 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002371 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002372
Simon Glasscd817d52018-09-14 04:57:36 -06002373 def testPackOverlapMap(self):
2374 """Test that overlapping regions are detected"""
2375 with test_util.capture_sys_output() as (stdout, stderr):
2376 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002377 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002378 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002379 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2380 stdout.getvalue())
2381
2382 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002383 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002384 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002385 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002386 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002387<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002388<none> 00000000 00000004 u-boot
2389<none> 00000003 00000004 u-boot-align
2390''', map_data)
2391
Simon Glass0d673792019-07-08 13:18:25 -06002392 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002393 """Test that an image with an Intel Reference code binary works"""
2394 data = self._DoReadFile('100_intel_refcode.dts')
2395 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2396
Simon Glasseb023b32019-04-25 21:58:39 -06002397 def testSectionOffset(self):
2398 """Tests use of a section with an offset"""
2399 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2400 map=True)
2401 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700240200000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600240300000004 00000004 00000010 section@0
240400000004 00000000 00000004 u-boot
240500000018 00000018 00000010 section@1
240600000018 00000000 00000004 u-boot
24070000002c 0000002c 00000004 section@2
24080000002c 00000000 00000004 u-boot
2409''', map_data)
2410 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002411 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2412 tools.get_bytes(0x21, 12) +
2413 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2414 tools.get_bytes(0x61, 12) +
2415 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2416 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002417
Simon Glass1de34482019-07-08 13:18:53 -06002418 def testCbfsRaw(self):
2419 """Test base handling of a Coreboot Filesystem (CBFS)
2420
2421 The exact contents of the CBFS is verified by similar tests in
2422 cbfs_util_test.py. The tests here merely check that the files added to
2423 the CBFS can be found in the final image.
2424 """
2425 data = self._DoReadFile('102_cbfs_raw.dts')
2426 size = 0xb0
2427
2428 cbfs = cbfs_util.CbfsReader(data)
2429 self.assertEqual(size, cbfs.rom_size)
2430
2431 self.assertIn('u-boot-dtb', cbfs.files)
2432 cfile = cbfs.files['u-boot-dtb']
2433 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2434
2435 def testCbfsArch(self):
2436 """Test on non-x86 architecture"""
2437 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2438 size = 0x100
2439
2440 cbfs = cbfs_util.CbfsReader(data)
2441 self.assertEqual(size, cbfs.rom_size)
2442
2443 self.assertIn('u-boot-dtb', cbfs.files)
2444 cfile = cbfs.files['u-boot-dtb']
2445 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2446
2447 def testCbfsStage(self):
2448 """Tests handling of a Coreboot Filesystem (CBFS)"""
2449 if not elf.ELF_TOOLS:
2450 self.skipTest('Python elftools not available')
2451 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2452 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2453 size = 0xb0
2454
2455 data = self._DoReadFile('104_cbfs_stage.dts')
2456 cbfs = cbfs_util.CbfsReader(data)
2457 self.assertEqual(size, cbfs.rom_size)
2458
2459 self.assertIn('u-boot', cbfs.files)
2460 cfile = cbfs.files['u-boot']
2461 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2462
2463 def testCbfsRawCompress(self):
2464 """Test handling of compressing raw files"""
2465 self._CheckLz4()
2466 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2467 size = 0x140
2468
2469 cbfs = cbfs_util.CbfsReader(data)
2470 self.assertIn('u-boot', cbfs.files)
2471 cfile = cbfs.files['u-boot']
2472 self.assertEqual(COMPRESS_DATA, cfile.data)
2473
2474 def testCbfsBadArch(self):
2475 """Test handling of a bad architecture"""
2476 with self.assertRaises(ValueError) as e:
2477 self._DoReadFile('106_cbfs_bad_arch.dts')
2478 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2479
2480 def testCbfsNoSize(self):
2481 """Test handling of a missing size property"""
2482 with self.assertRaises(ValueError) as e:
2483 self._DoReadFile('107_cbfs_no_size.dts')
2484 self.assertIn('entry must have a size property', str(e.exception))
2485
Simon Glass3e28f4f2021-11-23 11:03:54 -07002486 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002487 """Test handling of a CBFS entry which does not provide contentsy"""
2488 with self.assertRaises(ValueError) as e:
2489 self._DoReadFile('108_cbfs_no_contents.dts')
2490 self.assertIn('Could not complete processing of contents',
2491 str(e.exception))
2492
2493 def testCbfsBadCompress(self):
2494 """Test handling of a bad architecture"""
2495 with self.assertRaises(ValueError) as e:
2496 self._DoReadFile('109_cbfs_bad_compress.dts')
2497 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2498 str(e.exception))
2499
2500 def testCbfsNamedEntries(self):
2501 """Test handling of named entries"""
2502 data = self._DoReadFile('110_cbfs_name.dts')
2503
2504 cbfs = cbfs_util.CbfsReader(data)
2505 self.assertIn('FRED', cbfs.files)
2506 cfile1 = cbfs.files['FRED']
2507 self.assertEqual(U_BOOT_DATA, cfile1.data)
2508
2509 self.assertIn('hello', cbfs.files)
2510 cfile2 = cbfs.files['hello']
2511 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2512
Simon Glass759af872019-07-08 13:18:54 -06002513 def _SetupIfwi(self, fname):
2514 """Set up to run an IFWI test
2515
2516 Args:
2517 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2518 """
2519 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002520 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002521
2522 # Intel Integrated Firmware Image (IFWI) file
2523 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2524 data = fd.read()
2525 TestFunctional._MakeInputFile(fname,data)
2526
2527 def _CheckIfwi(self, data):
2528 """Check that an image with an IFWI contains the correct output
2529
2530 Args:
2531 data: Conents of output file
2532 """
Simon Glass80025522022-01-29 14:14:04 -07002533 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002534 if data[:0x1000] != expected_desc:
2535 self.fail('Expected descriptor binary at start of image')
2536
2537 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002538 image_fname = tools.get_output_filename('image.bin')
2539 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002540 ifwitool = bintool.Bintool.create('ifwitool')
2541 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002542
Simon Glass80025522022-01-29 14:14:04 -07002543 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002544 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002545
2546 def testPackX86RomIfwi(self):
2547 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2548 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002549 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002550 self._CheckIfwi(data)
2551
2552 def testPackX86RomIfwiNoDesc(self):
2553 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2554 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002555 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002556 self._CheckIfwi(data)
2557
2558 def testPackX86RomIfwiNoData(self):
2559 """Test that an x86 ROM with IFWI handles missing data"""
2560 self._SetupIfwi('ifwi.bin')
2561 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002562 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002563 self.assertIn('Could not complete processing of contents',
2564 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002565
Simon Glass66152ce2022-01-09 20:14:09 -07002566 def testIfwiMissing(self):
2567 """Test that binman still produces an image if ifwitool is missing"""
2568 self._SetupIfwi('fitimage.bin')
2569 with test_util.capture_sys_output() as (_, stderr):
2570 self._DoTestFile('111_x86_rom_ifwi.dts',
2571 force_missing_bintools='ifwitool')
2572 err = stderr.getvalue()
2573 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002574 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002575
Simon Glassc2f1aed2019-07-08 13:18:56 -06002576 def testCbfsOffset(self):
2577 """Test a CBFS with files at particular offsets
2578
2579 Like all CFBS tests, this is just checking the logic that calls
2580 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2581 """
2582 data = self._DoReadFile('114_cbfs_offset.dts')
2583 size = 0x200
2584
2585 cbfs = cbfs_util.CbfsReader(data)
2586 self.assertEqual(size, cbfs.rom_size)
2587
2588 self.assertIn('u-boot', cbfs.files)
2589 cfile = cbfs.files['u-boot']
2590 self.assertEqual(U_BOOT_DATA, cfile.data)
2591 self.assertEqual(0x40, cfile.cbfs_offset)
2592
2593 self.assertIn('u-boot-dtb', cbfs.files)
2594 cfile2 = cbfs.files['u-boot-dtb']
2595 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2596 self.assertEqual(0x140, cfile2.cbfs_offset)
2597
Simon Glass0f621332019-07-08 14:25:27 -06002598 def testFdtmap(self):
2599 """Test an FDT map can be inserted in the image"""
2600 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2601 fdtmap_data = data[len(U_BOOT_DATA):]
2602 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002603 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002604 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002605
2606 fdt_data = fdtmap_data[16:]
2607 dtb = fdt.Fdt.FromData(fdt_data)
2608 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002609 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002610 self.assertEqual({
2611 'image-pos': 0,
2612 'offset': 0,
2613 'u-boot:offset': 0,
2614 'u-boot:size': len(U_BOOT_DATA),
2615 'u-boot:image-pos': 0,
2616 'fdtmap:image-pos': 4,
2617 'fdtmap:offset': 4,
2618 'fdtmap:size': len(fdtmap_data),
2619 'size': len(data),
2620 }, props)
2621
2622 def testFdtmapNoMatch(self):
2623 """Check handling of an FDT map when the section cannot be found"""
2624 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2625
2626 # Mangle the section name, which should cause a mismatch between the
2627 # correct FDT path and the one expected by the section
2628 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002629 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002630 entries = image.GetEntries()
2631 fdtmap = entries['fdtmap']
2632 with self.assertRaises(ValueError) as e:
2633 fdtmap._GetFdtmap()
2634 self.assertIn("Cannot locate node for path '/binman-suffix'",
2635 str(e.exception))
2636
Simon Glasscec34ba2019-07-08 14:25:28 -06002637 def testFdtmapHeader(self):
2638 """Test an FDT map and image header can be inserted in the image"""
2639 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2640 fdtmap_pos = len(U_BOOT_DATA)
2641 fdtmap_data = data[fdtmap_pos:]
2642 fdt_data = fdtmap_data[16:]
2643 dtb = fdt.Fdt.FromData(fdt_data)
2644 fdt_size = dtb.GetFdtObj().totalsize()
2645 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002646 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002647 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2648 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2649
2650 def testFdtmapHeaderStart(self):
2651 """Test an image header can be inserted at the image start"""
2652 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2653 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2654 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002655 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002656 offset = struct.unpack('<I', hdr_data[4:])[0]
2657 self.assertEqual(fdtmap_pos, offset)
2658
2659 def testFdtmapHeaderPos(self):
2660 """Test an image header can be inserted at a chosen position"""
2661 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2662 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2663 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002664 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002665 offset = struct.unpack('<I', hdr_data[4:])[0]
2666 self.assertEqual(fdtmap_pos, offset)
2667
2668 def testHeaderMissingFdtmap(self):
2669 """Test an image header requires an fdtmap"""
2670 with self.assertRaises(ValueError) as e:
2671 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2672 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2673 str(e.exception))
2674
2675 def testHeaderNoLocation(self):
2676 """Test an image header with a no specified location is detected"""
2677 with self.assertRaises(ValueError) as e:
2678 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2679 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2680 str(e.exception))
2681
Simon Glasse61b6f62019-07-08 14:25:37 -06002682 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002683 """Test extending an entry after it is packed"""
2684 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002685 self.assertEqual(b'aaa', data[:3])
2686 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2687 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002688
Simon Glassdd156a42022-03-05 20:18:59 -07002689 def testEntryExtendBad(self):
2690 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002691 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002692 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002693 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002694 str(e.exception))
2695
Simon Glassdd156a42022-03-05 20:18:59 -07002696 def testEntryExtendSection(self):
2697 """Test extending an entry within a section after it is packed"""
2698 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002699 self.assertEqual(b'aaa', data[:3])
2700 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2701 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002702
Simon Glass90d29682019-07-08 14:25:38 -06002703 def testCompressDtb(self):
2704 """Test that compress of device-tree files is supported"""
2705 self._CheckLz4()
2706 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2707 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2708 comp_data = data[len(U_BOOT_DATA):]
2709 orig = self._decompress(comp_data)
2710 dtb = fdt.Fdt.FromData(orig)
2711 dtb.Scan()
2712 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2713 expected = {
2714 'u-boot:size': len(U_BOOT_DATA),
2715 'u-boot-dtb:uncomp-size': len(orig),
2716 'u-boot-dtb:size': len(comp_data),
2717 'size': len(data),
2718 }
2719 self.assertEqual(expected, props)
2720
Simon Glass151bbbf2019-07-08 14:25:41 -06002721 def testCbfsUpdateFdt(self):
2722 """Test that we can update the device tree with CBFS offset/size info"""
2723 self._CheckLz4()
2724 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2725 update_dtb=True)
2726 dtb = fdt.Fdt(out_dtb_fname)
2727 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002728 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002729 del props['cbfs/u-boot:size']
2730 self.assertEqual({
2731 'offset': 0,
2732 'size': len(data),
2733 'image-pos': 0,
2734 'cbfs:offset': 0,
2735 'cbfs:size': len(data),
2736 'cbfs:image-pos': 0,
Simon Glassfa144222023-10-14 14:40:28 -06002737 'cbfs/u-boot:offset': 0x30,
Simon Glass151bbbf2019-07-08 14:25:41 -06002738 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002739 'cbfs/u-boot:image-pos': 0x30,
2740 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002741 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002742 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002743 }, props)
2744
Simon Glass3c9b4f22019-07-08 14:25:42 -06002745 def testCbfsBadType(self):
2746 """Test an image header with a no specified location is detected"""
2747 with self.assertRaises(ValueError) as e:
2748 self._DoReadFile('126_cbfs_bad_type.dts')
2749 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2750
Simon Glass6b156f82019-07-08 14:25:43 -06002751 def testList(self):
2752 """Test listing the files in an image"""
2753 self._CheckLz4()
2754 data = self._DoReadFile('127_list.dts')
2755 image = control.images['image']
2756 entries = image.BuildEntryList()
2757 self.assertEqual(7, len(entries))
2758
2759 ent = entries[0]
2760 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002761 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002762 self.assertEqual('section', ent.etype)
2763 self.assertEqual(len(data), ent.size)
2764 self.assertEqual(0, ent.image_pos)
2765 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002766 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002767
2768 ent = entries[1]
2769 self.assertEqual(1, ent.indent)
2770 self.assertEqual('u-boot', ent.name)
2771 self.assertEqual('u-boot', ent.etype)
2772 self.assertEqual(len(U_BOOT_DATA), ent.size)
2773 self.assertEqual(0, ent.image_pos)
2774 self.assertEqual(None, ent.uncomp_size)
2775 self.assertEqual(0, ent.offset)
2776
2777 ent = entries[2]
2778 self.assertEqual(1, ent.indent)
2779 self.assertEqual('section', ent.name)
2780 self.assertEqual('section', ent.etype)
2781 section_size = ent.size
2782 self.assertEqual(0x100, ent.image_pos)
2783 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002784 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002785
2786 ent = entries[3]
2787 self.assertEqual(2, ent.indent)
2788 self.assertEqual('cbfs', ent.name)
2789 self.assertEqual('cbfs', ent.etype)
2790 self.assertEqual(0x400, ent.size)
2791 self.assertEqual(0x100, ent.image_pos)
2792 self.assertEqual(None, ent.uncomp_size)
2793 self.assertEqual(0, ent.offset)
2794
2795 ent = entries[4]
2796 self.assertEqual(3, ent.indent)
2797 self.assertEqual('u-boot', ent.name)
2798 self.assertEqual('u-boot', ent.etype)
2799 self.assertEqual(len(U_BOOT_DATA), ent.size)
2800 self.assertEqual(0x138, ent.image_pos)
2801 self.assertEqual(None, ent.uncomp_size)
2802 self.assertEqual(0x38, ent.offset)
2803
2804 ent = entries[5]
2805 self.assertEqual(3, ent.indent)
2806 self.assertEqual('u-boot-dtb', ent.name)
2807 self.assertEqual('text', ent.etype)
2808 self.assertGreater(len(COMPRESS_DATA), ent.size)
2809 self.assertEqual(0x178, ent.image_pos)
2810 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2811 self.assertEqual(0x78, ent.offset)
2812
2813 ent = entries[6]
2814 self.assertEqual(2, ent.indent)
2815 self.assertEqual('u-boot-dtb', ent.name)
2816 self.assertEqual('u-boot-dtb', ent.etype)
2817 self.assertEqual(0x500, ent.image_pos)
2818 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2819 dtb_size = ent.size
2820 # Compressing this data expands it since headers are added
2821 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2822 self.assertEqual(0x400, ent.offset)
2823
2824 self.assertEqual(len(data), 0x100 + section_size)
2825 self.assertEqual(section_size, 0x400 + dtb_size)
2826
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002827 def testFindFdtmap(self):
2828 """Test locating an FDT map in an image"""
2829 self._CheckLz4()
2830 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2831 image = control.images['image']
2832 entries = image.GetEntries()
2833 entry = entries['fdtmap']
2834 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2835
2836 def testFindFdtmapMissing(self):
2837 """Test failing to locate an FDP map"""
2838 data = self._DoReadFile('005_simple.dts')
2839 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2840
Simon Glassed39a3c2019-07-08 14:25:45 -06002841 def testFindImageHeader(self):
2842 """Test locating a image header"""
2843 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002844 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002845 image = control.images['image']
2846 entries = image.GetEntries()
2847 entry = entries['fdtmap']
2848 # The header should point to the FDT map
2849 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2850
2851 def testFindImageHeaderStart(self):
2852 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002853 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002854 image = control.images['image']
2855 entries = image.GetEntries()
2856 entry = entries['fdtmap']
2857 # The header should point to the FDT map
2858 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2859
2860 def testFindImageHeaderMissing(self):
2861 """Test failing to locate an image header"""
2862 data = self._DoReadFile('005_simple.dts')
2863 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2864
Simon Glassb8424fa2019-07-08 14:25:46 -06002865 def testReadImage(self):
2866 """Test reading an image and accessing its FDT map"""
2867 self._CheckLz4()
2868 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002869 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002870 orig_image = control.images['image']
2871 image = Image.FromFile(image_fname)
2872 self.assertEqual(orig_image.GetEntries().keys(),
2873 image.GetEntries().keys())
2874
2875 orig_entry = orig_image.GetEntries()['fdtmap']
2876 entry = image.GetEntries()['fdtmap']
Brandon Maiera657bc62024-06-04 16:16:05 +00002877 self.assertEqual(orig_entry.offset, entry.offset)
2878 self.assertEqual(orig_entry.size, entry.size)
2879 self.assertEqual(orig_entry.image_pos, entry.image_pos)
Simon Glassb8424fa2019-07-08 14:25:46 -06002880
2881 def testReadImageNoHeader(self):
2882 """Test accessing an image's FDT map without an image header"""
2883 self._CheckLz4()
2884 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002885 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002886 image = Image.FromFile(image_fname)
2887 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002888 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002889
2890 def testReadImageFail(self):
2891 """Test failing to read an image image's FDT map"""
2892 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002893 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002894 with self.assertRaises(ValueError) as e:
2895 image = Image.FromFile(image_fname)
2896 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002897
Simon Glassb2fd11d2019-07-08 14:25:48 -06002898 def testListCmd(self):
2899 """Test listing the files in an image using an Fdtmap"""
2900 self._CheckLz4()
2901 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2902
2903 # lz4 compression size differs depending on the version
2904 image = control.images['image']
2905 entries = image.GetEntries()
2906 section_size = entries['section'].size
2907 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2908 fdtmap_offset = entries['fdtmap'].offset
2909
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002910 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002911 try:
2912 tmpdir, updated_fname = self._SetupImageInTmpdir()
2913 with test_util.capture_sys_output() as (stdout, stderr):
2914 self._DoBinman('ls', '-i', updated_fname)
2915 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002916 if tmpdir:
2917 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002918 lines = stdout.getvalue().splitlines()
2919 expected = [
2920'Name Image-pos Size Entry-type Offset Uncomp-size',
2921'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002922'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002923' u-boot 0 4 u-boot 0',
2924' section 100 %x section 100' % section_size,
2925' cbfs 100 400 cbfs 0',
Simon Glassfa144222023-10-14 14:40:28 -06002926' u-boot 120 4 u-boot 20',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002927' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002928' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002929' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002930 (fdtmap_offset, fdtmap_offset),
2931' image-header bf8 8 image-header bf8',
2932 ]
2933 self.assertEqual(expected, lines)
2934
2935 def testListCmdFail(self):
2936 """Test failing to list an image"""
2937 self._DoReadFile('005_simple.dts')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002938 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002939 try:
2940 tmpdir, updated_fname = self._SetupImageInTmpdir()
2941 with self.assertRaises(ValueError) as e:
2942 self._DoBinman('ls', '-i', updated_fname)
2943 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002944 if tmpdir:
2945 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002946 self.assertIn("Cannot find FDT map in image", str(e.exception))
2947
2948 def _RunListCmd(self, paths, expected):
2949 """List out entries and check the result
2950
2951 Args:
2952 paths: List of paths to pass to the list command
2953 expected: Expected list of filenames to be returned, in order
2954 """
2955 self._CheckLz4()
2956 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002957 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002958 image = Image.FromFile(image_fname)
2959 lines = image.GetListEntries(paths)[1]
2960 files = [line[0].strip() for line in lines[1:]]
2961 self.assertEqual(expected, files)
2962
2963 def testListCmdSection(self):
2964 """Test listing the files in a section"""
2965 self._RunListCmd(['section'],
2966 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2967
2968 def testListCmdFile(self):
2969 """Test listing a particular file"""
2970 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2971
2972 def testListCmdWildcard(self):
2973 """Test listing a wildcarded file"""
2974 self._RunListCmd(['*boot*'],
2975 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2976
2977 def testListCmdWildcardMulti(self):
2978 """Test listing a wildcarded file"""
2979 self._RunListCmd(['*cb*', '*head*'],
2980 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2981
2982 def testListCmdEmpty(self):
2983 """Test listing a wildcarded file"""
2984 self._RunListCmd(['nothing'], [])
2985
2986 def testListCmdPath(self):
2987 """Test listing the files in a sub-entry of a section"""
2988 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2989
Simon Glass4c613bf2019-07-08 14:25:50 -06002990 def _RunExtractCmd(self, entry_name, decomp=True):
2991 """Extract an entry from an image
2992
2993 Args:
2994 entry_name: Entry name to extract
2995 decomp: True to decompress the data if compressed, False to leave
2996 it in its raw uncompressed format
2997
2998 Returns:
2999 data from entry
3000 """
3001 self._CheckLz4()
3002 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003003 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06003004 return control.ReadEntry(image_fname, entry_name, decomp)
3005
3006 def testExtractSimple(self):
3007 """Test extracting a single file"""
3008 data = self._RunExtractCmd('u-boot')
3009 self.assertEqual(U_BOOT_DATA, data)
3010
Simon Glass980a2842019-07-08 14:25:52 -06003011 def testExtractSection(self):
3012 """Test extracting the files in a section"""
3013 data = self._RunExtractCmd('section')
3014 cbfs_data = data[:0x400]
3015 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06003016 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06003017 dtb_data = data[0x400:]
3018 dtb = self._decompress(dtb_data)
3019 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3020
3021 def testExtractCompressed(self):
3022 """Test extracting compressed data"""
3023 data = self._RunExtractCmd('section/u-boot-dtb')
3024 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3025
3026 def testExtractRaw(self):
3027 """Test extracting compressed data without decompressing it"""
3028 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
3029 dtb = self._decompress(data)
3030 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3031
3032 def testExtractCbfs(self):
3033 """Test extracting CBFS data"""
3034 data = self._RunExtractCmd('section/cbfs/u-boot')
3035 self.assertEqual(U_BOOT_DATA, data)
3036
3037 def testExtractCbfsCompressed(self):
3038 """Test extracting CBFS compressed data"""
3039 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
3040 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3041
3042 def testExtractCbfsRaw(self):
3043 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003044 bintool = self.comp_bintools['lzma_alone']
3045 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06003046 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003047 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06003048 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3049
Simon Glass4c613bf2019-07-08 14:25:50 -06003050 def testExtractBadEntry(self):
3051 """Test extracting a bad section path"""
3052 with self.assertRaises(ValueError) as e:
3053 self._RunExtractCmd('section/does-not-exist')
3054 self.assertIn("Entry 'does-not-exist' not found in '/section'",
3055 str(e.exception))
3056
3057 def testExtractMissingFile(self):
3058 """Test extracting file that does not exist"""
3059 with self.assertRaises(IOError) as e:
3060 control.ReadEntry('missing-file', 'name')
3061
3062 def testExtractBadFile(self):
3063 """Test extracting an invalid file"""
3064 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07003065 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06003066 with self.assertRaises(ValueError) as e:
3067 control.ReadEntry(fname, 'name')
3068
Simon Glass980a2842019-07-08 14:25:52 -06003069 def testExtractCmd(self):
3070 """Test extracting a file fron an image on the command line"""
3071 self._CheckLz4()
3072 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06003073 fname = os.path.join(self._indir, 'output.extact')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003074 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06003075 try:
3076 tmpdir, updated_fname = self._SetupImageInTmpdir()
3077 with test_util.capture_sys_output() as (stdout, stderr):
3078 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3079 '-f', fname)
3080 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003081 if tmpdir:
3082 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07003083 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003084 self.assertEqual(U_BOOT_DATA, data)
3085
3086 def testExtractOneEntry(self):
3087 """Test extracting a single entry fron an image """
3088 self._CheckLz4()
3089 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003090 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003091 fname = os.path.join(self._indir, 'output.extact')
3092 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003093 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003094 self.assertEqual(U_BOOT_DATA, data)
3095
3096 def _CheckExtractOutput(self, decomp):
3097 """Helper to test file output with and without decompression
3098
3099 Args:
3100 decomp: True to decompress entry data, False to output it raw
3101 """
3102 def _CheckPresent(entry_path, expect_data, expect_size=None):
3103 """Check and remove expected file
3104
3105 This checks the data/size of a file and removes the file both from
3106 the outfiles set and from the output directory. Once all files are
3107 processed, both the set and directory should be empty.
3108
3109 Args:
3110 entry_path: Entry path
3111 expect_data: Data to expect in file, or None to skip check
3112 expect_size: Size of data to expect in file, or None to skip
3113 """
3114 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003115 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003116 os.remove(path)
3117 if expect_data:
3118 self.assertEqual(expect_data, data)
3119 elif expect_size:
3120 self.assertEqual(expect_size, len(data))
3121 outfiles.remove(path)
3122
3123 def _CheckDirPresent(name):
3124 """Remove expected directory
3125
3126 This gives an error if the directory does not exist as expected
3127
3128 Args:
3129 name: Name of directory to remove
3130 """
3131 path = os.path.join(outdir, name)
3132 os.rmdir(path)
3133
3134 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003135 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003136 outdir = os.path.join(self._indir, 'extract')
3137 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3138
3139 # Create a set of all file that were output (should be 9)
3140 outfiles = set()
3141 for root, dirs, files in os.walk(outdir):
3142 outfiles |= set([os.path.join(root, fname) for fname in files])
3143 self.assertEqual(9, len(outfiles))
3144 self.assertEqual(9, len(einfos))
3145
3146 image = control.images['image']
3147 entries = image.GetEntries()
3148
3149 # Check the 9 files in various ways
3150 section = entries['section']
3151 section_entries = section.GetEntries()
3152 cbfs_entries = section_entries['cbfs'].GetEntries()
3153 _CheckPresent('u-boot', U_BOOT_DATA)
3154 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3155 dtb_len = EXTRACT_DTB_SIZE
3156 if not decomp:
3157 dtb_len = cbfs_entries['u-boot-dtb'].size
3158 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3159 if not decomp:
3160 dtb_len = section_entries['u-boot-dtb'].size
3161 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3162
3163 fdtmap = entries['fdtmap']
3164 _CheckPresent('fdtmap', fdtmap.data)
3165 hdr = entries['image-header']
3166 _CheckPresent('image-header', hdr.data)
3167
3168 _CheckPresent('section/root', section.data)
3169 cbfs = section_entries['cbfs']
3170 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003171 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003172 _CheckPresent('root', data)
3173
3174 # There should be no files left. Remove all the directories to check.
3175 # If there are any files/dirs remaining, one of these checks will fail.
3176 self.assertEqual(0, len(outfiles))
3177 _CheckDirPresent('section/cbfs')
3178 _CheckDirPresent('section')
3179 _CheckDirPresent('')
3180 self.assertFalse(os.path.exists(outdir))
3181
3182 def testExtractAllEntries(self):
3183 """Test extracting all entries"""
3184 self._CheckLz4()
3185 self._CheckExtractOutput(decomp=True)
3186
3187 def testExtractAllEntriesRaw(self):
3188 """Test extracting all entries without decompressing them"""
3189 self._CheckLz4()
3190 self._CheckExtractOutput(decomp=False)
3191
3192 def testExtractSelectedEntries(self):
3193 """Test extracting some entries"""
3194 self._CheckLz4()
3195 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003196 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003197 outdir = os.path.join(self._indir, 'extract')
3198 einfos = control.ExtractEntries(image_fname, None, outdir,
3199 ['*cb*', '*head*'])
3200
3201 # File output is tested by testExtractAllEntries(), so just check that
3202 # the expected entries are selected
3203 names = [einfo.name for einfo in einfos]
3204 self.assertEqual(names,
3205 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3206
3207 def testExtractNoEntryPaths(self):
3208 """Test extracting some entries"""
3209 self._CheckLz4()
3210 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003211 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003212 with self.assertRaises(ValueError) as e:
3213 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003214 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003215 str(e.exception))
3216
3217 def testExtractTooManyEntryPaths(self):
3218 """Test extracting some entries"""
3219 self._CheckLz4()
3220 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003221 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003222 with self.assertRaises(ValueError) as e:
3223 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003224 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003225 str(e.exception))
3226
Simon Glass52d06212019-07-08 14:25:53 -06003227 def testPackAlignSection(self):
3228 """Test that sections can have alignment"""
3229 self._DoReadFile('131_pack_align_section.dts')
3230
3231 self.assertIn('image', control.images)
3232 image = control.images['image']
3233 entries = image.GetEntries()
3234 self.assertEqual(3, len(entries))
3235
3236 # First u-boot
3237 self.assertIn('u-boot', entries)
3238 entry = entries['u-boot']
3239 self.assertEqual(0, entry.offset)
3240 self.assertEqual(0, entry.image_pos)
3241 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3242 self.assertEqual(len(U_BOOT_DATA), entry.size)
3243
3244 # Section0
3245 self.assertIn('section0', entries)
3246 section0 = entries['section0']
3247 self.assertEqual(0x10, section0.offset)
3248 self.assertEqual(0x10, section0.image_pos)
3249 self.assertEqual(len(U_BOOT_DATA), section0.size)
3250
3251 # Second u-boot
3252 section_entries = section0.GetEntries()
3253 self.assertIn('u-boot', section_entries)
3254 entry = section_entries['u-boot']
3255 self.assertEqual(0, entry.offset)
3256 self.assertEqual(0x10, entry.image_pos)
3257 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3258 self.assertEqual(len(U_BOOT_DATA), entry.size)
3259
3260 # Section1
3261 self.assertIn('section1', entries)
3262 section1 = entries['section1']
3263 self.assertEqual(0x14, section1.offset)
3264 self.assertEqual(0x14, section1.image_pos)
3265 self.assertEqual(0x20, section1.size)
3266
3267 # Second u-boot
3268 section_entries = section1.GetEntries()
3269 self.assertIn('u-boot', section_entries)
3270 entry = section_entries['u-boot']
3271 self.assertEqual(0, entry.offset)
3272 self.assertEqual(0x14, entry.image_pos)
3273 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3274 self.assertEqual(len(U_BOOT_DATA), entry.size)
3275
3276 # Section2
3277 self.assertIn('section2', section_entries)
3278 section2 = section_entries['section2']
3279 self.assertEqual(0x4, section2.offset)
3280 self.assertEqual(0x18, section2.image_pos)
3281 self.assertEqual(4, section2.size)
3282
3283 # Third u-boot
3284 section_entries = section2.GetEntries()
3285 self.assertIn('u-boot', section_entries)
3286 entry = section_entries['u-boot']
3287 self.assertEqual(0, entry.offset)
3288 self.assertEqual(0x18, entry.image_pos)
3289 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3290 self.assertEqual(len(U_BOOT_DATA), entry.size)
3291
Simon Glassf8a54bc2019-07-20 12:23:56 -06003292 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3293 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003294 """Replace an entry in an image
3295
3296 This writes the entry data to update it, then opens the updated file and
3297 returns the value that it now finds there.
3298
3299 Args:
3300 entry_name: Entry name to replace
3301 data: Data to replace it with
3302 decomp: True to compress the data if needed, False if data is
3303 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003304 allow_resize: True to allow entries to change size, False to raise
3305 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003306
3307 Returns:
3308 Tuple:
3309 data from entry
3310 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003311 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003312 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003313 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003314 update_dtb=True)[1]
3315
3316 self.assertIn('image', control.images)
3317 image = control.images['image']
3318 entries = image.GetEntries()
3319 orig_dtb_data = entries['u-boot-dtb'].data
3320 orig_fdtmap_data = entries['fdtmap'].data
3321
Simon Glass80025522022-01-29 14:14:04 -07003322 image_fname = tools.get_output_filename('image.bin')
3323 updated_fname = tools.get_output_filename('image-updated.bin')
3324 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003325 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3326 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003327 data = control.ReadEntry(updated_fname, entry_name, decomp)
3328
Simon Glassf8a54bc2019-07-20 12:23:56 -06003329 # The DT data should not change unless resized:
3330 if not allow_resize:
3331 new_dtb_data = entries['u-boot-dtb'].data
3332 self.assertEqual(new_dtb_data, orig_dtb_data)
3333 new_fdtmap_data = entries['fdtmap'].data
3334 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003335
Simon Glassf8a54bc2019-07-20 12:23:56 -06003336 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003337
3338 def testReplaceSimple(self):
3339 """Test replacing a single file"""
3340 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003341 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3342 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003343 self.assertEqual(expected, data)
3344
3345 # Test that the state looks right. There should be an FDT for the fdtmap
3346 # that we jsut read back in, and it should match what we find in the
3347 # 'control' tables. Checking for an FDT that does not exist should
3348 # return None.
3349 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003350 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003351 self.assertEqual(expected_fdtmap, fdtmap)
3352
3353 dtb = state.GetFdtForEtype('fdtmap')
3354 self.assertEqual(dtb.GetContents(), fdtmap)
3355
3356 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3357 self.assertIsNone(missing_path)
3358 self.assertIsNone(missing_fdtmap)
3359
3360 missing_dtb = state.GetFdtForEtype('missing')
3361 self.assertIsNone(missing_dtb)
3362
3363 self.assertEqual('/binman', state.fdt_path_prefix)
3364
3365 def testReplaceResizeFail(self):
3366 """Test replacing a file by something larger"""
3367 expected = U_BOOT_DATA + b'x'
3368 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003369 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3370 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003371 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3372 str(e.exception))
3373
3374 def testReplaceMulti(self):
3375 """Test replacing entry data where multiple images are generated"""
3376 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3377 update_dtb=True)[0]
3378 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003379 updated_fname = tools.get_output_filename('image-updated.bin')
3380 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003381 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003382 control.WriteEntry(updated_fname, entry_name, expected,
3383 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003384 data = control.ReadEntry(updated_fname, entry_name)
3385 self.assertEqual(expected, data)
3386
3387 # Check the state looks right.
3388 self.assertEqual('/binman/image', state.fdt_path_prefix)
3389
3390 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003391 image_fname = tools.get_output_filename('first-image.bin')
3392 updated_fname = tools.get_output_filename('first-updated.bin')
3393 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003394 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003395 control.WriteEntry(updated_fname, entry_name, expected,
3396 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003397 data = control.ReadEntry(updated_fname, entry_name)
3398 self.assertEqual(expected, data)
3399
3400 # Check the state looks right.
3401 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003402
Simon Glassfb30e292019-07-20 12:23:51 -06003403 def testUpdateFdtAllRepack(self):
3404 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003405 self._SetupSplElf()
3406 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003407 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3408 SECTION_SIZE = 0x300
3409 DTB_SIZE = 602
3410 FDTMAP_SIZE = 608
3411 base_expected = {
3412 'offset': 0,
3413 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3414 'image-pos': 0,
3415 'section:offset': 0,
3416 'section:size': SECTION_SIZE,
3417 'section:image-pos': 0,
3418 'section/u-boot-dtb:offset': 4,
3419 'section/u-boot-dtb:size': 636,
3420 'section/u-boot-dtb:image-pos': 4,
3421 'u-boot-spl-dtb:offset': SECTION_SIZE,
3422 'u-boot-spl-dtb:size': DTB_SIZE,
3423 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3424 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3425 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3426 'u-boot-tpl-dtb:size': DTB_SIZE,
3427 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3428 'fdtmap:size': FDTMAP_SIZE,
3429 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3430 }
3431 main_expected = {
3432 'section:orig-size': SECTION_SIZE,
3433 'section/u-boot-dtb:orig-offset': 4,
3434 }
3435
3436 # We expect three device-tree files in the output, with the first one
3437 # within a fixed-size section.
3438 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3439 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3440 # main U-Boot tree. All three should have the same positions and offset
3441 # except that the main tree should include the main_expected properties
3442 start = 4
3443 for item in ['', 'spl', 'tpl', None]:
3444 if item is None:
3445 start += 16 # Move past fdtmap header
3446 dtb = fdt.Fdt.FromData(data[start:])
3447 dtb.Scan()
3448 props = self._GetPropTree(dtb,
3449 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3450 prefix='/' if item is None else '/binman/')
3451 expected = dict(base_expected)
3452 if item:
3453 expected[item] = 0
3454 else:
3455 # Main DTB and fdtdec should include the 'orig-' properties
3456 expected.update(main_expected)
3457 # Helpful for debugging:
3458 #for prop in sorted(props):
3459 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3460 self.assertEqual(expected, props)
3461 if item == '':
3462 start = SECTION_SIZE
3463 else:
3464 start += dtb._fdt_obj.totalsize()
3465
Simon Glass11453762019-07-20 12:23:55 -06003466 def testFdtmapHeaderMiddle(self):
3467 """Test an FDT map in the middle of an image when it should be at end"""
3468 with self.assertRaises(ValueError) as e:
3469 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3470 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3471 str(e.exception))
3472
3473 def testFdtmapHeaderStartBad(self):
3474 """Test an FDT map in middle of an image when it should be at start"""
3475 with self.assertRaises(ValueError) as e:
3476 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3477 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3478 str(e.exception))
3479
3480 def testFdtmapHeaderEndBad(self):
3481 """Test an FDT map at the start of an image when it should be at end"""
3482 with self.assertRaises(ValueError) as e:
3483 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3484 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3485 str(e.exception))
3486
3487 def testFdtmapHeaderNoSize(self):
3488 """Test an image header at the end of an image with undefined size"""
3489 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3490
Simon Glassf8a54bc2019-07-20 12:23:56 -06003491 def testReplaceResize(self):
3492 """Test replacing a single file in an entry with a larger file"""
3493 expected = U_BOOT_DATA + b'x'
3494 data, _, image = self._RunReplaceCmd('u-boot', expected,
3495 dts='139_replace_repack.dts')
3496 self.assertEqual(expected, data)
3497
3498 entries = image.GetEntries()
3499 dtb_data = entries['u-boot-dtb'].data
3500 dtb = fdt.Fdt.FromData(dtb_data)
3501 dtb.Scan()
3502
3503 # The u-boot section should now be larger in the dtb
3504 node = dtb.GetNode('/binman/u-boot')
3505 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3506
3507 # Same for the fdtmap
3508 fdata = entries['fdtmap'].data
3509 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3510 fdtb.Scan()
3511 fnode = fdtb.GetNode('/u-boot')
3512 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3513
3514 def testReplaceResizeNoRepack(self):
3515 """Test replacing an entry with a larger file when not allowed"""
3516 expected = U_BOOT_DATA + b'x'
3517 with self.assertRaises(ValueError) as e:
3518 self._RunReplaceCmd('u-boot', expected)
3519 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3520 str(e.exception))
3521
Simon Glass9d8ee322019-07-20 12:23:58 -06003522 def testEntryShrink(self):
3523 """Test contracting an entry after it is packed"""
3524 try:
3525 state.SetAllowEntryContraction(True)
3526 data = self._DoReadFileDtb('140_entry_shrink.dts',
3527 update_dtb=True)[0]
3528 finally:
3529 state.SetAllowEntryContraction(False)
3530 self.assertEqual(b'a', data[:1])
3531 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3532 self.assertEqual(b'a', data[-1:])
3533
3534 def testEntryShrinkFail(self):
3535 """Test not being allowed to contract an entry after it is packed"""
3536 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3537
3538 # In this case there is a spare byte at the end of the data. The size of
3539 # the contents is only 1 byte but we still have the size before it
3540 # shrunk.
3541 self.assertEqual(b'a\0', data[:2])
3542 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3543 self.assertEqual(b'a\0', data[-2:])
3544
Simon Glass70e32982019-07-20 12:24:01 -06003545 def testDescriptorOffset(self):
3546 """Test that the Intel descriptor is always placed at at the start"""
3547 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3548 image = control.images['image']
3549 entries = image.GetEntries()
3550 desc = entries['intel-descriptor']
Simon Glassed836ac2025-02-26 09:26:17 -07003551 self.assertEqual(0xff800000, desc.offset)
3552 self.assertEqual(0xff800000, desc.image_pos)
Simon Glass70e32982019-07-20 12:24:01 -06003553
Simon Glass37fdd142019-07-20 12:24:06 -06003554 def testReplaceCbfs(self):
3555 """Test replacing a single file in CBFS without changing the size"""
3556 self._CheckLz4()
3557 expected = b'x' * len(U_BOOT_DATA)
3558 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003559 updated_fname = tools.get_output_filename('image-updated.bin')
3560 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003561 entry_name = 'section/cbfs/u-boot'
3562 control.WriteEntry(updated_fname, entry_name, expected,
3563 allow_resize=True)
3564 data = control.ReadEntry(updated_fname, entry_name)
3565 self.assertEqual(expected, data)
3566
3567 def testReplaceResizeCbfs(self):
3568 """Test replacing a single file in CBFS with one of a different size"""
3569 self._CheckLz4()
3570 expected = U_BOOT_DATA + b'x'
3571 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003572 updated_fname = tools.get_output_filename('image-updated.bin')
3573 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003574 entry_name = 'section/cbfs/u-boot'
3575 control.WriteEntry(updated_fname, entry_name, expected,
3576 allow_resize=True)
3577 data = control.ReadEntry(updated_fname, entry_name)
3578 self.assertEqual(expected, data)
3579
Simon Glass30033c22019-07-20 12:24:15 -06003580 def _SetupForReplace(self):
3581 """Set up some files to use to replace entries
3582
3583 This generates an image, copies it to a new file, extracts all the files
3584 in it and updates some of them
3585
3586 Returns:
3587 List
3588 Image filename
3589 Output directory
3590 Expected values for updated entries, each a string
3591 """
3592 data = self._DoReadFileRealDtb('143_replace_all.dts')
3593
Simon Glass80025522022-01-29 14:14:04 -07003594 updated_fname = tools.get_output_filename('image-updated.bin')
3595 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003596
3597 outdir = os.path.join(self._indir, 'extract')
3598 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3599
3600 expected1 = b'x' + U_BOOT_DATA + b'y'
3601 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003602 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003603
3604 expected2 = b'a' + U_BOOT_DATA + b'b'
3605 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003606 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003607
3608 expected_text = b'not the same text'
3609 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003610 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003611
3612 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3613 dtb = fdt.FdtScan(dtb_fname)
3614 node = dtb.GetNode('/binman/text')
3615 node.AddString('my-property', 'the value')
3616 dtb.Sync(auto_resize=True)
3617 dtb.Flush()
3618
3619 return updated_fname, outdir, expected1, expected2, expected_text
3620
3621 def _CheckReplaceMultiple(self, entry_paths):
3622 """Handle replacing the contents of multiple entries
3623
3624 Args:
3625 entry_paths: List of entry paths to replace
3626
3627 Returns:
3628 List
3629 Dict of entries in the image:
3630 key: Entry name
3631 Value: Entry object
3632 Expected values for updated entries, each a string
3633 """
3634 updated_fname, outdir, expected1, expected2, expected_text = (
3635 self._SetupForReplace())
3636 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3637
3638 image = Image.FromFile(updated_fname)
3639 image.LoadData()
3640 return image.GetEntries(), expected1, expected2, expected_text
3641
3642 def testReplaceAll(self):
3643 """Test replacing the contents of all entries"""
3644 entries, expected1, expected2, expected_text = (
3645 self._CheckReplaceMultiple([]))
3646 data = entries['u-boot'].data
3647 self.assertEqual(expected1, data)
3648
3649 data = entries['u-boot2'].data
3650 self.assertEqual(expected2, data)
3651
3652 data = entries['text'].data
3653 self.assertEqual(expected_text, data)
3654
3655 # Check that the device tree is updated
3656 data = entries['u-boot-dtb'].data
3657 dtb = fdt.Fdt.FromData(data)
3658 dtb.Scan()
3659 node = dtb.GetNode('/binman/text')
3660 self.assertEqual('the value', node.props['my-property'].value)
3661
3662 def testReplaceSome(self):
3663 """Test replacing the contents of a few entries"""
3664 entries, expected1, expected2, expected_text = (
3665 self._CheckReplaceMultiple(['u-boot2', 'text']))
3666
3667 # This one should not change
3668 data = entries['u-boot'].data
3669 self.assertEqual(U_BOOT_DATA, data)
3670
3671 data = entries['u-boot2'].data
3672 self.assertEqual(expected2, data)
3673
3674 data = entries['text'].data
3675 self.assertEqual(expected_text, data)
3676
3677 def testReplaceCmd(self):
3678 """Test replacing a file fron an image on the command line"""
3679 self._DoReadFileRealDtb('143_replace_all.dts')
3680
3681 try:
3682 tmpdir, updated_fname = self._SetupImageInTmpdir()
3683
3684 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3685 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003686 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003687
3688 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003689 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003690 self.assertEqual(expected, data[:len(expected)])
3691 map_fname = os.path.join(tmpdir, 'image-updated.map')
3692 self.assertFalse(os.path.exists(map_fname))
3693 finally:
3694 shutil.rmtree(tmpdir)
3695
3696 def testReplaceCmdSome(self):
3697 """Test replacing some files fron an image on the command line"""
3698 updated_fname, outdir, expected1, expected2, expected_text = (
3699 self._SetupForReplace())
3700
3701 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3702 'u-boot2', 'text')
3703
Simon Glass80025522022-01-29 14:14:04 -07003704 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003705 image = Image.FromFile(updated_fname)
3706 image.LoadData()
3707 entries = image.GetEntries()
3708
3709 # This one should not change
3710 data = entries['u-boot'].data
3711 self.assertEqual(U_BOOT_DATA, data)
3712
3713 data = entries['u-boot2'].data
3714 self.assertEqual(expected2, data)
3715
3716 data = entries['text'].data
3717 self.assertEqual(expected_text, data)
3718
3719 def testReplaceMissing(self):
3720 """Test replacing entries where the file is missing"""
3721 updated_fname, outdir, expected1, expected2, expected_text = (
3722 self._SetupForReplace())
3723
3724 # Remove one of the files, to generate a warning
3725 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3726 os.remove(u_boot_fname1)
3727
3728 with test_util.capture_sys_output() as (stdout, stderr):
3729 control.ReplaceEntries(updated_fname, None, outdir, [])
3730 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003731 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003732
3733 def testReplaceCmdMap(self):
3734 """Test replacing a file fron an image on the command line"""
3735 self._DoReadFileRealDtb('143_replace_all.dts')
3736
3737 try:
3738 tmpdir, updated_fname = self._SetupImageInTmpdir()
3739
3740 fname = os.path.join(self._indir, 'update-u-boot.bin')
3741 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003742 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003743
3744 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3745 '-f', fname, '-m')
3746 map_fname = os.path.join(tmpdir, 'image-updated.map')
3747 self.assertTrue(os.path.exists(map_fname))
3748 finally:
3749 shutil.rmtree(tmpdir)
3750
3751 def testReplaceNoEntryPaths(self):
3752 """Test replacing an entry without an entry path"""
3753 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003754 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003755 with self.assertRaises(ValueError) as e:
3756 control.ReplaceEntries(image_fname, 'fname', None, [])
3757 self.assertIn('Must specify an entry path to read with -f',
3758 str(e.exception))
3759
3760 def testReplaceTooManyEntryPaths(self):
3761 """Test extracting some entries"""
3762 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003763 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003764 with self.assertRaises(ValueError) as e:
3765 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3766 self.assertIn('Must specify exactly one entry path to write with -f',
3767 str(e.exception))
3768
Simon Glass0b074d62019-08-24 07:22:48 -06003769 def testPackReset16(self):
3770 """Test that an image with an x86 reset16 region can be created"""
3771 data = self._DoReadFile('144_x86_reset16.dts')
3772 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3773
3774 def testPackReset16Spl(self):
3775 """Test that an image with an x86 reset16-spl region can be created"""
3776 data = self._DoReadFile('145_x86_reset16_spl.dts')
3777 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3778
3779 def testPackReset16Tpl(self):
3780 """Test that an image with an x86 reset16-tpl region can be created"""
3781 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3782 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3783
Simon Glass232f90c2019-08-24 07:22:50 -06003784 def testPackIntelFit(self):
3785 """Test that an image with an Intel FIT and pointer can be created"""
3786 data = self._DoReadFile('147_intel_fit.dts')
3787 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3788 fit = data[16:32];
3789 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3790 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3791
3792 image = control.images['image']
3793 entries = image.GetEntries()
Simon Glassed836ac2025-02-26 09:26:17 -07003794 expected_ptr = entries['intel-fit'].image_pos #- (1 << 32)
3795 self.assertEqual(expected_ptr, ptr + (1 << 32))
Simon Glass232f90c2019-08-24 07:22:50 -06003796
3797 def testPackIntelFitMissing(self):
3798 """Test detection of a FIT pointer with not FIT region"""
3799 with self.assertRaises(ValueError) as e:
3800 self._DoReadFile('148_intel_fit_missing.dts')
3801 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3802 str(e.exception))
3803
Simon Glass72555fa2019-11-06 17:22:44 -07003804 def _CheckSymbolsTplSection(self, dts, expected_vals):
3805 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003806 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003807 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003808 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003809 self.assertEqual(expected1, data[:upto1])
3810
3811 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003812 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003813 self.assertEqual(expected2, data[upto1:upto2])
3814
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003815 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003816 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003817 self.assertEqual(expected3, data[upto2:upto3])
3818
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003819 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003820 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3821
3822 def testSymbolsTplSection(self):
3823 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3824 self._SetupSplElf('u_boot_binman_syms')
3825 self._SetupTplElf('u_boot_binman_syms')
3826 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003827 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003828
3829 def testSymbolsTplSectionX86(self):
3830 """Test binman can assign symbols in a section with end-at-4gb"""
3831 self._SetupSplElf('u_boot_binman_syms_x86')
3832 self._SetupTplElf('u_boot_binman_syms_x86')
3833 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003834 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003835 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003836
Simon Glass98c59572019-08-24 07:23:03 -06003837 def testPackX86RomIfwiSectiom(self):
3838 """Test that a section can be placed in an IFWI region"""
3839 self._SetupIfwi('fitimage.bin')
3840 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3841 self._CheckIfwi(data)
3842
Simon Glassba7985d2019-08-24 07:23:07 -06003843 def testPackFspM(self):
3844 """Test that an image with a FSP memory-init binary can be created"""
3845 data = self._DoReadFile('152_intel_fsp_m.dts')
3846 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3847
Simon Glass4d9086d2019-10-20 21:31:35 -06003848 def testPackFspS(self):
3849 """Test that an image with a FSP silicon-init binary can be created"""
3850 data = self._DoReadFile('153_intel_fsp_s.dts')
3851 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003852
Simon Glass9ea87b22019-10-20 21:31:36 -06003853 def testPackFspT(self):
3854 """Test that an image with a FSP temp-ram-init binary can be created"""
3855 data = self._DoReadFile('154_intel_fsp_t.dts')
3856 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3857
Simon Glass48f3aad2020-07-09 18:39:31 -06003858 def testMkimage(self):
3859 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003860 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003861 data = self._DoReadFile('156_mkimage.dts')
3862
3863 # Just check that the data appears in the file somewhere
3864 self.assertIn(U_BOOT_SPL_DATA, data)
3865
Simon Glass66152ce2022-01-09 20:14:09 -07003866 def testMkimageMissing(self):
3867 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003868 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003869 with test_util.capture_sys_output() as (_, stderr):
3870 self._DoTestFile('156_mkimage.dts',
3871 force_missing_bintools='mkimage')
3872 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003873 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003874
Simon Glass5e560182020-07-09 18:39:36 -06003875 def testExtblob(self):
3876 """Test an image with an external blob"""
3877 data = self._DoReadFile('157_blob_ext.dts')
3878 self.assertEqual(REFCODE_DATA, data)
3879
3880 def testExtblobMissing(self):
3881 """Test an image with a missing external blob"""
3882 with self.assertRaises(ValueError) as e:
3883 self._DoReadFile('158_blob_ext_missing.dts')
3884 self.assertIn("Filename 'missing-file' not found in input path",
3885 str(e.exception))
3886
Simon Glass5d94cc62020-07-09 18:39:38 -06003887 def testExtblobMissingOk(self):
3888 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003889 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003890 ret = self._DoTestFile('158_blob_ext_missing.dts',
3891 allow_missing=True)
3892 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003893 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003894 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003895 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003896 self.assertIn('Some images are invalid', err)
3897
3898 def testExtblobMissingOkFlag(self):
3899 """Test an image with an missing external blob allowed with -W"""
3900 with test_util.capture_sys_output() as (stdout, stderr):
3901 ret = self._DoTestFile('158_blob_ext_missing.dts',
3902 allow_missing=True, ignore_missing=True)
3903 self.assertEqual(0, ret)
3904 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003905 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003906 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003907 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003908
3909 def testExtblobMissingOkSect(self):
3910 """Test an image with an missing external blob that is allowed"""
3911 with test_util.capture_sys_output() as (stdout, stderr):
3912 self._DoTestFile('159_blob_ext_missing_sect.dts',
3913 allow_missing=True)
3914 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003915 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003916
Simon Glasse88cef92020-07-09 18:39:41 -06003917 def testPackX86RomMeMissingDesc(self):
3918 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003919 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003920 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003921 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003922 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003923
3924 def testPackX86RomMissingIfwi(self):
3925 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3926 self._SetupIfwi('fitimage.bin')
3927 pathname = os.path.join(self._indir, 'fitimage.bin')
3928 os.remove(pathname)
3929 with test_util.capture_sys_output() as (stdout, stderr):
3930 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3931 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003932 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003933
Simon Glass2a0fa982022-02-11 13:23:21 -07003934 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003935 """Test that zero-size overlapping regions are ignored"""
3936 self._DoTestFile('160_pack_overlap_zero.dts')
3937
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003938 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003939 # The data should be inside the FIT
3940 dtb = fdt.Fdt.FromData(fit_data)
3941 dtb.Scan()
3942 fnode = dtb.GetNode('/images/kernel')
3943 self.assertIn('data', fnode.props)
3944
3945 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003946 tools.write_file(fname, fit_data)
3947 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003948
3949 # Check a few features to make sure the plumbing works. We don't need
3950 # to test the operation of mkimage or dumpimage here. First convert the
3951 # output into a dict where the keys are the fields printed by dumpimage
3952 # and the values are a list of values for each field
3953 lines = out.splitlines()
3954
3955 # Converts "Compression: gzip compressed" into two groups:
3956 # 'Compression' and 'gzip compressed'
3957 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3958 vals = collections.defaultdict(list)
3959 for line in lines:
3960 mat = re_line.match(line)
3961 vals[mat.group(1)].append(mat.group(2))
3962
Brandon Maiera657bc62024-06-04 16:16:05 +00003963 self.assertEqual('FIT description: test-desc', lines[0])
Simon Glass45d556d2020-07-09 18:39:45 -06003964 self.assertIn('Created:', lines[1])
3965 self.assertIn('Image 0 (kernel)', vals)
3966 self.assertIn('Hash value', vals)
3967 data_sizes = vals.get('Data Size')
3968 self.assertIsNotNone(data_sizes)
3969 self.assertEqual(2, len(data_sizes))
3970 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003971 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3972 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3973
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003974 # Check if entry listing correctly omits /images/
3975 image = control.images['image']
3976 fit_entry = image.GetEntries()['fit']
3977 subentries = list(fit_entry.GetEntries().keys())
3978 expected = ['kernel', 'fdt-1']
3979 self.assertEqual(expected, subentries)
3980
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003981 def testSimpleFit(self):
3982 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003983 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003984 data = self._DoReadFile('161_fit.dts')
3985 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3986 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3987 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3988
3989 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3990
3991 def testSimpleFitExpandsSubentries(self):
3992 """Test that FIT images expand their subentries"""
3993 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3994 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3995 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3996 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3997
3998 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003999
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004000 def testSimpleFitImagePos(self):
4001 """Test that we have correct image-pos for FIT subentries"""
4002 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
4003 update_dtb=True)
4004 dtb = fdt.Fdt(out_dtb_fname)
4005 dtb.Scan()
4006 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4007
Simon Glassb7bad182022-03-05 20:19:01 -07004008 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004009 self.assertEqual({
4010 'image-pos': 0,
4011 'offset': 0,
4012 'size': 1890,
4013
4014 'u-boot:image-pos': 0,
4015 'u-boot:offset': 0,
4016 'u-boot:size': 4,
4017
4018 'fit:image-pos': 4,
4019 'fit:offset': 4,
4020 'fit:size': 1840,
4021
Simon Glassb7bad182022-03-05 20:19:01 -07004022 'fit/images/kernel:image-pos': 304,
4023 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004024 'fit/images/kernel:size': 4,
4025
Simon Glassb7bad182022-03-05 20:19:01 -07004026 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004027 'fit/images/kernel/u-boot:offset': 0,
4028 'fit/images/kernel/u-boot:size': 4,
4029
Simon Glassb7bad182022-03-05 20:19:01 -07004030 'fit/images/fdt-1:image-pos': 552,
4031 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004032 'fit/images/fdt-1:size': 6,
4033
Simon Glassb7bad182022-03-05 20:19:01 -07004034 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004035 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
4036 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
4037
4038 'u-boot-nodtb:image-pos': 1844,
4039 'u-boot-nodtb:offset': 1844,
4040 'u-boot-nodtb:size': 46,
4041 }, props)
4042
4043 # Actually check the data is where we think it is
4044 for node, expected in [
4045 ("u-boot", U_BOOT_DATA),
4046 ("fit/images/kernel", U_BOOT_DATA),
4047 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4048 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
4049 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
4050 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4051 ]:
4052 image_pos = props[f"{node}:image-pos"]
4053 size = props[f"{node}:size"]
4054 self.assertEqual(len(expected), size)
4055 self.assertEqual(expected, data[image_pos:image_pos+size])
4056
Simon Glass45d556d2020-07-09 18:39:45 -06004057 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06004058 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06004059 data = self._DoReadFile('162_fit_external.dts')
4060 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
4061
Simon Glass7932c882022-01-09 20:13:39 -07004062 # Size of the external-data region as set up by mkimage
4063 external_data_size = len(U_BOOT_DATA) + 2
4064 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07004065 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07004066 len(U_BOOT_NODTB_DATA))
4067
Simon Glass45d556d2020-07-09 18:39:45 -06004068 # The data should be outside the FIT
4069 dtb = fdt.Fdt.FromData(fit_data)
4070 dtb.Scan()
4071 fnode = dtb.GetNode('/images/kernel')
4072 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07004073 self.assertEqual(len(U_BOOT_DATA),
4074 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4075 fit_pos = 0x400;
4076 self.assertEqual(
4077 fit_pos,
4078 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4079
Brandon Maiera657bc62024-06-04 16:16:05 +00004080 self.assertEqual(expected_size, len(data))
Simon Glass7932c882022-01-09 20:13:39 -07004081 actual_pos = len(U_BOOT_DATA) + fit_pos
4082 self.assertEqual(U_BOOT_DATA + b'aa',
4083 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004084
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004085 def testFitExternalImagePos(self):
4086 """Test that we have correct image-pos for external FIT subentries"""
4087 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4088 update_dtb=True)
4089 dtb = fdt.Fdt(out_dtb_fname)
4090 dtb.Scan()
4091 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4092
4093 self.assertEqual({
4094 'image-pos': 0,
4095 'offset': 0,
4096 'size': 1082,
4097
4098 'u-boot:image-pos': 0,
4099 'u-boot:offset': 0,
4100 'u-boot:size': 4,
4101
4102 'fit:size': 1032,
4103 'fit:offset': 4,
4104 'fit:image-pos': 4,
4105
4106 'fit/images/kernel:size': 4,
4107 'fit/images/kernel:offset': 1024,
4108 'fit/images/kernel:image-pos': 1028,
4109
4110 'fit/images/kernel/u-boot:size': 4,
4111 'fit/images/kernel/u-boot:offset': 0,
4112 'fit/images/kernel/u-boot:image-pos': 1028,
4113
4114 'fit/images/fdt-1:size': 2,
4115 'fit/images/fdt-1:offset': 1028,
4116 'fit/images/fdt-1:image-pos': 1032,
4117
4118 'fit/images/fdt-1/_testing:size': 2,
4119 'fit/images/fdt-1/_testing:offset': 0,
4120 'fit/images/fdt-1/_testing:image-pos': 1032,
4121
4122 'u-boot-nodtb:image-pos': 1036,
4123 'u-boot-nodtb:offset': 1036,
4124 'u-boot-nodtb:size': 46,
4125 }, props)
4126
4127 # Actually check the data is where we think it is
4128 for node, expected in [
4129 ("u-boot", U_BOOT_DATA),
4130 ("fit/images/kernel", U_BOOT_DATA),
4131 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4132 ("fit/images/fdt-1", b'aa'),
4133 ("fit/images/fdt-1/_testing", b'aa'),
4134 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4135 ]:
4136 image_pos = props[f"{node}:image-pos"]
4137 size = props[f"{node}:size"]
4138 self.assertEqual(len(expected), size)
4139 self.assertEqual(expected, data[image_pos:image_pos+size])
4140
Simon Glass66152ce2022-01-09 20:14:09 -07004141 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004142 """Test that binman complains if mkimage is missing"""
4143 with self.assertRaises(ValueError) as e:
4144 self._DoTestFile('162_fit_external.dts',
4145 force_missing_bintools='mkimage')
4146 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4147 str(e.exception))
4148
4149 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004150 """Test that binman still produces a FIT image if mkimage is missing"""
4151 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004152 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004153 force_missing_bintools='mkimage')
4154 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004155 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004156
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004157 def testSectionIgnoreHashSignature(self):
4158 """Test that sections ignore hash, signature nodes for its data"""
4159 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4160 expected = (U_BOOT_DATA + U_BOOT_DATA)
4161 self.assertEqual(expected, data)
4162
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004163 def testPadInSections(self):
4164 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004165 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4166 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004167 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4168 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004169 U_BOOT_DATA)
4170 self.assertEqual(expected, data)
4171
Simon Glassd12599d2020-10-26 17:40:09 -06004172 dtb = fdt.Fdt(out_dtb_fname)
4173 dtb.Scan()
4174 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4175 expected = {
4176 'image-pos': 0,
4177 'offset': 0,
4178 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4179
4180 'section:image-pos': 0,
4181 'section:offset': 0,
4182 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4183
4184 'section/before:image-pos': 0,
4185 'section/before:offset': 0,
4186 'section/before:size': len(U_BOOT_DATA),
4187
4188 'section/u-boot:image-pos': 4,
4189 'section/u-boot:offset': 4,
4190 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4191
4192 'section/after:image-pos': 26,
4193 'section/after:offset': 26,
4194 'section/after:size': len(U_BOOT_DATA),
4195 }
4196 self.assertEqual(expected, props)
4197
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004198 def testFitImageSubentryAlignment(self):
4199 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004200 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004201 entry_args = {
4202 'test-id': TEXT_DATA,
4203 }
4204 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4205 entry_args=entry_args)
4206 dtb = fdt.Fdt.FromData(data)
4207 dtb.Scan()
4208
4209 node = dtb.GetNode('/images/kernel')
4210 data = dtb.GetProps(node)["data"].bytes
4211 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004212 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4213 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004214 self.assertEqual(expected, data)
4215
4216 node = dtb.GetNode('/images/fdt-1')
4217 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004218 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4219 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004220 U_BOOT_DTB_DATA)
4221 self.assertEqual(expected, data)
4222
4223 def testFitExtblobMissingOk(self):
4224 """Test a FIT with a missing external blob that is allowed"""
4225 with test_util.capture_sys_output() as (stdout, stderr):
4226 self._DoTestFile('168_fit_missing_blob.dts',
4227 allow_missing=True)
4228 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004229 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004230
Simon Glass21db0ff2020-09-01 05:13:54 -06004231 def testBlobNamedByArgMissing(self):
4232 """Test handling of a missing entry arg"""
4233 with self.assertRaises(ValueError) as e:
4234 self._DoReadFile('068_blob_named_by_arg.dts')
4235 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4236 str(e.exception))
4237
Simon Glass559c4de2020-09-01 05:13:58 -06004238 def testPackBl31(self):
4239 """Test that an image with an ATF BL31 binary can be created"""
4240 data = self._DoReadFile('169_atf_bl31.dts')
4241 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4242
Samuel Holland9d8cc632020-10-21 21:12:15 -05004243 def testPackScp(self):
4244 """Test that an image with an SCP binary can be created"""
4245 data = self._DoReadFile('172_scp.dts')
4246 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4247
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004248 def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True,
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004249 default_dt=None, use_seq_num=True):
Simon Glasscd2783e2024-07-20 11:49:46 +01004250 """Check an image with an FIT with multiple FDT images"""
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004251 def _CheckFdt(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004252 """Check the FDT nodes
4253
4254 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004255 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004256 expected_data: Expected contents of 'data' property
4257 """
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004258 name = 'fdt-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004259 fnode = dtb.GetNode('/images/%s' % name)
4260 self.assertIsNotNone(fnode)
4261 self.assertEqual({'description','type', 'compression', 'data'},
4262 set(fnode.props.keys()))
4263 self.assertEqual(expected_data, fnode.props['data'].bytes)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004264 description = (
4265 'fdt-test-fdt%s.dtb' % val if len(val) == 1 else
4266 'fdt-%s.dtb' % val
4267 )
4268 self.assertEqual(description, fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004269 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004270
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004271 def _CheckConfig(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004272 """Check the configuration nodes
4273
4274 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004275 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004276 expected_data: Expected contents of 'data' property
4277 """
4278 cnode = dtb.GetNode('/configurations')
4279 self.assertIn('default', cnode.props)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004280 default = (
4281 'config-2' if len(val) == 1 else
4282 'config-test-fdt2'
4283 )
4284 self.assertEqual(default, cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004285
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004286 name = 'config-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004287 fnode = dtb.GetNode('/configurations/%s' % name)
4288 self.assertIsNotNone(fnode)
4289 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4290 set(fnode.props.keys()))
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004291 description = (
4292 'conf-test-fdt%s.dtb' % val if len(val) == 1 else
4293 'conf-%s.dtb' % val
4294 )
4295 self.assertEqual(description, fnode.props['description'].value)
4296 self.assertEqual('fdt-%s' % val, fnode.props['fdt'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004297
4298 entry_args = {
Simon Glass1032acc2020-09-06 10:39:08 -06004299 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004300 }
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004301 extra_indirs = None
Simon Glasscd2783e2024-07-20 11:49:46 +01004302 if use_fdt_list:
4303 entry_args['of-list'] = 'test-fdt1 test-fdt2'
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004304 if default_dt:
4305 entry_args['default-dt'] = default_dt
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004306 if use_fdt_list:
4307 extra_indirs = [os.path.join(self._indir, TEST_FDT_SUBDIR)]
Simon Glassa435cd12020-09-01 05:13:59 -06004308 data = self._DoReadFileDtb(
Simon Glasscd2783e2024-07-20 11:49:46 +01004309 dts,
Simon Glassa435cd12020-09-01 05:13:59 -06004310 entry_args=entry_args,
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004311 extra_indirs=extra_indirs)[0]
Simon Glassa435cd12020-09-01 05:13:59 -06004312 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4313 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4314
4315 dtb = fdt.Fdt.FromData(fit_data)
4316 dtb.Scan()
4317 fnode = dtb.GetNode('/images/kernel')
4318 self.assertIn('data', fnode.props)
4319
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004320 if use_seq_num == True:
4321 # Check all the properties in fdt-1 and fdt-2
4322 _CheckFdt('1', TEST_FDT1_DATA)
4323 _CheckFdt('2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004324
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004325 # Check configurations
4326 _CheckConfig('1', TEST_FDT1_DATA)
4327 _CheckConfig('2', TEST_FDT2_DATA)
4328 else:
4329 # Check all the properties in fdt-1 and fdt-2
4330 _CheckFdt('test-fdt1', TEST_FDT1_DATA)
4331 _CheckFdt('test-fdt2', TEST_FDT2_DATA)
4332
4333 # Check configurations
4334 _CheckConfig('test-fdt1', TEST_FDT1_DATA)
4335 _CheckConfig('test-fdt2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004336
Simon Glasscd2783e2024-07-20 11:49:46 +01004337 def testFitFdt(self):
4338 """Test an image with an FIT with multiple FDT images"""
4339 self.CheckFitFdt()
4340
Simon Glassa435cd12020-09-01 05:13:59 -06004341 def testFitFdtMissingList(self):
4342 """Test handling of a missing 'of-list' entry arg"""
4343 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004344 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004345 self.assertIn("Generator node requires 'of-list' entry argument",
4346 str(e.exception))
4347
4348 def testFitFdtEmptyList(self):
4349 """Test handling of an empty 'of-list' entry arg"""
4350 entry_args = {
4351 'of-list': '',
4352 }
4353 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4354
4355 def testFitFdtMissingProp(self):
4356 """Test handling of a missing 'fit,fdt-list' property"""
4357 with self.assertRaises(ValueError) as e:
4358 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4359 self.assertIn("Generator node requires 'fit,fdt-list' property",
4360 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004361
Simon Glass1032acc2020-09-06 10:39:08 -06004362 def testFitFdtMissing(self):
4363 """Test handling of a missing 'default-dt' entry arg"""
4364 entry_args = {
4365 'of-list': 'test-fdt1 test-fdt2',
4366 }
4367 with self.assertRaises(ValueError) as e:
4368 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004369 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004370 entry_args=entry_args,
4371 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4372 self.assertIn("Generated 'default' node requires default-dt entry argument",
4373 str(e.exception))
4374
4375 def testFitFdtNotInList(self):
4376 """Test handling of a default-dt that is not in the of-list"""
4377 entry_args = {
4378 'of-list': 'test-fdt1 test-fdt2',
4379 'default-dt': 'test-fdt3',
4380 }
4381 with self.assertRaises(ValueError) as e:
4382 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004383 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004384 entry_args=entry_args,
4385 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4386 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4387 str(e.exception))
4388
Simon Glassa820af72020-09-06 10:39:09 -06004389 def testFitExtblobMissingHelp(self):
4390 """Test display of help messages when an external blob is missing"""
4391 control.missing_blob_help = control._ReadMissingBlobHelp()
4392 control.missing_blob_help['wibble'] = 'Wibble test'
4393 control.missing_blob_help['another'] = 'Another test'
4394 with test_util.capture_sys_output() as (stdout, stderr):
4395 self._DoTestFile('168_fit_missing_blob.dts',
4396 allow_missing=True)
4397 err = stderr.getvalue()
4398
4399 # We can get the tag from the name, the type or the missing-msg
4400 # property. Check all three.
4401 self.assertIn('You may need to build ARM Trusted', err)
4402 self.assertIn('Wibble test', err)
4403 self.assertIn('Another test', err)
4404
Simon Glass6f1f4d42020-09-06 10:35:32 -06004405 def testMissingBlob(self):
4406 """Test handling of a blob containing a missing file"""
4407 with self.assertRaises(ValueError) as e:
4408 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4409 self.assertIn("Filename 'missing' not found in input path",
4410 str(e.exception))
4411
Simon Glassa0729502020-09-06 10:35:33 -06004412 def testEnvironment(self):
4413 """Test adding a U-Boot environment"""
4414 data = self._DoReadFile('174_env.dts')
4415 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4416 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4417 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4418 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4419 env)
4420
4421 def testEnvironmentNoSize(self):
4422 """Test that a missing 'size' property is detected"""
4423 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004424 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004425 self.assertIn("'u-boot-env' entry must have a size property",
4426 str(e.exception))
4427
4428 def testEnvironmentTooSmall(self):
4429 """Test handling of an environment that does not fit"""
4430 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004431 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004432
4433 # checksum, start byte, environment with \0 terminator, final \0
4434 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4435 short = need - 0x8
4436 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4437 str(e.exception))
4438
Simon Glassd1fdf752020-10-26 17:40:01 -06004439 def testSkipAtStart(self):
4440 """Test handling of skip-at-start section"""
4441 data = self._DoReadFile('177_skip_at_start.dts')
4442 self.assertEqual(U_BOOT_DATA, data)
4443
4444 image = control.images['image']
4445 entries = image.GetEntries()
4446 section = entries['section']
4447 self.assertEqual(0, section.offset)
4448 self.assertEqual(len(U_BOOT_DATA), section.size)
4449 self.assertEqual(U_BOOT_DATA, section.GetData())
4450
4451 entry = section.GetEntries()['u-boot']
4452 self.assertEqual(16, entry.offset)
4453 self.assertEqual(len(U_BOOT_DATA), entry.size)
4454 self.assertEqual(U_BOOT_DATA, entry.data)
4455
4456 def testSkipAtStartPad(self):
4457 """Test handling of skip-at-start section with padded entry"""
4458 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004459 before = tools.get_bytes(0, 8)
4460 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004461 all = before + U_BOOT_DATA + after
4462 self.assertEqual(all, data)
4463
4464 image = control.images['image']
4465 entries = image.GetEntries()
4466 section = entries['section']
4467 self.assertEqual(0, section.offset)
4468 self.assertEqual(len(all), section.size)
4469 self.assertEqual(all, section.GetData())
4470
4471 entry = section.GetEntries()['u-boot']
4472 self.assertEqual(16, entry.offset)
4473 self.assertEqual(len(all), entry.size)
4474 self.assertEqual(U_BOOT_DATA, entry.data)
4475
4476 def testSkipAtStartSectionPad(self):
4477 """Test handling of skip-at-start section with padding"""
4478 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004479 before = tools.get_bytes(0, 8)
4480 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004481 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004482 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004483
4484 image = control.images['image']
4485 entries = image.GetEntries()
4486 section = entries['section']
4487 self.assertEqual(0, section.offset)
4488 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004489 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004490 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004491
4492 entry = section.GetEntries()['u-boot']
4493 self.assertEqual(16, entry.offset)
4494 self.assertEqual(len(U_BOOT_DATA), entry.size)
4495 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004496
Simon Glassbb395742020-10-26 17:40:14 -06004497 def testSectionPad(self):
4498 """Testing padding with sections"""
4499 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004500 expected = (tools.get_bytes(ord('&'), 3) +
4501 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004502 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004503 tools.get_bytes(ord('!'), 1) +
4504 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004505 self.assertEqual(expected, data)
4506
4507 def testSectionAlign(self):
4508 """Testing alignment with sections"""
4509 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4510 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004511 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004512 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004513 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004514 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004515 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4516 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004517 self.assertEqual(expected, data)
4518
Simon Glassd92c8362020-10-26 17:40:25 -06004519 def testCompressImage(self):
4520 """Test compression of the entire image"""
4521 self._CheckLz4()
4522 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4523 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4524 dtb = fdt.Fdt(out_dtb_fname)
4525 dtb.Scan()
4526 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4527 'uncomp-size'])
4528 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004529 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004530
4531 # Do a sanity check on various fields
4532 image = control.images['image']
4533 entries = image.GetEntries()
4534 self.assertEqual(2, len(entries))
4535
4536 entry = entries['blob']
4537 self.assertEqual(COMPRESS_DATA, entry.data)
4538 self.assertEqual(len(COMPRESS_DATA), entry.size)
4539
4540 entry = entries['u-boot']
4541 self.assertEqual(U_BOOT_DATA, entry.data)
4542 self.assertEqual(len(U_BOOT_DATA), entry.size)
4543
4544 self.assertEqual(len(data), image.size)
4545 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4546 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4547 orig = self._decompress(image.data)
4548 self.assertEqual(orig, image.uncomp_data)
4549
4550 expected = {
4551 'blob:offset': 0,
4552 'blob:size': len(COMPRESS_DATA),
4553 'u-boot:offset': len(COMPRESS_DATA),
4554 'u-boot:size': len(U_BOOT_DATA),
4555 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4556 'offset': 0,
4557 'image-pos': 0,
4558 'size': len(data),
4559 }
4560 self.assertEqual(expected, props)
4561
4562 def testCompressImageLess(self):
4563 """Test compression where compression reduces the image size"""
4564 self._CheckLz4()
4565 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4566 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4567 dtb = fdt.Fdt(out_dtb_fname)
4568 dtb.Scan()
4569 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4570 'uncomp-size'])
4571 orig = self._decompress(data)
4572
Brandon Maiera657bc62024-06-04 16:16:05 +00004573 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004574
4575 # Do a sanity check on various fields
4576 image = control.images['image']
4577 entries = image.GetEntries()
4578 self.assertEqual(2, len(entries))
4579
4580 entry = entries['blob']
4581 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4582 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4583
4584 entry = entries['u-boot']
4585 self.assertEqual(U_BOOT_DATA, entry.data)
4586 self.assertEqual(len(U_BOOT_DATA), entry.size)
4587
4588 self.assertEqual(len(data), image.size)
4589 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4590 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4591 image.uncomp_size)
4592 orig = self._decompress(image.data)
4593 self.assertEqual(orig, image.uncomp_data)
4594
4595 expected = {
4596 'blob:offset': 0,
4597 'blob:size': len(COMPRESS_DATA_BIG),
4598 'u-boot:offset': len(COMPRESS_DATA_BIG),
4599 'u-boot:size': len(U_BOOT_DATA),
4600 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4601 'offset': 0,
4602 'image-pos': 0,
4603 'size': len(data),
4604 }
4605 self.assertEqual(expected, props)
4606
4607 def testCompressSectionSize(self):
4608 """Test compression of a section with a fixed size"""
4609 self._CheckLz4()
4610 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4611 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4612 dtb = fdt.Fdt(out_dtb_fname)
4613 dtb.Scan()
4614 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4615 'uncomp-size'])
4616 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004617 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004618 expected = {
4619 'section/blob:offset': 0,
4620 'section/blob:size': len(COMPRESS_DATA),
4621 'section/u-boot:offset': len(COMPRESS_DATA),
4622 'section/u-boot:size': len(U_BOOT_DATA),
4623 'section:offset': 0,
4624 'section:image-pos': 0,
4625 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4626 'section:size': 0x30,
4627 'offset': 0,
4628 'image-pos': 0,
4629 'size': 0x30,
4630 }
4631 self.assertEqual(expected, props)
4632
4633 def testCompressSection(self):
4634 """Test compression of a section with no fixed size"""
4635 self._CheckLz4()
4636 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4637 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4638 dtb = fdt.Fdt(out_dtb_fname)
4639 dtb.Scan()
4640 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4641 'uncomp-size'])
4642 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004643 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004644 expected = {
4645 'section/blob:offset': 0,
4646 'section/blob:size': len(COMPRESS_DATA),
4647 'section/u-boot:offset': len(COMPRESS_DATA),
4648 'section/u-boot:size': len(U_BOOT_DATA),
4649 'section:offset': 0,
4650 'section:image-pos': 0,
4651 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4652 'section:size': len(data),
4653 'offset': 0,
4654 'image-pos': 0,
4655 'size': len(data),
4656 }
4657 self.assertEqual(expected, props)
4658
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004659 def testLz4Missing(self):
4660 """Test that binman still produces an image if lz4 is missing"""
4661 with test_util.capture_sys_output() as (_, stderr):
4662 self._DoTestFile('185_compress_section.dts',
4663 force_missing_bintools='lz4')
4664 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004665 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004666
Simon Glassd92c8362020-10-26 17:40:25 -06004667 def testCompressExtra(self):
4668 """Test compression of a section with no fixed size"""
4669 self._CheckLz4()
4670 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4671 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4672 dtb = fdt.Fdt(out_dtb_fname)
4673 dtb.Scan()
4674 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4675 'uncomp-size'])
4676
4677 base = data[len(U_BOOT_DATA):]
Brandon Maiera657bc62024-06-04 16:16:05 +00004678 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glassd92c8362020-10-26 17:40:25 -06004679 rest = base[len(U_BOOT_DATA):]
4680
4681 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004682 bintool = self.comp_bintools['lz4']
4683 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004684 data1 = rest[:len(expect1)]
4685 section1 = self._decompress(data1)
Brandon Maiera657bc62024-06-04 16:16:05 +00004686 self.assertEqual(expect1, data1)
4687 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glassd92c8362020-10-26 17:40:25 -06004688 rest1 = rest[len(expect1):]
4689
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004690 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004691 data2 = rest1[:len(expect2)]
4692 section2 = self._decompress(data2)
Brandon Maiera657bc62024-06-04 16:16:05 +00004693 self.assertEqual(expect2, data2)
4694 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glassd92c8362020-10-26 17:40:25 -06004695 rest2 = rest1[len(expect2):]
4696
4697 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4698 len(expect2) + len(U_BOOT_DATA))
Brandon Maiera657bc62024-06-04 16:16:05 +00004699 #self.assertEqual(expect_size, len(data))
Simon Glassd92c8362020-10-26 17:40:25 -06004700
Brandon Maiera657bc62024-06-04 16:16:05 +00004701 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glassd92c8362020-10-26 17:40:25 -06004702
4703 self.maxDiff = None
4704 expected = {
4705 'u-boot:offset': 0,
4706 'u-boot:image-pos': 0,
4707 'u-boot:size': len(U_BOOT_DATA),
4708
4709 'base:offset': len(U_BOOT_DATA),
4710 'base:image-pos': len(U_BOOT_DATA),
4711 'base:size': len(data) - len(U_BOOT_DATA),
4712 'base/u-boot:offset': 0,
4713 'base/u-boot:image-pos': len(U_BOOT_DATA),
4714 'base/u-boot:size': len(U_BOOT_DATA),
4715 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4716 len(expect2),
4717 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4718 len(expect2),
4719 'base/u-boot2:size': len(U_BOOT_DATA),
4720
4721 'base/section:offset': len(U_BOOT_DATA),
4722 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4723 'base/section:size': len(expect1),
4724 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4725 'base/section/blob:offset': 0,
4726 'base/section/blob:size': len(COMPRESS_DATA),
4727 'base/section/u-boot:offset': len(COMPRESS_DATA),
4728 'base/section/u-boot:size': len(U_BOOT_DATA),
4729
4730 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4731 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4732 'base/section2:size': len(expect2),
4733 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4734 'base/section2/blob:offset': 0,
4735 'base/section2/blob:size': len(COMPRESS_DATA),
4736 'base/section2/blob2:offset': len(COMPRESS_DATA),
4737 'base/section2/blob2:size': len(COMPRESS_DATA),
4738
4739 'offset': 0,
4740 'image-pos': 0,
4741 'size': len(data),
4742 }
4743 self.assertEqual(expected, props)
4744
Simon Glassecbe4732021-01-06 21:35:15 -07004745 def testSymbolsSubsection(self):
4746 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004747 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004748
Simon Glass3fb25402021-01-06 21:35:16 -07004749 def testReadImageEntryArg(self):
4750 """Test reading an image that would need an entry arg to generate"""
4751 entry_args = {
4752 'cros-ec-rw-path': 'ecrw.bin',
4753 }
4754 data = self.data = self._DoReadFileDtb(
4755 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4756 entry_args=entry_args)
4757
Simon Glass80025522022-01-29 14:14:04 -07004758 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004759 orig_image = control.images['image']
4760
4761 # This should not generate an error about the missing 'cros-ec-rw-path'
4762 # since we are reading the image from a file. Compare with
4763 # testEntryArgsRequired()
4764 image = Image.FromFile(image_fname)
4765 self.assertEqual(orig_image.GetEntries().keys(),
4766 image.GetEntries().keys())
4767
Simon Glassa2af7302021-01-06 21:35:18 -07004768 def testFilesAlign(self):
4769 """Test alignment with files"""
4770 data = self._DoReadFile('190_files_align.dts')
4771
4772 # The first string is 15 bytes so will align to 16
4773 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4774 self.assertEqual(expect, data)
4775
Simon Glassdb84b562021-01-06 21:35:19 -07004776 def testReadImageSkip(self):
4777 """Test reading an image and accessing its FDT map"""
4778 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004779 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004780 orig_image = control.images['image']
4781 image = Image.FromFile(image_fname)
4782 self.assertEqual(orig_image.GetEntries().keys(),
4783 image.GetEntries().keys())
4784
4785 orig_entry = orig_image.GetEntries()['fdtmap']
4786 entry = image.GetEntries()['fdtmap']
4787 self.assertEqual(orig_entry.offset, entry.offset)
4788 self.assertEqual(orig_entry.size, entry.size)
Simon Glassed836ac2025-02-26 09:26:17 -07004789 self.assertEqual((1 << 32) - 0x400 + 16, entry.image_pos)
Simon Glassdb84b562021-01-06 21:35:19 -07004790
4791 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4792
Brandon Maiera657bc62024-06-04 16:16:05 +00004793 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glassdb84b562021-01-06 21:35:19 -07004794
Simon Glassc98de972021-03-18 20:24:57 +13004795 def testTplNoDtb(self):
4796 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004797 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004798 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4799 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4800 data[:len(U_BOOT_TPL_NODTB_DATA)])
4801
Simon Glass63f41d42021-03-18 20:24:58 +13004802 def testTplBssPad(self):
4803 """Test that we can pad TPL's BSS with zeros"""
4804 # ELF file with a '__bss_size' symbol
4805 self._SetupTplElf()
4806 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004807 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004808 data)
4809
4810 def testTplBssPadMissing(self):
4811 """Test that a missing symbol is detected"""
4812 self._SetupTplElf('u_boot_ucode_ptr')
4813 with self.assertRaises(ValueError) as e:
4814 self._DoReadFile('193_tpl_bss_pad.dts')
4815 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4816 str(e.exception))
4817
Simon Glass718b5292021-03-18 20:25:07 +13004818 def checkDtbSizes(self, data, pad_len, start):
4819 """Check the size arguments in a dtb embedded in an image
4820
4821 Args:
4822 data: The image data
4823 pad_len: Length of the pad section in the image, in bytes
4824 start: Start offset of the devicetree to examine, within the image
4825
4826 Returns:
4827 Size of the devicetree in bytes
4828 """
4829 dtb_data = data[start:]
4830 dtb = fdt.Fdt.FromData(dtb_data)
4831 fdt_size = dtb.GetFdtObj().totalsize()
4832 dtb.Scan()
4833 props = self._GetPropTree(dtb, 'size')
4834 self.assertEqual({
4835 'size': len(data),
4836 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4837 'u-boot-spl/u-boot-spl-dtb:size': 801,
4838 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4839 'u-boot-spl:size': 860,
4840 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4841 'u-boot/u-boot-dtb:size': 781,
4842 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4843 'u-boot:size': 827,
4844 }, props)
4845 return fdt_size
4846
4847 def testExpanded(self):
4848 """Test that an expanded entry type is selected when needed"""
4849 self._SetupSplElf()
4850 self._SetupTplElf()
4851
4852 # SPL has a devicetree, TPL does not
4853 entry_args = {
4854 'spl-dtb': '1',
4855 'spl-bss-pad': 'y',
4856 'tpl-dtb': '',
4857 }
4858 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4859 entry_args=entry_args)
4860 image = control.images['image']
4861 entries = image.GetEntries()
4862 self.assertEqual(3, len(entries))
4863
4864 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4865 self.assertIn('u-boot', entries)
4866 entry = entries['u-boot']
4867 self.assertEqual('u-boot-expanded', entry.etype)
4868 subent = entry.GetEntries()
4869 self.assertEqual(2, len(subent))
4870 self.assertIn('u-boot-nodtb', subent)
4871 self.assertIn('u-boot-dtb', subent)
4872
4873 # Second, u-boot-spl, which should be expanded into three parts
4874 self.assertIn('u-boot-spl', entries)
4875 entry = entries['u-boot-spl']
4876 self.assertEqual('u-boot-spl-expanded', entry.etype)
4877 subent = entry.GetEntries()
4878 self.assertEqual(3, len(subent))
4879 self.assertIn('u-boot-spl-nodtb', subent)
4880 self.assertIn('u-boot-spl-bss-pad', subent)
4881 self.assertIn('u-boot-spl-dtb', subent)
4882
4883 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4884 # devicetree
4885 self.assertIn('u-boot-tpl', entries)
4886 entry = entries['u-boot-tpl']
4887 self.assertEqual('u-boot-tpl', entry.etype)
4888 self.assertEqual(None, entry.GetEntries())
4889
4890 def testExpandedTpl(self):
4891 """Test that an expanded entry type is selected for TPL when needed"""
4892 self._SetupTplElf()
4893
4894 entry_args = {
4895 'tpl-bss-pad': 'y',
4896 'tpl-dtb': 'y',
4897 }
4898 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4899 entry_args=entry_args)
4900 image = control.images['image']
4901 entries = image.GetEntries()
4902 self.assertEqual(1, len(entries))
4903
4904 # We only have u-boot-tpl, which be expanded
4905 self.assertIn('u-boot-tpl', entries)
4906 entry = entries['u-boot-tpl']
4907 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4908 subent = entry.GetEntries()
4909 self.assertEqual(3, len(subent))
4910 self.assertIn('u-boot-tpl-nodtb', subent)
4911 self.assertIn('u-boot-tpl-bss-pad', subent)
4912 self.assertIn('u-boot-tpl-dtb', subent)
4913
4914 def testExpandedNoPad(self):
4915 """Test an expanded entry without BSS pad enabled"""
4916 self._SetupSplElf()
4917 self._SetupTplElf()
4918
4919 # SPL has a devicetree, TPL does not
4920 entry_args = {
4921 'spl-dtb': 'something',
4922 'spl-bss-pad': 'n',
4923 'tpl-dtb': '',
4924 }
4925 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4926 entry_args=entry_args)
4927 image = control.images['image']
4928 entries = image.GetEntries()
4929
4930 # Just check u-boot-spl, which should be expanded into two parts
4931 self.assertIn('u-boot-spl', entries)
4932 entry = entries['u-boot-spl']
4933 self.assertEqual('u-boot-spl-expanded', entry.etype)
4934 subent = entry.GetEntries()
4935 self.assertEqual(2, len(subent))
4936 self.assertIn('u-boot-spl-nodtb', subent)
4937 self.assertIn('u-boot-spl-dtb', subent)
4938
4939 def testExpandedTplNoPad(self):
4940 """Test that an expanded entry type with padding disabled in TPL"""
4941 self._SetupTplElf()
4942
4943 entry_args = {
4944 'tpl-bss-pad': '',
4945 'tpl-dtb': 'y',
4946 }
4947 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4948 entry_args=entry_args)
4949 image = control.images['image']
4950 entries = image.GetEntries()
4951 self.assertEqual(1, len(entries))
4952
4953 # We only have u-boot-tpl, which be expanded
4954 self.assertIn('u-boot-tpl', entries)
4955 entry = entries['u-boot-tpl']
4956 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4957 subent = entry.GetEntries()
4958 self.assertEqual(2, len(subent))
4959 self.assertIn('u-boot-tpl-nodtb', subent)
4960 self.assertIn('u-boot-tpl-dtb', subent)
4961
4962 def testFdtInclude(self):
4963 """Test that an Fdt is update within all binaries"""
4964 self._SetupSplElf()
4965 self._SetupTplElf()
4966
4967 # SPL has a devicetree, TPL does not
4968 self.maxDiff = None
4969 entry_args = {
4970 'spl-dtb': '1',
4971 'spl-bss-pad': 'y',
4972 'tpl-dtb': '',
4973 }
4974 # Build the image. It includes two separate devicetree binaries, each
4975 # with their own contents, but all contain the binman definition.
4976 data = self._DoReadFileDtb(
4977 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4978 update_dtb=True, entry_args=entry_args)[0]
4979 pad_len = 10
4980
4981 # Check the U-Boot dtb
4982 start = len(U_BOOT_NODTB_DATA)
4983 fdt_size = self.checkDtbSizes(data, pad_len, start)
4984
4985 # Now check SPL
4986 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4987 fdt_size = self.checkDtbSizes(data, pad_len, start)
4988
4989 # TPL has no devicetree
4990 start += fdt_size + len(U_BOOT_TPL_DATA)
4991 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004992
Simon Glass7098b7f2021-03-21 18:24:30 +13004993 def testSymbolsExpanded(self):
4994 """Test binman can assign symbols in expanded entries"""
4995 entry_args = {
4996 'spl-dtb': '1',
4997 }
4998 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4999 U_BOOT_SPL_DTB_DATA, 0x38,
5000 entry_args=entry_args, use_expanded=True)
5001
Simon Glasse1915782021-03-21 18:24:31 +13005002 def testCollection(self):
5003 """Test a collection"""
5004 data = self._DoReadFile('198_collection.dts')
5005 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07005006 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5007 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13005008 data)
5009
Simon Glass27a7f772021-03-21 18:24:32 +13005010 def testCollectionSection(self):
5011 """Test a collection where a section must be built first"""
5012 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07005013 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13005014 # building the contents, producing an error is anything is still
5015 # missing.
5016 data = self._DoReadFile('199_collection_section.dts')
5017 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07005018 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
5019 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13005020 data)
5021
Simon Glassf427c5f2021-03-21 18:24:33 +13005022 def testAlignDefault(self):
5023 """Test that default alignment works on sections"""
5024 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07005025 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13005026 U_BOOT_DATA)
5027 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07005028 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13005029 # No alignment within the nested section
5030 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
5031 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07005032 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13005033 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13005034
Bin Mengc0b15742021-05-10 20:23:33 +08005035 def testPackOpenSBI(self):
5036 """Test that an image with an OpenSBI binary can be created"""
5037 data = self._DoReadFile('201_opensbi.dts')
5038 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
5039
Simon Glass76f496d2021-07-06 10:36:37 -06005040 def testSectionsSingleThread(self):
5041 """Test sections without multithreading"""
5042 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07005043 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
5044 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
5045 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06005046 self.assertEqual(expected, data)
5047
5048 def testThreadTimeout(self):
5049 """Test handling a thread that takes too long"""
5050 with self.assertRaises(ValueError) as e:
5051 self._DoTestFile('202_section_timeout.dts',
5052 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06005053 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06005054
Simon Glass748a1d42021-07-06 10:36:41 -06005055 def testTiming(self):
5056 """Test output of timing information"""
5057 data = self._DoReadFile('055_sections.dts')
5058 with test_util.capture_sys_output() as (stdout, stderr):
5059 state.TimingShow()
5060 self.assertIn('read:', stdout.getvalue())
5061 self.assertIn('compress:', stdout.getvalue())
5062
Simon Glassadfb8492021-11-03 21:09:18 -06005063 def testUpdateFdtInElf(self):
5064 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005065 if not elf.ELF_TOOLS:
5066 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005067 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5068 outfile = os.path.join(self._indir, 'u-boot.out')
5069 begin_sym = 'dtb_embed_begin'
5070 end_sym = 'dtb_embed_end'
5071 retcode = self._DoTestFile(
5072 '060_fdt_update.dts', update_dtb=True,
5073 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5074 self.assertEqual(0, retcode)
5075
5076 # Check that the output file does in fact contact a dtb with the binman
5077 # definition in the correct place
5078 syms = elf.GetSymbolFileOffset(infile,
5079 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07005080 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06005081 dtb_data = data[syms['dtb_embed_begin'].offset:
5082 syms['dtb_embed_end'].offset]
5083
5084 dtb = fdt.Fdt.FromData(dtb_data)
5085 dtb.Scan()
5086 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
5087 self.assertEqual({
5088 'image-pos': 0,
5089 'offset': 0,
5090 '_testing:offset': 32,
5091 '_testing:size': 2,
5092 '_testing:image-pos': 32,
5093 'section@0/u-boot:offset': 0,
5094 'section@0/u-boot:size': len(U_BOOT_DATA),
5095 'section@0/u-boot:image-pos': 0,
5096 'section@0:offset': 0,
5097 'section@0:size': 16,
5098 'section@0:image-pos': 0,
5099
5100 'section@1/u-boot:offset': 0,
5101 'section@1/u-boot:size': len(U_BOOT_DATA),
5102 'section@1/u-boot:image-pos': 16,
5103 'section@1:offset': 16,
5104 'section@1:size': 16,
5105 'section@1:image-pos': 16,
5106 'size': 40
5107 }, props)
5108
5109 def testUpdateFdtInElfInvalid(self):
5110 """Test that invalid args are detected with --update-fdt-in-elf"""
5111 with self.assertRaises(ValueError) as e:
5112 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5113 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5114 str(e.exception))
5115
5116 def testUpdateFdtInElfNoSyms(self):
5117 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005118 if not elf.ELF_TOOLS:
5119 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005120 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5121 outfile = ''
5122 begin_sym = 'wrong_begin'
5123 end_sym = 'wrong_end'
5124 with self.assertRaises(ValueError) as e:
5125 self._DoTestFile(
5126 '060_fdt_update.dts',
5127 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5128 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5129 str(e.exception))
5130
5131 def testUpdateFdtInElfTooSmall(self):
5132 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005133 if not elf.ELF_TOOLS:
5134 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005135 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5136 outfile = os.path.join(self._indir, 'u-boot.out')
5137 begin_sym = 'dtb_embed_begin'
5138 end_sym = 'dtb_embed_end'
5139 with self.assertRaises(ValueError) as e:
5140 self._DoTestFile(
5141 '060_fdt_update.dts', update_dtb=True,
5142 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5143 self.assertRegex(
5144 str(e.exception),
5145 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5146
Simon Glass88e04da2021-11-23 11:03:42 -07005147 def testVersion(self):
5148 """Test we can get the binman version"""
5149 version = '(unreleased)'
5150 self.assertEqual(version, state.GetVersion(self._indir))
5151
5152 with self.assertRaises(SystemExit):
5153 with test_util.capture_sys_output() as (_, stderr):
5154 self._DoBinman('-V')
5155 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5156
5157 # Try running the tool too, just to be safe
5158 result = self._RunBinman('-V')
5159 self.assertEqual('Binman %s\n' % version, result.stderr)
5160
5161 # Set up a version file to make sure that works
5162 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005163 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005164 binary=False)
5165 self.assertEqual(version, state.GetVersion(self._indir))
5166
Simon Glass637958f2021-11-23 21:09:50 -07005167 def testAltFormat(self):
5168 """Test that alternative formats can be used to extract"""
5169 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5170
5171 try:
5172 tmpdir, updated_fname = self._SetupImageInTmpdir()
5173 with test_util.capture_sys_output() as (stdout, _):
5174 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5175 self.assertEqual(
5176 '''Flag (-F) Entry type Description
5177fdt fdtmap Extract the devicetree blob from the fdtmap
5178''',
5179 stdout.getvalue())
5180
5181 dtb = os.path.join(tmpdir, 'fdt.dtb')
5182 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5183 dtb, 'fdtmap')
5184
5185 # Check that we can read it and it can be scanning, meaning it does
5186 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005187 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005188 dtb = fdt.Fdt.FromData(data)
5189 dtb.Scan()
5190
5191 # Now check u-boot which has no alt_format
5192 fname = os.path.join(tmpdir, 'fdt.dtb')
5193 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5194 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005195 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005196 self.assertEqual(U_BOOT_DATA, data)
5197
5198 finally:
5199 shutil.rmtree(tmpdir)
5200
Simon Glass0b00ae62021-11-23 21:09:52 -07005201 def testExtblobList(self):
5202 """Test an image with an external blob list"""
5203 data = self._DoReadFile('215_blob_ext_list.dts')
5204 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5205
5206 def testExtblobListMissing(self):
5207 """Test an image with a missing external blob"""
5208 with self.assertRaises(ValueError) as e:
5209 self._DoReadFile('216_blob_ext_list_missing.dts')
5210 self.assertIn("Filename 'missing-file' not found in input path",
5211 str(e.exception))
5212
5213 def testExtblobListMissingOk(self):
5214 """Test an image with an missing external blob that is allowed"""
5215 with test_util.capture_sys_output() as (stdout, stderr):
5216 self._DoTestFile('216_blob_ext_list_missing.dts',
5217 allow_missing=True)
5218 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005219 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005220
Simon Glass3efb2972021-11-23 21:08:59 -07005221 def testFip(self):
5222 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5223 data = self._DoReadFile('203_fip.dts')
5224 hdr, fents = fip_util.decode_fip(data)
5225 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5226 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5227 self.assertEqual(0x123, hdr.flags)
5228
5229 self.assertEqual(2, len(fents))
5230
5231 fent = fents[0]
5232 self.assertEqual(
5233 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5234 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5235 self.assertEqual('soc-fw', fent.fip_type)
5236 self.assertEqual(0x88, fent.offset)
5237 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5238 self.assertEqual(0x123456789abcdef, fent.flags)
5239 self.assertEqual(ATF_BL31_DATA, fent.data)
5240 self.assertEqual(True, fent.valid)
5241
5242 fent = fents[1]
5243 self.assertEqual(
5244 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5245 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5246 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5247 self.assertEqual(0x8c, fent.offset)
5248 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5249 self.assertEqual(0, fent.flags)
5250 self.assertEqual(ATF_BL2U_DATA, fent.data)
5251 self.assertEqual(True, fent.valid)
5252
5253 def testFipOther(self):
5254 """Basic FIP with something that isn't a external blob"""
5255 data = self._DoReadFile('204_fip_other.dts')
5256 hdr, fents = fip_util.decode_fip(data)
5257
5258 self.assertEqual(2, len(fents))
5259 fent = fents[1]
5260 self.assertEqual('rot-cert', fent.fip_type)
5261 self.assertEqual(b'aa', fent.data)
5262
Simon Glass3efb2972021-11-23 21:08:59 -07005263 def testFipNoType(self):
5264 """FIP with an entry of an unknown type"""
5265 with self.assertRaises(ValueError) as e:
5266 self._DoReadFile('205_fip_no_type.dts')
5267 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5268 str(e.exception))
5269
5270 def testFipUuid(self):
5271 """Basic FIP with a manual uuid"""
5272 data = self._DoReadFile('206_fip_uuid.dts')
5273 hdr, fents = fip_util.decode_fip(data)
5274
5275 self.assertEqual(2, len(fents))
5276 fent = fents[1]
5277 self.assertEqual(None, fent.fip_type)
5278 self.assertEqual(
5279 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5280 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5281 fent.uuid)
5282 self.assertEqual(U_BOOT_DATA, fent.data)
5283
5284 def testFipLs(self):
5285 """Test listing a FIP"""
5286 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5287 hdr, fents = fip_util.decode_fip(data)
5288
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005289 tmpdir = None
Simon Glass3efb2972021-11-23 21:08:59 -07005290 try:
5291 tmpdir, updated_fname = self._SetupImageInTmpdir()
5292 with test_util.capture_sys_output() as (stdout, stderr):
5293 self._DoBinman('ls', '-i', updated_fname)
5294 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005295 if tmpdir:
5296 shutil.rmtree(tmpdir)
Simon Glass3efb2972021-11-23 21:08:59 -07005297 lines = stdout.getvalue().splitlines()
5298 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005299'Name Image-pos Size Entry-type Offset Uncomp-size',
5300'--------------------------------------------------------------',
5301'image 0 2d3 section 0',
5302' atf-fip 0 90 atf-fip 0',
5303' soc-fw 88 4 blob-ext 88',
5304' u-boot 8c 4 u-boot 8c',
5305' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005306]
5307 self.assertEqual(expected, lines)
5308
5309 image = control.images['image']
5310 entries = image.GetEntries()
5311 fdtmap = entries['fdtmap']
5312
5313 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5314 magic = fdtmap_data[:8]
5315 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005316 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005317
5318 fdt_data = fdtmap_data[16:]
5319 dtb = fdt.Fdt.FromData(fdt_data)
5320 dtb.Scan()
5321 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5322 self.assertEqual({
5323 'atf-fip/soc-fw:image-pos': 136,
5324 'atf-fip/soc-fw:offset': 136,
5325 'atf-fip/soc-fw:size': 4,
5326 'atf-fip/u-boot:image-pos': 140,
5327 'atf-fip/u-boot:offset': 140,
5328 'atf-fip/u-boot:size': 4,
5329 'atf-fip:image-pos': 0,
5330 'atf-fip:offset': 0,
5331 'atf-fip:size': 144,
5332 'image-pos': 0,
5333 'offset': 0,
5334 'fdtmap:image-pos': fdtmap.image_pos,
5335 'fdtmap:offset': fdtmap.offset,
5336 'fdtmap:size': len(fdtmap_data),
5337 'size': len(data),
5338 }, props)
5339
5340 def testFipExtractOneEntry(self):
5341 """Test extracting a single entry fron an FIP"""
5342 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005343 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005344 fname = os.path.join(self._indir, 'output.extact')
5345 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005346 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005347 self.assertEqual(U_BOOT_DATA, data)
5348
5349 def testFipReplace(self):
5350 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005351 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005352 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005353 updated_fname = tools.get_output_filename('image-updated.bin')
5354 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005355 entry_name = 'atf-fip/u-boot'
5356 control.WriteEntry(updated_fname, entry_name, expected,
5357 allow_resize=True)
5358 actual = control.ReadEntry(updated_fname, entry_name)
5359 self.assertEqual(expected, actual)
5360
Simon Glass80025522022-01-29 14:14:04 -07005361 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005362 hdr, fents = fip_util.decode_fip(new_data)
5363
5364 self.assertEqual(2, len(fents))
5365
5366 # Check that the FIP entry is updated
5367 fent = fents[1]
5368 self.assertEqual(0x8c, fent.offset)
5369 self.assertEqual(len(expected), fent.size)
5370 self.assertEqual(0, fent.flags)
5371 self.assertEqual(expected, fent.data)
5372 self.assertEqual(True, fent.valid)
5373
5374 def testFipMissing(self):
5375 with test_util.capture_sys_output() as (stdout, stderr):
5376 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5377 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005378 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005379
5380 def testFipSize(self):
5381 """Test a FIP with a size property"""
5382 data = self._DoReadFile('210_fip_size.dts')
5383 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5384 hdr, fents = fip_util.decode_fip(data)
5385 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5386 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5387
5388 self.assertEqual(1, len(fents))
5389
5390 fent = fents[0]
5391 self.assertEqual('soc-fw', fent.fip_type)
5392 self.assertEqual(0x60, fent.offset)
5393 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5394 self.assertEqual(ATF_BL31_DATA, fent.data)
5395 self.assertEqual(True, fent.valid)
5396
5397 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005398 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005399
5400 def testFipBadAlign(self):
5401 """Test that an invalid alignment value in a FIP is detected"""
5402 with self.assertRaises(ValueError) as e:
5403 self._DoTestFile('211_fip_bad_align.dts')
5404 self.assertIn(
5405 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5406 str(e.exception))
5407
5408 def testFipCollection(self):
5409 """Test using a FIP in a collection"""
5410 data = self._DoReadFile('212_fip_collection.dts')
5411 entry1 = control.images['image'].GetEntries()['collection']
5412 data1 = data[:entry1.size]
5413 hdr1, fents2 = fip_util.decode_fip(data1)
5414
5415 entry2 = control.images['image'].GetEntries()['atf-fip']
5416 data2 = data[entry2.offset:entry2.offset + entry2.size]
5417 hdr1, fents2 = fip_util.decode_fip(data2)
5418
5419 # The 'collection' entry should have U-Boot included at the end
5420 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5421 self.assertEqual(data1, data2 + U_BOOT_DATA)
5422 self.assertEqual(U_BOOT_DATA, data1[-4:])
5423
5424 # There should be a U-Boot after the final FIP
5425 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005426
Simon Glassccae6862022-01-12 13:10:35 -07005427 def testFakeBlob(self):
5428 """Test handling of faking an external blob"""
5429 with test_util.capture_sys_output() as (stdout, stderr):
5430 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5431 allow_fake_blobs=True)
5432 err = stderr.getvalue()
5433 self.assertRegex(
5434 err,
5435 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005436
Simon Glassceb5f912022-01-09 20:13:46 -07005437 def testExtblobListFaked(self):
5438 """Test an extblob with missing external blob that are faked"""
5439 with test_util.capture_sys_output() as (stdout, stderr):
5440 self._DoTestFile('216_blob_ext_list_missing.dts',
5441 allow_fake_blobs=True)
5442 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005443 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005444
Simon Glass162017b2022-01-09 20:13:57 -07005445 def testListBintools(self):
5446 args = ['tool', '--list']
5447 with test_util.capture_sys_output() as (stdout, _):
5448 self._DoBinman(*args)
5449 out = stdout.getvalue().splitlines()
5450 self.assertTrue(len(out) >= 2)
5451
5452 def testFetchBintools(self):
5453 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005454 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005455 raise urllib.error.URLError('my error')
5456
5457 args = ['tool']
5458 with self.assertRaises(ValueError) as e:
5459 self._DoBinman(*args)
5460 self.assertIn("Invalid arguments to 'tool' subcommand",
5461 str(e.exception))
5462
5463 args = ['tool', '--fetch']
5464 with self.assertRaises(ValueError) as e:
5465 self._DoBinman(*args)
5466 self.assertIn('Please specify bintools to fetch', str(e.exception))
5467
5468 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005469 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005470 side_effect=fail_download):
5471 with test_util.capture_sys_output() as (stdout, _):
5472 self._DoBinman(*args)
5473 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5474
Simon Glass620c4462022-01-09 20:14:11 -07005475 def testBintoolDocs(self):
5476 """Test for creation of bintool documentation"""
5477 with test_util.capture_sys_output() as (stdout, stderr):
5478 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5479 self.assertTrue(len(stdout.getvalue()) > 0)
5480
5481 def testBintoolDocsMissing(self):
5482 """Test handling of missing bintool documentation"""
5483 with self.assertRaises(ValueError) as e:
5484 with test_util.capture_sys_output() as (stdout, stderr):
5485 control.write_bintool_docs(
5486 control.bintool.Bintool.get_tool_list(), 'mkimage')
5487 self.assertIn('Documentation is missing for modules: mkimage',
5488 str(e.exception))
5489
Jan Kiszka58c407f2022-01-28 20:37:53 +01005490 def testListWithGenNode(self):
5491 """Check handling of an FDT map when the section cannot be found"""
5492 entry_args = {
5493 'of-list': 'test-fdt1 test-fdt2',
5494 }
5495 data = self._DoReadFileDtb(
5496 '219_fit_gennode.dts',
5497 entry_args=entry_args,
5498 use_real_dtb=True,
5499 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5500
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005501 tmpdir = None
Jan Kiszka58c407f2022-01-28 20:37:53 +01005502 try:
5503 tmpdir, updated_fname = self._SetupImageInTmpdir()
5504 with test_util.capture_sys_output() as (stdout, stderr):
5505 self._RunBinman('ls', '-i', updated_fname)
5506 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005507 if tmpdir:
5508 shutil.rmtree(tmpdir)
Jan Kiszka58c407f2022-01-28 20:37:53 +01005509
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005510 def testFitSubentryUsesBintool(self):
5511 """Test that binman FIT subentries can use bintools"""
Simon Glass5dc22cf2025-02-03 09:26:42 -07005512 command.TEST_RESULT = self._HandleGbbCommand
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005513 entry_args = {
5514 'keydir': 'devkeys',
5515 'bmpblk': 'bmpblk.bin',
5516 }
5517 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5518 entry_args=entry_args)
5519
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005520 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5521 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005522 self.assertIn(expected, data)
5523
5524 def testFitSubentryMissingBintool(self):
5525 """Test that binman reports missing bintools for FIT subentries"""
5526 entry_args = {
5527 'keydir': 'devkeys',
5528 }
5529 with test_util.capture_sys_output() as (_, stderr):
5530 self._DoTestFile('220_fit_subentry_bintool.dts',
5531 force_missing_bintools='futility', entry_args=entry_args)
5532 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005533 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005534
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005535 def testFitSubentryHashSubnode(self):
5536 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005537 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005538 data, _, _, out_dtb_name = self._DoReadFileDtb(
5539 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5540
5541 mkimage_dtb = fdt.Fdt.FromData(data)
5542 mkimage_dtb.Scan()
5543 binman_dtb = fdt.Fdt(out_dtb_name)
5544 binman_dtb.Scan()
5545
5546 # Check that binman didn't add hash values
5547 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5548 self.assertNotIn('value', fnode.props)
5549
5550 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5551 self.assertNotIn('value', fnode.props)
5552
5553 # Check that mkimage added hash values
5554 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5555 self.assertIn('value', fnode.props)
5556
5557 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5558 self.assertIn('value', fnode.props)
5559
Roger Quadros5cdcea02022-02-19 20:50:04 +02005560 def testPackTeeOs(self):
5561 """Test that an image with an TEE binary can be created"""
5562 data = self._DoReadFile('222_tee_os.dts')
5563 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5564
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305565 def testPackTiDm(self):
5566 """Test that an image with a TI DM binary can be created"""
5567 data = self._DoReadFile('225_ti_dm.dts')
5568 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5569
Simon Glass912339f2022-02-08 11:50:03 -07005570 def testFitFdtOper(self):
5571 """Check handling of a specified FIT operation"""
5572 entry_args = {
5573 'of-list': 'test-fdt1 test-fdt2',
5574 'default-dt': 'test-fdt2',
5575 }
5576 self._DoReadFileDtb(
5577 '223_fit_fdt_oper.dts',
5578 entry_args=entry_args,
5579 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5580
5581 def testFitFdtBadOper(self):
5582 """Check handling of an FDT map when the section cannot be found"""
5583 with self.assertRaises(ValueError) as exc:
5584 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005585 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005586 str(exc.exception))
5587
Simon Glassdd156a42022-03-05 20:18:59 -07005588 def test_uses_expand_size(self):
5589 """Test that the 'expand-size' property cannot be used anymore"""
5590 with self.assertRaises(ValueError) as e:
5591 data = self._DoReadFile('225_expand_size_bad.dts')
5592 self.assertIn(
5593 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5594 str(e.exception))
5595
Simon Glass5f423422022-03-05 20:19:12 -07005596 def testFitSplitElf(self):
5597 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005598 if not elf.ELF_TOOLS:
5599 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005600 entry_args = {
5601 'of-list': 'test-fdt1 test-fdt2',
5602 'default-dt': 'test-fdt2',
5603 'atf-bl31-path': 'bl31.elf',
5604 'tee-os-path': 'tee.elf',
5605 }
5606 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5607 data = self._DoReadFileDtb(
5608 '226_fit_split_elf.dts',
5609 entry_args=entry_args,
5610 extra_indirs=[test_subdir])[0]
5611
5612 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5613 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5614
5615 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5616 'data', 'load'}
5617 dtb = fdt.Fdt.FromData(fit_data)
5618 dtb.Scan()
5619
5620 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5621 segments, entry = elf.read_loadable_segments(elf_data)
5622
5623 # We assume there are two segments
Brandon Maiera657bc62024-06-04 16:16:05 +00005624 self.assertEqual(2, len(segments))
Simon Glass5f423422022-03-05 20:19:12 -07005625
5626 atf1 = dtb.GetNode('/images/atf-1')
5627 _, start, data = segments[0]
5628 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5629 self.assertEqual(entry,
5630 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5631 self.assertEqual(start,
5632 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5633 self.assertEqual(data, atf1.props['data'].bytes)
5634
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005635 hash_node = atf1.FindNode('hash')
5636 self.assertIsNotNone(hash_node)
5637 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5638
Simon Glass5f423422022-03-05 20:19:12 -07005639 atf2 = dtb.GetNode('/images/atf-2')
5640 self.assertEqual(base_keys, atf2.props.keys())
5641 _, start, data = segments[1]
5642 self.assertEqual(start,
5643 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5644 self.assertEqual(data, atf2.props['data'].bytes)
5645
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005646 hash_node = atf2.FindNode('hash')
5647 self.assertIsNotNone(hash_node)
5648 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5649
5650 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5651 self.assertIsNotNone(hash_node)
5652 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5653
Simon Glass5f423422022-03-05 20:19:12 -07005654 conf = dtb.GetNode('/configurations')
5655 self.assertEqual({'default'}, conf.props.keys())
5656
5657 for subnode in conf.subnodes:
5658 self.assertEqual({'description', 'fdt', 'loadables'},
5659 subnode.props.keys())
5660 self.assertEqual(
5661 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5662 fdt_util.GetStringList(subnode, 'loadables'))
5663
5664 def _check_bad_fit(self, dts):
5665 """Check a bad FIT
5666
5667 This runs with the given dts and returns the assertion raised
5668
5669 Args:
5670 dts (str): dts filename to use
5671
5672 Returns:
5673 str: Assertion string raised
5674 """
5675 entry_args = {
5676 'of-list': 'test-fdt1 test-fdt2',
5677 'default-dt': 'test-fdt2',
5678 'atf-bl31-path': 'bl31.elf',
5679 'tee-os-path': 'tee.elf',
5680 }
5681 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5682 with self.assertRaises(ValueError) as exc:
5683 self._DoReadFileDtb(dts, entry_args=entry_args,
5684 extra_indirs=[test_subdir])[0]
5685 return str(exc.exception)
5686
5687 def testFitSplitElfBadElf(self):
5688 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005689 if not elf.ELF_TOOLS:
5690 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005691 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5692 entry_args = {
5693 'of-list': 'test-fdt1 test-fdt2',
5694 'default-dt': 'test-fdt2',
5695 'atf-bl31-path': 'bad.elf',
5696 'tee-os-path': 'tee.elf',
5697 }
5698 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5699 with self.assertRaises(ValueError) as exc:
5700 self._DoReadFileDtb(
5701 '226_fit_split_elf.dts',
5702 entry_args=entry_args,
5703 extra_indirs=[test_subdir])[0]
5704 self.assertIn(
5705 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5706 str(exc.exception))
5707
Simon Glass5f423422022-03-05 20:19:12 -07005708 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005709 """Test an split-elf FIT with a missing ELF file
5710
5711 Args:
5712 kwargs (dict of str): Arguments to pass to _DoTestFile()
5713
5714 Returns:
5715 tuple:
5716 str: stdout result
5717 str: stderr result
5718 """
Simon Glass5f423422022-03-05 20:19:12 -07005719 entry_args = {
5720 'of-list': 'test-fdt1 test-fdt2',
5721 'default-dt': 'test-fdt2',
5722 'atf-bl31-path': 'bl31.elf',
5723 'tee-os-path': 'missing.elf',
5724 }
5725 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5726 with test_util.capture_sys_output() as (stdout, stderr):
5727 self._DoTestFile(
5728 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005729 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5730 out = stdout.getvalue()
5731 err = stderr.getvalue()
5732 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005733
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005734 def testFitSplitElfBadDirective(self):
5735 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5736 if not elf.ELF_TOOLS:
5737 self.skipTest('Python elftools not available')
5738 err = self._check_bad_fit('227_fit_bad_dir.dts')
5739 self.assertIn(
5740 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5741 err)
5742
5743 def testFitSplitElfBadDirectiveConfig(self):
5744 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5745 if not elf.ELF_TOOLS:
5746 self.skipTest('Python elftools not available')
5747 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5748 self.assertEqual(
5749 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5750 err)
5751
5752
Simon Glass5f423422022-03-05 20:19:12 -07005753 def testFitSplitElfMissing(self):
5754 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005755 if not elf.ELF_TOOLS:
5756 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005757 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005758 self.assertRegex(
5759 err,
5760 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005761 self.assertNotRegex(out, '.*Faked blob.*')
5762 fname = tools.get_output_filename('binman-fake/missing.elf')
5763 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005764
5765 def testFitSplitElfFaked(self):
5766 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005767 if not elf.ELF_TOOLS:
5768 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005769 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005770 self.assertRegex(
5771 err,
5772 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005773 self.assertRegex(
5774 out,
5775 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5776 fname = tools.get_output_filename('binman-fake/missing.elf')
5777 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005778
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005779 def testMkimageMissingBlob(self):
5780 """Test using mkimage to build an image"""
5781 with test_util.capture_sys_output() as (stdout, stderr):
5782 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5783 allow_fake_blobs=True)
5784 err = stderr.getvalue()
5785 self.assertRegex(
5786 err,
5787 "Image '.*' has faked external blobs and is non-functional: .*")
5788
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005789 def testPreLoad(self):
5790 """Test an image with a pre-load header"""
5791 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005792 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005793 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005794 data = self._DoReadFileDtb(
5795 '230_pre_load.dts', entry_args=entry_args,
5796 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Paul HENRYS5cf82892025-02-24 22:20:55 +01005797
5798 image_fname = tools.get_output_filename('image.bin')
5799 is_signed = self._CheckPreload(image_fname, self.TestFile("dev.key"))
5800
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005801 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5802 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5803 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Paul HENRYS5cf82892025-02-24 22:20:55 +01005804 self.assertEqual(is_signed, True)
Simon Glasse2dfb962023-07-24 09:19:57 -06005805
5806 def testPreLoadNoKey(self):
5807 """Test an image with a pre-load heade0r with missing key"""
5808 with self.assertRaises(FileNotFoundError) as exc:
5809 self._DoReadFile('230_pre_load.dts')
5810 self.assertIn("No such file or directory: 'dev.key'",
5811 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005812
5813 def testPreLoadPkcs(self):
5814 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005815 entry_args = {
5816 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5817 }
5818 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5819 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005820 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5821 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5822 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5823
5824 def testPreLoadPss(self):
5825 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005826 entry_args = {
5827 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5828 }
5829 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5830 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005831 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5832 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5833 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5834
5835 def testPreLoadInvalidPadding(self):
5836 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005837 entry_args = {
5838 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5839 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005840 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005841 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5842 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005843
5844 def testPreLoadInvalidSha(self):
5845 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005846 entry_args = {
5847 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5848 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005849 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005850 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5851 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005852
5853 def testPreLoadInvalidAlgo(self):
5854 """Test an image with a pre-load header with an invalid algo"""
5855 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005856 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005857
5858 def testPreLoadInvalidKey(self):
5859 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005860 entry_args = {
5861 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5862 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005863 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005864 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5865 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005866
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005867 def _CheckSafeUniqueNames(self, *images):
5868 """Check all entries of given images for unsafe unique names"""
5869 for image in images:
5870 entries = {}
5871 image._CollectEntries(entries, {}, image)
5872 for entry in entries.values():
5873 uniq = entry.GetUniqueName()
5874
5875 # Used as part of a filename, so must not be absolute paths.
5876 self.assertFalse(os.path.isabs(uniq))
5877
5878 def testSafeUniqueNames(self):
5879 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005880 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005881
5882 orig_image = control.images['image']
5883 image_fname = tools.get_output_filename('image.bin')
5884 image = Image.FromFile(image_fname)
5885
5886 self._CheckSafeUniqueNames(orig_image, image)
5887
5888 def testSafeUniqueNamesMulti(self):
5889 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005890 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005891
5892 orig_image = control.images['image']
5893 image_fname = tools.get_output_filename('image.bin')
5894 image = Image.FromFile(image_fname)
5895
5896 self._CheckSafeUniqueNames(orig_image, image)
5897
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005898 def testReplaceCmdWithBintool(self):
5899 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005900 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005901 expected = U_BOOT_DATA + b'aa'
5902 self.assertEqual(expected, data[:len(expected)])
5903
5904 try:
5905 tmpdir, updated_fname = self._SetupImageInTmpdir()
5906 fname = os.path.join(tmpdir, 'update-testing.bin')
5907 tools.write_file(fname, b'zz')
5908 self._DoBinman('replace', '-i', updated_fname,
5909 '_testing', '-f', fname)
5910
5911 data = tools.read_file(updated_fname)
5912 expected = U_BOOT_DATA + b'zz'
5913 self.assertEqual(expected, data[:len(expected)])
5914 finally:
5915 shutil.rmtree(tmpdir)
5916
5917 def testReplaceCmdOtherWithBintool(self):
5918 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005919 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005920 expected = U_BOOT_DATA + b'aa'
5921 self.assertEqual(expected, data[:len(expected)])
5922
5923 try:
5924 tmpdir, updated_fname = self._SetupImageInTmpdir()
5925 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5926 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5927 self._DoBinman('replace', '-i', updated_fname,
5928 'u-boot', '-f', fname)
5929
5930 data = tools.read_file(updated_fname)
5931 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5932 self.assertEqual(expected, data[:len(expected)])
5933 finally:
5934 shutil.rmtree(tmpdir)
5935
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005936 def testReplaceResizeNoRepackSameSize(self):
5937 """Test replacing entries with same-size data without repacking"""
5938 expected = b'x' * len(U_BOOT_DATA)
5939 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5940 self.assertEqual(expected, data)
5941
5942 path, fdtmap = state.GetFdtContents('fdtmap')
5943 self.assertIsNotNone(path)
5944 self.assertEqual(expected_fdtmap, fdtmap)
5945
5946 def testReplaceResizeNoRepackSmallerSize(self):
5947 """Test replacing entries with smaller-size data without repacking"""
5948 new_data = b'x'
5949 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5950 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5951 self.assertEqual(expected, data)
5952
5953 path, fdtmap = state.GetFdtContents('fdtmap')
5954 self.assertIsNotNone(path)
5955 self.assertEqual(expected_fdtmap, fdtmap)
5956
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005957 def testExtractFit(self):
5958 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005959 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005960 image_fname = tools.get_output_filename('image.bin')
5961
5962 fit_data = control.ReadEntry(image_fname, 'fit')
5963 fit = fdt.Fdt.FromData(fit_data)
5964 fit.Scan()
5965
5966 # Check subentry data inside the extracted fit
5967 for node_path, expected in [
5968 ('/images/kernel', U_BOOT_DATA),
5969 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5970 ('/images/scr-1', COMPRESS_DATA),
5971 ]:
5972 node = fit.GetNode(node_path)
5973 data = fit.GetProps(node)['data'].bytes
5974 self.assertEqual(expected, data)
5975
5976 def testExtractFitSubentries(self):
5977 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005978 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005979 image_fname = tools.get_output_filename('image.bin')
5980
5981 for entry_path, expected in [
5982 ('fit/kernel', U_BOOT_DATA),
5983 ('fit/kernel/u-boot', U_BOOT_DATA),
5984 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5985 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5986 ('fit/scr-1', COMPRESS_DATA),
5987 ('fit/scr-1/blob', COMPRESS_DATA),
5988 ]:
5989 data = control.ReadEntry(image_fname, entry_path)
5990 self.assertEqual(expected, data)
5991
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005992 def testReplaceFitSubentryLeafSameSize(self):
5993 """Test replacing a FIT leaf subentry with same-size data"""
5994 new_data = b'x' * len(U_BOOT_DATA)
5995 data, expected_fdtmap, _ = self._RunReplaceCmd(
5996 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005997 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005998 self.assertEqual(new_data, data)
5999
6000 path, fdtmap = state.GetFdtContents('fdtmap')
6001 self.assertIsNotNone(path)
6002 self.assertEqual(expected_fdtmap, fdtmap)
6003
6004 def testReplaceFitSubentryLeafBiggerSize(self):
6005 """Test replacing a FIT leaf subentry with bigger-size data"""
6006 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
6007 data, expected_fdtmap, _ = self._RunReplaceCmd(
6008 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006009 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006010 self.assertEqual(new_data, data)
6011
6012 # Will be repacked, so fdtmap must change
6013 path, fdtmap = state.GetFdtContents('fdtmap')
6014 self.assertIsNotNone(path)
6015 self.assertNotEqual(expected_fdtmap, fdtmap)
6016
6017 def testReplaceFitSubentryLeafSmallerSize(self):
6018 """Test replacing a FIT leaf subentry with smaller-size data"""
6019 new_data = b'x'
6020 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
6021 data, expected_fdtmap, _ = self._RunReplaceCmd(
6022 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006023 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006024 self.assertEqual(expected, data)
6025
6026 path, fdtmap = state.GetFdtContents('fdtmap')
6027 self.assertIsNotNone(path)
6028 self.assertEqual(expected_fdtmap, fdtmap)
6029
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006030 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07006031 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006032 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07006033 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6034 new_data, dts='241_replace_section_simple.dts')
6035 self.assertEqual(new_data, data)
6036
6037 entries = image.GetEntries()
6038 self.assertIn('section', entries)
6039 entry = entries['section']
6040 self.assertEqual(len(new_data), entry.size)
6041
6042 def testReplaceSectionLarger(self):
6043 """Test replacing a simple section with larger data"""
6044 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6045 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6046 new_data, dts='241_replace_section_simple.dts')
6047 self.assertEqual(new_data, data)
6048
6049 entries = image.GetEntries()
6050 self.assertIn('section', entries)
6051 entry = entries['section']
6052 self.assertEqual(len(new_data), entry.size)
6053 fentry = entries['fdtmap']
6054 self.assertEqual(entry.offset + entry.size, fentry.offset)
6055
6056 def testReplaceSectionSmaller(self):
6057 """Test replacing a simple section with smaller data"""
6058 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
6059 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6060 new_data, dts='241_replace_section_simple.dts')
6061 self.assertEqual(new_data, data)
6062
6063 # The new size is the same as the old, just with a pad byte at the end
6064 entries = image.GetEntries()
6065 self.assertIn('section', entries)
6066 entry = entries['section']
6067 self.assertEqual(len(new_data), entry.size)
6068
6069 def testReplaceSectionSmallerAllow(self):
6070 """Test failing to replace a simple section with smaller data"""
6071 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
6072 try:
6073 state.SetAllowEntryContraction(True)
6074 with self.assertRaises(ValueError) as exc:
6075 self._RunReplaceCmd('section', new_data,
6076 dts='241_replace_section_simple.dts')
6077 finally:
6078 state.SetAllowEntryContraction(False)
6079
6080 # Since we have no information about the position of things within the
6081 # section, we cannot adjust the position of /section-u-boot so it ends
6082 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06006083 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07006084 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
6085 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06006086 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006087
Simon Glass8fbca772022-08-13 11:40:48 -06006088 def testMkimageImagename(self):
6089 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006090 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006091 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06006092
6093 # Check that the data appears in the file somewhere
6094 self.assertIn(U_BOOT_SPL_DATA, data)
6095
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006096 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06006097 name = data[0x20:0x40]
6098
6099 # Build the filename that we expect to be placed in there, by virtue of
6100 # the -n paraameter
6101 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6102
6103 # Check that the image name is set to the temporary filename used
6104 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6105
Simon Glassb1669752022-08-13 11:40:49 -06006106 def testMkimageImage(self):
6107 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006108 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006109 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006110
6111 # Check that the data appears in the file somewhere
6112 self.assertIn(U_BOOT_SPL_DATA, data)
6113
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006114 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006115 name = data[0x20:0x40]
6116
6117 # Build the filename that we expect to be placed in there, by virtue of
6118 # the -n paraameter
6119 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6120
6121 # Check that the image name is set to the temporary filename used
6122 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6123
6124 # Check the corect data is in the imagename file
6125 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6126
6127 def testMkimageImageNoContent(self):
6128 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006129 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006130 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006131 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006132 self.assertIn('Could not complete processing of contents',
6133 str(exc.exception))
6134
6135 def testMkimageImageBad(self):
6136 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006137 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006138 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006139 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006140 self.assertIn('Cannot use both imagename node and data-to-imagename',
6141 str(exc.exception))
6142
Simon Glassbd5cd882022-08-13 11:40:50 -06006143 def testCollectionOther(self):
6144 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006145 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006146 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6147 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6148 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6149 data)
6150
6151 def testMkimageCollection(self):
6152 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006153 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006154 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006155 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6156 self.assertEqual(expect, data[:len(expect)])
6157
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006158 def testCompressDtbPrependInvalid(self):
6159 """Test that invalid header is detected"""
6160 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006161 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006162 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6163 "'u-boot-dtb': 'invalid'", str(e.exception))
6164
6165 def testCompressDtbPrependLength(self):
6166 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006167 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006168 image = control.images['image']
6169 entries = image.GetEntries()
6170 self.assertIn('u-boot-dtb', entries)
6171 u_boot_dtb = entries['u-boot-dtb']
6172 self.assertIn('fdtmap', entries)
6173 fdtmap = entries['fdtmap']
6174
6175 image_fname = tools.get_output_filename('image.bin')
6176 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6177 dtb = fdt.Fdt.FromData(orig)
6178 dtb.Scan()
6179 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6180 expected = {
6181 'u-boot:size': len(U_BOOT_DATA),
6182 'u-boot-dtb:uncomp-size': len(orig),
6183 'u-boot-dtb:size': u_boot_dtb.size,
6184 'fdtmap:size': fdtmap.size,
6185 'size': len(data),
6186 }
6187 self.assertEqual(expected, props)
6188
6189 # Check implementation
6190 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6191 rest = data[len(U_BOOT_DATA):]
6192 comp_data_len = struct.unpack('<I', rest[:4])[0]
6193 comp_data = rest[4:4 + comp_data_len]
6194 orig2 = self._decompress(comp_data)
6195 self.assertEqual(orig, orig2)
6196
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006197 def testInvalidCompress(self):
6198 """Test that invalid compress algorithm is detected"""
6199 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006200 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006201 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6202
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006203 def testCompUtilCompressions(self):
6204 """Test compression algorithms"""
6205 for bintool in self.comp_bintools.values():
6206 self._CheckBintool(bintool)
6207 data = bintool.compress(COMPRESS_DATA)
6208 self.assertNotEqual(COMPRESS_DATA, data)
6209 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006210 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006211
6212 def testCompUtilVersions(self):
6213 """Test tool version of compression algorithms"""
6214 for bintool in self.comp_bintools.values():
6215 self._CheckBintool(bintool)
6216 version = bintool.version()
6217 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6218
6219 def testCompUtilPadding(self):
6220 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006221 # Skip zstd because it doesn't support padding
6222 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006223 self._CheckBintool(bintool)
6224 data = bintool.compress(COMPRESS_DATA)
6225 self.assertNotEqual(COMPRESS_DATA, data)
6226 data += tools.get_bytes(0, 64)
6227 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006228 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006229
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006230 def testCompressDtbZstd(self):
6231 """Test that zstd compress of device-tree files failed"""
6232 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006233 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006234 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6235 "requires a length header", str(e.exception))
6236
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006237 def testMkimageMultipleDataFiles(self):
6238 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006239 self._SetupSplElf()
6240 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006241 data = self._DoReadFile('252_mkimage_mult_data.dts')
6242 # Size of files are packed in their 4B big-endian format
6243 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6244 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6245 # Size info is always followed by a 4B zero value.
6246 expect += tools.get_bytes(0, 4)
6247 expect += U_BOOT_TPL_DATA
6248 # All but last files are 4B-aligned
6249 align_pad = len(U_BOOT_TPL_DATA) % 4
6250 if align_pad:
6251 expect += tools.get_bytes(0, align_pad)
6252 expect += U_BOOT_SPL_DATA
6253 self.assertEqual(expect, data[-len(expect):])
6254
Marek Vasutf7413f02023-07-18 07:23:58 -06006255 def testMkimageMultipleExpanded(self):
6256 """Test passing multiple files to mkimage in a mkimage entry"""
6257 self._SetupSplElf()
6258 self._SetupTplElf()
6259 entry_args = {
6260 'spl-bss-pad': 'y',
6261 'spl-dtb': 'y',
6262 }
6263 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6264 use_expanded=True, entry_args=entry_args)[0]
6265 pad_len = 10
6266 tpl_expect = U_BOOT_TPL_DATA
6267 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6268 spl_expect += U_BOOT_SPL_DTB_DATA
6269
6270 content = data[0x40:]
6271 lens = struct.unpack('>III', content[:12])
6272
6273 # Size of files are packed in their 4B big-endian format
6274 # Size info is always followed by a 4B zero value.
6275 self.assertEqual(len(tpl_expect), lens[0])
6276 self.assertEqual(len(spl_expect), lens[1])
6277 self.assertEqual(0, lens[2])
6278
6279 rest = content[12:]
6280 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6281
6282 rest = rest[len(tpl_expect):]
6283 align_pad = len(tpl_expect) % 4
6284 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6285 rest = rest[align_pad:]
6286 self.assertEqual(spl_expect, rest)
6287
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006288 def testMkimageMultipleNoContent(self):
6289 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006290 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006291 with self.assertRaises(ValueError) as exc:
6292 self._DoReadFile('253_mkimage_mult_no_content.dts')
6293 self.assertIn('Could not complete processing of contents',
6294 str(exc.exception))
6295
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006296 def testMkimageFilename(self):
6297 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006298 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006299 retcode = self._DoTestFile('254_mkimage_filename.dts')
6300 self.assertEqual(0, retcode)
6301 fname = tools.get_output_filename('mkimage-test.bin')
6302 self.assertTrue(os.path.exists(fname))
6303
Simon Glass56d05412022-02-28 07:16:54 -07006304 def testVpl(self):
6305 """Test that an image with VPL and its device tree can be created"""
6306 # ELF file with a '__bss_size' symbol
6307 self._SetupVplElf()
6308 data = self._DoReadFile('255_u_boot_vpl.dts')
6309 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6310
6311 def testVplNoDtb(self):
6312 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6313 self._SetupVplElf()
6314 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6315 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6316 data[:len(U_BOOT_VPL_NODTB_DATA)])
6317
6318 def testExpandedVpl(self):
6319 """Test that an expanded entry type is selected for TPL when needed"""
6320 self._SetupVplElf()
6321
6322 entry_args = {
6323 'vpl-bss-pad': 'y',
6324 'vpl-dtb': 'y',
6325 }
6326 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6327 entry_args=entry_args)
6328 image = control.images['image']
6329 entries = image.GetEntries()
6330 self.assertEqual(1, len(entries))
6331
6332 # We only have u-boot-vpl, which be expanded
6333 self.assertIn('u-boot-vpl', entries)
6334 entry = entries['u-boot-vpl']
6335 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6336 subent = entry.GetEntries()
6337 self.assertEqual(3, len(subent))
6338 self.assertIn('u-boot-vpl-nodtb', subent)
6339 self.assertIn('u-boot-vpl-bss-pad', subent)
6340 self.assertIn('u-boot-vpl-dtb', subent)
6341
6342 def testVplBssPadMissing(self):
6343 """Test that a missing symbol is detected"""
6344 self._SetupVplElf('u_boot_ucode_ptr')
6345 with self.assertRaises(ValueError) as e:
6346 self._DoReadFile('258_vpl_bss_pad.dts')
6347 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6348 str(e.exception))
6349
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306350 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306351 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306352 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6353 self.assertEqual(0, retcode)
6354 image = control.images['test_image']
6355 fname = tools.get_output_filename('test_image.bin')
6356 sname = tools.get_output_filename('symlink_to_test.bin')
6357 self.assertTrue(os.path.islink(sname))
6358 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006359
Andrew Davis6b463da2023-07-22 00:14:44 +05306360 def testSymlinkOverwrite(self):
6361 """Test that symlinked images can be overwritten"""
6362 testdir = TestFunctional._MakeInputDir('symlinktest')
6363 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6364 # build the same image again in the same directory so that existing symlink is present
6365 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6366 fname = tools.get_output_filename('test_image.bin')
6367 sname = tools.get_output_filename('symlink_to_test.bin')
6368 self.assertTrue(os.path.islink(sname))
6369 self.assertEqual(os.readlink(sname), fname)
6370
Simon Glass37f85de2022-10-20 18:22:47 -06006371 def testSymbolsElf(self):
6372 """Test binman can assign symbols embedded in an ELF file"""
6373 if not elf.ELF_TOOLS:
6374 self.skipTest('Python elftools not available')
6375 self._SetupTplElf('u_boot_binman_syms')
6376 self._SetupVplElf('u_boot_binman_syms')
6377 self._SetupSplElf('u_boot_binman_syms')
6378 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6379 image_fname = tools.get_output_filename('image.bin')
6380
6381 image = control.images['image']
6382 entries = image.GetEntries()
6383
6384 for entry in entries.values():
6385 # No symbols in u-boot and it has faked contents anyway
6386 if entry.name == 'u-boot':
6387 continue
6388 edata = data[entry.image_pos:entry.image_pos + entry.size]
6389 efname = tools.get_output_filename(f'edata-{entry.name}')
6390 tools.write_file(efname, edata)
6391
6392 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6393 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6394 for name, sym in syms.items():
6395 msg = 'test'
6396 val = elf.GetSymbolValue(sym, edata, msg)
6397 entry_m = re_name.match(name)
6398 if entry_m:
6399 ename, prop = entry_m.group(1), entry_m.group(3)
6400 entry, entry_name, prop_name = image.LookupEntry(entries,
6401 name, msg)
Simon Glassd3d3a102025-02-19 08:11:16 -07006402 expect_val = None
Simon Glass37f85de2022-10-20 18:22:47 -06006403 if prop_name == 'offset':
6404 expect_val = entry.offset
6405 elif prop_name == 'image_pos':
6406 expect_val = entry.image_pos
6407 elif prop_name == 'size':
6408 expect_val = entry.size
6409 self.assertEqual(expect_val, val)
6410
6411 def testSymbolsElfBad(self):
6412 """Check error when trying to write symbols without the elftools lib"""
6413 if not elf.ELF_TOOLS:
6414 self.skipTest('Python elftools not available')
6415 self._SetupTplElf('u_boot_binman_syms')
6416 self._SetupVplElf('u_boot_binman_syms')
6417 self._SetupSplElf('u_boot_binman_syms')
6418 try:
6419 elf.ELF_TOOLS = False
6420 with self.assertRaises(ValueError) as exc:
6421 self._DoReadFileDtb('260_symbols_elf.dts')
6422 finally:
6423 elf.ELF_TOOLS = True
6424 self.assertIn(
6425 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6426 'Cannot write symbols to an ELF file without Python elftools',
6427 str(exc.exception))
6428
Simon Glassde244162023-01-07 14:07:08 -07006429 def testSectionFilename(self):
6430 """Check writing of section contents to a file"""
6431 data = self._DoReadFile('261_section_fname.dts')
6432 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6433 tools.get_bytes(ord('!'), 7) +
6434 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6435 self.assertEqual(expected, data)
6436
6437 sect_fname = tools.get_output_filename('outfile.bin')
6438 self.assertTrue(os.path.exists(sect_fname))
6439 sect_data = tools.read_file(sect_fname)
6440 self.assertEqual(U_BOOT_DATA, sect_data)
6441
Simon Glass1e9e61c2023-01-07 14:07:12 -07006442 def testAbsent(self):
6443 """Check handling of absent entries"""
6444 data = self._DoReadFile('262_absent.dts')
6445 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6446
Simon Glassad5cfe12023-01-07 14:07:14 -07006447 def testPackTeeOsOptional(self):
6448 """Test that an image with an optional TEE binary can be created"""
6449 entry_args = {
6450 'tee-os-path': 'tee.elf',
6451 }
6452 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6453 entry_args=entry_args)[0]
6454 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6455
6456 def checkFitTee(self, dts, tee_fname):
6457 """Check that a tee-os entry works and returns data
6458
6459 Args:
6460 dts (str): Device tree filename to use
6461 tee_fname (str): filename containing tee-os
6462
6463 Returns:
6464 bytes: Image contents
6465 """
6466 if not elf.ELF_TOOLS:
6467 self.skipTest('Python elftools not available')
6468 entry_args = {
6469 'of-list': 'test-fdt1 test-fdt2',
6470 'default-dt': 'test-fdt2',
6471 'tee-os-path': tee_fname,
6472 }
6473 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6474 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6475 extra_indirs=[test_subdir])[0]
6476 return data
6477
6478 def testFitTeeOsOptionalFit(self):
6479 """Test an image with a FIT with an optional OP-TEE binary"""
6480 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6481
6482 # There should be only one node, holding the data set up in SetUpClass()
6483 # for tee.bin
6484 dtb = fdt.Fdt.FromData(data)
6485 dtb.Scan()
6486 node = dtb.GetNode('/images/tee-1')
6487 self.assertEqual(TEE_ADDR,
6488 fdt_util.fdt32_to_cpu(node.props['load'].value))
6489 self.assertEqual(TEE_ADDR,
6490 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6491 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6492
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006493 with test_util.capture_sys_output() as (stdout, stderr):
6494 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6495 err = stderr.getvalue()
6496 self.assertRegex(
6497 err,
6498 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6499
Simon Glassad5cfe12023-01-07 14:07:14 -07006500 def testFitTeeOsOptionalFitBad(self):
6501 """Test an image with a FIT with an optional OP-TEE binary"""
6502 with self.assertRaises(ValueError) as exc:
6503 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6504 self.assertIn(
6505 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6506 str(exc.exception))
6507
6508 def testFitTeeOsBad(self):
6509 """Test an OP-TEE binary with wrong formats"""
6510 self.make_tee_bin('tee.bad1', 123)
6511 with self.assertRaises(ValueError) as exc:
6512 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6513 self.assertIn(
6514 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6515 str(exc.exception))
6516
6517 self.make_tee_bin('tee.bad2', 0, b'extra data')
6518 with self.assertRaises(ValueError) as exc:
6519 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6520 self.assertIn(
6521 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6522 str(exc.exception))
6523
Simon Glass63328f12023-01-07 14:07:15 -07006524 def testExtblobOptional(self):
6525 """Test an image with an external blob that is optional"""
6526 with test_util.capture_sys_output() as (stdout, stderr):
6527 data = self._DoReadFile('266_blob_ext_opt.dts')
6528 self.assertEqual(REFCODE_DATA, data)
6529 err = stderr.getvalue()
6530 self.assertRegex(
6531 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006532 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006533
Simon Glass7447a9d2023-01-11 16:10:12 -07006534 def testSectionInner(self):
6535 """Test an inner section with a size"""
6536 data = self._DoReadFile('267_section_inner.dts')
6537 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6538 self.assertEqual(expected, data)
6539
Simon Glassa4948b22023-01-11 16:10:14 -07006540 def testNull(self):
6541 """Test an image with a null entry"""
6542 data = self._DoReadFile('268_null.dts')
6543 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6544
Simon Glassf1ee03b2023-01-11 16:10:16 -07006545 def testOverlap(self):
6546 """Test an image with a overlapping entry"""
6547 data = self._DoReadFile('269_overlap.dts')
6548 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6549
6550 image = control.images['image']
6551 entries = image.GetEntries()
6552
6553 self.assertIn('inset', entries)
6554 inset = entries['inset']
6555 self.assertEqual(1, inset.offset);
6556 self.assertEqual(1, inset.image_pos);
6557 self.assertEqual(2, inset.size);
6558
6559 def testOverlapNull(self):
6560 """Test an image with a null overlap"""
6561 data = self._DoReadFile('270_overlap_null.dts')
6562 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6563
6564 # Check the FMAP
6565 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6566 self.assertEqual(4, fhdr.nareas)
6567 fiter = iter(fentries)
6568
6569 fentry = next(fiter)
6570 self.assertEqual(b'SECTION', fentry.name)
6571 self.assertEqual(0, fentry.offset)
6572 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6573 self.assertEqual(0, fentry.flags)
6574
6575 fentry = next(fiter)
6576 self.assertEqual(b'U_BOOT', fentry.name)
6577 self.assertEqual(0, fentry.offset)
6578 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6579 self.assertEqual(0, fentry.flags)
6580
6581 # Make sure that the NULL entry appears in the FMAP
6582 fentry = next(fiter)
6583 self.assertEqual(b'NULL', fentry.name)
6584 self.assertEqual(1, fentry.offset)
6585 self.assertEqual(2, fentry.size)
6586 self.assertEqual(0, fentry.flags)
6587
6588 fentry = next(fiter)
6589 self.assertEqual(b'FMAP', fentry.name)
6590 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6591
6592 def testOverlapBad(self):
6593 """Test an image with a bad overlapping entry"""
6594 with self.assertRaises(ValueError) as exc:
6595 self._DoReadFile('271_overlap_bad.dts')
6596 self.assertIn(
6597 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6598 str(exc.exception))
6599
6600 def testOverlapNoOffset(self):
6601 """Test an image with a bad overlapping entry"""
6602 with self.assertRaises(ValueError) as exc:
6603 self._DoReadFile('272_overlap_no_size.dts')
6604 self.assertIn(
6605 "Node '/binman/inset': 'fill' entry is missing properties: size",
6606 str(exc.exception))
6607
Simon Glasse0035c92023-01-11 16:10:17 -07006608 def testBlobSymbol(self):
6609 """Test a blob with symbols read from an ELF file"""
6610 elf_fname = self.ElfTestFile('blob_syms')
6611 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6612 TestFunctional._MakeInputFile('blob_syms.bin',
6613 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6614
6615 data = self._DoReadFile('273_blob_symbol.dts')
6616
6617 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6618 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6619 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6620 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6621 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6622
6623 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6624 expected = sym_values
6625 self.assertEqual(expected, data[:len(expected)])
6626
Simon Glass49e9c002023-01-11 16:10:19 -07006627 def testOffsetFromElf(self):
6628 """Test a blob with symbols read from an ELF file"""
6629 elf_fname = self.ElfTestFile('blob_syms')
6630 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6631 TestFunctional._MakeInputFile('blob_syms.bin',
6632 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6633
6634 data = self._DoReadFile('274_offset_from_elf.dts')
6635
6636 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6637 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6638
6639 image = control.images['image']
6640 entries = image.GetEntries()
6641
6642 self.assertIn('inset', entries)
6643 inset = entries['inset']
6644
6645 self.assertEqual(base + 4, inset.offset);
6646 self.assertEqual(base + 4, inset.image_pos);
6647 self.assertEqual(4, inset.size);
6648
6649 self.assertIn('inset2', entries)
6650 inset = entries['inset2']
6651 self.assertEqual(base + 8, inset.offset);
6652 self.assertEqual(base + 8, inset.image_pos);
6653 self.assertEqual(4, inset.size);
6654
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006655 def testFitAlign(self):
6656 """Test an image with an FIT with aligned external data"""
6657 data = self._DoReadFile('275_fit_align.dts')
6658 self.assertEqual(4096, len(data))
6659
6660 dtb = fdt.Fdt.FromData(data)
6661 dtb.Scan()
6662
6663 props = self._GetPropTree(dtb, ['data-position'])
6664 expected = {
6665 'u-boot:data-position': 1024,
6666 'fdt-1:data-position': 2048,
6667 'fdt-2:data-position': 3072,
6668 }
6669 self.assertEqual(expected, props)
6670
Jonas Karlman490f73c2023-01-21 19:02:12 +00006671 def testFitFirmwareLoadables(self):
6672 """Test an image with an FIT that use fit,firmware"""
6673 if not elf.ELF_TOOLS:
6674 self.skipTest('Python elftools not available')
6675 entry_args = {
6676 'of-list': 'test-fdt1',
6677 'default-dt': 'test-fdt1',
6678 'atf-bl31-path': 'bl31.elf',
6679 'tee-os-path': 'missing.bin',
6680 }
6681 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006682 with test_util.capture_sys_output() as (stdout, stderr):
6683 data = self._DoReadFileDtb(
6684 '276_fit_firmware_loadables.dts',
6685 entry_args=entry_args,
6686 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006687
6688 dtb = fdt.Fdt.FromData(data)
6689 dtb.Scan()
6690
6691 node = dtb.GetNode('/configurations/conf-uboot-1')
6692 self.assertEqual('u-boot', node.props['firmware'].value)
6693 self.assertEqual(['atf-1', 'atf-2'],
6694 fdt_util.GetStringList(node, 'loadables'))
6695
6696 node = dtb.GetNode('/configurations/conf-atf-1')
6697 self.assertEqual('atf-1', node.props['firmware'].value)
6698 self.assertEqual(['u-boot', 'atf-2'],
6699 fdt_util.GetStringList(node, 'loadables'))
6700
6701 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6702 self.assertEqual('u-boot', node.props['firmware'].value)
6703 self.assertEqual(['atf-1', 'atf-2'],
6704 fdt_util.GetStringList(node, 'loadables'))
6705
6706 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6707 self.assertEqual('atf-1', node.props['firmware'].value)
6708 self.assertEqual(['u-boot', 'atf-2'],
6709 fdt_util.GetStringList(node, 'loadables'))
6710
6711 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6712 self.assertEqual('atf-1', node.props['firmware'].value)
6713 self.assertEqual(['u-boot', 'atf-2'],
6714 fdt_util.GetStringList(node, 'loadables'))
6715
Simon Glass9a1c7262023-02-22 12:14:49 -07006716 def testTooldir(self):
6717 """Test that we can specify the tooldir"""
6718 with test_util.capture_sys_output() as (stdout, stderr):
6719 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6720 'tool', '-l'))
6721 self.assertEqual('fred', bintool.Bintool.tooldir)
6722
6723 # Check that the toolpath is updated correctly
6724 self.assertEqual(['fred'], tools.tool_search_paths)
6725
6726 # Try with a few toolpaths; the tooldir should be at the end
6727 with test_util.capture_sys_output() as (stdout, stderr):
6728 self.assertEqual(0, self._DoBinman(
6729 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6730 'tool', '-l'))
6731 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6732
Simon Glass49b77e82023-03-02 17:02:44 -07006733 def testReplaceSectionEntry(self):
6734 """Test replacing an entry in a section"""
6735 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6736 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6737 expect_data, dts='241_replace_section_simple.dts')
6738 self.assertEqual(expect_data, entry_data)
6739
6740 entries = image.GetEntries()
6741 self.assertIn('section', entries)
6742 section = entries['section']
6743
6744 sect_entries = section.GetEntries()
6745 self.assertIn('blob', sect_entries)
6746 entry = sect_entries['blob']
6747 self.assertEqual(len(expect_data), entry.size)
6748
6749 fname = tools.get_output_filename('image-updated.bin')
6750 data = tools.read_file(fname)
6751
6752 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6753 self.assertEqual(expect_data, new_blob_data)
6754
6755 self.assertEqual(U_BOOT_DATA,
6756 data[entry.image_pos + len(expect_data):]
6757 [:len(U_BOOT_DATA)])
6758
6759 def testReplaceSectionDeep(self):
6760 """Test replacing an entry in two levels of sections"""
6761 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6762 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6763 'section/section/blob', expect_data,
6764 dts='278_replace_section_deep.dts')
6765 self.assertEqual(expect_data, entry_data)
6766
6767 entries = image.GetEntries()
6768 self.assertIn('section', entries)
6769 section = entries['section']
6770
6771 subentries = section.GetEntries()
6772 self.assertIn('section', subentries)
6773 section = subentries['section']
6774
6775 sect_entries = section.GetEntries()
6776 self.assertIn('blob', sect_entries)
6777 entry = sect_entries['blob']
6778 self.assertEqual(len(expect_data), entry.size)
6779
6780 fname = tools.get_output_filename('image-updated.bin')
6781 data = tools.read_file(fname)
6782
6783 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6784 self.assertEqual(expect_data, new_blob_data)
6785
6786 self.assertEqual(U_BOOT_DATA,
6787 data[entry.image_pos + len(expect_data):]
6788 [:len(U_BOOT_DATA)])
6789
6790 def testReplaceFitSibling(self):
6791 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006792 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006793 fname = TestFunctional._MakeInputFile('once', b'available once')
6794 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6795 os.remove(fname)
6796
6797 try:
6798 tmpdir, updated_fname = self._SetupImageInTmpdir()
6799
6800 fname = os.path.join(tmpdir, 'update-blob')
6801 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6802 tools.write_file(fname, expected)
6803
6804 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6805 data = tools.read_file(updated_fname)
6806 start = len(U_BOOT_DTB_DATA)
6807 self.assertEqual(expected, data[start:start + len(expected)])
6808 map_fname = os.path.join(tmpdir, 'image-updated.map')
6809 self.assertFalse(os.path.exists(map_fname))
6810 finally:
6811 shutil.rmtree(tmpdir)
6812
Simon Glassc3fe97f2023-03-02 17:02:45 -07006813 def testX509Cert(self):
6814 """Test creating an X509 certificate"""
6815 keyfile = self.TestFile('key.key')
6816 entry_args = {
6817 'keyfile': keyfile,
6818 }
6819 data = self._DoReadFileDtb('279_x509_cert.dts',
6820 entry_args=entry_args)[0]
6821 cert = data[:-4]
6822 self.assertEqual(U_BOOT_DATA, data[-4:])
6823
6824 # TODO: verify the signature
6825
6826 def testX509CertMissing(self):
6827 """Test that binman still produces an image if openssl is missing"""
6828 keyfile = self.TestFile('key.key')
6829 entry_args = {
6830 'keyfile': 'keyfile',
6831 }
6832 with test_util.capture_sys_output() as (_, stderr):
6833 self._DoTestFile('279_x509_cert.dts',
6834 force_missing_bintools='openssl',
6835 entry_args=entry_args)
6836 err = stderr.getvalue()
6837 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6838
Jonas Karlman35305492023-02-25 19:01:33 +00006839 def testPackRockchipTpl(self):
6840 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006841 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006842 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6843
Jonas Karlman1016ec72023-02-25 19:01:35 +00006844 def testMkimageMissingBlobMultiple(self):
6845 """Test missing blob with mkimage entry and multiple-data-files"""
6846 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006847 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006848 err = stderr.getvalue()
6849 self.assertIn("is missing external blobs and is non-functional", err)
6850
6851 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006852 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006853 self.assertIn("not found in input path", str(e.exception))
6854
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006855 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6856 """Prepare sign environment
6857
6858 Create private and public keys, add pubkey into dtb.
6859
6860 Returns:
6861 Tuple:
6862 FIT container
6863 Image name
6864 Private key
6865 DTB
6866 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006867 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006868 data = self._DoReadFileRealDtb(dts)
6869 updated_fname = tools.get_output_filename('image-updated.bin')
6870 tools.write_file(updated_fname, data)
6871 dtb = tools.get_output_filename('source.dtb')
6872 private_key = tools.get_output_filename('test_key.key')
6873 public_key = tools.get_output_filename('test_key.crt')
6874 fit = tools.get_output_filename('fit.fit')
6875 key_dir = tools.get_output_dir()
6876
6877 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6878 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6879 private_key, '-out', public_key)
6880 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6881 '-n', 'test_key', '-r', 'conf', dtb)
6882
6883 return fit, updated_fname, private_key, dtb
6884
6885 def testSignSimple(self):
6886 """Test that a FIT container can be signed in image"""
6887 is_signed = False
6888 fit, fname, private_key, dtb = self._PrepareSignEnv()
6889
6890 # do sign with private key
6891 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6892 ['fit'])
6893 is_signed = self._CheckSign(fit, dtb)
6894
6895 self.assertEqual(is_signed, True)
6896
6897 def testSignExactFIT(self):
6898 """Test that a FIT container can be signed and replaced in image"""
6899 is_signed = False
6900 fit, fname, private_key, dtb = self._PrepareSignEnv()
6901
6902 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6903 args = []
6904 if self.toolpath:
6905 for path in self.toolpath:
6906 args += ['--toolpath', path]
6907
6908 # do sign with private key
6909 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6910 'sha256,rsa4096', '-f', fit, 'fit')
6911 is_signed = self._CheckSign(fit, dtb)
6912
6913 self.assertEqual(is_signed, True)
6914
6915 def testSignNonFit(self):
6916 """Test a non-FIT entry cannot be signed"""
6917 is_signed = False
6918 fit, fname, private_key, _ = self._PrepareSignEnv(
6919 '281_sign_non_fit.dts')
6920
6921 # do sign with private key
6922 with self.assertRaises(ValueError) as e:
6923 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6924 'sha256,rsa4096', '-f', fit, 'u-boot')
6925 self.assertIn(
6926 "Node '/u-boot': Updating signatures is not supported with this entry type",
6927 str(e.exception))
6928
6929 def testSignMissingMkimage(self):
6930 """Test that FIT signing handles a missing mkimage tool"""
6931 fit, fname, private_key, _ = self._PrepareSignEnv()
6932
6933 # try to sign with a missing mkimage tool
6934 bintool.Bintool.set_missing_list(['mkimage'])
6935 with self.assertRaises(ValueError) as e:
6936 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6937 ['fit'])
6938 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6939
Simon Glass4abf7842023-07-18 07:23:54 -06006940 def testSymbolNoWrite(self):
6941 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006942 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006943 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6944 no_write_symbols=True)
6945
6946 def testSymbolNoWriteExpanded(self):
6947 """Test disabling of symbol writing in expanded entries"""
6948 entry_args = {
6949 'spl-dtb': '1',
6950 }
6951 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6952 U_BOOT_SPL_DTB_DATA, 0x38,
6953 entry_args=entry_args, use_expanded=True,
6954 no_write_symbols=True)
6955
Marek Vasutf7413f02023-07-18 07:23:58 -06006956 def testMkimageSpecial(self):
6957 """Test mkimage ignores special hash-1 node"""
6958 data = self._DoReadFile('283_mkimage_special.dts')
6959
6960 # Just check that the data appears in the file somewhere
6961 self.assertIn(U_BOOT_DATA, data)
6962
Simon Glass2d94c422023-07-18 07:23:59 -06006963 def testFitFdtList(self):
6964 """Test an image with an FIT with the fit,fdt-list-val option"""
6965 entry_args = {
6966 'default-dt': 'test-fdt2',
6967 }
6968 data = self._DoReadFileDtb(
6969 '284_fit_fdt_list.dts',
6970 entry_args=entry_args,
6971 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6972 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6973 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6974
Simon Glass83b8bfe2023-07-18 07:24:01 -06006975 def testSplEmptyBss(self):
6976 """Test an expanded SPL with a zero-size BSS"""
6977 # ELF file with a '__bss_size' symbol
6978 self._SetupSplElf(src_fname='bss_data_zero')
6979
6980 entry_args = {
6981 'spl-bss-pad': 'y',
6982 'spl-dtb': 'y',
6983 }
6984 data = self._DoReadFileDtb('285_spl_expand.dts',
6985 use_expanded=True, entry_args=entry_args)[0]
6986
Simon Glassfc792842023-07-18 07:24:04 -06006987 def testTemplate(self):
6988 """Test using a template"""
6989 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6990 data = self._DoReadFile('286_template.dts')
6991 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6992 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6993 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6994
Simon Glass09490b02023-07-22 21:43:52 -06006995 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6996 self.assertTrue(os.path.exists(dtb_fname1))
6997 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6998 dtb.Scan()
6999 node1 = dtb.GetNode('/binman/template')
7000 self.assertTrue(node1)
7001 vga = dtb.GetNode('/binman/first/intel-vga')
7002 self.assertTrue(vga)
7003
Simon Glass54825e12023-07-22 21:43:56 -06007004 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
7005 self.assertTrue(os.path.exists(dtb_fname2))
7006 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
7007 dtb2.Scan()
7008 node2 = dtb2.GetNode('/binman/template')
7009 self.assertFalse(node2)
7010
Simon Glass9909c112023-07-18 07:24:05 -06007011 def testTemplateBlobMulti(self):
7012 """Test using a template with 'multiple-images' enabled"""
7013 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
7014 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
7015 retcode = self._DoTestFile('287_template_multi.dts')
7016
7017 self.assertEqual(0, retcode)
7018 image = control.images['image']
7019 image_fname = tools.get_output_filename('my-image.bin')
7020 data = tools.read_file(image_fname)
7021 self.assertEqual(b'blob@@@@other', data)
7022
Simon Glass5dc511b2023-07-18 07:24:06 -06007023 def testTemplateFit(self):
7024 """Test using a template in a FIT"""
7025 fit_data = self._DoReadFile('288_template_fit.dts')
7026 fname = os.path.join(self._indir, 'fit_data.fit')
7027 tools.write_file(fname, fit_data)
7028 out = tools.run('dumpimage', '-l', fname)
7029
Simon Glassaa6e0552023-07-18 07:24:07 -06007030 def testTemplateSection(self):
7031 """Test using a template in a section (not at top level)"""
7032 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
7033 data = self._DoReadFile('289_template_section.dts')
7034 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
7035 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
7036 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
7037
Simon Glassf53a7bc2023-07-18 07:24:08 -06007038 def testMkimageSymbols(self):
7039 """Test using mkimage to build an image with symbols in it"""
7040 self._SetupSplElf('u_boot_binman_syms')
7041 data = self._DoReadFile('290_mkimage_sym.dts')
7042
7043 image = control.images['image']
7044 entries = image.GetEntries()
7045 self.assertIn('u-boot', entries)
7046 u_boot = entries['u-boot']
7047
7048 mkim = entries['mkimage']
7049 mkim_entries = mkim.GetEntries()
7050 self.assertIn('u-boot-spl', mkim_entries)
7051 spl = mkim_entries['u-boot-spl']
7052 self.assertIn('u-boot-spl2', mkim_entries)
7053 spl2 = mkim_entries['u-boot-spl2']
7054
7055 # skip the mkimage header and the area sizes
7056 mk_data = data[mkim.offset + 0x40:]
7057 size, term = struct.unpack('>LL', mk_data[:8])
7058
7059 # There should be only one image, so check that the zero terminator is
7060 # present
7061 self.assertEqual(0, term)
7062
7063 content = mk_data[8:8 + size]
7064
7065 # The image should contain the symbols from u_boot_binman_syms.c
7066 # Note that image_pos is adjusted by the base address of the image,
7067 # which is 0x10 in our test image
7068 spl_data = content[:0x18]
7069 content = content[0x1b:]
7070
7071 # After the header is a table of offsets for each image. There should
7072 # only be one image, then a 0 terminator, so figure out the real start
7073 # of the image data
7074 base = 0x40 + 8
7075
7076 # Check symbols in both u-boot-spl and u-boot-spl2
7077 for i in range(2):
7078 vals = struct.unpack('<LLQLL', spl_data)
7079
7080 # The image should contain the symbols from u_boot_binman_syms.c
7081 # Note that image_pos is adjusted by the base address of the image,
7082 # which is 0x10 in our 'u_boot_binman_syms' test image
7083 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
7084 self.assertEqual(base, vals[1])
7085 self.assertEqual(spl2.offset, vals[2])
7086 # figure out the internal positions of its components
7087 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
7088
7089 # Check that spl and spl2 are actually at the indicated positions
7090 self.assertEqual(
7091 elf.BINMAN_SYM_MAGIC_VALUE,
7092 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
7093 self.assertEqual(
7094 elf.BINMAN_SYM_MAGIC_VALUE,
7095 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
7096
7097 self.assertEqual(len(U_BOOT_DATA), vals[4])
7098
7099 # Move to next
7100 spl_data = content[:0x18]
7101
Simon Glass86b3e472023-07-22 21:43:57 -06007102 def testTemplatePhandle(self):
7103 """Test using a template in a node containing a phandle"""
7104 entry_args = {
7105 'atf-bl31-path': 'bl31.elf',
7106 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06007107 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007108 entry_args=entry_args)
7109 fname = tools.get_output_filename('image.bin')
7110 out = tools.run('dumpimage', '-l', fname)
7111
7112 # We should see the FIT description and one for each of the two images
7113 lines = out.splitlines()
7114 descs = [line.split()[-1] for line in lines if 'escription' in line]
7115 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7116
7117 def testTemplatePhandleDup(self):
7118 """Test using a template in a node containing a phandle"""
7119 entry_args = {
7120 'atf-bl31-path': 'bl31.elf',
7121 }
7122 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007123 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007124 entry_args=entry_args)
7125 self.assertIn(
7126 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7127 str(e.exception))
7128
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307129 def testTIBoardConfig(self):
7130 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007131 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307132 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7133
Neha Malcom Francis8cd04512024-01-05 17:09:17 +05307134 def testTIBoardConfigLint(self):
7135 """Test that an incorrectly linted config file would generate error"""
7136 with self.assertRaises(ValueError) as e:
7137 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7138 self.assertIn("Yamllint error", str(e.exception))
7139
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307140 def testTIBoardConfigCombined(self):
7141 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007142 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307143 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7144 self.assertGreater(data, configlen_noheader)
7145
7146 def testTIBoardConfigNoDataType(self):
7147 """Test that error is thrown when data type is not supported"""
7148 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007149 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307150 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007151
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307152 def testPackTiSecure(self):
7153 """Test that an image with a TI secured binary can be created"""
7154 keyfile = self.TestFile('key.key')
7155 entry_args = {
7156 'keyfile': keyfile,
7157 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007158 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307159 entry_args=entry_args)[0]
7160 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7161
Manorit Chawdhry2e523b02023-12-29 16:16:27 +05307162 def testPackTiSecureFirewall(self):
7163 """Test that an image with a TI secured binary can be created"""
7164 keyfile = self.TestFile('key.key')
7165 entry_args = {
7166 'keyfile': keyfile,
7167 }
7168 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7169 entry_args=entry_args)[0]
7170 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7171 entry_args=entry_args)[0]
7172 self.assertGreater(len(data_firewall),len(data_no_firewall))
7173
7174 def testPackTiSecureFirewallMissingProperty(self):
7175 """Test that an image with a TI secured binary can be created"""
7176 keyfile = self.TestFile('key.key')
7177 entry_args = {
7178 'keyfile': keyfile,
7179 }
7180 with self.assertRaises(ValueError) as e:
7181 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7182 entry_args=entry_args)[0]
7183 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7184
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307185 def testPackTiSecureMissingTool(self):
7186 """Test that an image with a TI secured binary (non-functional) can be created
7187 when openssl is missing"""
7188 keyfile = self.TestFile('key.key')
7189 entry_args = {
7190 'keyfile': keyfile,
7191 }
7192 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007193 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307194 force_missing_bintools='openssl',
7195 entry_args=entry_args)
7196 err = stderr.getvalue()
7197 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7198
7199 def testPackTiSecureROM(self):
7200 """Test that a ROM image with a TI secured binary can be created"""
7201 keyfile = self.TestFile('key.key')
7202 entry_args = {
7203 'keyfile': keyfile,
7204 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007205 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307206 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007207 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307208 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007209 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307210 entry_args=entry_args)[0]
7211 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7212 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7213 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7214
7215 def testPackTiSecureROMCombined(self):
7216 """Test that a ROM image with a TI secured binary can be created"""
7217 keyfile = self.TestFile('key.key')
7218 entry_args = {
7219 'keyfile': keyfile,
7220 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007221 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307222 entry_args=entry_args)[0]
7223 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7224
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007225 def testEncryptedNoAlgo(self):
7226 """Test encrypted node with missing required properties"""
7227 with self.assertRaises(ValueError) as e:
7228 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7229 self.assertIn(
7230 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7231 str(e.exception))
7232
7233 def testEncryptedInvalidIvfile(self):
7234 """Test encrypted node with invalid iv file"""
7235 with self.assertRaises(ValueError) as e:
7236 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7237 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7238 str(e.exception))
7239
7240 def testEncryptedMissingKey(self):
7241 """Test encrypted node with missing key properties"""
7242 with self.assertRaises(ValueError) as e:
7243 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7244 self.assertIn(
7245 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7246 str(e.exception))
7247
7248 def testEncryptedKeySource(self):
7249 """Test encrypted node with key-source property"""
7250 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7251
7252 dtb = fdt.Fdt.FromData(data)
7253 dtb.Scan()
7254
7255 node = dtb.GetNode('/images/u-boot/cipher')
7256 self.assertEqual('algo-name', node.props['algo'].value)
7257 self.assertEqual('key-source-value', node.props['key-source'].value)
7258 self.assertEqual(ENCRYPTED_IV_DATA,
7259 tools.to_bytes(''.join(node.props['iv'].value)))
7260 self.assertNotIn('key', node.props)
7261
7262 def testEncryptedKeyFile(self):
7263 """Test encrypted node with key-filename property"""
7264 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7265
7266 dtb = fdt.Fdt.FromData(data)
7267 dtb.Scan()
7268
7269 node = dtb.GetNode('/images/u-boot/cipher')
7270 self.assertEqual('algo-name', node.props['algo'].value)
7271 self.assertEqual(ENCRYPTED_IV_DATA,
7272 tools.to_bytes(''.join(node.props['iv'].value)))
7273 self.assertEqual(ENCRYPTED_KEY_DATA,
7274 tools.to_bytes(''.join(node.props['key'].value)))
7275 self.assertNotIn('key-source', node.props)
7276
Lukas Funkee901faf2023-07-18 13:53:13 +02007277
7278 def testSplPubkeyDtb(self):
Simon Glass4b861272024-07-20 11:49:41 +01007279 """Test u_boot_spl_pubkey_dtb etype"""
7280 data = tools.read_file(self.TestFile("key.pem"))
7281 self._MakeInputFile("key.crt", data)
7282 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7283 image = control.images['image']
7284 entries = image.GetEntries()
7285 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7286 dtb_data = dtb_entry.GetData()
7287 dtb = fdt.Fdt.FromData(dtb_data)
7288 dtb.Scan()
Lukas Funkee901faf2023-07-18 13:53:13 +02007289
Simon Glass4b861272024-07-20 11:49:41 +01007290 signature_node = dtb.GetNode('/signature')
7291 self.assertIsNotNone(signature_node)
7292 key_node = signature_node.FindNode("key-key")
7293 self.assertIsNotNone(key_node)
7294 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7295 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7296 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007297
Lukas Funke712e1062023-08-03 17:22:14 +02007298 def testXilinxBootgenSigning(self):
7299 """Test xilinx-bootgen etype"""
7300 bootgen = bintool.Bintool.create('bootgen')
7301 self._CheckBintool(bootgen)
7302 data = tools.read_file(self.TestFile("key.key"))
7303 self._MakeInputFile("psk.pem", data)
7304 self._MakeInputFile("ssk.pem", data)
7305 self._SetupPmuFwlElf()
7306 self._SetupSplElf()
7307 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7308 image_fname = tools.get_output_filename('image.bin')
7309
7310 # Read partition header table and check if authentication is enabled
7311 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7312 "-read", image_fname, "pht").splitlines()
7313 attributes = {"authentication": None,
7314 "core": None,
7315 "encryption": None}
7316
7317 for l in bootgen_out:
7318 for a in attributes.keys():
7319 if a in l:
7320 m = re.match(fr".*{a} \[([^]]+)\]", l)
7321 attributes[a] = m.group(1)
7322
7323 self.assertTrue(attributes['authentication'] == "rsa")
7324 self.assertTrue(attributes['core'] == "a53-0")
7325 self.assertTrue(attributes['encryption'] == "no")
7326
7327 def testXilinxBootgenSigningEncryption(self):
7328 """Test xilinx-bootgen etype"""
7329 bootgen = bintool.Bintool.create('bootgen')
7330 self._CheckBintool(bootgen)
7331 data = tools.read_file(self.TestFile("key.key"))
7332 self._MakeInputFile("psk.pem", data)
7333 self._MakeInputFile("ssk.pem", data)
7334 self._SetupPmuFwlElf()
7335 self._SetupSplElf()
7336 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7337 image_fname = tools.get_output_filename('image.bin')
7338
7339 # Read boot header in order to verify encryption source and
7340 # encryption parameter
7341 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7342 "-read", image_fname, "bh").splitlines()
7343 attributes = {"auth_only":
7344 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7345 "encryption_keystore":
7346 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7347 "value": None},
7348 }
7349
7350 for l in bootgen_out:
7351 for a in attributes.keys():
7352 if a in l:
7353 m = re.match(attributes[a]['re'], l)
7354 attributes[a] = m.group(1)
7355
7356 # Check if fsbl-attribute is set correctly
7357 self.assertTrue(attributes['auth_only'] == "true")
7358 # Check if key is stored in efuse
7359 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7360
7361 def testXilinxBootgenMissing(self):
7362 """Test that binman still produces an image if bootgen is missing"""
7363 data = tools.read_file(self.TestFile("key.key"))
7364 self._MakeInputFile("psk.pem", data)
7365 self._MakeInputFile("ssk.pem", data)
7366 self._SetupPmuFwlElf()
7367 self._SetupSplElf()
7368 with test_util.capture_sys_output() as (_, stderr):
7369 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7370 force_missing_bintools='bootgen')
7371 err = stderr.getvalue()
7372 self.assertRegex(err,
7373 "Image 'image'.*missing bintools.*: bootgen")
7374
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307375 def _GetCapsuleHeaders(self, data):
7376 """Get the capsule header contents
7377
7378 Args:
7379 data: Capsule file contents
7380
7381 Returns:
7382 Dict:
7383 key: Capsule Header name (str)
7384 value: Header field value (str)
7385 """
7386 capsule_file = os.path.join(self._indir, 'test.capsule')
7387 tools.write_file(capsule_file, data)
7388
7389 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7390 lines = out.splitlines()
7391
7392 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7393 vals = {}
7394 for line in lines:
7395 mat = re_line.match(line)
7396 if mat:
7397 vals[mat.group(1)] = mat.group(2)
7398
7399 return vals
7400
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307401 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7402 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307403 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7404 fmp_size = "00000010"
7405 fmp_fw_version = "00000002"
7406 capsule_image_index = "00000001"
7407 oemflag = "00018000"
7408 auth_hdr_revision = "00000200"
7409 auth_hdr_cert_type = "00000EF1"
7410
7411 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307412
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307413 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307414
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307415 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307416
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307417 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7418 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7419 self.assertEqual(capsule_image_index,
7420 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307421
7422 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307423 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7424
7425 if signed_capsule:
7426 self.assertEqual(auth_hdr_revision,
7427 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7428 self.assertEqual(auth_hdr_cert_type,
7429 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7430 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7431 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7432
7433 if version_check:
7434 self.assertEqual(fmp_signature,
7435 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7436 self.assertEqual(fmp_size,
7437 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7438 self.assertEqual(fmp_fw_version,
7439 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7440
7441 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307442
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307443 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7444 if accept_capsule:
7445 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7446 else:
7447 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7448
7449 hdr = self._GetCapsuleHeaders(data)
7450
7451 self.assertEqual(capsule_hdr_guid.upper(),
7452 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7453
7454 if accept_capsule:
7455 capsule_size = "0000002C"
7456 else:
7457 capsule_size = "0000001C"
7458 self.assertEqual(capsule_size,
7459 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7460
7461 if accept_capsule:
7462 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7463
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307464 def testCapsuleGen(self):
7465 """Test generation of EFI capsule"""
7466 data = self._DoReadFile('311_capsule.dts')
7467
7468 self._CheckCapsule(data)
7469
7470 def testSignedCapsuleGen(self):
7471 """Test generation of EFI capsule"""
7472 data = tools.read_file(self.TestFile("key.key"))
7473 self._MakeInputFile("key.key", data)
7474 data = tools.read_file(self.TestFile("key.pem"))
7475 self._MakeInputFile("key.crt", data)
7476
7477 data = self._DoReadFile('312_capsule_signed.dts')
7478
7479 self._CheckCapsule(data, signed_capsule=True)
7480
7481 def testCapsuleGenVersionSupport(self):
7482 """Test generation of EFI capsule with version support"""
7483 data = self._DoReadFile('313_capsule_version.dts')
7484
7485 self._CheckCapsule(data, version_check=True)
7486
7487 def testCapsuleGenSignedVer(self):
7488 """Test generation of signed EFI capsule with version information"""
7489 data = tools.read_file(self.TestFile("key.key"))
7490 self._MakeInputFile("key.key", data)
7491 data = tools.read_file(self.TestFile("key.pem"))
7492 self._MakeInputFile("key.crt", data)
7493
7494 data = self._DoReadFile('314_capsule_signed_ver.dts')
7495
7496 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7497
7498 def testCapsuleGenCapOemFlags(self):
7499 """Test generation of EFI capsule with OEM Flags set"""
7500 data = self._DoReadFile('315_capsule_oemflags.dts')
7501
7502 self._CheckCapsule(data, capoemflags=True)
7503
7504 def testCapsuleGenKeyMissing(self):
7505 """Test that binman errors out on missing key"""
7506 with self.assertRaises(ValueError) as e:
7507 self._DoReadFile('316_capsule_missing_key.dts')
7508
7509 self.assertIn("Both private key and public key certificate need to be provided",
7510 str(e.exception))
7511
7512 def testCapsuleGenIndexMissing(self):
7513 """Test that binman errors out on missing image index"""
7514 with self.assertRaises(ValueError) as e:
7515 self._DoReadFile('317_capsule_missing_index.dts')
7516
7517 self.assertIn("entry is missing properties: image-index",
7518 str(e.exception))
7519
7520 def testCapsuleGenGuidMissing(self):
7521 """Test that binman errors out on missing image GUID"""
7522 with self.assertRaises(ValueError) as e:
7523 self._DoReadFile('318_capsule_missing_guid.dts')
7524
7525 self.assertIn("entry is missing properties: image-guid",
7526 str(e.exception))
7527
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307528 def testCapsuleGenAcceptCapsule(self):
7529 """Test generationg of accept EFI capsule"""
7530 data = self._DoReadFile('319_capsule_accept.dts')
7531
7532 self._CheckEmptyCapsule(data, accept_capsule=True)
7533
7534 def testCapsuleGenRevertCapsule(self):
7535 """Test generationg of revert EFI capsule"""
7536 data = self._DoReadFile('320_capsule_revert.dts')
7537
7538 self._CheckEmptyCapsule(data)
7539
7540 def testCapsuleGenAcceptGuidMissing(self):
7541 """Test that binman errors out on missing image GUID for accept capsule"""
7542 with self.assertRaises(ValueError) as e:
7543 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7544
7545 self.assertIn("Image GUID needed for generating accept capsule",
7546 str(e.exception))
7547
7548 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7549 """Test that capsule-type is specified"""
7550 with self.assertRaises(ValueError) as e:
7551 self._DoReadFile('322_empty_capsule_type_missing.dts')
7552
7553 self.assertIn("entry is missing properties: capsule-type",
7554 str(e.exception))
7555
7556 def testCapsuleGenAcceptOrRevertMissing(self):
7557 """Test that both accept and revert capsule are not specified"""
7558 with self.assertRaises(ValueError) as e:
7559 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7560
Simon Glassa360b8f2024-06-23 11:55:06 -06007561 def test_assume_size(self):
7562 """Test handling of the assume-size property for external blob"""
7563 with self.assertRaises(ValueError) as e:
7564 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7565 allow_fake_blobs=True)
7566 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7567 str(e.exception))
7568
7569 def test_assume_size_ok(self):
7570 """Test handling of the assume-size where it fits OK"""
7571 with test_util.capture_sys_output() as (stdout, stderr):
7572 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7573 allow_fake_blobs=True)
7574 err = stderr.getvalue()
7575 self.assertRegex(
7576 err,
7577 "Image '.*' has faked external blobs and is non-functional: .*")
7578
7579 def test_assume_size_no_fake(self):
7580 """Test handling of the assume-size where it fits OK"""
7581 with test_util.capture_sys_output() as (stdout, stderr):
7582 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7583 err = stderr.getvalue()
7584 self.assertRegex(
7585 err,
7586 "Image '.*' is missing external blobs and is non-functional: .*")
7587
Simon Glass5f7aadf2024-07-20 11:49:47 +01007588 def SetupAlternateDts(self):
7589 """Compile the .dts test files for alternative-fdt
7590
7591 Returns:
7592 tuple:
7593 str: Test directory created
7594 list of str: '.bin' files which we expect Binman to create
7595 """
7596 testdir = TestFunctional._MakeInputDir('dtb')
7597 dtb_list = []
7598 for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
7599 tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
7600 base = os.path.splitext(os.path.basename(fname))[0]
7601 dtb_list.append(base + '.bin')
7602 shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
7603
7604 return testdir, dtb_list
7605
Simon Glassf3598922024-07-20 11:49:45 +01007606 def CheckAlternates(self, dts, phase, xpl_data):
7607 """Run the test for the alterative-fdt etype
7608
7609 Args:
7610 dts (str): Devicetree file to process
7611 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7612 xpl_data (bytes): Expected data for the phase's binary
7613
7614 Returns:
7615 dict of .dtb files produced
7616 key: str filename
7617 value: Fdt object
7618 """
Simon Glass5f7aadf2024-07-20 11:49:47 +01007619 dtb_list = self.SetupAlternateDts()[1]
Simon Glassf3598922024-07-20 11:49:45 +01007620
7621 entry_args = {
7622 f'{phase}-dtb': '1',
7623 f'{phase}-bss-pad': 'y',
7624 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7625 }
7626 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7627 use_expanded=True, entry_args=entry_args)[0]
7628 self.assertEqual(xpl_data, data[:len(xpl_data)])
7629 rest = data[len(xpl_data):]
7630 pad_len = 10
7631 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7632
7633 # Check the dtb is using the test file
7634 dtb_data = rest[pad_len:]
7635 dtb = fdt.Fdt.FromData(dtb_data)
7636 dtb.Scan()
7637 fdt_size = dtb.GetFdtObj().totalsize()
7638 self.assertEqual('model-not-set',
7639 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7640
7641 pad_len = 10
7642
7643 # Check the other output files
7644 dtbs = {}
7645 for fname in dtb_list:
7646 pathname = tools.get_output_filename(fname)
7647 self.assertTrue(os.path.exists(pathname))
7648
7649 data = tools.read_file(pathname)
7650 self.assertEqual(xpl_data, data[:len(xpl_data)])
7651 rest = data[len(xpl_data):]
7652
7653 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7654 rest = rest[pad_len:]
7655
7656 dtb = fdt.Fdt.FromData(rest)
7657 dtb.Scan()
7658 dtbs[fname] = dtb
7659
7660 expected = 'one' if '1' in fname else 'two'
7661 self.assertEqual(f'u-boot,model-{expected}',
7662 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7663
7664 # Make sure the FDT is the same size as the 'main' one
7665 rest = rest[fdt_size:]
7666
7667 self.assertEqual(b'', rest)
7668 return dtbs
7669
7670 def testAlternatesFdt(self):
7671 """Test handling of alternates-fdt etype"""
7672 self._SetupTplElf()
7673 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7674 U_BOOT_TPL_NODTB_DATA)
7675 for dtb in dtbs.values():
7676 # Check for the node with the tag
7677 node = dtb.GetNode('/node')
7678 self.assertIsNotNone(node)
7679 self.assertEqual(5, len(node.props.keys()))
7680
7681 # Make sure the other node is still there
7682 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7683
7684 def testAlternatesFdtgrep(self):
7685 """Test handling of alternates-fdt etype using fdtgrep"""
7686 self._SetupTplElf()
7687 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7688 U_BOOT_TPL_NODTB_DATA)
7689 for dtb in dtbs.values():
7690 # Check for the node with the tag
7691 node = dtb.GetNode('/node')
7692 self.assertIsNotNone(node)
7693 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7694 node.props.keys())
7695
7696 # Make sure the other node is gone
7697 self.assertIsNone(dtb.GetNode('/node/other-node'))
7698
7699 def testAlternatesFdtgrepVpl(self):
7700 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7701 self._SetupVplElf()
7702 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7703 U_BOOT_VPL_NODTB_DATA)
7704
7705 def testAlternatesFdtgrepSpl(self):
7706 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7707 self._SetupSplElf()
7708 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7709 U_BOOT_SPL_NODTB_DATA)
7710
7711 def testAlternatesFdtgrepInval(self):
7712 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7713 self._SetupSplElf()
7714 with self.assertRaises(ValueError) as e:
7715 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7716 U_BOOT_SPL_NODTB_DATA)
7717 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7718 str(e.exception))
7719
Simon Glasscd2783e2024-07-20 11:49:46 +01007720 def testFitFdtListDir(self):
7721 """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
Simon Glass1bba8942024-08-26 13:11:34 -06007722 old_dir = os.getcwd()
7723 try:
7724 os.chdir(self._indir)
7725 self.CheckFitFdt('333_fit_fdt_dir.dts', False)
7726 finally:
7727 os.chdir(old_dir)
Simon Glasscd2783e2024-07-20 11:49:46 +01007728
Simon Glassd2a9d6e2024-08-26 13:11:37 -06007729 def testFitFdtListDirDefault(self):
7730 """Test an FIT fit,fdt-list-dir where the default DT in is a subdir"""
7731 old_dir = os.getcwd()
7732 try:
7733 os.chdir(self._indir)
7734 self.CheckFitFdt('333_fit_fdt_dir.dts', False,
7735 default_dt='rockchip/test-fdt2')
7736 finally:
7737 os.chdir(old_dir)
7738
Simon Glass5f7aadf2024-07-20 11:49:47 +01007739 def testFitFdtCompat(self):
7740 """Test an image with an FIT with compatible in the config nodes"""
7741 entry_args = {
7742 'of-list': 'model1 model2',
7743 'default-dt': 'model2',
7744 }
7745 testdir, dtb_list = self.SetupAlternateDts()
7746 data = self._DoReadFileDtb(
7747 '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
7748 entry_args=entry_args, extra_indirs=[testdir])[0]
7749
7750 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7751
7752 fit = fdt.Fdt.FromData(fit_data)
7753 fit.Scan()
7754
7755 cnode = fit.GetNode('/configurations')
7756 self.assertIn('default', cnode.props)
7757 self.assertEqual('config-2', cnode.props['default'].value)
7758
7759 for seq in range(1, 2):
7760 name = f'config-{seq}'
7761 fnode = fit.GetNode('/configurations/%s' % name)
7762 self.assertIsNotNone(fnode)
7763 self.assertIn('compatible', fnode.props.keys())
7764 expected = 'one' if seq == 1 else 'two'
7765 self.assertEqual(f'u-boot,model-{expected}',
7766 fnode.props['compatible'].value)
7767
Simon Glassa04b9942024-07-20 11:49:48 +01007768 def testFitFdtPhase(self):
7769 """Test an image with an FIT with fdt-phase in the fdt nodes"""
7770 phase = 'tpl'
7771 entry_args = {
7772 f'{phase}-dtb': '1',
7773 f'{phase}-bss-pad': 'y',
7774 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7775 'of-list': 'model1 model2',
7776 'default-dt': 'model2',
7777 }
7778 testdir, dtb_list = self.SetupAlternateDts()
7779 data = self._DoReadFileDtb(
7780 '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
7781 entry_args=entry_args, extra_indirs=[testdir])[0]
7782 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7783 fit = fdt.Fdt.FromData(fit_data)
7784 fit.Scan()
7785
7786 # Check that each FDT has only the expected properties for the phase
7787 for seq in range(1, 2):
7788 fnode = fit.GetNode(f'/images/fdt-{seq}')
7789 self.assertIsNotNone(fnode)
7790 dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
7791 dtb.Scan()
7792
7793 # Make sure that the 'bootph-pre-sram' tag in /node protects it from
7794 # removal
7795 node = dtb.GetNode('/node')
7796 self.assertIsNotNone(node)
7797 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7798 node.props.keys())
7799
7800 # Make sure the other node is gone
7801 self.assertIsNone(dtb.GetNode('/node/other-node'))
7802
Simon Glassb553e8a2024-08-26 13:11:29 -06007803 def testMkeficapsuleMissing(self):
7804 """Test that binman complains if mkeficapsule is missing"""
7805 with self.assertRaises(ValueError) as e:
7806 self._DoTestFile('311_capsule.dts',
7807 force_missing_bintools='mkeficapsule')
7808 self.assertIn("Node '/binman/efi-capsule': Missing tool: 'mkeficapsule'",
7809 str(e.exception))
7810
7811 def testMkeficapsuleMissingOk(self):
7812 """Test that binman deals with mkeficapsule being missing"""
7813 with test_util.capture_sys_output() as (stdout, stderr):
7814 ret = self._DoTestFile('311_capsule.dts',
7815 force_missing_bintools='mkeficapsule',
7816 allow_missing=True)
7817 self.assertEqual(103, ret)
7818 err = stderr.getvalue()
7819 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkeficapsule")
7820
Simon Glass4b0f4142024-08-26 13:11:40 -06007821 def testSymbolsBase(self):
7822 """Test handling of symbols-base"""
7823 self.checkSymbols('336_symbols_base.dts', U_BOOT_SPL_DATA, 0x1c,
7824 symbols_base=0)
7825
7826 def testSymbolsBaseExpanded(self):
7827 """Test handling of symbols-base with expanded entries"""
7828 entry_args = {
7829 'spl-dtb': '1',
7830 }
7831 self.checkSymbols('337_symbols_base_expand.dts', U_BOOT_SPL_NODTB_DATA +
7832 U_BOOT_SPL_DTB_DATA, 0x38,
7833 entry_args=entry_args, use_expanded=True,
7834 symbols_base=0)
7835
Simon Glass3eb30a42024-08-26 13:11:42 -06007836 def testSymbolsCompressed(self):
7837 """Test binman complains about symbols from a compressed section"""
7838 with test_util.capture_sys_output() as (stdout, stderr):
7839 self.checkSymbols('338_symbols_comp.dts', U_BOOT_SPL_DATA, None)
7840 out = stdout.getvalue()
7841 self.assertIn('Symbol-writing: no value for /binman/section/u-boot',
7842 out)
7843
Simon Glass9c25ef22024-08-26 13:11:43 -06007844 def testNxpImx8Image(self):
7845 """Test that binman can produce an iMX8 image"""
7846 self._DoTestFile('339_nxp_imx8.dts')
7847
Alexander Kochetkova730a282024-09-16 11:24:46 +03007848 def testFitSignSimple(self):
7849 """Test that image with FIT and signature nodes can be signed"""
7850 if not elf.ELF_TOOLS:
7851 self.skipTest('Python elftools not available')
7852 entry_args = {
7853 'of-list': 'test-fdt1',
7854 'default-dt': 'test-fdt1',
7855 'atf-bl31-path': 'bl31.elf',
7856 }
7857 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7858 self._MakeInputFile("keys/rsa2048.key", data)
7859
7860 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7861 keys_subdir = os.path.join(self._indir, "keys")
7862 data = self._DoReadFileDtb(
7863 '340_fit_signature.dts',
7864 entry_args=entry_args,
7865 extra_indirs=[test_subdir, keys_subdir])[0]
7866
7867 dtb = fdt.Fdt.FromData(data)
7868 dtb.Scan()
7869
7870 conf = dtb.GetNode('/configurations/conf-uboot-1')
7871 self.assertIsNotNone(conf)
7872 signature = conf.FindNode('signature')
7873 self.assertIsNotNone(signature)
7874 self.assertIsNotNone(signature.props.get('value'))
7875
7876 images = dtb.GetNode('/images')
7877 self.assertIsNotNone(images)
7878 for subnode in images.subnodes:
7879 signature = subnode.FindNode('signature')
7880 self.assertIsNotNone(signature)
7881 self.assertIsNotNone(signature.props.get('value'))
7882
7883 def testFitSignKeyNotFound(self):
7884 """Test that missing keys raise an error"""
7885 if not elf.ELF_TOOLS:
7886 self.skipTest('Python elftools not available')
7887 entry_args = {
7888 'of-list': 'test-fdt1',
7889 'default-dt': 'test-fdt1',
7890 'atf-bl31-path': 'bl31.elf',
7891 }
7892 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7893 with self.assertRaises(ValueError) as e:
7894 self._DoReadFileDtb(
7895 '340_fit_signature.dts',
7896 entry_args=entry_args,
7897 extra_indirs=[test_subdir])[0]
7898 self.assertIn(
7899 'Filename \'rsa2048.key\' not found in input path',
7900 str(e.exception))
7901
7902 def testFitSignMultipleKeyPaths(self):
7903 """Test that keys found in multiple paths raise an error"""
7904 if not elf.ELF_TOOLS:
7905 self.skipTest('Python elftools not available')
7906 entry_args = {
7907 'of-list': 'test-fdt1',
7908 'default-dt': 'test-fdt1',
7909 'atf-bl31-path': 'bl31.elf',
7910 }
7911 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7912 self._MakeInputFile("keys1/rsa2048.key", data)
7913 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7914 self._MakeInputFile("keys2/conf-rsa2048.key", data)
7915
7916 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7917 keys_subdir1 = os.path.join(self._indir, "keys1")
7918 keys_subdir2 = os.path.join(self._indir, "keys2")
7919 with self.assertRaises(ValueError) as e:
7920 self._DoReadFileDtb(
7921 '341_fit_signature.dts',
7922 entry_args=entry_args,
7923 extra_indirs=[test_subdir, keys_subdir1, keys_subdir2])[0]
7924 self.assertIn(
7925 'Node \'/binman/fit\': multiple key paths found',
7926 str(e.exception))
7927
7928 def testFitSignNoSingatureNodes(self):
7929 """Test that fit,sign doens't raise error if no signature nodes found"""
7930 if not elf.ELF_TOOLS:
7931 self.skipTest('Python elftools not available')
7932 entry_args = {
7933 'of-list': 'test-fdt1',
7934 'default-dt': 'test-fdt1',
7935 'atf-bl31-path': 'bl31.elf',
7936 }
7937 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7938 self._DoReadFileDtb(
7939 '342_fit_signature.dts',
7940 entry_args=entry_args,
7941 extra_indirs=[test_subdir])[0]
7942
Simon Glassa360b8f2024-06-23 11:55:06 -06007943
Paul HENRYSff318462024-11-25 18:47:17 +01007944 def testSimpleFitEncryptedData(self):
7945 """Test an image with a FIT containing data to be encrypted"""
7946 data = tools.read_file(self.TestFile("aes256.bin"))
7947 self._MakeInputFile("keys/aes256.bin", data)
7948
7949 keys_subdir = os.path.join(self._indir, "keys")
7950 data = self._DoReadFileDtb(
7951 '343_fit_encrypt_data.dts',
7952 extra_indirs=[keys_subdir])[0]
7953
7954 fit = fdt.Fdt.FromData(data)
7955 fit.Scan()
7956
7957 # Extract the encrypted data and the Initialization Vector from the FIT
7958 node = fit.GetNode('/images/u-boot')
7959 subnode = fit.GetNode('/images/u-boot/cipher')
7960 data_size_unciphered = int.from_bytes(fit.GetProps(node)['data-size-unciphered'].bytes,
7961 byteorder='big')
7962 self.assertEqual(data_size_unciphered, len(U_BOOT_NODTB_DATA))
7963
7964 # Retrieve the key name from the FIT removing any null byte
7965 key_name = fit.GetProps(subnode)['key-name-hint'].bytes.replace(b'\x00', b'')
7966 with open(self.TestFile(key_name.decode('ascii') + '.bin'), 'rb') as file:
7967 key = file.read()
7968 iv = fit.GetProps(subnode)['iv'].bytes.hex()
7969 enc_data = fit.GetProps(node)['data'].bytes
7970 outdir = tools.get_output_dir()
7971 enc_data_file = os.path.join(outdir, 'encrypted_data.bin')
7972 tools.write_file(enc_data_file, enc_data)
7973 data_file = os.path.join(outdir, 'data.bin')
7974
7975 # Decrypt the encrypted data from the FIT and compare the data
7976 tools.run('openssl', 'enc', '-aes-256-cbc', '-nosalt', '-d', '-in',
7977 enc_data_file, '-out', data_file, '-K', key.hex(), '-iv', iv)
7978 with open(data_file, 'r') as file:
7979 dec_data = file.read()
7980 self.assertEqual(U_BOOT_NODTB_DATA, dec_data.encode('ascii'))
7981
7982 def testSimpleFitEncryptedDataMissingKey(self):
7983 """Test an image with a FIT containing data to be encrypted but with a missing key"""
7984 with self.assertRaises(ValueError) as e:
7985 self._DoReadFile('344_fit_encrypt_data_no_key.dts')
7986
7987 self.assertIn("Filename 'aes256.bin' not found in input path", str(e.exception))
7988
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01007989 def testFitFdtName(self):
7990 """Test an image with an FIT with multiple FDT images using NAME"""
7991 self.CheckFitFdt('345_fit_fdt_name.dts', use_seq_num=False)
7992
Neha Malcom Francisa25b4832025-03-17 10:24:20 +05307993 def testRemoveTemplate(self):
7994 """Test whether template is removed"""
7995 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
7996 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
7997 self._DoTestFile('346_remove_template.dts',
7998 force_missing_bintools='openssl',)
7999
Simon Glassac599912017-11-12 21:52:22 -07008000if __name__ == "__main__":
8001 unittest.main()