blob: 4a2a9f2288524e5fa9400ea54ff12b873ba0f393 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass57454f42016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass57454f42016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glass45d556d2020-07-09 18:39:45 -06009import collections
Simon Glassf3598922024-07-20 11:49:45 +010010import glob
Simon Glassc585dd42020-04-17 18:09:03 -060011import gzip
Simon Glassae7cf032018-09-14 04:57:31 -060012import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070013from optparse import OptionParser
14import os
Simon Glass45d556d2020-07-09 18:39:45 -060015import re
Simon Glass57454f42016-11-25 20:15:52 -070016import shutil
17import struct
18import sys
19import tempfile
20import unittest
Simon Glass162017b2022-01-09 20:13:57 -070021import unittest.mock
22import urllib.error
Simon Glass57454f42016-11-25 20:15:52 -070023
Simon Glass4eae9252022-01-09 20:13:50 -070024from binman import bintool
Simon Glassc585dd42020-04-17 18:09:03 -060025from binman import cbfs_util
26from binman import cmdline
27from binman import control
28from binman import elf
29from binman import elf_test
Simon Glass3efb2972021-11-23 21:08:59 -070030from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060031from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060032from binman import state
33from dtoc import fdt
34from dtoc import fdt_util
35from binman.etype import fdtmap
36from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060037from binman.image import Image
Simon Glass131444f2023-02-23 18:18:04 -070038from u_boot_pylib import command
39from u_boot_pylib import test_util
40from u_boot_pylib import tools
41from u_boot_pylib import tout
Simon Glass57454f42016-11-25 20:15:52 -070042
43# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060044U_BOOT_DATA = b'1234'
45U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +030046U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass56d05412022-02-28 07:16:54 -070048U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glass303f62f2019-05-17 22:00:46 -060049BLOB_DATA = b'89'
50ME_DATA = b'0abcd'
51VGA_DATA = b'vga'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +053052EFI_CAPSULE_DATA = b'efi'
Simon Glass303f62f2019-05-17 22:00:46 -060053U_BOOT_DTB_DATA = b'udtb'
54U_BOOT_SPL_DTB_DATA = b'spldtb'
55U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass56d05412022-02-28 07:16:54 -070056U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glass303f62f2019-05-17 22:00:46 -060057X86_START16_DATA = b'start16'
58X86_START16_SPL_DATA = b'start16spl'
59X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060060X86_RESET16_DATA = b'reset16'
61X86_RESET16_SPL_DATA = b'reset16spl'
62X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060063PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
64U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
65U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
66U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass56d05412022-02-28 07:16:54 -070067U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +030068U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
69U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
70U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glass303f62f2019-05-17 22:00:46 -060071FSP_DATA = b'fsp'
72CMC_DATA = b'cmc'
73VBT_DATA = b'vbt'
74MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060075TEXT_DATA = 'text'
76TEXT_DATA2 = 'text2'
77TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060078CROS_EC_RW_DATA = b'ecrw'
79GBB_DATA = b'gbbd'
80BMPBLK_DATA = b'bmp'
81VBLOCK_DATA = b'vblk'
82FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
83 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060084COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060085COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060086REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060087FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060088FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060089FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060090ATF_BL31_DATA = b'bl31'
Roger Quadros5cdcea02022-02-19 20:50:04 +020091TEE_OS_DATA = b'this is some tee OS data'
Neha Malcom Francis59be2552023-12-05 15:12:18 +053092TI_DM_DATA = b'tidmtidm'
Simon Glass3efb2972021-11-23 21:08:59 -070093ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080094OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050095SCP_DATA = b'scp'
Jonas Karlman35305492023-02-25 19:01:33 +000096ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glassa435cd12020-09-01 05:13:59 -060097TEST_FDT1_DATA = b'fdt1'
98TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060099ENV_DATA = b'var1=1\nvar2="2"'
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200100ENCRYPTED_IV_DATA = b'123456'
101ENCRYPTED_KEY_DATA = b'abcde'
Philippe Reynesebe96cb2022-03-28 22:57:04 +0200102PRE_LOAD_MAGIC = b'UBSH'
103PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
104PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530105TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530106TI_UNSECURE_DATA = b'unsecuredata'
Simon Glassa435cd12020-09-01 05:13:59 -0600107
108# Subdirectory of the input dir to use to put test FDTs
109TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600110
Simon Glass2c6adba2019-07-20 12:23:47 -0600111# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600112EXTRACT_DTB_SIZE = 0x3c9
113
Simon Glass2c6adba2019-07-20 12:23:47 -0600114# Properties expected to be in the device tree when update_dtb is used
115BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
116
Simon Glassfb30e292019-07-20 12:23:51 -0600117# Extra properties expected to be in the device tree when allow-repack is used
118REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
119
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200120# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200121COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700122
Simon Glassad5cfe12023-01-07 14:07:14 -0700123TEE_ADDR = 0x5678
124
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530125# Firmware Management Protocol(FMP) GUID
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530126FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530127# Image GUID specified in the DTS
Caleb Connolly4bdc9602024-08-30 13:34:35 +0100128CAPSULE_IMAGE_GUID = '985F2937-7C2E-5E9A-8A5E-8E063312964B'
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530129# Windows cert GUID
130WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +0530131# Empty capsule GUIDs
132EMPTY_CAPSULE_ACCEPT_GUID = '0c996046-bcc0-4d04-85ec-e1fcedf1c6f8'
133EMPTY_CAPSULE_REVERT_GUID = 'acd58b4b-c0e8-475f-99b5-6b3f7e07aaf0'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530134
Simon Glass57454f42016-11-25 20:15:52 -0700135class TestFunctional(unittest.TestCase):
136 """Functional tests for binman
137
138 Most of these use a sample .dts file to build an image and then check
139 that it looks correct. The sample files are in the test/ subdirectory
140 and are numbered.
141
142 For each entry type a very small test file is created using fixed
143 string contents. This makes it easy to test that things look right, and
144 debug problems.
145
146 In some cases a 'real' file must be used - these are also supplied in
147 the test/ diurectory.
148 """
149 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600150 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700151 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600152 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700153
Simon Glass57454f42016-11-25 20:15:52 -0700154 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600155 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
156 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700157
158 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600159 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700160
161 # Create some test files
162 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
163 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
164 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600165 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700166 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700167 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700168 TestFunctional._MakeInputFile('me.bin', ME_DATA)
169 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600170 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600171
Jagdish Gediya311d4842018-09-03 21:35:08 +0530172 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600173
Simon Glassabab18c2019-08-24 07:22:49 -0600174 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
175 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700176 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600177 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600178 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600179
180 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
181 X86_RESET16_DATA)
182 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
183 X86_RESET16_SPL_DATA)
184 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
185 X86_RESET16_TPL_DATA)
186
Simon Glass57454f42016-11-25 20:15:52 -0700187 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700188 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
189 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600190 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
191 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700192 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
193 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700194 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
195 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700196 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700197 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600198 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600199 TestFunctional._MakeInputDir('devkeys')
200 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600201 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600202 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600203 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600204 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700205
Simon Glassf6290892019-08-24 07:22:53 -0600206 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
207 elf_test.BuildElfTestFiles(cls._elf_testdir)
208
Simon Glass72232452016-11-25 20:15:53 -0700209 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600210 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700211 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700212
213 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600214 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700215
Simon Glass862f8e22019-08-24 07:22:43 -0600216 shutil.copytree(cls.TestFile('files'),
217 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600218
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530219 shutil.copytree(cls.TestFile('yaml'),
220 os.path.join(cls._indir, 'yaml'))
221
Simon Glass7ba33592018-09-14 04:57:26 -0600222 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600223 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600224 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200225 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Neha Malcom Francis59be2552023-12-05 15:12:18 +0530226 TestFunctional._MakeInputFile('dm.bin', TI_DM_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700227 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800228 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500229 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman35305492023-02-25 19:01:33 +0000230 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530231 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530232 TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600233
Simon Glassa435cd12020-09-01 05:13:59 -0600234 # Add a few .dtb files for testing
235 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
236 TEST_FDT1_DATA)
237 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
238 TEST_FDT2_DATA)
239
Simon Glassa0729502020-09-06 10:35:33 -0600240 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
241
Simon Glass5f423422022-03-05 20:19:12 -0700242 # ELF file with two sections in different parts of memory, used for both
243 # ATF and OP_TEE
244 TestFunctional._MakeInputFile('bl31.elf',
245 tools.read_file(cls.ElfTestFile('elf_sections')))
246 TestFunctional._MakeInputFile('tee.elf',
247 tools.read_file(cls.ElfTestFile('elf_sections')))
248
Simon Glassad5cfe12023-01-07 14:07:14 -0700249 # Newer OP_TEE file in v1 binary format
250 cls.make_tee_bin('tee.bin')
251
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200252 # test files for encrypted tests
253 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
254 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
255
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200256 cls.comp_bintools = {}
257 for name in COMP_BINTOOLS:
258 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600259
Simon Glass57454f42016-11-25 20:15:52 -0700260 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600261 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700262 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600263 if cls.preserve_indir:
264 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600265 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600266 if cls._indir:
267 shutil.rmtree(cls._indir)
268 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700269
Simon Glass1c420c92019-07-08 13:18:49 -0600270 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600271 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600272 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600273 """Accept arguments controlling test execution
274
275 Args:
276 preserve_indir: Preserve the shared input directory used by all
277 tests in this class.
278 preserve_outdir: Preserve the output directories used by tests. Each
279 test has its own, so this is normally only useful when running a
280 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600281 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600282 """
283 cls.preserve_indir = preserve_indir
284 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600285 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600286 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600287
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200288 def _CheckBintool(self, bintool):
289 if not bintool.is_present():
290 self.skipTest('%s not available' % bintool.name)
291
Simon Glass1de34482019-07-08 13:18:53 -0600292 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200293 bintool = self.comp_bintools['lz4']
294 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600295
Simon Glassee9d10d2019-07-20 12:24:09 -0600296 def _CleanupOutputDir(self):
297 """Remove the temporary output directory"""
298 if self.preserve_outdirs:
299 print('Preserving output dir: %s' % tools.outdir)
300 else:
Simon Glass80025522022-01-29 14:14:04 -0700301 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600302
Simon Glass57454f42016-11-25 20:15:52 -0700303 def setUp(self):
304 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700305 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700306 command.test_result = None
307
308 def tearDown(self):
309 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600310 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700311
Simon Glassb3d6fc72019-07-20 12:24:10 -0600312 def _SetupImageInTmpdir(self):
313 """Set up the output image in a new temporary directory
314
315 This is used when an image has been generated in the output directory,
316 but we want to run binman again. This will create a new output
317 directory and fail to delete the original one.
318
319 This creates a new temporary directory, copies the image to it (with a
320 new name) and removes the old output directory.
321
322 Returns:
323 Tuple:
324 Temporary directory to use
325 New image filename
326 """
Simon Glass80025522022-01-29 14:14:04 -0700327 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600328 tmpdir = tempfile.mkdtemp(prefix='binman.')
329 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700330 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600331 self._CleanupOutputDir()
332 return tmpdir, updated_fname
333
Simon Glass8425a1f2018-07-17 13:25:48 -0600334 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600335 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600336 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
337 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
338 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700339 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600340
Simon Glass57454f42016-11-25 20:15:52 -0700341 def _RunBinman(self, *args, **kwargs):
342 """Run binman using the command line
343
344 Args:
345 Arguments to pass, as a list of strings
346 kwargs: Arguments to pass to Command.RunPipe()
347 """
Simon Glass840be732022-01-29 14:14:05 -0700348 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700349 capture=True, capture_stderr=True, raise_on_error=False)
350 if result.return_code and kwargs.get('raise_on_error', True):
351 raise Exception("Error running '%s': %s" % (' '.join(args),
352 result.stdout + result.stderr))
353 return result
354
Simon Glassf46732a2019-07-08 14:25:29 -0600355 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700356 """Run binman using directly (in the same process)
357
358 Args:
359 Arguments to pass, as a list of strings
360 Returns:
361 Return value (0 for success)
362 """
Simon Glassf46732a2019-07-08 14:25:29 -0600363 argv = list(argv)
364 args = cmdline.ParseArgs(argv)
365 args.pager = 'binman-invalid-pager'
366 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700367
368 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600369 # args.verbosity = tout.DEBUG
370 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700371
Simon Glass91710b32018-07-17 13:25:32 -0600372 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600373 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300374 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100375 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700376 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis6b463da2023-07-22 00:14:44 +0530377 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass57454f42016-11-25 20:15:52 -0700378 """Run binman with a given test file
379
380 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600381 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600382 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600383 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600384 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600385 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600386 entry_args: Dict of entry args to supply to binman
387 key: arg name
388 value: value of that arg
389 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600390 use_real_dtb: True to use the test file as the contents of
391 the u-boot-dtb entry. Normally this is not needed and the
392 test contents (the U_BOOT_DTB_DATA string) can be used.
393 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300394 use_expanded: True to use expanded entries where available, e.g.
395 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600396 verbosity: Verbosity level to use (0-3, None=don't set it)
397 allow_missing: Set the '--allow-missing' flag so that missing
398 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100399 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600400 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600401 threads: Number of threads to use (None for default, 0 for
402 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600403 test_section_timeout: True to force the first time to timeout, as
404 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600405 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glassb553e8a2024-08-26 13:11:29 -0600406 force_missing_bintools (str): comma-separated list of bintools to
Simon Glass66152ce2022-01-09 20:14:09 -0700407 regard as missing
Simon Glassb553e8a2024-08-26 13:11:29 -0600408 ignore_missing (bool): True to return success even if there are
409 missing blobs or bintools
Andrew Davis6b463da2023-07-22 00:14:44 +0530410 output_dir: Specific output directory to use for image using -O
Simon Glass9a798402021-11-03 21:09:17 -0600411
412 Returns:
413 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700414 """
Simon Glassf46732a2019-07-08 14:25:29 -0600415 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700416 if debug:
417 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600418 if verbosity is not None:
419 args.append('-v%d' % verbosity)
420 elif self.verbosity:
421 args.append('-v%d' % self.verbosity)
422 if self.toolpath:
423 for path in self.toolpath:
424 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600425 if threads is not None:
426 args.append('-T%d' % threads)
427 if test_section_timeout:
428 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600429 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600430 if map:
431 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600432 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600433 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600434 if not use_real_dtb:
435 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300436 if not use_expanded:
437 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600438 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600439 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600440 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600441 if allow_missing:
442 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700443 if ignore_missing:
444 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100445 if allow_fake_blobs:
446 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700447 if force_missing_bintools:
448 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600449 if update_fdt_in_elf:
450 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600451 if images:
452 for image in images:
453 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600454 if extra_indirs:
455 for indir in extra_indirs:
456 args += ['-I', indir]
Andrew Davis6b463da2023-07-22 00:14:44 +0530457 if output_dir:
458 args += ['-O', output_dir]
Simon Glass075a45c2017-11-13 18:55:00 -0700459 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700460
461 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700462 """Set up a new test device-tree file
463
464 The given file is compiled and set up as the device tree to be used
465 for ths test.
466
467 Args:
468 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600469 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700470
471 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600472 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700473 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600474 tmpdir = tempfile.mkdtemp(prefix='binmant.')
475 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600476 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700477 data = fd.read()
478 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600479 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600480 return data
Simon Glass57454f42016-11-25 20:15:52 -0700481
Simon Glass56d05412022-02-28 07:16:54 -0700482 def _GetDtbContentsForSpls(self, dtb_data, name):
483 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600484
485 For testing we don't actually have different versions of the DTB. With
486 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
487 we don't normally have any unwanted nodes.
488
489 We still want the DTBs for SPL and TPL to be different though, since
490 otherwise it is confusing to know which one we are looking at. So add
491 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600492
493 Args:
494 dtb_data: dtb data to modify (this should be a value devicetree)
495 name: Name of a new property to add
496
497 Returns:
498 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600499 """
500 dtb = fdt.Fdt.FromData(dtb_data)
501 dtb.Scan()
502 dtb.GetNode('/binman').AddZeroProp(name)
503 dtb.Sync(auto_resize=True)
504 dtb.Pack()
505 return dtb.GetContents()
506
Simon Glassed930672021-03-18 20:25:05 +1300507 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
Simon Glass3eb30a42024-08-26 13:11:42 -0600508 verbosity=None, map=False, update_dtb=False,
509 entry_args=None, reset_dtbs=True, extra_indirs=None,
510 threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700511 """Run binman and return the resulting image
512
513 This runs binman with a given test file and then reads the resulting
514 output file. It is a shortcut function since most tests need to do
515 these steps.
516
517 Raises an assertion failure if binman returns a non-zero exit code.
518
519 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600520 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700521 use_real_dtb: True to use the test file as the contents of
522 the u-boot-dtb entry. Normally this is not needed and the
523 test contents (the U_BOOT_DTB_DATA string) can be used.
524 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300525 use_expanded: True to use expanded entries where available, e.g.
526 'u-boot-expanded' instead of 'u-boot'
Simon Glass3eb30a42024-08-26 13:11:42 -0600527 verbosity: Verbosity level to use (0-3, None=don't set it)
Simon Glass30732662018-06-01 09:38:20 -0600528 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600529 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600530 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600531 entry_args: Dict of entry args to supply to binman
532 key: arg name
533 value: value of that arg
534 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
535 function. If reset_dtbs is True, then the original test dtb
536 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600537 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600538 threads: Number of threads to use (None for default, 0 for
539 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700540
541 Returns:
542 Tuple:
543 Resulting image contents
544 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600545 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600546 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700547 """
Simon Glass72232452016-11-25 20:15:53 -0700548 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700549 # Use the compiled test file as the u-boot-dtb input
550 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700551 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600552
553 # For testing purposes, make a copy of the DT for SPL and TPL. Add
Simon Glassd9e01d22024-07-20 11:49:40 +0100554 # a node indicating which it is, to aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700555 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600556 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
557 outfile = os.path.join(self._indir, dtb_fname)
558 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700559 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700560
561 try:
Simon Glass91710b32018-07-17 13:25:32 -0600562 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600563 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass3eb30a42024-08-26 13:11:42 -0600564 use_expanded=use_expanded, verbosity=verbosity,
565 extra_indirs=extra_indirs,
Simon Glass76f496d2021-07-06 10:36:37 -0600566 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700567 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700568 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700569
570 # Find the (only) image, read it and return its contents
571 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700572 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600573 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600574 if map:
Simon Glass80025522022-01-29 14:14:04 -0700575 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600576 with open(map_fname) as fd:
577 map_data = fd.read()
578 else:
579 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600580 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600581 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700582 finally:
583 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600584 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600585 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700586
Simon Glass5b4bce32019-07-08 14:25:26 -0600587 def _DoReadFileRealDtb(self, fname):
588 """Run binman with a real .dtb file and return the resulting data
589
590 Args:
591 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
592
593 Returns:
594 Resulting image contents
595 """
596 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
597
Simon Glass72232452016-11-25 20:15:53 -0700598 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600599 """Helper function which discards the device-tree binary
600
601 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600602 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600603 use_real_dtb: True to use the test file as the contents of
604 the u-boot-dtb entry. Normally this is not needed and the
605 test contents (the U_BOOT_DTB_DATA string) can be used.
606 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600607
608 Returns:
609 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600610 """
Simon Glass72232452016-11-25 20:15:53 -0700611 return self._DoReadFileDtb(fname, use_real_dtb)[0]
612
Simon Glass57454f42016-11-25 20:15:52 -0700613 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600614 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700615 """Create a new test input file, creating directories as needed
616
617 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600618 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700619 contents: File contents to write in to the file
620 Returns:
621 Full pathname of file created
622 """
Simon Glass862f8e22019-08-24 07:22:43 -0600623 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700624 dirname = os.path.dirname(pathname)
625 if dirname and not os.path.exists(dirname):
626 os.makedirs(dirname)
627 with open(pathname, 'wb') as fd:
628 fd.write(contents)
629 return pathname
630
631 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600632 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600633 """Create a new test input directory, creating directories as needed
634
635 Args:
636 dirname: Directory name to create
637
638 Returns:
639 Full pathname of directory created
640 """
Simon Glass862f8e22019-08-24 07:22:43 -0600641 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600642 if not os.path.exists(pathname):
643 os.makedirs(pathname)
644 return pathname
645
646 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600647 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600648 """Set up an ELF file with a '_dt_ucode_base_size' symbol
649
650 Args:
651 Filename of ELF file to use as SPL
652 """
Simon Glass93a806f2019-08-24 07:22:59 -0600653 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700654 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600655
656 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600657 def _SetupTplElf(cls, src_fname='bss_data'):
658 """Set up an ELF file with a '_dt_ucode_base_size' symbol
659
660 Args:
661 Filename of ELF file to use as TPL
662 """
663 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700664 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600665
666 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700667 def _SetupVplElf(cls, src_fname='bss_data'):
668 """Set up an ELF file with a '_dt_ucode_base_size' symbol
669
670 Args:
671 Filename of ELF file to use as VPL
672 """
673 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
674 tools.read_file(cls.ElfTestFile(src_fname)))
675
676 @classmethod
Lukas Funkee901faf2023-07-18 13:53:13 +0200677 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
678 """Set up an ELF file with a '_dt_ucode_base_size' symbol
679
680 Args:
681 Filename of ELF file to use as VPL
682 """
683 TestFunctional._MakeInputFile('pmu-firmware.elf',
684 tools.read_file(cls.ElfTestFile(src_fname)))
685
686 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600687 def _SetupDescriptor(cls):
688 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
689 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
690
691 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600692 def TestFile(cls, fname):
693 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700694
Simon Glassf6290892019-08-24 07:22:53 -0600695 @classmethod
696 def ElfTestFile(cls, fname):
697 return os.path.join(cls._elf_testdir, fname)
698
Simon Glassad5cfe12023-01-07 14:07:14 -0700699 @classmethod
700 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
701 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
702 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
703 dummy, paged_sz) + U_BOOT_DATA
704 data += extra_data
705 TestFunctional._MakeInputFile(fname, data)
706
Simon Glass57454f42016-11-25 20:15:52 -0700707 def AssertInList(self, grep_list, target):
708 """Assert that at least one of a list of things is in a target
709
710 Args:
711 grep_list: List of strings to check
712 target: Target string
713 """
714 for grep in grep_list:
715 if grep in target:
716 return
Simon Glass848cdb52019-05-17 22:00:50 -0600717 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700718
719 def CheckNoGaps(self, entries):
720 """Check that all entries fit together without gaps
721
722 Args:
723 entries: List of entries to check
724 """
Simon Glasse8561af2018-08-01 15:22:37 -0600725 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700726 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600727 self.assertEqual(offset, entry.offset)
728 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700729
Simon Glass72232452016-11-25 20:15:53 -0700730 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600731 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700732
733 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600734 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700735
736 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600737 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700738 """
739 return struct.unpack('>L', dtb[4:8])[0]
740
Simon Glass0f621332019-07-08 14:25:27 -0600741 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600742 def AddNode(node, path):
743 if node.name != '/':
744 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600745 for prop in node.props.values():
746 if prop.name in prop_names:
747 prop_path = path + ':' + prop.name
748 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
749 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600750 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600751 AddNode(subnode, path)
752
753 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600754 AddNode(dtb.GetRoot(), '')
755 return tree
756
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000757 def _CheckSign(self, fit, key):
758 try:
759 tools.run('fit_check_sign', '-k', key, '-f', fit)
760 except:
761 self.fail('Expected signed FIT container')
762 return False
763 return True
764
Simon Glass57454f42016-11-25 20:15:52 -0700765 def testRun(self):
766 """Test a basic run with valid args"""
767 result = self._RunBinman('-h')
768
769 def testFullHelp(self):
770 """Test that the full help is displayed with -H"""
771 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300772 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500773 # Remove possible extraneous strings
774 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
775 gothelp = result.stdout.replace(extra, '')
776 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700777 self.assertEqual(0, len(result.stderr))
778 self.assertEqual(0, result.return_code)
779
780 def testFullHelpInternal(self):
781 """Test that the full help is displayed with -H"""
782 try:
783 command.test_result = command.CommandResult()
784 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300785 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700786 finally:
787 command.test_result = None
788
789 def testHelp(self):
790 """Test that the basic help is displayed with -h"""
791 result = self._RunBinman('-h')
792 self.assertTrue(len(result.stdout) > 200)
793 self.assertEqual(0, len(result.stderr))
794 self.assertEqual(0, result.return_code)
795
Simon Glass57454f42016-11-25 20:15:52 -0700796 def testBoard(self):
797 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600798 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700799 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300800 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700801 self.assertEqual(0, result)
802
803 def testNeedBoard(self):
804 """Test that we get an error when no board ius supplied"""
805 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600806 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700807 self.assertIn("Must provide a board to process (use -b <board>)",
808 str(e.exception))
809
810 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600811 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700812 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600813 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700814 # We get one error from libfdt, and a different one from fdtget.
815 self.AssertInList(["Couldn't open blob from 'missing_file'",
816 'No such file or directory'], str(e.exception))
817
818 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600819 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700820
821 Since this is a source file it should be compiled and the error
822 will come from the device-tree compiler (dtc).
823 """
824 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600825 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700826 self.assertIn("FATAL ERROR: Unable to parse input tree",
827 str(e.exception))
828
829 def testMissingNode(self):
830 """Test that a device tree without a 'binman' node generates an error"""
831 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600832 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700833 self.assertIn("does not have a 'binman' node", str(e.exception))
834
835 def testEmpty(self):
836 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600837 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700838 self.assertEqual(0, len(result.stderr))
839 self.assertEqual(0, result.return_code)
840
841 def testInvalidEntry(self):
842 """Test that an invalid entry is flagged"""
843 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600844 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600845 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700846 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
847 "'/binman/not-a-valid-type'", str(e.exception))
848
849 def testSimple(self):
850 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600851 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700852 self.assertEqual(U_BOOT_DATA, data)
853
Simon Glass075a45c2017-11-13 18:55:00 -0700854 def testSimpleDebug(self):
855 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600856 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700857
Simon Glass57454f42016-11-25 20:15:52 -0700858 def testDual(self):
859 """Test that we can handle creating two images
860
861 This also tests image padding.
862 """
Simon Glass511f6582018-10-01 12:22:30 -0600863 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700864 self.assertEqual(0, retcode)
865
866 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600867 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700868 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700869 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600870 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700871 data = fd.read()
872 self.assertEqual(U_BOOT_DATA, data)
873
874 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600875 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700876 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700877 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600878 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700879 data = fd.read()
880 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700881 self.assertEqual(tools.get_bytes(0, 3), data[:3])
882 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700883
884 def testBadAlign(self):
885 """Test that an invalid alignment value is detected"""
886 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600887 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700888 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
889 "of two", str(e.exception))
890
891 def testPackSimple(self):
892 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600893 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700894 self.assertEqual(0, retcode)
895 self.assertIn('image', control.images)
896 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600897 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700898 self.assertEqual(5, len(entries))
899
900 # First u-boot
901 self.assertIn('u-boot', entries)
902 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600903 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700904 self.assertEqual(len(U_BOOT_DATA), entry.size)
905
906 # Second u-boot, aligned to 16-byte boundary
907 self.assertIn('u-boot-align', entries)
908 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600909 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700910 self.assertEqual(len(U_BOOT_DATA), entry.size)
911
912 # Third u-boot, size 23 bytes
913 self.assertIn('u-boot-size', entries)
914 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600915 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700916 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
917 self.assertEqual(23, entry.size)
918
919 # Fourth u-boot, placed immediate after the above
920 self.assertIn('u-boot-next', entries)
921 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600922 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700923 self.assertEqual(len(U_BOOT_DATA), entry.size)
924
Simon Glasse8561af2018-08-01 15:22:37 -0600925 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700926 self.assertIn('u-boot-fixed', entries)
927 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600928 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700929 self.assertEqual(len(U_BOOT_DATA), entry.size)
930
Simon Glass39dd2152019-07-08 14:25:47 -0600931 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700932
933 def testPackExtra(self):
934 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600935 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
936 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700937
Simon Glass57454f42016-11-25 20:15:52 -0700938 self.assertIn('image', control.images)
939 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600940 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600941 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700942
Samuel Hollande2574022023-01-21 17:25:16 -0600943 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700944 self.assertIn('u-boot', entries)
945 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600946 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700947 self.assertEqual(3, entry.pad_before)
948 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600949 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700950 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
951 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600952 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700953
954 # Second u-boot has an aligned size, but it has no effect
955 self.assertIn('u-boot-align-size-nop', entries)
956 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600957 self.assertEqual(pos, entry.offset)
958 self.assertEqual(len(U_BOOT_DATA), entry.size)
959 self.assertEqual(U_BOOT_DATA, entry.data)
960 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
961 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700962
963 # Third u-boot has an aligned size too
964 self.assertIn('u-boot-align-size', entries)
965 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600966 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700967 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600968 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700969 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600970 data[pos:pos + entry.size])
971 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700972
973 # Fourth u-boot has an aligned end
974 self.assertIn('u-boot-align-end', entries)
975 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600976 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700977 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600978 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700979 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600980 data[pos:pos + entry.size])
981 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700982
983 # Fifth u-boot immediately afterwards
984 self.assertIn('u-boot-align-both', entries)
985 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600986 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700987 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600988 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700989 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600990 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700991
Samuel Hollande2574022023-01-21 17:25:16 -0600992 # Sixth u-boot with both minimum size and aligned size
993 self.assertIn('u-boot-min-size', entries)
994 entry = entries['u-boot-min-size']
995 self.assertEqual(128, entry.offset)
996 self.assertEqual(32, entry.size)
997 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
998 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
999 data[pos:pos + entry.size])
1000
Simon Glass57454f42016-11-25 20:15:52 -07001001 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -06001002 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001003
Simon Glassafb9caa2020-10-26 17:40:10 -06001004 dtb = fdt.Fdt(out_dtb_fname)
1005 dtb.Scan()
1006 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
1007 expected = {
1008 'image-pos': 0,
1009 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -06001010 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -06001011
1012 'u-boot:image-pos': 0,
1013 'u-boot:offset': 0,
1014 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1015
1016 'u-boot-align-size-nop:image-pos': 12,
1017 'u-boot-align-size-nop:offset': 12,
1018 'u-boot-align-size-nop:size': 4,
1019
1020 'u-boot-align-size:image-pos': 16,
1021 'u-boot-align-size:offset': 16,
1022 'u-boot-align-size:size': 32,
1023
1024 'u-boot-align-end:image-pos': 48,
1025 'u-boot-align-end:offset': 48,
1026 'u-boot-align-end:size': 16,
1027
1028 'u-boot-align-both:image-pos': 64,
1029 'u-boot-align-both:offset': 64,
1030 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -06001031
1032 'u-boot-min-size:image-pos': 128,
1033 'u-boot-min-size:offset': 128,
1034 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -06001035 }
1036 self.assertEqual(expected, props)
1037
Simon Glass57454f42016-11-25 20:15:52 -07001038 def testPackAlignPowerOf2(self):
1039 """Test that invalid entry alignment is detected"""
1040 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001041 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001042 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1043 "of two", str(e.exception))
1044
1045 def testPackAlignSizePowerOf2(self):
1046 """Test that invalid entry size alignment is detected"""
1047 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001048 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001049 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1050 "power of two", str(e.exception))
1051
1052 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001053 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001054 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001055 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001056 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001057 "align 0x4 (4)", str(e.exception))
1058
1059 def testPackInvalidSizeAlign(self):
1060 """Test that invalid entry size alignment is detected"""
1061 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001062 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001063 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1064 "align-size 0x4 (4)", str(e.exception))
1065
1066 def testPackOverlap(self):
1067 """Test that overlapping regions are detected"""
1068 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001069 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001070 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001071 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1072 str(e.exception))
1073
1074 def testPackEntryOverflow(self):
1075 """Test that entries that overflow their size are detected"""
1076 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001077 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001078 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1079 "but entry size is 0x3 (3)", str(e.exception))
1080
1081 def testPackImageOverflow(self):
1082 """Test that entries which overflow the image size are detected"""
1083 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001084 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001085 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001086 "size 0x3 (3)", str(e.exception))
1087
1088 def testPackImageSize(self):
1089 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001090 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001091 self.assertEqual(0, retcode)
1092 self.assertIn('image', control.images)
1093 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001094 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001095
1096 def testPackImageSizeAlign(self):
1097 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001098 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001099 self.assertEqual(0, retcode)
1100 self.assertIn('image', control.images)
1101 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001102 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001103
1104 def testPackInvalidImageAlign(self):
1105 """Test that invalid image alignment is detected"""
1106 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001107 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001108 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001109 "align-size 0x8 (8)", str(e.exception))
1110
Simon Glass2a0fa982022-02-11 13:23:21 -07001111 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001112 """Test that invalid image alignment is detected"""
1113 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001114 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001115 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001116 "two", str(e.exception))
1117
1118 def testImagePadByte(self):
1119 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001120 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001121 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001122 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001123 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001124
1125 def testImageName(self):
1126 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001127 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001128 self.assertEqual(0, retcode)
1129 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001130 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001131 self.assertTrue(os.path.exists(fname))
1132
1133 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001134 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001135 self.assertTrue(os.path.exists(fname))
1136
1137 def testBlobFilename(self):
1138 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001139 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001140 self.assertEqual(BLOB_DATA, data)
1141
1142 def testPackSorted(self):
1143 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001144 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001145 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001146 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1147 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001148
Simon Glasse8561af2018-08-01 15:22:37 -06001149 def testPackZeroOffset(self):
1150 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001151 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001152 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001153 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001154 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001155 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1156 str(e.exception))
1157
1158 def testPackUbootDtb(self):
1159 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001160 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001161 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001162
1163 def testPackX86RomNoSize(self):
1164 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001165 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001166 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001167 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001168 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001169 "using end-at-4gb", str(e.exception))
1170
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301171 def test4gbAndSkipAtStartTogether(self):
1172 """Test that the end-at-4gb and skip-at-size property can't be used
1173 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001174 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301175 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001176 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001177 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301178 "'skip-at-start'", str(e.exception))
1179
Simon Glass72232452016-11-25 20:15:53 -07001180 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001181 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001182 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001183 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001184 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001185 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1186 "is outside the section '/binman' starting at "
1187 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001188 str(e.exception))
1189
1190 def testPackX86Rom(self):
1191 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001192 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001193 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001194 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1195 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001196
1197 def testPackX86RomMeNoDesc(self):
1198 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001199 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001200 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001201 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001202 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001203 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1204 str(e.exception))
1205 finally:
1206 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001207
1208 def testPackX86RomBadDesc(self):
1209 """Test that the Intel requires a descriptor entry"""
1210 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001211 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001212 self.assertIn("Node '/binman/intel-me': No offset set with "
1213 "offset-unset: should another entry provide this correct "
1214 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001215
1216 def testPackX86RomMe(self):
1217 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001218 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001219 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001220 if data[:0x1000] != expected_desc:
1221 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001222 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1223
1224 def testPackVga(self):
1225 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001226 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001227 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1228
1229 def testPackStart16(self):
1230 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001231 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001232 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1233
Jagdish Gediya311d4842018-09-03 21:35:08 +05301234 def testPackPowerpcMpc85xxBootpgResetvec(self):
1235 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1236 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001237 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301238 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1239
Simon Glass6ba679c2018-07-06 10:27:17 -06001240 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001241 """Handle running a test for insertion of microcode
1242
1243 Args:
1244 dts_fname: Name of test .dts file
1245 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001246 ucode_second: True if the microsecond entry is second instead of
1247 third
Simon Glass820af1d2018-07-06 10:27:16 -06001248
1249 Returns:
1250 Tuple:
1251 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001252 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001253 in the above (two 4-byte words)
1254 """
Simon Glass3d274232017-11-12 21:52:27 -07001255 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001256
1257 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001258 if ucode_second:
1259 ucode_content = data[len(nodtb_data):]
1260 ucode_pos = len(nodtb_data)
1261 dtb_with_ucode = ucode_content[16:]
1262 fdt_len = self.GetFdtLen(dtb_with_ucode)
1263 else:
1264 dtb_with_ucode = data[len(nodtb_data):]
1265 fdt_len = self.GetFdtLen(dtb_with_ucode)
1266 ucode_content = dtb_with_ucode[fdt_len:]
1267 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001268 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001269 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001270 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001271 dtb = fdt.FdtScan(fname)
1272 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001273 self.assertTrue(ucode)
1274 for node in ucode.subnodes:
1275 self.assertFalse(node.props.get('data'))
1276
Simon Glass72232452016-11-25 20:15:53 -07001277 # Check that the microcode appears immediately after the Fdt
1278 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001279 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001280 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1281 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001282 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001283
1284 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001285 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001286 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1287 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001288 u_boot = data[:len(nodtb_data)]
1289 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001290
1291 def testPackUbootMicrocode(self):
1292 """Test that x86 microcode can be handled correctly
1293
1294 We expect to see the following in the image, in order:
1295 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1296 place
1297 u-boot.dtb with the microcode removed
1298 the microcode
1299 """
Simon Glass511f6582018-10-01 12:22:30 -06001300 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001301 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001302 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1303 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001304
Simon Glassbac25c82017-05-27 07:38:26 -06001305 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001306 """Test that x86 microcode can be handled correctly
1307
1308 We expect to see the following in the image, in order:
1309 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1310 place
1311 u-boot.dtb with the microcode
1312 an empty microcode region
1313 """
1314 # We need the libfdt library to run this test since only that allows
1315 # finding the offset of a property. This is required by
1316 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001317 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001318
1319 second = data[len(U_BOOT_NODTB_DATA):]
1320
1321 fdt_len = self.GetFdtLen(second)
1322 third = second[fdt_len:]
1323 second = second[:fdt_len]
1324
Simon Glassbac25c82017-05-27 07:38:26 -06001325 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1326 self.assertIn(ucode_data, second)
1327 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001328
Simon Glassbac25c82017-05-27 07:38:26 -06001329 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001330 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001331 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1332 len(ucode_data))
1333 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001334 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1335 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001336
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001337 def testPackUbootSingleMicrocode(self):
1338 """Test that x86 microcode can be handled correctly with fdt_normal.
1339 """
Simon Glassbac25c82017-05-27 07:38:26 -06001340 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001341
Simon Glass996021e2016-11-25 20:15:54 -07001342 def testUBootImg(self):
1343 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001344 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001345 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001346
1347 def testNoMicrocode(self):
1348 """Test that a missing microcode region is detected"""
1349 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001350 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001351 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1352 "node found in ", str(e.exception))
1353
1354 def testMicrocodeWithoutNode(self):
1355 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1356 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001357 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001358 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1359 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1360
1361 def testMicrocodeWithoutNode2(self):
1362 """Test that a missing u-boot-ucode node is detected"""
1363 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001364 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001365 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1366 "microcode region u-boot-ucode", str(e.exception))
1367
1368 def testMicrocodeWithoutPtrInElf(self):
1369 """Test that a U-Boot binary without the microcode symbol is detected"""
1370 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001371 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001372 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001373 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001374
1375 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001376 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001377 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1378 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1379
1380 finally:
1381 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001382 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001383 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001384
1385 def testMicrocodeNotInImage(self):
1386 """Test that microcode must be placed within the image"""
1387 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001388 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001389 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1390 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001391 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001392
1393 def testWithoutMicrocode(self):
1394 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001395 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001396 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001397 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001398
1399 # Now check the device tree has no microcode
1400 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1401 second = data[len(U_BOOT_NODTB_DATA):]
1402
1403 fdt_len = self.GetFdtLen(second)
1404 self.assertEqual(dtb, second[:fdt_len])
1405
1406 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1407 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001408 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001409
1410 def testUnknownPosSize(self):
1411 """Test that microcode must be placed within the image"""
1412 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001413 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001414 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001415 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001416
1417 def testPackFsp(self):
1418 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001419 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001420 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1421
1422 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001423 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001424 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001425 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001426
1427 def testPackVbt(self):
1428 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001429 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001430 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001431
Simon Glass7f94e832017-11-12 21:52:25 -07001432 def testSplBssPad(self):
1433 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001434 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001435 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001436 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001437 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001438 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001439
Simon Glass04cda032018-10-01 21:12:42 -06001440 def testSplBssPadMissing(self):
1441 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001442 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001443 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001444 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001445 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1446 str(e.exception))
1447
Simon Glasse83679d2017-11-12 21:52:26 -07001448 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001449 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001450 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001451 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1452
Simon Glass6ba679c2018-07-06 10:27:17 -06001453 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1454 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001455
1456 We expect to see the following in the image, in order:
1457 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1458 correct place
1459 u-boot.dtb with the microcode removed
1460 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001461
1462 Args:
1463 dts: Device tree file to use for test
1464 ucode_second: True if the microsecond entry is second instead of
1465 third
Simon Glass3d274232017-11-12 21:52:27 -07001466 """
Simon Glass7057d022018-10-01 21:12:47 -06001467 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001468 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1469 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001470 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1471 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001472
Simon Glass6ba679c2018-07-06 10:27:17 -06001473 def testPackUbootSplMicrocode(self):
1474 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001475 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001476 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001477
1478 def testPackUbootSplMicrocodeReorder(self):
1479 """Test that order doesn't matter for microcode entries
1480
1481 This is the same as testPackUbootSplMicrocode but when we process the
1482 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1483 entry, so we reply on binman to try later.
1484 """
Simon Glass511f6582018-10-01 12:22:30 -06001485 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001486 ucode_second=True)
1487
Simon Glassa409c932017-11-12 21:52:28 -07001488 def testPackMrc(self):
1489 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001490 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001491 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1492
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001493 def testSplDtb(self):
1494 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001495 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001496 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001497 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1498
Simon Glass0a6da312017-11-13 18:54:56 -07001499 def testSplNoDtb(self):
1500 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001501 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001502 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001503 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1504
Simon Glass7098b7f2021-03-21 18:24:30 +13001505 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4b0f4142024-08-26 13:11:40 -06001506 use_expanded=False, no_write_symbols=False,
1507 symbols_base=None):
Simon Glass31e04cb2021-03-18 20:24:56 +13001508 """Check the image contains the expected symbol values
1509
1510 Args:
1511 dts: Device tree file to use for test
1512 base_data: Data before and after 'u-boot' section
Simon Glass3eb30a42024-08-26 13:11:42 -06001513 u_boot_offset (int): Offset of 'u-boot' section in image, or None if
1514 the offset not available due to it being in a compressed section
Simon Glass7098b7f2021-03-21 18:24:30 +13001515 entry_args: Dict of entry args to supply to binman
1516 key: arg name
1517 value: value of that arg
1518 use_expanded: True to use expanded entries where available, e.g.
1519 'u-boot-expanded' instead of 'u-boot'
Simon Glass4b0f4142024-08-26 13:11:40 -06001520 symbols_base (int): Value to expect for symbols-base in u-boot-spl,
1521 None if none
Simon Glass31e04cb2021-03-18 20:24:56 +13001522 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001523 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001524 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1525 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001526 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001527 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001528 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001529
Simon Glass7057d022018-10-01 21:12:47 -06001530 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001531 data = self._DoReadFileDtb(dts, entry_args=entry_args,
Simon Glass3eb30a42024-08-26 13:11:42 -06001532 use_expanded=use_expanded,
1533 verbosity=None if u_boot_offset else 3)[0]
1534
1535 # The lz4-compressed version of the U-Boot data is 19 bytes long
1536 comp_uboot_len = 19
1537
Simon Glass31e04cb2021-03-18 20:24:56 +13001538 # The image should contain the symbols from u_boot_binman_syms.c
1539 # Note that image_pos is adjusted by the base address of the image,
1540 # which is 0x10 in our test image
Simon Glass3eb30a42024-08-26 13:11:42 -06001541 # If u_boot_offset is None, Binman should write -1U into the image
Simon Glass4b0f4142024-08-26 13:11:40 -06001542 vals2 = (elf.BINMAN_SYM_MAGIC_VALUE, 0x00,
Simon Glass3eb30a42024-08-26 13:11:42 -06001543 u_boot_offset + len(U_BOOT_DATA) if u_boot_offset else
1544 len(U_BOOT_SPL_DATA) + 1 + comp_uboot_len,
1545 0x10 + u_boot_offset if u_boot_offset else 0xffffffff, 0x04)
Simon Glass4b0f4142024-08-26 13:11:40 -06001546
1547 # u-boot-spl has a symbols-base property, so take that into account if
1548 # required. The caller must supply the value
1549 vals = list(vals2)
1550 if symbols_base is not None:
1551 vals[3] = symbols_base + u_boot_offset
1552 vals = tuple(vals)
1553
Simon Glass4b4049e2024-08-26 13:11:39 -06001554 sym_values = struct.pack('<LLQLL', *vals)
Simon Glass4b0f4142024-08-26 13:11:40 -06001555 sym_values2 = struct.pack('<LLQLL', *vals2)
Simon Glass4abf7842023-07-18 07:23:54 -06001556 if no_write_symbols:
Simon Glass4b4049e2024-08-26 13:11:39 -06001557 self.assertEqual(
1558 base_data +
1559 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1560 U_BOOT_DATA + base_data, data)
Simon Glass4abf7842023-07-18 07:23:54 -06001561 else:
Simon Glass4b4049e2024-08-26 13:11:39 -06001562 got_vals = struct.unpack('<LLQLL', data[:24])
1563
1564 # For debugging:
1565 #print('expect:', list(f'{v:x}' for v in vals))
1566 #print(' got:', list(f'{v:x}' for v in got_vals))
1567
1568 self.assertEqual(vals, got_vals)
1569 self.assertEqual(sym_values, data[:24])
1570
1571 blen = len(base_data)
1572 self.assertEqual(base_data[24:], data[24:blen])
1573 self.assertEqual(0xff, data[blen])
1574
Simon Glass3eb30a42024-08-26 13:11:42 -06001575 if u_boot_offset:
1576 ofs = blen + 1 + len(U_BOOT_DATA)
1577 self.assertEqual(U_BOOT_DATA, data[blen + 1:ofs])
1578 else:
1579 ofs = blen + 1 + comp_uboot_len
Simon Glass4b4049e2024-08-26 13:11:39 -06001580
Simon Glass4b0f4142024-08-26 13:11:40 -06001581 self.assertEqual(sym_values2, data[ofs:ofs + 24])
Simon Glass4b4049e2024-08-26 13:11:39 -06001582 self.assertEqual(base_data[24:], data[ofs + 24:])
1583
1584 # Just repeating the above asserts all at once, for clarity
Simon Glass3eb30a42024-08-26 13:11:42 -06001585 if u_boot_offset:
1586 expected = (sym_values + base_data[24:] +
1587 tools.get_bytes(0xff, 1) + U_BOOT_DATA +
1588 sym_values2 + base_data[24:])
1589 self.assertEqual(expected, data)
Simon Glass4ca8e042017-11-13 18:55:01 -07001590
Simon Glass31e04cb2021-03-18 20:24:56 +13001591 def testSymbols(self):
1592 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001593 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001594
1595 def testSymbolsNoDtb(self):
1596 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001597 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001598 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1599 0x38)
1600
Simon Glasse76a3e62018-06-01 09:38:11 -06001601 def testPackUnitAddress(self):
1602 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001603 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001604 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1605
Simon Glassa91e1152018-06-01 09:38:16 -06001606 def testSections(self):
1607 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001608 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001609 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1610 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1611 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001612 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001613
Simon Glass30732662018-06-01 09:38:20 -06001614 def testMap(self):
1615 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001616 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001617 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700161800000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600161900000000 00000000 00000010 section@0
162000000000 00000000 00000004 u-boot
162100000010 00000010 00000010 section@1
162200000010 00000000 00000004 u-boot
162300000020 00000020 00000004 section@2
162400000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001625''', map_data)
1626
Simon Glass3b78d532018-06-01 09:38:21 -06001627 def testNamePrefix(self):
1628 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001629 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001630 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700163100000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600163200000000 00000000 00000010 section@0
163300000000 00000000 00000004 ro-u-boot
163400000010 00000010 00000010 section@1
163500000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001636''', map_data)
1637
Simon Glass6ba679c2018-07-06 10:27:17 -06001638 def testUnknownContents(self):
1639 """Test that obtaining the contents works as expected"""
1640 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001641 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001642 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001643 "processing of contents: remaining ["
1644 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001645
Simon Glass2e1169f2018-07-06 10:27:19 -06001646 def testBadChangeSize(self):
1647 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001648 try:
1649 state.SetAllowEntryExpansion(False)
1650 with self.assertRaises(ValueError) as e:
1651 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001652 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001653 str(e.exception))
1654 finally:
1655 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001656
Simon Glassa87014e2018-07-06 10:27:42 -06001657 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001658 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001659 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001660 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001661 dtb = fdt.Fdt(out_dtb_fname)
1662 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001663 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001664 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001665 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001666 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001667 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001668 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001669 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001670 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001671 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001672 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001673 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001674 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001675 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001676
Simon Glasse8561af2018-08-01 15:22:37 -06001677 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001678 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001679 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001680 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001681 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001682 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001683 'size': 40
1684 }, props)
1685
1686 def testUpdateFdtBad(self):
1687 """Test that we detect when ProcessFdt never completes"""
1688 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001689 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001690 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001691 '[<binman.etype._testing.Entry__testing',
1692 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001693
Simon Glass91710b32018-07-17 13:25:32 -06001694 def testEntryArgs(self):
1695 """Test passing arguments to entries from the command line"""
1696 entry_args = {
1697 'test-str-arg': 'test1',
1698 'test-int-arg': '456',
1699 }
Simon Glass511f6582018-10-01 12:22:30 -06001700 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001701 self.assertIn('image', control.images)
1702 entry = control.images['image'].GetEntries()['_testing']
1703 self.assertEqual('test0', entry.test_str_fdt)
1704 self.assertEqual('test1', entry.test_str_arg)
1705 self.assertEqual(123, entry.test_int_fdt)
1706 self.assertEqual(456, entry.test_int_arg)
1707
1708 def testEntryArgsMissing(self):
1709 """Test missing arguments and properties"""
1710 entry_args = {
1711 'test-int-arg': '456',
1712 }
Simon Glass511f6582018-10-01 12:22:30 -06001713 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001714 entry = control.images['image'].GetEntries()['_testing']
1715 self.assertEqual('test0', entry.test_str_fdt)
1716 self.assertEqual(None, entry.test_str_arg)
1717 self.assertEqual(None, entry.test_int_fdt)
1718 self.assertEqual(456, entry.test_int_arg)
1719
1720 def testEntryArgsRequired(self):
1721 """Test missing arguments and properties"""
1722 entry_args = {
1723 'test-int-arg': '456',
1724 }
1725 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001726 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001727 self.assertIn("Node '/binman/_testing': "
1728 'Missing required properties/entry args: test-str-arg, '
1729 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001730 str(e.exception))
1731
1732 def testEntryArgsInvalidFormat(self):
1733 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001734 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1735 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001736 with self.assertRaises(ValueError) as e:
1737 self._DoBinman(*args)
1738 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1739
1740 def testEntryArgsInvalidInteger(self):
1741 """Test that an invalid entry-argument integer is detected"""
1742 entry_args = {
1743 'test-int-arg': 'abc',
1744 }
1745 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001746 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001747 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1748 "'test-int-arg' (value 'abc') to integer",
1749 str(e.exception))
1750
1751 def testEntryArgsInvalidDatatype(self):
1752 """Test that an invalid entry-argument datatype is detected
1753
1754 This test could be written in entry_test.py except that it needs
1755 access to control.entry_args, which seems more than that module should
1756 be able to see.
1757 """
1758 entry_args = {
1759 'test-bad-datatype-arg': '12',
1760 }
1761 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001762 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001763 entry_args=entry_args)
1764 self.assertIn('GetArg() internal error: Unknown data type ',
1765 str(e.exception))
1766
Simon Glass2ca52032018-07-17 13:25:33 -06001767 def testText(self):
1768 """Test for a text entry type"""
1769 entry_args = {
1770 'test-id': TEXT_DATA,
1771 'test-id2': TEXT_DATA2,
1772 'test-id3': TEXT_DATA3,
1773 }
Simon Glass511f6582018-10-01 12:22:30 -06001774 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001775 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001776 expected = (tools.to_bytes(TEXT_DATA) +
1777 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1778 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001779 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001780 self.assertEqual(expected, data)
1781
Simon Glass969616c2018-07-17 13:25:36 -06001782 def testEntryDocs(self):
1783 """Test for creation of entry documentation"""
1784 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001785 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001786 self.assertTrue(len(stdout.getvalue()) > 0)
1787
1788 def testEntryDocsMissing(self):
1789 """Test handling of missing entry documentation"""
1790 with self.assertRaises(ValueError) as e:
1791 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001792 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001793 self.assertIn('Documentation is missing for modules: u_boot',
1794 str(e.exception))
1795
Simon Glass704784b2018-07-17 13:25:38 -06001796 def testFmap(self):
1797 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001798 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001799 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001800 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1801 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001802 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001803 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001804 self.assertEqual(1, fhdr.ver_major)
1805 self.assertEqual(0, fhdr.ver_minor)
1806 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001807 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001808 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001809 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001810 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001811 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001812
Simon Glass82059c22021-04-03 11:05:09 +13001813 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001814 self.assertEqual(b'SECTION0', fentry.name)
1815 self.assertEqual(0, fentry.offset)
1816 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001817 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001818
1819 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001820 self.assertEqual(b'RO_U_BOOT', fentry.name)
1821 self.assertEqual(0, fentry.offset)
1822 self.assertEqual(4, fentry.size)
1823 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001824
Simon Glass82059c22021-04-03 11:05:09 +13001825 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001826 self.assertEqual(b'SECTION1', fentry.name)
1827 self.assertEqual(16, fentry.offset)
1828 self.assertEqual(16, fentry.size)
1829 self.assertEqual(0, fentry.flags)
1830
1831 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001832 self.assertEqual(b'RW_U_BOOT', fentry.name)
1833 self.assertEqual(16, fentry.offset)
1834 self.assertEqual(4, fentry.size)
1835 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001836
Simon Glass82059c22021-04-03 11:05:09 +13001837 fentry = next(fiter)
1838 self.assertEqual(b'FMAP', fentry.name)
1839 self.assertEqual(32, fentry.offset)
1840 self.assertEqual(expect_size, fentry.size)
1841 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001842
Simon Glassdb168d42018-07-17 13:25:39 -06001843 def testBlobNamedByArg(self):
1844 """Test we can add a blob with the filename coming from an entry arg"""
1845 entry_args = {
1846 'cros-ec-rw-path': 'ecrw.bin',
1847 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001848 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001849
Simon Glass53f53992018-07-17 13:25:40 -06001850 def testFill(self):
1851 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001852 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001853 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001854 self.assertEqual(expected, data)
1855
1856 def testFillNoSize(self):
1857 """Test for an fill entry type with no size"""
1858 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001859 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001860 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001861 str(e.exception))
1862
Simon Glassc1ae83c2018-07-17 13:25:44 -06001863 def _HandleGbbCommand(self, pipe_list):
1864 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001865 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001866 fname = pipe_list[0][-1]
1867 # Append our GBB data to the file, which will happen every time the
1868 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001869 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001870 fd.write(GBB_DATA)
1871 return command.CommandResult()
1872
1873 def testGbb(self):
1874 """Test for the Chromium OS Google Binary Block"""
1875 command.test_result = self._HandleGbbCommand
1876 entry_args = {
1877 'keydir': 'devkeys',
1878 'bmpblk': 'bmpblk.bin',
1879 }
Simon Glass511f6582018-10-01 12:22:30 -06001880 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001881
1882 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001883 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1884 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001885 self.assertEqual(expected, data)
1886
1887 def testGbbTooSmall(self):
1888 """Test for the Chromium OS Google Binary Block being large enough"""
1889 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001890 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001891 self.assertIn("Node '/binman/gbb': GBB is too small",
1892 str(e.exception))
1893
1894 def testGbbNoSize(self):
1895 """Test for the Chromium OS Google Binary Block having a size"""
1896 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001897 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001898 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1899 str(e.exception))
1900
Simon Glass66152ce2022-01-09 20:14:09 -07001901 def testGbbMissing(self):
1902 """Test that binman still produces an image if futility is missing"""
1903 entry_args = {
1904 'keydir': 'devkeys',
1905 }
1906 with test_util.capture_sys_output() as (_, stderr):
1907 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1908 entry_args=entry_args)
1909 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001910 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001911
Simon Glass5c350162018-07-17 13:25:47 -06001912 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001913 """Fake calls to the futility utility
1914
1915 The expected pipe is:
1916
1917 [('futility', 'vbutil_firmware', '--vblock',
1918 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1919 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1920 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1921 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1922
1923 This writes to the output file (here, 'vblock.vblock'). If
1924 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1925 of the input data (here, 'input.vblock').
1926 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001927 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001928 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001929 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001930 if self._hash_data:
1931 infile = pipe_list[0][11]
1932 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001933 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001934 m.update(data)
1935 fd.write(m.digest())
1936 else:
1937 fd.write(VBLOCK_DATA)
1938
Simon Glass5c350162018-07-17 13:25:47 -06001939 return command.CommandResult()
1940
1941 def testVblock(self):
1942 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001943 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001944 command.test_result = self._HandleVblockCommand
1945 entry_args = {
1946 'keydir': 'devkeys',
1947 }
Simon Glass511f6582018-10-01 12:22:30 -06001948 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001949 entry_args=entry_args)
1950 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1951 self.assertEqual(expected, data)
1952
1953 def testVblockNoContent(self):
1954 """Test we detect a vblock which has no content to sign"""
1955 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001956 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001957 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001958 'property', str(e.exception))
1959
1960 def testVblockBadPhandle(self):
1961 """Test that we detect a vblock with an invalid phandle in contents"""
1962 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001963 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001964 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1965 '1000', str(e.exception))
1966
1967 def testVblockBadEntry(self):
1968 """Test that we detect an entry that points to a non-entry"""
1969 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001970 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001971 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1972 "'other'", str(e.exception))
1973
Simon Glass220c6222021-01-06 21:35:17 -07001974 def testVblockContent(self):
1975 """Test that the vblock signs the right data"""
1976 self._hash_data = True
1977 command.test_result = self._HandleVblockCommand
1978 entry_args = {
1979 'keydir': 'devkeys',
1980 }
1981 data = self._DoReadFileDtb(
1982 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1983 entry_args=entry_args)[0]
1984 hashlen = 32 # SHA256 hash is 32 bytes
1985 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1986 hashval = data[-hashlen:]
1987 dtb = data[len(U_BOOT_DATA):-hashlen]
1988
1989 expected_data = U_BOOT_DATA + dtb
1990
1991 # The hashval should be a hash of the dtb
1992 m = hashlib.sha256()
1993 m.update(expected_data)
1994 expected_hashval = m.digest()
1995 self.assertEqual(expected_hashval, hashval)
1996
Simon Glass66152ce2022-01-09 20:14:09 -07001997 def testVblockMissing(self):
1998 """Test that binman still produces an image if futility is missing"""
1999 entry_args = {
2000 'keydir': 'devkeys',
2001 }
2002 with test_util.capture_sys_output() as (_, stderr):
2003 self._DoTestFile('074_vblock.dts',
2004 force_missing_bintools='futility',
2005 entry_args=entry_args)
2006 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07002007 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07002008
Simon Glass8425a1f2018-07-17 13:25:48 -06002009 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06002010 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06002011 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06002012 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06002013 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06002014 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
2015
Simon Glass24b97442018-07-17 13:25:51 -06002016 def testUsesPos(self):
2017 """Test that the 'pos' property cannot be used anymore"""
2018 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002019 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06002020 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
2021 "'pos'", str(e.exception))
2022
Simon Glass274bf092018-09-14 04:57:08 -06002023 def testFillZero(self):
2024 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06002025 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07002026 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06002027
Simon Glass267de432018-09-14 04:57:09 -06002028 def testTextMissing(self):
2029 """Test for a text entry type where there is no text"""
2030 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002031 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06002032 self.assertIn("Node '/binman/text': No value provided for text label "
2033 "'test-id'", str(e.exception))
2034
Simon Glassed40e962018-09-14 04:57:10 -06002035 def testPackStart16Tpl(self):
2036 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06002037 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06002038 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
2039
Simon Glass3b376c32018-09-14 04:57:12 -06002040 def testSelectImage(self):
2041 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06002042 expected = 'Skipping images: image1'
2043
2044 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06002045 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06002046 with test_util.capture_sys_output() as (stdout, stderr):
2047 retcode = self._DoTestFile('006_dual_image.dts',
2048 verbosity=verbosity,
2049 images=['image2'])
2050 self.assertEqual(0, retcode)
2051 if verbosity:
2052 self.assertIn(expected, stdout.getvalue())
2053 else:
2054 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06002055
Simon Glass80025522022-01-29 14:14:04 -07002056 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2057 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06002058 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06002059
Simon Glasse219aa42018-09-14 04:57:24 -06002060 def testUpdateFdtAll(self):
2061 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06002062 self._SetupSplElf()
2063 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06002064 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06002065
2066 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06002067 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002068 'image-pos': 0,
2069 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06002070 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002071 'section:image-pos': 0,
2072 'section:size': 565,
2073 'section/u-boot-dtb:offset': 0,
2074 'section/u-boot-dtb:image-pos': 0,
2075 'section/u-boot-dtb:size': 565,
2076 'u-boot-spl-dtb:offset': 565,
2077 'u-boot-spl-dtb:image-pos': 565,
2078 'u-boot-spl-dtb:size': 585,
2079 'u-boot-tpl-dtb:offset': 1150,
2080 'u-boot-tpl-dtb:image-pos': 1150,
2081 'u-boot-tpl-dtb:size': 585,
2082 'u-boot-vpl-dtb:image-pos': 1735,
2083 'u-boot-vpl-dtb:offset': 1735,
2084 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002085 }
2086
2087 # We expect three device-tree files in the output, one after the other.
2088 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2089 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2090 # main U-Boot tree. All three should have the same postions and offset.
2091 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002092 self.maxDiff = None
2093 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002094 dtb = fdt.Fdt.FromData(data[start:])
2095 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002096 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002097 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002098 expected = dict(base_expected)
2099 if item:
2100 expected[item] = 0
2101 self.assertEqual(expected, props)
2102 start += dtb._fdt_obj.totalsize()
2103
2104 def testUpdateFdtOutput(self):
2105 """Test that output DTB files are updated"""
2106 try:
Simon Glass511f6582018-10-01 12:22:30 -06002107 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002108 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2109
2110 # Unfortunately, compiling a source file always results in a file
2111 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002112 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002113 # binman as a file called u-boot.dtb. To fix this, copy the file
2114 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002115 start = 0
2116 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002117 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002118 dtb = fdt.Fdt.FromData(data[start:])
2119 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002120 pathname = tools.get_output_filename(os.path.split(fname)[1])
2121 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002122 name = os.path.split(fname)[0]
2123
2124 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002125 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002126 else:
2127 orig_indata = dtb_data
2128 self.assertNotEqual(outdata, orig_indata,
2129 "Expected output file '%s' be updated" % pathname)
2130 self.assertEqual(outdata, data[start:start + size],
2131 "Expected output file '%s' to match output image" %
2132 pathname)
2133 start += size
2134 finally:
2135 self._ResetDtbs()
2136
Simon Glass7ba33592018-09-14 04:57:26 -06002137 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002138 bintool = self.comp_bintools['lz4']
2139 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002140
2141 def testCompress(self):
2142 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002143 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002144 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002145 use_real_dtb=True, update_dtb=True)
2146 dtb = fdt.Fdt(out_dtb_fname)
2147 dtb.Scan()
2148 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2149 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00002150 self.assertEqual(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002151
2152 # Do a sanity check on various fields
2153 image = control.images['image']
2154 entries = image.GetEntries()
2155 self.assertEqual(1, len(entries))
2156
2157 entry = entries['blob']
2158 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2159 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2160 orig = self._decompress(entry.data)
2161 self.assertEqual(orig, entry.uncomp_data)
2162
Simon Glass72eeff12020-10-26 17:40:16 -06002163 self.assertEqual(image.data, entry.data)
2164
Simon Glass7ba33592018-09-14 04:57:26 -06002165 expected = {
2166 'blob:uncomp-size': len(COMPRESS_DATA),
2167 'blob:size': len(data),
2168 'size': len(data),
2169 }
2170 self.assertEqual(expected, props)
2171
Simon Glassac6328c2018-09-14 04:57:28 -06002172 def testFiles(self):
2173 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002174 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002175 self.assertEqual(FILES_DATA, data)
2176
2177 def testFilesCompress(self):
2178 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002179 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002180 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002181
2182 image = control.images['image']
2183 entries = image.GetEntries()
2184 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002185 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002186
Simon Glass303f62f2019-05-17 22:00:46 -06002187 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002188 for i in range(1, 3):
2189 key = '%d.dat' % i
2190 start = entries[key].image_pos
2191 len = entries[key].size
2192 chunk = data[start:start + len]
2193 orig += self._decompress(chunk)
2194
2195 self.assertEqual(FILES_DATA, orig)
2196
2197 def testFilesMissing(self):
2198 """Test missing files"""
2199 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002200 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002201 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2202 'no files', str(e.exception))
2203
2204 def testFilesNoPattern(self):
2205 """Test missing files"""
2206 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002207 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002208 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2209 str(e.exception))
2210
Simon Glassdd156a42022-03-05 20:18:59 -07002211 def testExtendSize(self):
2212 """Test an extending entry"""
2213 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002214 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002215 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2216 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2217 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2218 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002219 self.assertEqual(expect, data)
2220 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700222100000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600222200000000 00000000 00000008 fill
222300000008 00000008 00000004 u-boot
22240000000c 0000000c 00000004 section
22250000000c 00000000 00000003 intel-mrc
222600000010 00000010 00000004 u-boot2
222700000014 00000014 0000000c section2
222800000014 00000000 00000008 fill
22290000001c 00000008 00000004 u-boot
223000000020 00000020 00000008 fill2
2231''', map_data)
2232
Simon Glassdd156a42022-03-05 20:18:59 -07002233 def testExtendSizeBad(self):
2234 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002235 with test_util.capture_sys_output() as (stdout, stderr):
2236 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002237 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002238 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2239 'expanding entry', str(e.exception))
2240
Simon Glassae7cf032018-09-14 04:57:31 -06002241 def testHash(self):
2242 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002243 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002244 use_real_dtb=True, update_dtb=True)
2245 dtb = fdt.Fdt(out_dtb_fname)
2246 dtb.Scan()
2247 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2248 m = hashlib.sha256()
2249 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002250 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002251
2252 def testHashNoAlgo(self):
2253 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002254 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002255 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2256 'hash node', str(e.exception))
2257
2258 def testHashBadAlgo(self):
2259 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002260 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002261 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002262 str(e.exception))
2263
2264 def testHashSection(self):
2265 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002266 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002267 use_real_dtb=True, update_dtb=True)
2268 dtb = fdt.Fdt(out_dtb_fname)
2269 dtb.Scan()
2270 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2271 m = hashlib.sha256()
2272 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002273 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002274 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002275
Simon Glass3fb4f422018-09-14 04:57:32 -06002276 def testPackUBootTplMicrocode(self):
2277 """Test that x86 microcode can be handled correctly in TPL
2278
2279 We expect to see the following in the image, in order:
2280 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2281 place
2282 u-boot-tpl.dtb with the microcode removed
2283 the microcode
2284 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002285 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002286 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002287 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002288 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2289 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002290
Simon Glassc64aea52018-09-14 04:57:34 -06002291 def testFmapX86(self):
2292 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002293 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002294 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002295 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002296 self.assertEqual(expected, data[:32])
2297 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2298
2299 self.assertEqual(0x100, fhdr.image_size)
2300
2301 self.assertEqual(0, fentries[0].offset)
2302 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002303 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002304
2305 self.assertEqual(4, fentries[1].offset)
2306 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002307 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002308
2309 self.assertEqual(32, fentries[2].offset)
2310 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2311 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002312 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002313
2314 def testFmapX86Section(self):
2315 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002316 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002317 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002318 self.assertEqual(expected, data[:32])
2319 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2320
Simon Glassb1d414c2021-04-03 11:05:10 +13002321 self.assertEqual(0x180, fhdr.image_size)
2322 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002323 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002324
Simon Glass82059c22021-04-03 11:05:09 +13002325 fentry = next(fiter)
2326 self.assertEqual(b'U_BOOT', fentry.name)
2327 self.assertEqual(0, fentry.offset)
2328 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002329
Simon Glass82059c22021-04-03 11:05:09 +13002330 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002331 self.assertEqual(b'SECTION', fentry.name)
2332 self.assertEqual(4, fentry.offset)
2333 self.assertEqual(0x20 + expect_size, fentry.size)
2334
2335 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002336 self.assertEqual(b'INTEL_MRC', fentry.name)
2337 self.assertEqual(4, fentry.offset)
2338 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002339
Simon Glass82059c22021-04-03 11:05:09 +13002340 fentry = next(fiter)
2341 self.assertEqual(b'FMAP', fentry.name)
2342 self.assertEqual(36, fentry.offset)
2343 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002344
Simon Glassb1714232018-09-14 04:57:35 -06002345 def testElf(self):
2346 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002347 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002348 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002349 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002350 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002351 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002352
Simon Glass0d673792019-07-08 13:18:25 -06002353 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002354 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002355 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002356 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002357 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002358 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002359
Simon Glasscd817d52018-09-14 04:57:36 -06002360 def testPackOverlapMap(self):
2361 """Test that overlapping regions are detected"""
2362 with test_util.capture_sys_output() as (stdout, stderr):
2363 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002364 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002365 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002366 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2367 stdout.getvalue())
2368
2369 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002370 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002371 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002372 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002373 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002374<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002375<none> 00000000 00000004 u-boot
2376<none> 00000003 00000004 u-boot-align
2377''', map_data)
2378
Simon Glass0d673792019-07-08 13:18:25 -06002379 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002380 """Test that an image with an Intel Reference code binary works"""
2381 data = self._DoReadFile('100_intel_refcode.dts')
2382 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2383
Simon Glasseb023b32019-04-25 21:58:39 -06002384 def testSectionOffset(self):
2385 """Tests use of a section with an offset"""
2386 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2387 map=True)
2388 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700238900000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600239000000004 00000004 00000010 section@0
239100000004 00000000 00000004 u-boot
239200000018 00000018 00000010 section@1
239300000018 00000000 00000004 u-boot
23940000002c 0000002c 00000004 section@2
23950000002c 00000000 00000004 u-boot
2396''', map_data)
2397 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002398 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2399 tools.get_bytes(0x21, 12) +
2400 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2401 tools.get_bytes(0x61, 12) +
2402 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2403 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002404
Simon Glass1de34482019-07-08 13:18:53 -06002405 def testCbfsRaw(self):
2406 """Test base handling of a Coreboot Filesystem (CBFS)
2407
2408 The exact contents of the CBFS is verified by similar tests in
2409 cbfs_util_test.py. The tests here merely check that the files added to
2410 the CBFS can be found in the final image.
2411 """
2412 data = self._DoReadFile('102_cbfs_raw.dts')
2413 size = 0xb0
2414
2415 cbfs = cbfs_util.CbfsReader(data)
2416 self.assertEqual(size, cbfs.rom_size)
2417
2418 self.assertIn('u-boot-dtb', cbfs.files)
2419 cfile = cbfs.files['u-boot-dtb']
2420 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2421
2422 def testCbfsArch(self):
2423 """Test on non-x86 architecture"""
2424 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2425 size = 0x100
2426
2427 cbfs = cbfs_util.CbfsReader(data)
2428 self.assertEqual(size, cbfs.rom_size)
2429
2430 self.assertIn('u-boot-dtb', cbfs.files)
2431 cfile = cbfs.files['u-boot-dtb']
2432 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2433
2434 def testCbfsStage(self):
2435 """Tests handling of a Coreboot Filesystem (CBFS)"""
2436 if not elf.ELF_TOOLS:
2437 self.skipTest('Python elftools not available')
2438 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2439 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2440 size = 0xb0
2441
2442 data = self._DoReadFile('104_cbfs_stage.dts')
2443 cbfs = cbfs_util.CbfsReader(data)
2444 self.assertEqual(size, cbfs.rom_size)
2445
2446 self.assertIn('u-boot', cbfs.files)
2447 cfile = cbfs.files['u-boot']
2448 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2449
2450 def testCbfsRawCompress(self):
2451 """Test handling of compressing raw files"""
2452 self._CheckLz4()
2453 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2454 size = 0x140
2455
2456 cbfs = cbfs_util.CbfsReader(data)
2457 self.assertIn('u-boot', cbfs.files)
2458 cfile = cbfs.files['u-boot']
2459 self.assertEqual(COMPRESS_DATA, cfile.data)
2460
2461 def testCbfsBadArch(self):
2462 """Test handling of a bad architecture"""
2463 with self.assertRaises(ValueError) as e:
2464 self._DoReadFile('106_cbfs_bad_arch.dts')
2465 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2466
2467 def testCbfsNoSize(self):
2468 """Test handling of a missing size property"""
2469 with self.assertRaises(ValueError) as e:
2470 self._DoReadFile('107_cbfs_no_size.dts')
2471 self.assertIn('entry must have a size property', str(e.exception))
2472
Simon Glass3e28f4f2021-11-23 11:03:54 -07002473 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002474 """Test handling of a CBFS entry which does not provide contentsy"""
2475 with self.assertRaises(ValueError) as e:
2476 self._DoReadFile('108_cbfs_no_contents.dts')
2477 self.assertIn('Could not complete processing of contents',
2478 str(e.exception))
2479
2480 def testCbfsBadCompress(self):
2481 """Test handling of a bad architecture"""
2482 with self.assertRaises(ValueError) as e:
2483 self._DoReadFile('109_cbfs_bad_compress.dts')
2484 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2485 str(e.exception))
2486
2487 def testCbfsNamedEntries(self):
2488 """Test handling of named entries"""
2489 data = self._DoReadFile('110_cbfs_name.dts')
2490
2491 cbfs = cbfs_util.CbfsReader(data)
2492 self.assertIn('FRED', cbfs.files)
2493 cfile1 = cbfs.files['FRED']
2494 self.assertEqual(U_BOOT_DATA, cfile1.data)
2495
2496 self.assertIn('hello', cbfs.files)
2497 cfile2 = cbfs.files['hello']
2498 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2499
Simon Glass759af872019-07-08 13:18:54 -06002500 def _SetupIfwi(self, fname):
2501 """Set up to run an IFWI test
2502
2503 Args:
2504 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2505 """
2506 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002507 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002508
2509 # Intel Integrated Firmware Image (IFWI) file
2510 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2511 data = fd.read()
2512 TestFunctional._MakeInputFile(fname,data)
2513
2514 def _CheckIfwi(self, data):
2515 """Check that an image with an IFWI contains the correct output
2516
2517 Args:
2518 data: Conents of output file
2519 """
Simon Glass80025522022-01-29 14:14:04 -07002520 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002521 if data[:0x1000] != expected_desc:
2522 self.fail('Expected descriptor binary at start of image')
2523
2524 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002525 image_fname = tools.get_output_filename('image.bin')
2526 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002527 ifwitool = bintool.Bintool.create('ifwitool')
2528 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002529
Simon Glass80025522022-01-29 14:14:04 -07002530 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002531 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002532
2533 def testPackX86RomIfwi(self):
2534 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2535 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002536 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002537 self._CheckIfwi(data)
2538
2539 def testPackX86RomIfwiNoDesc(self):
2540 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2541 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002542 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002543 self._CheckIfwi(data)
2544
2545 def testPackX86RomIfwiNoData(self):
2546 """Test that an x86 ROM with IFWI handles missing data"""
2547 self._SetupIfwi('ifwi.bin')
2548 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002549 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002550 self.assertIn('Could not complete processing of contents',
2551 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002552
Simon Glass66152ce2022-01-09 20:14:09 -07002553 def testIfwiMissing(self):
2554 """Test that binman still produces an image if ifwitool is missing"""
2555 self._SetupIfwi('fitimage.bin')
2556 with test_util.capture_sys_output() as (_, stderr):
2557 self._DoTestFile('111_x86_rom_ifwi.dts',
2558 force_missing_bintools='ifwitool')
2559 err = stderr.getvalue()
2560 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002561 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002562
Simon Glassc2f1aed2019-07-08 13:18:56 -06002563 def testCbfsOffset(self):
2564 """Test a CBFS with files at particular offsets
2565
2566 Like all CFBS tests, this is just checking the logic that calls
2567 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2568 """
2569 data = self._DoReadFile('114_cbfs_offset.dts')
2570 size = 0x200
2571
2572 cbfs = cbfs_util.CbfsReader(data)
2573 self.assertEqual(size, cbfs.rom_size)
2574
2575 self.assertIn('u-boot', cbfs.files)
2576 cfile = cbfs.files['u-boot']
2577 self.assertEqual(U_BOOT_DATA, cfile.data)
2578 self.assertEqual(0x40, cfile.cbfs_offset)
2579
2580 self.assertIn('u-boot-dtb', cbfs.files)
2581 cfile2 = cbfs.files['u-boot-dtb']
2582 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2583 self.assertEqual(0x140, cfile2.cbfs_offset)
2584
Simon Glass0f621332019-07-08 14:25:27 -06002585 def testFdtmap(self):
2586 """Test an FDT map can be inserted in the image"""
2587 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2588 fdtmap_data = data[len(U_BOOT_DATA):]
2589 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002590 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002591 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002592
2593 fdt_data = fdtmap_data[16:]
2594 dtb = fdt.Fdt.FromData(fdt_data)
2595 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002596 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002597 self.assertEqual({
2598 'image-pos': 0,
2599 'offset': 0,
2600 'u-boot:offset': 0,
2601 'u-boot:size': len(U_BOOT_DATA),
2602 'u-boot:image-pos': 0,
2603 'fdtmap:image-pos': 4,
2604 'fdtmap:offset': 4,
2605 'fdtmap:size': len(fdtmap_data),
2606 'size': len(data),
2607 }, props)
2608
2609 def testFdtmapNoMatch(self):
2610 """Check handling of an FDT map when the section cannot be found"""
2611 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2612
2613 # Mangle the section name, which should cause a mismatch between the
2614 # correct FDT path and the one expected by the section
2615 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002616 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002617 entries = image.GetEntries()
2618 fdtmap = entries['fdtmap']
2619 with self.assertRaises(ValueError) as e:
2620 fdtmap._GetFdtmap()
2621 self.assertIn("Cannot locate node for path '/binman-suffix'",
2622 str(e.exception))
2623
Simon Glasscec34ba2019-07-08 14:25:28 -06002624 def testFdtmapHeader(self):
2625 """Test an FDT map and image header can be inserted in the image"""
2626 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2627 fdtmap_pos = len(U_BOOT_DATA)
2628 fdtmap_data = data[fdtmap_pos:]
2629 fdt_data = fdtmap_data[16:]
2630 dtb = fdt.Fdt.FromData(fdt_data)
2631 fdt_size = dtb.GetFdtObj().totalsize()
2632 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002633 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002634 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2635 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2636
2637 def testFdtmapHeaderStart(self):
2638 """Test an image header can be inserted at the image start"""
2639 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2640 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2641 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002642 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002643 offset = struct.unpack('<I', hdr_data[4:])[0]
2644 self.assertEqual(fdtmap_pos, offset)
2645
2646 def testFdtmapHeaderPos(self):
2647 """Test an image header can be inserted at a chosen position"""
2648 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2649 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2650 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002651 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002652 offset = struct.unpack('<I', hdr_data[4:])[0]
2653 self.assertEqual(fdtmap_pos, offset)
2654
2655 def testHeaderMissingFdtmap(self):
2656 """Test an image header requires an fdtmap"""
2657 with self.assertRaises(ValueError) as e:
2658 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2659 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2660 str(e.exception))
2661
2662 def testHeaderNoLocation(self):
2663 """Test an image header with a no specified location is detected"""
2664 with self.assertRaises(ValueError) as e:
2665 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2666 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2667 str(e.exception))
2668
Simon Glasse61b6f62019-07-08 14:25:37 -06002669 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002670 """Test extending an entry after it is packed"""
2671 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002672 self.assertEqual(b'aaa', data[:3])
2673 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2674 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002675
Simon Glassdd156a42022-03-05 20:18:59 -07002676 def testEntryExtendBad(self):
2677 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002678 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002679 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002680 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002681 str(e.exception))
2682
Simon Glassdd156a42022-03-05 20:18:59 -07002683 def testEntryExtendSection(self):
2684 """Test extending an entry within a section after it is packed"""
2685 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002686 self.assertEqual(b'aaa', data[:3])
2687 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2688 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002689
Simon Glass90d29682019-07-08 14:25:38 -06002690 def testCompressDtb(self):
2691 """Test that compress of device-tree files is supported"""
2692 self._CheckLz4()
2693 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2694 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2695 comp_data = data[len(U_BOOT_DATA):]
2696 orig = self._decompress(comp_data)
2697 dtb = fdt.Fdt.FromData(orig)
2698 dtb.Scan()
2699 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2700 expected = {
2701 'u-boot:size': len(U_BOOT_DATA),
2702 'u-boot-dtb:uncomp-size': len(orig),
2703 'u-boot-dtb:size': len(comp_data),
2704 'size': len(data),
2705 }
2706 self.assertEqual(expected, props)
2707
Simon Glass151bbbf2019-07-08 14:25:41 -06002708 def testCbfsUpdateFdt(self):
2709 """Test that we can update the device tree with CBFS offset/size info"""
2710 self._CheckLz4()
2711 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2712 update_dtb=True)
2713 dtb = fdt.Fdt(out_dtb_fname)
2714 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002715 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002716 del props['cbfs/u-boot:size']
2717 self.assertEqual({
2718 'offset': 0,
2719 'size': len(data),
2720 'image-pos': 0,
2721 'cbfs:offset': 0,
2722 'cbfs:size': len(data),
2723 'cbfs:image-pos': 0,
Simon Glassfa144222023-10-14 14:40:28 -06002724 'cbfs/u-boot:offset': 0x30,
Simon Glass151bbbf2019-07-08 14:25:41 -06002725 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002726 'cbfs/u-boot:image-pos': 0x30,
2727 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002728 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002729 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002730 }, props)
2731
Simon Glass3c9b4f22019-07-08 14:25:42 -06002732 def testCbfsBadType(self):
2733 """Test an image header with a no specified location is detected"""
2734 with self.assertRaises(ValueError) as e:
2735 self._DoReadFile('126_cbfs_bad_type.dts')
2736 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2737
Simon Glass6b156f82019-07-08 14:25:43 -06002738 def testList(self):
2739 """Test listing the files in an image"""
2740 self._CheckLz4()
2741 data = self._DoReadFile('127_list.dts')
2742 image = control.images['image']
2743 entries = image.BuildEntryList()
2744 self.assertEqual(7, len(entries))
2745
2746 ent = entries[0]
2747 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002748 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002749 self.assertEqual('section', ent.etype)
2750 self.assertEqual(len(data), ent.size)
2751 self.assertEqual(0, ent.image_pos)
2752 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002753 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002754
2755 ent = entries[1]
2756 self.assertEqual(1, ent.indent)
2757 self.assertEqual('u-boot', ent.name)
2758 self.assertEqual('u-boot', ent.etype)
2759 self.assertEqual(len(U_BOOT_DATA), ent.size)
2760 self.assertEqual(0, ent.image_pos)
2761 self.assertEqual(None, ent.uncomp_size)
2762 self.assertEqual(0, ent.offset)
2763
2764 ent = entries[2]
2765 self.assertEqual(1, ent.indent)
2766 self.assertEqual('section', ent.name)
2767 self.assertEqual('section', ent.etype)
2768 section_size = ent.size
2769 self.assertEqual(0x100, ent.image_pos)
2770 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002771 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002772
2773 ent = entries[3]
2774 self.assertEqual(2, ent.indent)
2775 self.assertEqual('cbfs', ent.name)
2776 self.assertEqual('cbfs', ent.etype)
2777 self.assertEqual(0x400, ent.size)
2778 self.assertEqual(0x100, ent.image_pos)
2779 self.assertEqual(None, ent.uncomp_size)
2780 self.assertEqual(0, ent.offset)
2781
2782 ent = entries[4]
2783 self.assertEqual(3, ent.indent)
2784 self.assertEqual('u-boot', ent.name)
2785 self.assertEqual('u-boot', ent.etype)
2786 self.assertEqual(len(U_BOOT_DATA), ent.size)
2787 self.assertEqual(0x138, ent.image_pos)
2788 self.assertEqual(None, ent.uncomp_size)
2789 self.assertEqual(0x38, ent.offset)
2790
2791 ent = entries[5]
2792 self.assertEqual(3, ent.indent)
2793 self.assertEqual('u-boot-dtb', ent.name)
2794 self.assertEqual('text', ent.etype)
2795 self.assertGreater(len(COMPRESS_DATA), ent.size)
2796 self.assertEqual(0x178, ent.image_pos)
2797 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2798 self.assertEqual(0x78, ent.offset)
2799
2800 ent = entries[6]
2801 self.assertEqual(2, ent.indent)
2802 self.assertEqual('u-boot-dtb', ent.name)
2803 self.assertEqual('u-boot-dtb', ent.etype)
2804 self.assertEqual(0x500, ent.image_pos)
2805 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2806 dtb_size = ent.size
2807 # Compressing this data expands it since headers are added
2808 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2809 self.assertEqual(0x400, ent.offset)
2810
2811 self.assertEqual(len(data), 0x100 + section_size)
2812 self.assertEqual(section_size, 0x400 + dtb_size)
2813
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002814 def testFindFdtmap(self):
2815 """Test locating an FDT map in an image"""
2816 self._CheckLz4()
2817 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2818 image = control.images['image']
2819 entries = image.GetEntries()
2820 entry = entries['fdtmap']
2821 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2822
2823 def testFindFdtmapMissing(self):
2824 """Test failing to locate an FDP map"""
2825 data = self._DoReadFile('005_simple.dts')
2826 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2827
Simon Glassed39a3c2019-07-08 14:25:45 -06002828 def testFindImageHeader(self):
2829 """Test locating a image header"""
2830 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002831 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002832 image = control.images['image']
2833 entries = image.GetEntries()
2834 entry = entries['fdtmap']
2835 # The header should point to the FDT map
2836 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2837
2838 def testFindImageHeaderStart(self):
2839 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002840 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002841 image = control.images['image']
2842 entries = image.GetEntries()
2843 entry = entries['fdtmap']
2844 # The header should point to the FDT map
2845 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2846
2847 def testFindImageHeaderMissing(self):
2848 """Test failing to locate an image header"""
2849 data = self._DoReadFile('005_simple.dts')
2850 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2851
Simon Glassb8424fa2019-07-08 14:25:46 -06002852 def testReadImage(self):
2853 """Test reading an image and accessing its FDT map"""
2854 self._CheckLz4()
2855 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002856 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002857 orig_image = control.images['image']
2858 image = Image.FromFile(image_fname)
2859 self.assertEqual(orig_image.GetEntries().keys(),
2860 image.GetEntries().keys())
2861
2862 orig_entry = orig_image.GetEntries()['fdtmap']
2863 entry = image.GetEntries()['fdtmap']
Brandon Maiera657bc62024-06-04 16:16:05 +00002864 self.assertEqual(orig_entry.offset, entry.offset)
2865 self.assertEqual(orig_entry.size, entry.size)
2866 self.assertEqual(orig_entry.image_pos, entry.image_pos)
Simon Glassb8424fa2019-07-08 14:25:46 -06002867
2868 def testReadImageNoHeader(self):
2869 """Test accessing an image's FDT map without an image header"""
2870 self._CheckLz4()
2871 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002872 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002873 image = Image.FromFile(image_fname)
2874 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002875 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002876
2877 def testReadImageFail(self):
2878 """Test failing to read an image image's FDT map"""
2879 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002880 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002881 with self.assertRaises(ValueError) as e:
2882 image = Image.FromFile(image_fname)
2883 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002884
Simon Glassb2fd11d2019-07-08 14:25:48 -06002885 def testListCmd(self):
2886 """Test listing the files in an image using an Fdtmap"""
2887 self._CheckLz4()
2888 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2889
2890 # lz4 compression size differs depending on the version
2891 image = control.images['image']
2892 entries = image.GetEntries()
2893 section_size = entries['section'].size
2894 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2895 fdtmap_offset = entries['fdtmap'].offset
2896
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002897 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002898 try:
2899 tmpdir, updated_fname = self._SetupImageInTmpdir()
2900 with test_util.capture_sys_output() as (stdout, stderr):
2901 self._DoBinman('ls', '-i', updated_fname)
2902 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002903 if tmpdir:
2904 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002905 lines = stdout.getvalue().splitlines()
2906 expected = [
2907'Name Image-pos Size Entry-type Offset Uncomp-size',
2908'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002909'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002910' u-boot 0 4 u-boot 0',
2911' section 100 %x section 100' % section_size,
2912' cbfs 100 400 cbfs 0',
Simon Glassfa144222023-10-14 14:40:28 -06002913' u-boot 120 4 u-boot 20',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002914' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002915' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002916' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002917 (fdtmap_offset, fdtmap_offset),
2918' image-header bf8 8 image-header bf8',
2919 ]
2920 self.assertEqual(expected, lines)
2921
2922 def testListCmdFail(self):
2923 """Test failing to list an image"""
2924 self._DoReadFile('005_simple.dts')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002925 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002926 try:
2927 tmpdir, updated_fname = self._SetupImageInTmpdir()
2928 with self.assertRaises(ValueError) as e:
2929 self._DoBinman('ls', '-i', updated_fname)
2930 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002931 if tmpdir:
2932 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002933 self.assertIn("Cannot find FDT map in image", str(e.exception))
2934
2935 def _RunListCmd(self, paths, expected):
2936 """List out entries and check the result
2937
2938 Args:
2939 paths: List of paths to pass to the list command
2940 expected: Expected list of filenames to be returned, in order
2941 """
2942 self._CheckLz4()
2943 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002944 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002945 image = Image.FromFile(image_fname)
2946 lines = image.GetListEntries(paths)[1]
2947 files = [line[0].strip() for line in lines[1:]]
2948 self.assertEqual(expected, files)
2949
2950 def testListCmdSection(self):
2951 """Test listing the files in a section"""
2952 self._RunListCmd(['section'],
2953 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2954
2955 def testListCmdFile(self):
2956 """Test listing a particular file"""
2957 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2958
2959 def testListCmdWildcard(self):
2960 """Test listing a wildcarded file"""
2961 self._RunListCmd(['*boot*'],
2962 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2963
2964 def testListCmdWildcardMulti(self):
2965 """Test listing a wildcarded file"""
2966 self._RunListCmd(['*cb*', '*head*'],
2967 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2968
2969 def testListCmdEmpty(self):
2970 """Test listing a wildcarded file"""
2971 self._RunListCmd(['nothing'], [])
2972
2973 def testListCmdPath(self):
2974 """Test listing the files in a sub-entry of a section"""
2975 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2976
Simon Glass4c613bf2019-07-08 14:25:50 -06002977 def _RunExtractCmd(self, entry_name, decomp=True):
2978 """Extract an entry from an image
2979
2980 Args:
2981 entry_name: Entry name to extract
2982 decomp: True to decompress the data if compressed, False to leave
2983 it in its raw uncompressed format
2984
2985 Returns:
2986 data from entry
2987 """
2988 self._CheckLz4()
2989 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002990 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002991 return control.ReadEntry(image_fname, entry_name, decomp)
2992
2993 def testExtractSimple(self):
2994 """Test extracting a single file"""
2995 data = self._RunExtractCmd('u-boot')
2996 self.assertEqual(U_BOOT_DATA, data)
2997
Simon Glass980a2842019-07-08 14:25:52 -06002998 def testExtractSection(self):
2999 """Test extracting the files in a section"""
3000 data = self._RunExtractCmd('section')
3001 cbfs_data = data[:0x400]
3002 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06003003 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06003004 dtb_data = data[0x400:]
3005 dtb = self._decompress(dtb_data)
3006 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3007
3008 def testExtractCompressed(self):
3009 """Test extracting compressed data"""
3010 data = self._RunExtractCmd('section/u-boot-dtb')
3011 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3012
3013 def testExtractRaw(self):
3014 """Test extracting compressed data without decompressing it"""
3015 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
3016 dtb = self._decompress(data)
3017 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3018
3019 def testExtractCbfs(self):
3020 """Test extracting CBFS data"""
3021 data = self._RunExtractCmd('section/cbfs/u-boot')
3022 self.assertEqual(U_BOOT_DATA, data)
3023
3024 def testExtractCbfsCompressed(self):
3025 """Test extracting CBFS compressed data"""
3026 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
3027 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3028
3029 def testExtractCbfsRaw(self):
3030 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003031 bintool = self.comp_bintools['lzma_alone']
3032 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06003033 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003034 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06003035 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3036
Simon Glass4c613bf2019-07-08 14:25:50 -06003037 def testExtractBadEntry(self):
3038 """Test extracting a bad section path"""
3039 with self.assertRaises(ValueError) as e:
3040 self._RunExtractCmd('section/does-not-exist')
3041 self.assertIn("Entry 'does-not-exist' not found in '/section'",
3042 str(e.exception))
3043
3044 def testExtractMissingFile(self):
3045 """Test extracting file that does not exist"""
3046 with self.assertRaises(IOError) as e:
3047 control.ReadEntry('missing-file', 'name')
3048
3049 def testExtractBadFile(self):
3050 """Test extracting an invalid file"""
3051 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07003052 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06003053 with self.assertRaises(ValueError) as e:
3054 control.ReadEntry(fname, 'name')
3055
Simon Glass980a2842019-07-08 14:25:52 -06003056 def testExtractCmd(self):
3057 """Test extracting a file fron an image on the command line"""
3058 self._CheckLz4()
3059 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06003060 fname = os.path.join(self._indir, 'output.extact')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003061 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06003062 try:
3063 tmpdir, updated_fname = self._SetupImageInTmpdir()
3064 with test_util.capture_sys_output() as (stdout, stderr):
3065 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3066 '-f', fname)
3067 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003068 if tmpdir:
3069 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07003070 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003071 self.assertEqual(U_BOOT_DATA, data)
3072
3073 def testExtractOneEntry(self):
3074 """Test extracting a single entry fron an image """
3075 self._CheckLz4()
3076 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003077 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003078 fname = os.path.join(self._indir, 'output.extact')
3079 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003080 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003081 self.assertEqual(U_BOOT_DATA, data)
3082
3083 def _CheckExtractOutput(self, decomp):
3084 """Helper to test file output with and without decompression
3085
3086 Args:
3087 decomp: True to decompress entry data, False to output it raw
3088 """
3089 def _CheckPresent(entry_path, expect_data, expect_size=None):
3090 """Check and remove expected file
3091
3092 This checks the data/size of a file and removes the file both from
3093 the outfiles set and from the output directory. Once all files are
3094 processed, both the set and directory should be empty.
3095
3096 Args:
3097 entry_path: Entry path
3098 expect_data: Data to expect in file, or None to skip check
3099 expect_size: Size of data to expect in file, or None to skip
3100 """
3101 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003102 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003103 os.remove(path)
3104 if expect_data:
3105 self.assertEqual(expect_data, data)
3106 elif expect_size:
3107 self.assertEqual(expect_size, len(data))
3108 outfiles.remove(path)
3109
3110 def _CheckDirPresent(name):
3111 """Remove expected directory
3112
3113 This gives an error if the directory does not exist as expected
3114
3115 Args:
3116 name: Name of directory to remove
3117 """
3118 path = os.path.join(outdir, name)
3119 os.rmdir(path)
3120
3121 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003122 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003123 outdir = os.path.join(self._indir, 'extract')
3124 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3125
3126 # Create a set of all file that were output (should be 9)
3127 outfiles = set()
3128 for root, dirs, files in os.walk(outdir):
3129 outfiles |= set([os.path.join(root, fname) for fname in files])
3130 self.assertEqual(9, len(outfiles))
3131 self.assertEqual(9, len(einfos))
3132
3133 image = control.images['image']
3134 entries = image.GetEntries()
3135
3136 # Check the 9 files in various ways
3137 section = entries['section']
3138 section_entries = section.GetEntries()
3139 cbfs_entries = section_entries['cbfs'].GetEntries()
3140 _CheckPresent('u-boot', U_BOOT_DATA)
3141 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3142 dtb_len = EXTRACT_DTB_SIZE
3143 if not decomp:
3144 dtb_len = cbfs_entries['u-boot-dtb'].size
3145 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3146 if not decomp:
3147 dtb_len = section_entries['u-boot-dtb'].size
3148 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3149
3150 fdtmap = entries['fdtmap']
3151 _CheckPresent('fdtmap', fdtmap.data)
3152 hdr = entries['image-header']
3153 _CheckPresent('image-header', hdr.data)
3154
3155 _CheckPresent('section/root', section.data)
3156 cbfs = section_entries['cbfs']
3157 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003158 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003159 _CheckPresent('root', data)
3160
3161 # There should be no files left. Remove all the directories to check.
3162 # If there are any files/dirs remaining, one of these checks will fail.
3163 self.assertEqual(0, len(outfiles))
3164 _CheckDirPresent('section/cbfs')
3165 _CheckDirPresent('section')
3166 _CheckDirPresent('')
3167 self.assertFalse(os.path.exists(outdir))
3168
3169 def testExtractAllEntries(self):
3170 """Test extracting all entries"""
3171 self._CheckLz4()
3172 self._CheckExtractOutput(decomp=True)
3173
3174 def testExtractAllEntriesRaw(self):
3175 """Test extracting all entries without decompressing them"""
3176 self._CheckLz4()
3177 self._CheckExtractOutput(decomp=False)
3178
3179 def testExtractSelectedEntries(self):
3180 """Test extracting some entries"""
3181 self._CheckLz4()
3182 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003183 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003184 outdir = os.path.join(self._indir, 'extract')
3185 einfos = control.ExtractEntries(image_fname, None, outdir,
3186 ['*cb*', '*head*'])
3187
3188 # File output is tested by testExtractAllEntries(), so just check that
3189 # the expected entries are selected
3190 names = [einfo.name for einfo in einfos]
3191 self.assertEqual(names,
3192 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3193
3194 def testExtractNoEntryPaths(self):
3195 """Test extracting some entries"""
3196 self._CheckLz4()
3197 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003198 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003199 with self.assertRaises(ValueError) as e:
3200 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003201 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003202 str(e.exception))
3203
3204 def testExtractTooManyEntryPaths(self):
3205 """Test extracting some entries"""
3206 self._CheckLz4()
3207 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003208 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003209 with self.assertRaises(ValueError) as e:
3210 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003211 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003212 str(e.exception))
3213
Simon Glass52d06212019-07-08 14:25:53 -06003214 def testPackAlignSection(self):
3215 """Test that sections can have alignment"""
3216 self._DoReadFile('131_pack_align_section.dts')
3217
3218 self.assertIn('image', control.images)
3219 image = control.images['image']
3220 entries = image.GetEntries()
3221 self.assertEqual(3, len(entries))
3222
3223 # First u-boot
3224 self.assertIn('u-boot', entries)
3225 entry = entries['u-boot']
3226 self.assertEqual(0, entry.offset)
3227 self.assertEqual(0, entry.image_pos)
3228 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3229 self.assertEqual(len(U_BOOT_DATA), entry.size)
3230
3231 # Section0
3232 self.assertIn('section0', entries)
3233 section0 = entries['section0']
3234 self.assertEqual(0x10, section0.offset)
3235 self.assertEqual(0x10, section0.image_pos)
3236 self.assertEqual(len(U_BOOT_DATA), section0.size)
3237
3238 # Second u-boot
3239 section_entries = section0.GetEntries()
3240 self.assertIn('u-boot', section_entries)
3241 entry = section_entries['u-boot']
3242 self.assertEqual(0, entry.offset)
3243 self.assertEqual(0x10, entry.image_pos)
3244 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3245 self.assertEqual(len(U_BOOT_DATA), entry.size)
3246
3247 # Section1
3248 self.assertIn('section1', entries)
3249 section1 = entries['section1']
3250 self.assertEqual(0x14, section1.offset)
3251 self.assertEqual(0x14, section1.image_pos)
3252 self.assertEqual(0x20, section1.size)
3253
3254 # Second u-boot
3255 section_entries = section1.GetEntries()
3256 self.assertIn('u-boot', section_entries)
3257 entry = section_entries['u-boot']
3258 self.assertEqual(0, entry.offset)
3259 self.assertEqual(0x14, entry.image_pos)
3260 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3261 self.assertEqual(len(U_BOOT_DATA), entry.size)
3262
3263 # Section2
3264 self.assertIn('section2', section_entries)
3265 section2 = section_entries['section2']
3266 self.assertEqual(0x4, section2.offset)
3267 self.assertEqual(0x18, section2.image_pos)
3268 self.assertEqual(4, section2.size)
3269
3270 # Third u-boot
3271 section_entries = section2.GetEntries()
3272 self.assertIn('u-boot', section_entries)
3273 entry = section_entries['u-boot']
3274 self.assertEqual(0, entry.offset)
3275 self.assertEqual(0x18, entry.image_pos)
3276 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3277 self.assertEqual(len(U_BOOT_DATA), entry.size)
3278
Simon Glassf8a54bc2019-07-20 12:23:56 -06003279 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3280 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003281 """Replace an entry in an image
3282
3283 This writes the entry data to update it, then opens the updated file and
3284 returns the value that it now finds there.
3285
3286 Args:
3287 entry_name: Entry name to replace
3288 data: Data to replace it with
3289 decomp: True to compress the data if needed, False if data is
3290 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003291 allow_resize: True to allow entries to change size, False to raise
3292 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003293
3294 Returns:
3295 Tuple:
3296 data from entry
3297 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003298 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003299 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003300 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003301 update_dtb=True)[1]
3302
3303 self.assertIn('image', control.images)
3304 image = control.images['image']
3305 entries = image.GetEntries()
3306 orig_dtb_data = entries['u-boot-dtb'].data
3307 orig_fdtmap_data = entries['fdtmap'].data
3308
Simon Glass80025522022-01-29 14:14:04 -07003309 image_fname = tools.get_output_filename('image.bin')
3310 updated_fname = tools.get_output_filename('image-updated.bin')
3311 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003312 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3313 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003314 data = control.ReadEntry(updated_fname, entry_name, decomp)
3315
Simon Glassf8a54bc2019-07-20 12:23:56 -06003316 # The DT data should not change unless resized:
3317 if not allow_resize:
3318 new_dtb_data = entries['u-boot-dtb'].data
3319 self.assertEqual(new_dtb_data, orig_dtb_data)
3320 new_fdtmap_data = entries['fdtmap'].data
3321 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003322
Simon Glassf8a54bc2019-07-20 12:23:56 -06003323 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003324
3325 def testReplaceSimple(self):
3326 """Test replacing a single file"""
3327 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003328 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3329 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003330 self.assertEqual(expected, data)
3331
3332 # Test that the state looks right. There should be an FDT for the fdtmap
3333 # that we jsut read back in, and it should match what we find in the
3334 # 'control' tables. Checking for an FDT that does not exist should
3335 # return None.
3336 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003337 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003338 self.assertEqual(expected_fdtmap, fdtmap)
3339
3340 dtb = state.GetFdtForEtype('fdtmap')
3341 self.assertEqual(dtb.GetContents(), fdtmap)
3342
3343 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3344 self.assertIsNone(missing_path)
3345 self.assertIsNone(missing_fdtmap)
3346
3347 missing_dtb = state.GetFdtForEtype('missing')
3348 self.assertIsNone(missing_dtb)
3349
3350 self.assertEqual('/binman', state.fdt_path_prefix)
3351
3352 def testReplaceResizeFail(self):
3353 """Test replacing a file by something larger"""
3354 expected = U_BOOT_DATA + b'x'
3355 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003356 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3357 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003358 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3359 str(e.exception))
3360
3361 def testReplaceMulti(self):
3362 """Test replacing entry data where multiple images are generated"""
3363 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3364 update_dtb=True)[0]
3365 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003366 updated_fname = tools.get_output_filename('image-updated.bin')
3367 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003368 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003369 control.WriteEntry(updated_fname, entry_name, expected,
3370 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003371 data = control.ReadEntry(updated_fname, entry_name)
3372 self.assertEqual(expected, data)
3373
3374 # Check the state looks right.
3375 self.assertEqual('/binman/image', state.fdt_path_prefix)
3376
3377 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003378 image_fname = tools.get_output_filename('first-image.bin')
3379 updated_fname = tools.get_output_filename('first-updated.bin')
3380 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003381 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003382 control.WriteEntry(updated_fname, entry_name, expected,
3383 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003384 data = control.ReadEntry(updated_fname, entry_name)
3385 self.assertEqual(expected, data)
3386
3387 # Check the state looks right.
3388 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003389
Simon Glassfb30e292019-07-20 12:23:51 -06003390 def testUpdateFdtAllRepack(self):
3391 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003392 self._SetupSplElf()
3393 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003394 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3395 SECTION_SIZE = 0x300
3396 DTB_SIZE = 602
3397 FDTMAP_SIZE = 608
3398 base_expected = {
3399 'offset': 0,
3400 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3401 'image-pos': 0,
3402 'section:offset': 0,
3403 'section:size': SECTION_SIZE,
3404 'section:image-pos': 0,
3405 'section/u-boot-dtb:offset': 4,
3406 'section/u-boot-dtb:size': 636,
3407 'section/u-boot-dtb:image-pos': 4,
3408 'u-boot-spl-dtb:offset': SECTION_SIZE,
3409 'u-boot-spl-dtb:size': DTB_SIZE,
3410 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3411 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3412 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3413 'u-boot-tpl-dtb:size': DTB_SIZE,
3414 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3415 'fdtmap:size': FDTMAP_SIZE,
3416 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3417 }
3418 main_expected = {
3419 'section:orig-size': SECTION_SIZE,
3420 'section/u-boot-dtb:orig-offset': 4,
3421 }
3422
3423 # We expect three device-tree files in the output, with the first one
3424 # within a fixed-size section.
3425 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3426 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3427 # main U-Boot tree. All three should have the same positions and offset
3428 # except that the main tree should include the main_expected properties
3429 start = 4
3430 for item in ['', 'spl', 'tpl', None]:
3431 if item is None:
3432 start += 16 # Move past fdtmap header
3433 dtb = fdt.Fdt.FromData(data[start:])
3434 dtb.Scan()
3435 props = self._GetPropTree(dtb,
3436 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3437 prefix='/' if item is None else '/binman/')
3438 expected = dict(base_expected)
3439 if item:
3440 expected[item] = 0
3441 else:
3442 # Main DTB and fdtdec should include the 'orig-' properties
3443 expected.update(main_expected)
3444 # Helpful for debugging:
3445 #for prop in sorted(props):
3446 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3447 self.assertEqual(expected, props)
3448 if item == '':
3449 start = SECTION_SIZE
3450 else:
3451 start += dtb._fdt_obj.totalsize()
3452
Simon Glass11453762019-07-20 12:23:55 -06003453 def testFdtmapHeaderMiddle(self):
3454 """Test an FDT map in the middle of an image when it should be at end"""
3455 with self.assertRaises(ValueError) as e:
3456 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3457 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3458 str(e.exception))
3459
3460 def testFdtmapHeaderStartBad(self):
3461 """Test an FDT map in middle of an image when it should be at start"""
3462 with self.assertRaises(ValueError) as e:
3463 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3464 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3465 str(e.exception))
3466
3467 def testFdtmapHeaderEndBad(self):
3468 """Test an FDT map at the start of an image when it should be at end"""
3469 with self.assertRaises(ValueError) as e:
3470 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3471 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3472 str(e.exception))
3473
3474 def testFdtmapHeaderNoSize(self):
3475 """Test an image header at the end of an image with undefined size"""
3476 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3477
Simon Glassf8a54bc2019-07-20 12:23:56 -06003478 def testReplaceResize(self):
3479 """Test replacing a single file in an entry with a larger file"""
3480 expected = U_BOOT_DATA + b'x'
3481 data, _, image = self._RunReplaceCmd('u-boot', expected,
3482 dts='139_replace_repack.dts')
3483 self.assertEqual(expected, data)
3484
3485 entries = image.GetEntries()
3486 dtb_data = entries['u-boot-dtb'].data
3487 dtb = fdt.Fdt.FromData(dtb_data)
3488 dtb.Scan()
3489
3490 # The u-boot section should now be larger in the dtb
3491 node = dtb.GetNode('/binman/u-boot')
3492 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3493
3494 # Same for the fdtmap
3495 fdata = entries['fdtmap'].data
3496 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3497 fdtb.Scan()
3498 fnode = fdtb.GetNode('/u-boot')
3499 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3500
3501 def testReplaceResizeNoRepack(self):
3502 """Test replacing an entry with a larger file when not allowed"""
3503 expected = U_BOOT_DATA + b'x'
3504 with self.assertRaises(ValueError) as e:
3505 self._RunReplaceCmd('u-boot', expected)
3506 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3507 str(e.exception))
3508
Simon Glass9d8ee322019-07-20 12:23:58 -06003509 def testEntryShrink(self):
3510 """Test contracting an entry after it is packed"""
3511 try:
3512 state.SetAllowEntryContraction(True)
3513 data = self._DoReadFileDtb('140_entry_shrink.dts',
3514 update_dtb=True)[0]
3515 finally:
3516 state.SetAllowEntryContraction(False)
3517 self.assertEqual(b'a', data[:1])
3518 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3519 self.assertEqual(b'a', data[-1:])
3520
3521 def testEntryShrinkFail(self):
3522 """Test not being allowed to contract an entry after it is packed"""
3523 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3524
3525 # In this case there is a spare byte at the end of the data. The size of
3526 # the contents is only 1 byte but we still have the size before it
3527 # shrunk.
3528 self.assertEqual(b'a\0', data[:2])
3529 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3530 self.assertEqual(b'a\0', data[-2:])
3531
Simon Glass70e32982019-07-20 12:24:01 -06003532 def testDescriptorOffset(self):
3533 """Test that the Intel descriptor is always placed at at the start"""
3534 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3535 image = control.images['image']
3536 entries = image.GetEntries()
3537 desc = entries['intel-descriptor']
3538 self.assertEqual(0xff800000, desc.offset);
3539 self.assertEqual(0xff800000, desc.image_pos);
3540
Simon Glass37fdd142019-07-20 12:24:06 -06003541 def testReplaceCbfs(self):
3542 """Test replacing a single file in CBFS without changing the size"""
3543 self._CheckLz4()
3544 expected = b'x' * len(U_BOOT_DATA)
3545 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003546 updated_fname = tools.get_output_filename('image-updated.bin')
3547 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003548 entry_name = 'section/cbfs/u-boot'
3549 control.WriteEntry(updated_fname, entry_name, expected,
3550 allow_resize=True)
3551 data = control.ReadEntry(updated_fname, entry_name)
3552 self.assertEqual(expected, data)
3553
3554 def testReplaceResizeCbfs(self):
3555 """Test replacing a single file in CBFS with one of a different size"""
3556 self._CheckLz4()
3557 expected = U_BOOT_DATA + b'x'
3558 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003559 updated_fname = tools.get_output_filename('image-updated.bin')
3560 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003561 entry_name = 'section/cbfs/u-boot'
3562 control.WriteEntry(updated_fname, entry_name, expected,
3563 allow_resize=True)
3564 data = control.ReadEntry(updated_fname, entry_name)
3565 self.assertEqual(expected, data)
3566
Simon Glass30033c22019-07-20 12:24:15 -06003567 def _SetupForReplace(self):
3568 """Set up some files to use to replace entries
3569
3570 This generates an image, copies it to a new file, extracts all the files
3571 in it and updates some of them
3572
3573 Returns:
3574 List
3575 Image filename
3576 Output directory
3577 Expected values for updated entries, each a string
3578 """
3579 data = self._DoReadFileRealDtb('143_replace_all.dts')
3580
Simon Glass80025522022-01-29 14:14:04 -07003581 updated_fname = tools.get_output_filename('image-updated.bin')
3582 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003583
3584 outdir = os.path.join(self._indir, 'extract')
3585 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3586
3587 expected1 = b'x' + U_BOOT_DATA + b'y'
3588 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003589 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003590
3591 expected2 = b'a' + U_BOOT_DATA + b'b'
3592 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003593 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003594
3595 expected_text = b'not the same text'
3596 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003597 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003598
3599 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3600 dtb = fdt.FdtScan(dtb_fname)
3601 node = dtb.GetNode('/binman/text')
3602 node.AddString('my-property', 'the value')
3603 dtb.Sync(auto_resize=True)
3604 dtb.Flush()
3605
3606 return updated_fname, outdir, expected1, expected2, expected_text
3607
3608 def _CheckReplaceMultiple(self, entry_paths):
3609 """Handle replacing the contents of multiple entries
3610
3611 Args:
3612 entry_paths: List of entry paths to replace
3613
3614 Returns:
3615 List
3616 Dict of entries in the image:
3617 key: Entry name
3618 Value: Entry object
3619 Expected values for updated entries, each a string
3620 """
3621 updated_fname, outdir, expected1, expected2, expected_text = (
3622 self._SetupForReplace())
3623 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3624
3625 image = Image.FromFile(updated_fname)
3626 image.LoadData()
3627 return image.GetEntries(), expected1, expected2, expected_text
3628
3629 def testReplaceAll(self):
3630 """Test replacing the contents of all entries"""
3631 entries, expected1, expected2, expected_text = (
3632 self._CheckReplaceMultiple([]))
3633 data = entries['u-boot'].data
3634 self.assertEqual(expected1, data)
3635
3636 data = entries['u-boot2'].data
3637 self.assertEqual(expected2, data)
3638
3639 data = entries['text'].data
3640 self.assertEqual(expected_text, data)
3641
3642 # Check that the device tree is updated
3643 data = entries['u-boot-dtb'].data
3644 dtb = fdt.Fdt.FromData(data)
3645 dtb.Scan()
3646 node = dtb.GetNode('/binman/text')
3647 self.assertEqual('the value', node.props['my-property'].value)
3648
3649 def testReplaceSome(self):
3650 """Test replacing the contents of a few entries"""
3651 entries, expected1, expected2, expected_text = (
3652 self._CheckReplaceMultiple(['u-boot2', 'text']))
3653
3654 # This one should not change
3655 data = entries['u-boot'].data
3656 self.assertEqual(U_BOOT_DATA, data)
3657
3658 data = entries['u-boot2'].data
3659 self.assertEqual(expected2, data)
3660
3661 data = entries['text'].data
3662 self.assertEqual(expected_text, data)
3663
3664 def testReplaceCmd(self):
3665 """Test replacing a file fron an image on the command line"""
3666 self._DoReadFileRealDtb('143_replace_all.dts')
3667
3668 try:
3669 tmpdir, updated_fname = self._SetupImageInTmpdir()
3670
3671 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3672 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003673 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003674
3675 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003676 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003677 self.assertEqual(expected, data[:len(expected)])
3678 map_fname = os.path.join(tmpdir, 'image-updated.map')
3679 self.assertFalse(os.path.exists(map_fname))
3680 finally:
3681 shutil.rmtree(tmpdir)
3682
3683 def testReplaceCmdSome(self):
3684 """Test replacing some files fron an image on the command line"""
3685 updated_fname, outdir, expected1, expected2, expected_text = (
3686 self._SetupForReplace())
3687
3688 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3689 'u-boot2', 'text')
3690
Simon Glass80025522022-01-29 14:14:04 -07003691 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003692 image = Image.FromFile(updated_fname)
3693 image.LoadData()
3694 entries = image.GetEntries()
3695
3696 # This one should not change
3697 data = entries['u-boot'].data
3698 self.assertEqual(U_BOOT_DATA, data)
3699
3700 data = entries['u-boot2'].data
3701 self.assertEqual(expected2, data)
3702
3703 data = entries['text'].data
3704 self.assertEqual(expected_text, data)
3705
3706 def testReplaceMissing(self):
3707 """Test replacing entries where the file is missing"""
3708 updated_fname, outdir, expected1, expected2, expected_text = (
3709 self._SetupForReplace())
3710
3711 # Remove one of the files, to generate a warning
3712 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3713 os.remove(u_boot_fname1)
3714
3715 with test_util.capture_sys_output() as (stdout, stderr):
3716 control.ReplaceEntries(updated_fname, None, outdir, [])
3717 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003718 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003719
3720 def testReplaceCmdMap(self):
3721 """Test replacing a file fron an image on the command line"""
3722 self._DoReadFileRealDtb('143_replace_all.dts')
3723
3724 try:
3725 tmpdir, updated_fname = self._SetupImageInTmpdir()
3726
3727 fname = os.path.join(self._indir, 'update-u-boot.bin')
3728 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003729 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003730
3731 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3732 '-f', fname, '-m')
3733 map_fname = os.path.join(tmpdir, 'image-updated.map')
3734 self.assertTrue(os.path.exists(map_fname))
3735 finally:
3736 shutil.rmtree(tmpdir)
3737
3738 def testReplaceNoEntryPaths(self):
3739 """Test replacing an entry without an entry path"""
3740 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003741 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003742 with self.assertRaises(ValueError) as e:
3743 control.ReplaceEntries(image_fname, 'fname', None, [])
3744 self.assertIn('Must specify an entry path to read with -f',
3745 str(e.exception))
3746
3747 def testReplaceTooManyEntryPaths(self):
3748 """Test extracting some entries"""
3749 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003750 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003751 with self.assertRaises(ValueError) as e:
3752 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3753 self.assertIn('Must specify exactly one entry path to write with -f',
3754 str(e.exception))
3755
Simon Glass0b074d62019-08-24 07:22:48 -06003756 def testPackReset16(self):
3757 """Test that an image with an x86 reset16 region can be created"""
3758 data = self._DoReadFile('144_x86_reset16.dts')
3759 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3760
3761 def testPackReset16Spl(self):
3762 """Test that an image with an x86 reset16-spl region can be created"""
3763 data = self._DoReadFile('145_x86_reset16_spl.dts')
3764 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3765
3766 def testPackReset16Tpl(self):
3767 """Test that an image with an x86 reset16-tpl region can be created"""
3768 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3769 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3770
Simon Glass232f90c2019-08-24 07:22:50 -06003771 def testPackIntelFit(self):
3772 """Test that an image with an Intel FIT and pointer can be created"""
3773 data = self._DoReadFile('147_intel_fit.dts')
3774 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3775 fit = data[16:32];
3776 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3777 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3778
3779 image = control.images['image']
3780 entries = image.GetEntries()
3781 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3782 self.assertEqual(expected_ptr, ptr)
3783
3784 def testPackIntelFitMissing(self):
3785 """Test detection of a FIT pointer with not FIT region"""
3786 with self.assertRaises(ValueError) as e:
3787 self._DoReadFile('148_intel_fit_missing.dts')
3788 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3789 str(e.exception))
3790
Simon Glass72555fa2019-11-06 17:22:44 -07003791 def _CheckSymbolsTplSection(self, dts, expected_vals):
3792 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003793 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003794 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003795 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003796 self.assertEqual(expected1, data[:upto1])
3797
3798 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003799 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003800 self.assertEqual(expected2, data[upto1:upto2])
3801
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003802 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003803 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003804 self.assertEqual(expected3, data[upto2:upto3])
3805
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003806 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003807 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3808
3809 def testSymbolsTplSection(self):
3810 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3811 self._SetupSplElf('u_boot_binman_syms')
3812 self._SetupTplElf('u_boot_binman_syms')
3813 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003814 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003815
3816 def testSymbolsTplSectionX86(self):
3817 """Test binman can assign symbols in a section with end-at-4gb"""
3818 self._SetupSplElf('u_boot_binman_syms_x86')
3819 self._SetupTplElf('u_boot_binman_syms_x86')
3820 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003821 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003822 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003823
Simon Glass98c59572019-08-24 07:23:03 -06003824 def testPackX86RomIfwiSectiom(self):
3825 """Test that a section can be placed in an IFWI region"""
3826 self._SetupIfwi('fitimage.bin')
3827 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3828 self._CheckIfwi(data)
3829
Simon Glassba7985d2019-08-24 07:23:07 -06003830 def testPackFspM(self):
3831 """Test that an image with a FSP memory-init binary can be created"""
3832 data = self._DoReadFile('152_intel_fsp_m.dts')
3833 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3834
Simon Glass4d9086d2019-10-20 21:31:35 -06003835 def testPackFspS(self):
3836 """Test that an image with a FSP silicon-init binary can be created"""
3837 data = self._DoReadFile('153_intel_fsp_s.dts')
3838 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003839
Simon Glass9ea87b22019-10-20 21:31:36 -06003840 def testPackFspT(self):
3841 """Test that an image with a FSP temp-ram-init binary can be created"""
3842 data = self._DoReadFile('154_intel_fsp_t.dts')
3843 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3844
Simon Glass48f3aad2020-07-09 18:39:31 -06003845 def testMkimage(self):
3846 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003847 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003848 data = self._DoReadFile('156_mkimage.dts')
3849
3850 # Just check that the data appears in the file somewhere
3851 self.assertIn(U_BOOT_SPL_DATA, data)
3852
Simon Glass66152ce2022-01-09 20:14:09 -07003853 def testMkimageMissing(self):
3854 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003855 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003856 with test_util.capture_sys_output() as (_, stderr):
3857 self._DoTestFile('156_mkimage.dts',
3858 force_missing_bintools='mkimage')
3859 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003860 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003861
Simon Glass5e560182020-07-09 18:39:36 -06003862 def testExtblob(self):
3863 """Test an image with an external blob"""
3864 data = self._DoReadFile('157_blob_ext.dts')
3865 self.assertEqual(REFCODE_DATA, data)
3866
3867 def testExtblobMissing(self):
3868 """Test an image with a missing external blob"""
3869 with self.assertRaises(ValueError) as e:
3870 self._DoReadFile('158_blob_ext_missing.dts')
3871 self.assertIn("Filename 'missing-file' not found in input path",
3872 str(e.exception))
3873
Simon Glass5d94cc62020-07-09 18:39:38 -06003874 def testExtblobMissingOk(self):
3875 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003876 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003877 ret = self._DoTestFile('158_blob_ext_missing.dts',
3878 allow_missing=True)
3879 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003880 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003881 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003882 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003883 self.assertIn('Some images are invalid', err)
3884
3885 def testExtblobMissingOkFlag(self):
3886 """Test an image with an missing external blob allowed with -W"""
3887 with test_util.capture_sys_output() as (stdout, stderr):
3888 ret = self._DoTestFile('158_blob_ext_missing.dts',
3889 allow_missing=True, ignore_missing=True)
3890 self.assertEqual(0, ret)
3891 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003892 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003893 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003894 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003895
3896 def testExtblobMissingOkSect(self):
3897 """Test an image with an missing external blob that is allowed"""
3898 with test_util.capture_sys_output() as (stdout, stderr):
3899 self._DoTestFile('159_blob_ext_missing_sect.dts',
3900 allow_missing=True)
3901 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003902 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003903
Simon Glasse88cef92020-07-09 18:39:41 -06003904 def testPackX86RomMeMissingDesc(self):
3905 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003906 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003907 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003908 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003909 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003910
3911 def testPackX86RomMissingIfwi(self):
3912 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3913 self._SetupIfwi('fitimage.bin')
3914 pathname = os.path.join(self._indir, 'fitimage.bin')
3915 os.remove(pathname)
3916 with test_util.capture_sys_output() as (stdout, stderr):
3917 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3918 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003919 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003920
Simon Glass2a0fa982022-02-11 13:23:21 -07003921 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003922 """Test that zero-size overlapping regions are ignored"""
3923 self._DoTestFile('160_pack_overlap_zero.dts')
3924
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003925 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003926 # The data should be inside the FIT
3927 dtb = fdt.Fdt.FromData(fit_data)
3928 dtb.Scan()
3929 fnode = dtb.GetNode('/images/kernel')
3930 self.assertIn('data', fnode.props)
3931
3932 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003933 tools.write_file(fname, fit_data)
3934 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003935
3936 # Check a few features to make sure the plumbing works. We don't need
3937 # to test the operation of mkimage or dumpimage here. First convert the
3938 # output into a dict where the keys are the fields printed by dumpimage
3939 # and the values are a list of values for each field
3940 lines = out.splitlines()
3941
3942 # Converts "Compression: gzip compressed" into two groups:
3943 # 'Compression' and 'gzip compressed'
3944 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3945 vals = collections.defaultdict(list)
3946 for line in lines:
3947 mat = re_line.match(line)
3948 vals[mat.group(1)].append(mat.group(2))
3949
Brandon Maiera657bc62024-06-04 16:16:05 +00003950 self.assertEqual('FIT description: test-desc', lines[0])
Simon Glass45d556d2020-07-09 18:39:45 -06003951 self.assertIn('Created:', lines[1])
3952 self.assertIn('Image 0 (kernel)', vals)
3953 self.assertIn('Hash value', vals)
3954 data_sizes = vals.get('Data Size')
3955 self.assertIsNotNone(data_sizes)
3956 self.assertEqual(2, len(data_sizes))
3957 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003958 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3959 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3960
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003961 # Check if entry listing correctly omits /images/
3962 image = control.images['image']
3963 fit_entry = image.GetEntries()['fit']
3964 subentries = list(fit_entry.GetEntries().keys())
3965 expected = ['kernel', 'fdt-1']
3966 self.assertEqual(expected, subentries)
3967
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003968 def testSimpleFit(self):
3969 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003970 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003971 data = self._DoReadFile('161_fit.dts')
3972 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3973 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3974 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3975
3976 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3977
3978 def testSimpleFitExpandsSubentries(self):
3979 """Test that FIT images expand their subentries"""
3980 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3981 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3982 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3983 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3984
3985 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003986
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003987 def testSimpleFitImagePos(self):
3988 """Test that we have correct image-pos for FIT subentries"""
3989 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3990 update_dtb=True)
3991 dtb = fdt.Fdt(out_dtb_fname)
3992 dtb.Scan()
3993 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3994
Simon Glassb7bad182022-03-05 20:19:01 -07003995 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003996 self.assertEqual({
3997 'image-pos': 0,
3998 'offset': 0,
3999 'size': 1890,
4000
4001 'u-boot:image-pos': 0,
4002 'u-boot:offset': 0,
4003 'u-boot:size': 4,
4004
4005 'fit:image-pos': 4,
4006 'fit:offset': 4,
4007 'fit:size': 1840,
4008
Simon Glassb7bad182022-03-05 20:19:01 -07004009 'fit/images/kernel:image-pos': 304,
4010 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004011 'fit/images/kernel:size': 4,
4012
Simon Glassb7bad182022-03-05 20:19:01 -07004013 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004014 'fit/images/kernel/u-boot:offset': 0,
4015 'fit/images/kernel/u-boot:size': 4,
4016
Simon Glassb7bad182022-03-05 20:19:01 -07004017 'fit/images/fdt-1:image-pos': 552,
4018 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004019 'fit/images/fdt-1:size': 6,
4020
Simon Glassb7bad182022-03-05 20:19:01 -07004021 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004022 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
4023 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
4024
4025 'u-boot-nodtb:image-pos': 1844,
4026 'u-boot-nodtb:offset': 1844,
4027 'u-boot-nodtb:size': 46,
4028 }, props)
4029
4030 # Actually check the data is where we think it is
4031 for node, expected in [
4032 ("u-boot", U_BOOT_DATA),
4033 ("fit/images/kernel", U_BOOT_DATA),
4034 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4035 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
4036 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
4037 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4038 ]:
4039 image_pos = props[f"{node}:image-pos"]
4040 size = props[f"{node}:size"]
4041 self.assertEqual(len(expected), size)
4042 self.assertEqual(expected, data[image_pos:image_pos+size])
4043
Simon Glass45d556d2020-07-09 18:39:45 -06004044 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06004045 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06004046 data = self._DoReadFile('162_fit_external.dts')
4047 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
4048
Simon Glass7932c882022-01-09 20:13:39 -07004049 # Size of the external-data region as set up by mkimage
4050 external_data_size = len(U_BOOT_DATA) + 2
4051 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07004052 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07004053 len(U_BOOT_NODTB_DATA))
4054
Simon Glass45d556d2020-07-09 18:39:45 -06004055 # The data should be outside the FIT
4056 dtb = fdt.Fdt.FromData(fit_data)
4057 dtb.Scan()
4058 fnode = dtb.GetNode('/images/kernel')
4059 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07004060 self.assertEqual(len(U_BOOT_DATA),
4061 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4062 fit_pos = 0x400;
4063 self.assertEqual(
4064 fit_pos,
4065 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4066
Brandon Maiera657bc62024-06-04 16:16:05 +00004067 self.assertEqual(expected_size, len(data))
Simon Glass7932c882022-01-09 20:13:39 -07004068 actual_pos = len(U_BOOT_DATA) + fit_pos
4069 self.assertEqual(U_BOOT_DATA + b'aa',
4070 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004071
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004072 def testFitExternalImagePos(self):
4073 """Test that we have correct image-pos for external FIT subentries"""
4074 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4075 update_dtb=True)
4076 dtb = fdt.Fdt(out_dtb_fname)
4077 dtb.Scan()
4078 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4079
4080 self.assertEqual({
4081 'image-pos': 0,
4082 'offset': 0,
4083 'size': 1082,
4084
4085 'u-boot:image-pos': 0,
4086 'u-boot:offset': 0,
4087 'u-boot:size': 4,
4088
4089 'fit:size': 1032,
4090 'fit:offset': 4,
4091 'fit:image-pos': 4,
4092
4093 'fit/images/kernel:size': 4,
4094 'fit/images/kernel:offset': 1024,
4095 'fit/images/kernel:image-pos': 1028,
4096
4097 'fit/images/kernel/u-boot:size': 4,
4098 'fit/images/kernel/u-boot:offset': 0,
4099 'fit/images/kernel/u-boot:image-pos': 1028,
4100
4101 'fit/images/fdt-1:size': 2,
4102 'fit/images/fdt-1:offset': 1028,
4103 'fit/images/fdt-1:image-pos': 1032,
4104
4105 'fit/images/fdt-1/_testing:size': 2,
4106 'fit/images/fdt-1/_testing:offset': 0,
4107 'fit/images/fdt-1/_testing:image-pos': 1032,
4108
4109 'u-boot-nodtb:image-pos': 1036,
4110 'u-boot-nodtb:offset': 1036,
4111 'u-boot-nodtb:size': 46,
4112 }, props)
4113
4114 # Actually check the data is where we think it is
4115 for node, expected in [
4116 ("u-boot", U_BOOT_DATA),
4117 ("fit/images/kernel", U_BOOT_DATA),
4118 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4119 ("fit/images/fdt-1", b'aa'),
4120 ("fit/images/fdt-1/_testing", b'aa'),
4121 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4122 ]:
4123 image_pos = props[f"{node}:image-pos"]
4124 size = props[f"{node}:size"]
4125 self.assertEqual(len(expected), size)
4126 self.assertEqual(expected, data[image_pos:image_pos+size])
4127
Simon Glass66152ce2022-01-09 20:14:09 -07004128 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004129 """Test that binman complains if mkimage is missing"""
4130 with self.assertRaises(ValueError) as e:
4131 self._DoTestFile('162_fit_external.dts',
4132 force_missing_bintools='mkimage')
4133 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4134 str(e.exception))
4135
4136 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004137 """Test that binman still produces a FIT image if mkimage is missing"""
4138 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004139 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004140 force_missing_bintools='mkimage')
4141 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004142 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004143
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004144 def testSectionIgnoreHashSignature(self):
4145 """Test that sections ignore hash, signature nodes for its data"""
4146 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4147 expected = (U_BOOT_DATA + U_BOOT_DATA)
4148 self.assertEqual(expected, data)
4149
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004150 def testPadInSections(self):
4151 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004152 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4153 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004154 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4155 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004156 U_BOOT_DATA)
4157 self.assertEqual(expected, data)
4158
Simon Glassd12599d2020-10-26 17:40:09 -06004159 dtb = fdt.Fdt(out_dtb_fname)
4160 dtb.Scan()
4161 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4162 expected = {
4163 'image-pos': 0,
4164 'offset': 0,
4165 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4166
4167 'section:image-pos': 0,
4168 'section:offset': 0,
4169 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4170
4171 'section/before:image-pos': 0,
4172 'section/before:offset': 0,
4173 'section/before:size': len(U_BOOT_DATA),
4174
4175 'section/u-boot:image-pos': 4,
4176 'section/u-boot:offset': 4,
4177 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4178
4179 'section/after:image-pos': 26,
4180 'section/after:offset': 26,
4181 'section/after:size': len(U_BOOT_DATA),
4182 }
4183 self.assertEqual(expected, props)
4184
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004185 def testFitImageSubentryAlignment(self):
4186 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004187 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004188 entry_args = {
4189 'test-id': TEXT_DATA,
4190 }
4191 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4192 entry_args=entry_args)
4193 dtb = fdt.Fdt.FromData(data)
4194 dtb.Scan()
4195
4196 node = dtb.GetNode('/images/kernel')
4197 data = dtb.GetProps(node)["data"].bytes
4198 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004199 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4200 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004201 self.assertEqual(expected, data)
4202
4203 node = dtb.GetNode('/images/fdt-1')
4204 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004205 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4206 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004207 U_BOOT_DTB_DATA)
4208 self.assertEqual(expected, data)
4209
4210 def testFitExtblobMissingOk(self):
4211 """Test a FIT with a missing external blob that is allowed"""
4212 with test_util.capture_sys_output() as (stdout, stderr):
4213 self._DoTestFile('168_fit_missing_blob.dts',
4214 allow_missing=True)
4215 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004216 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004217
Simon Glass21db0ff2020-09-01 05:13:54 -06004218 def testBlobNamedByArgMissing(self):
4219 """Test handling of a missing entry arg"""
4220 with self.assertRaises(ValueError) as e:
4221 self._DoReadFile('068_blob_named_by_arg.dts')
4222 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4223 str(e.exception))
4224
Simon Glass559c4de2020-09-01 05:13:58 -06004225 def testPackBl31(self):
4226 """Test that an image with an ATF BL31 binary can be created"""
4227 data = self._DoReadFile('169_atf_bl31.dts')
4228 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4229
Samuel Holland9d8cc632020-10-21 21:12:15 -05004230 def testPackScp(self):
4231 """Test that an image with an SCP binary can be created"""
4232 data = self._DoReadFile('172_scp.dts')
4233 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4234
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004235 def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True,
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004236 default_dt=None, use_seq_num=True):
Simon Glasscd2783e2024-07-20 11:49:46 +01004237 """Check an image with an FIT with multiple FDT images"""
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004238 def _CheckFdt(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004239 """Check the FDT nodes
4240
4241 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004242 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004243 expected_data: Expected contents of 'data' property
4244 """
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004245 name = 'fdt-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004246 fnode = dtb.GetNode('/images/%s' % name)
4247 self.assertIsNotNone(fnode)
4248 self.assertEqual({'description','type', 'compression', 'data'},
4249 set(fnode.props.keys()))
4250 self.assertEqual(expected_data, fnode.props['data'].bytes)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004251 description = (
4252 'fdt-test-fdt%s.dtb' % val if len(val) == 1 else
4253 'fdt-%s.dtb' % val
4254 )
4255 self.assertEqual(description, fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004256 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004257
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004258 def _CheckConfig(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004259 """Check the configuration nodes
4260
4261 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004262 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004263 expected_data: Expected contents of 'data' property
4264 """
4265 cnode = dtb.GetNode('/configurations')
4266 self.assertIn('default', cnode.props)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004267 default = (
4268 'config-2' if len(val) == 1 else
4269 'config-test-fdt2'
4270 )
4271 self.assertEqual(default, cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004272
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004273 name = 'config-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004274 fnode = dtb.GetNode('/configurations/%s' % name)
4275 self.assertIsNotNone(fnode)
4276 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4277 set(fnode.props.keys()))
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004278 description = (
4279 'conf-test-fdt%s.dtb' % val if len(val) == 1 else
4280 'conf-%s.dtb' % val
4281 )
4282 self.assertEqual(description, fnode.props['description'].value)
4283 self.assertEqual('fdt-%s' % val, fnode.props['fdt'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004284
4285 entry_args = {
Simon Glass1032acc2020-09-06 10:39:08 -06004286 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004287 }
Simon Glasscd2783e2024-07-20 11:49:46 +01004288 if use_fdt_list:
4289 entry_args['of-list'] = 'test-fdt1 test-fdt2'
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004290 if default_dt:
4291 entry_args['default-dt'] = default_dt
Simon Glassa435cd12020-09-01 05:13:59 -06004292 data = self._DoReadFileDtb(
Simon Glasscd2783e2024-07-20 11:49:46 +01004293 dts,
Simon Glassa435cd12020-09-01 05:13:59 -06004294 entry_args=entry_args,
4295 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4296 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4297 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4298
4299 dtb = fdt.Fdt.FromData(fit_data)
4300 dtb.Scan()
4301 fnode = dtb.GetNode('/images/kernel')
4302 self.assertIn('data', fnode.props)
4303
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004304 if use_seq_num == True:
4305 # Check all the properties in fdt-1 and fdt-2
4306 _CheckFdt('1', TEST_FDT1_DATA)
4307 _CheckFdt('2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004308
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004309 # Check configurations
4310 _CheckConfig('1', TEST_FDT1_DATA)
4311 _CheckConfig('2', TEST_FDT2_DATA)
4312 else:
4313 # Check all the properties in fdt-1 and fdt-2
4314 _CheckFdt('test-fdt1', TEST_FDT1_DATA)
4315 _CheckFdt('test-fdt2', TEST_FDT2_DATA)
4316
4317 # Check configurations
4318 _CheckConfig('test-fdt1', TEST_FDT1_DATA)
4319 _CheckConfig('test-fdt2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004320
Simon Glasscd2783e2024-07-20 11:49:46 +01004321 def testFitFdt(self):
4322 """Test an image with an FIT with multiple FDT images"""
4323 self.CheckFitFdt()
4324
Simon Glassa435cd12020-09-01 05:13:59 -06004325 def testFitFdtMissingList(self):
4326 """Test handling of a missing 'of-list' entry arg"""
4327 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004328 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004329 self.assertIn("Generator node requires 'of-list' entry argument",
4330 str(e.exception))
4331
4332 def testFitFdtEmptyList(self):
4333 """Test handling of an empty 'of-list' entry arg"""
4334 entry_args = {
4335 'of-list': '',
4336 }
4337 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4338
4339 def testFitFdtMissingProp(self):
4340 """Test handling of a missing 'fit,fdt-list' property"""
4341 with self.assertRaises(ValueError) as e:
4342 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4343 self.assertIn("Generator node requires 'fit,fdt-list' property",
4344 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004345
Simon Glass1032acc2020-09-06 10:39:08 -06004346 def testFitFdtMissing(self):
4347 """Test handling of a missing 'default-dt' entry arg"""
4348 entry_args = {
4349 'of-list': 'test-fdt1 test-fdt2',
4350 }
4351 with self.assertRaises(ValueError) as e:
4352 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004353 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004354 entry_args=entry_args,
4355 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4356 self.assertIn("Generated 'default' node requires default-dt entry argument",
4357 str(e.exception))
4358
4359 def testFitFdtNotInList(self):
4360 """Test handling of a default-dt that is not in the of-list"""
4361 entry_args = {
4362 'of-list': 'test-fdt1 test-fdt2',
4363 'default-dt': 'test-fdt3',
4364 }
4365 with self.assertRaises(ValueError) as e:
4366 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004367 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004368 entry_args=entry_args,
4369 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4370 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4371 str(e.exception))
4372
Simon Glassa820af72020-09-06 10:39:09 -06004373 def testFitExtblobMissingHelp(self):
4374 """Test display of help messages when an external blob is missing"""
4375 control.missing_blob_help = control._ReadMissingBlobHelp()
4376 control.missing_blob_help['wibble'] = 'Wibble test'
4377 control.missing_blob_help['another'] = 'Another test'
4378 with test_util.capture_sys_output() as (stdout, stderr):
4379 self._DoTestFile('168_fit_missing_blob.dts',
4380 allow_missing=True)
4381 err = stderr.getvalue()
4382
4383 # We can get the tag from the name, the type or the missing-msg
4384 # property. Check all three.
4385 self.assertIn('You may need to build ARM Trusted', err)
4386 self.assertIn('Wibble test', err)
4387 self.assertIn('Another test', err)
4388
Simon Glass6f1f4d42020-09-06 10:35:32 -06004389 def testMissingBlob(self):
4390 """Test handling of a blob containing a missing file"""
4391 with self.assertRaises(ValueError) as e:
4392 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4393 self.assertIn("Filename 'missing' not found in input path",
4394 str(e.exception))
4395
Simon Glassa0729502020-09-06 10:35:33 -06004396 def testEnvironment(self):
4397 """Test adding a U-Boot environment"""
4398 data = self._DoReadFile('174_env.dts')
4399 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4400 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4401 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4402 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4403 env)
4404
4405 def testEnvironmentNoSize(self):
4406 """Test that a missing 'size' property is detected"""
4407 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004408 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004409 self.assertIn("'u-boot-env' entry must have a size property",
4410 str(e.exception))
4411
4412 def testEnvironmentTooSmall(self):
4413 """Test handling of an environment that does not fit"""
4414 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004415 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004416
4417 # checksum, start byte, environment with \0 terminator, final \0
4418 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4419 short = need - 0x8
4420 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4421 str(e.exception))
4422
Simon Glassd1fdf752020-10-26 17:40:01 -06004423 def testSkipAtStart(self):
4424 """Test handling of skip-at-start section"""
4425 data = self._DoReadFile('177_skip_at_start.dts')
4426 self.assertEqual(U_BOOT_DATA, data)
4427
4428 image = control.images['image']
4429 entries = image.GetEntries()
4430 section = entries['section']
4431 self.assertEqual(0, section.offset)
4432 self.assertEqual(len(U_BOOT_DATA), section.size)
4433 self.assertEqual(U_BOOT_DATA, section.GetData())
4434
4435 entry = section.GetEntries()['u-boot']
4436 self.assertEqual(16, entry.offset)
4437 self.assertEqual(len(U_BOOT_DATA), entry.size)
4438 self.assertEqual(U_BOOT_DATA, entry.data)
4439
4440 def testSkipAtStartPad(self):
4441 """Test handling of skip-at-start section with padded entry"""
4442 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004443 before = tools.get_bytes(0, 8)
4444 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004445 all = before + U_BOOT_DATA + after
4446 self.assertEqual(all, data)
4447
4448 image = control.images['image']
4449 entries = image.GetEntries()
4450 section = entries['section']
4451 self.assertEqual(0, section.offset)
4452 self.assertEqual(len(all), section.size)
4453 self.assertEqual(all, section.GetData())
4454
4455 entry = section.GetEntries()['u-boot']
4456 self.assertEqual(16, entry.offset)
4457 self.assertEqual(len(all), entry.size)
4458 self.assertEqual(U_BOOT_DATA, entry.data)
4459
4460 def testSkipAtStartSectionPad(self):
4461 """Test handling of skip-at-start section with padding"""
4462 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004463 before = tools.get_bytes(0, 8)
4464 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004465 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004466 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004467
4468 image = control.images['image']
4469 entries = image.GetEntries()
4470 section = entries['section']
4471 self.assertEqual(0, section.offset)
4472 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004473 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004474 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004475
4476 entry = section.GetEntries()['u-boot']
4477 self.assertEqual(16, entry.offset)
4478 self.assertEqual(len(U_BOOT_DATA), entry.size)
4479 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004480
Simon Glassbb395742020-10-26 17:40:14 -06004481 def testSectionPad(self):
4482 """Testing padding with sections"""
4483 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004484 expected = (tools.get_bytes(ord('&'), 3) +
4485 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004486 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004487 tools.get_bytes(ord('!'), 1) +
4488 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004489 self.assertEqual(expected, data)
4490
4491 def testSectionAlign(self):
4492 """Testing alignment with sections"""
4493 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4494 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004495 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004496 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004497 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004498 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004499 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4500 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004501 self.assertEqual(expected, data)
4502
Simon Glassd92c8362020-10-26 17:40:25 -06004503 def testCompressImage(self):
4504 """Test compression of the entire image"""
4505 self._CheckLz4()
4506 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4507 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4508 dtb = fdt.Fdt(out_dtb_fname)
4509 dtb.Scan()
4510 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4511 'uncomp-size'])
4512 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004513 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004514
4515 # Do a sanity check on various fields
4516 image = control.images['image']
4517 entries = image.GetEntries()
4518 self.assertEqual(2, len(entries))
4519
4520 entry = entries['blob']
4521 self.assertEqual(COMPRESS_DATA, entry.data)
4522 self.assertEqual(len(COMPRESS_DATA), entry.size)
4523
4524 entry = entries['u-boot']
4525 self.assertEqual(U_BOOT_DATA, entry.data)
4526 self.assertEqual(len(U_BOOT_DATA), entry.size)
4527
4528 self.assertEqual(len(data), image.size)
4529 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4530 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4531 orig = self._decompress(image.data)
4532 self.assertEqual(orig, image.uncomp_data)
4533
4534 expected = {
4535 'blob:offset': 0,
4536 'blob:size': len(COMPRESS_DATA),
4537 'u-boot:offset': len(COMPRESS_DATA),
4538 'u-boot:size': len(U_BOOT_DATA),
4539 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4540 'offset': 0,
4541 'image-pos': 0,
4542 'size': len(data),
4543 }
4544 self.assertEqual(expected, props)
4545
4546 def testCompressImageLess(self):
4547 """Test compression where compression reduces the image size"""
4548 self._CheckLz4()
4549 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4550 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4551 dtb = fdt.Fdt(out_dtb_fname)
4552 dtb.Scan()
4553 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4554 'uncomp-size'])
4555 orig = self._decompress(data)
4556
Brandon Maiera657bc62024-06-04 16:16:05 +00004557 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004558
4559 # Do a sanity check on various fields
4560 image = control.images['image']
4561 entries = image.GetEntries()
4562 self.assertEqual(2, len(entries))
4563
4564 entry = entries['blob']
4565 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4566 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4567
4568 entry = entries['u-boot']
4569 self.assertEqual(U_BOOT_DATA, entry.data)
4570 self.assertEqual(len(U_BOOT_DATA), entry.size)
4571
4572 self.assertEqual(len(data), image.size)
4573 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4574 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4575 image.uncomp_size)
4576 orig = self._decompress(image.data)
4577 self.assertEqual(orig, image.uncomp_data)
4578
4579 expected = {
4580 'blob:offset': 0,
4581 'blob:size': len(COMPRESS_DATA_BIG),
4582 'u-boot:offset': len(COMPRESS_DATA_BIG),
4583 'u-boot:size': len(U_BOOT_DATA),
4584 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4585 'offset': 0,
4586 'image-pos': 0,
4587 'size': len(data),
4588 }
4589 self.assertEqual(expected, props)
4590
4591 def testCompressSectionSize(self):
4592 """Test compression of a section with a fixed size"""
4593 self._CheckLz4()
4594 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4595 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4596 dtb = fdt.Fdt(out_dtb_fname)
4597 dtb.Scan()
4598 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4599 'uncomp-size'])
4600 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004601 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004602 expected = {
4603 'section/blob:offset': 0,
4604 'section/blob:size': len(COMPRESS_DATA),
4605 'section/u-boot:offset': len(COMPRESS_DATA),
4606 'section/u-boot:size': len(U_BOOT_DATA),
4607 'section:offset': 0,
4608 'section:image-pos': 0,
4609 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4610 'section:size': 0x30,
4611 'offset': 0,
4612 'image-pos': 0,
4613 'size': 0x30,
4614 }
4615 self.assertEqual(expected, props)
4616
4617 def testCompressSection(self):
4618 """Test compression of a section with no fixed size"""
4619 self._CheckLz4()
4620 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4621 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4622 dtb = fdt.Fdt(out_dtb_fname)
4623 dtb.Scan()
4624 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4625 'uncomp-size'])
4626 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004627 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004628 expected = {
4629 'section/blob:offset': 0,
4630 'section/blob:size': len(COMPRESS_DATA),
4631 'section/u-boot:offset': len(COMPRESS_DATA),
4632 'section/u-boot:size': len(U_BOOT_DATA),
4633 'section:offset': 0,
4634 'section:image-pos': 0,
4635 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4636 'section:size': len(data),
4637 'offset': 0,
4638 'image-pos': 0,
4639 'size': len(data),
4640 }
4641 self.assertEqual(expected, props)
4642
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004643 def testLz4Missing(self):
4644 """Test that binman still produces an image if lz4 is missing"""
4645 with test_util.capture_sys_output() as (_, stderr):
4646 self._DoTestFile('185_compress_section.dts',
4647 force_missing_bintools='lz4')
4648 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004649 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004650
Simon Glassd92c8362020-10-26 17:40:25 -06004651 def testCompressExtra(self):
4652 """Test compression of a section with no fixed size"""
4653 self._CheckLz4()
4654 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4655 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4656 dtb = fdt.Fdt(out_dtb_fname)
4657 dtb.Scan()
4658 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4659 'uncomp-size'])
4660
4661 base = data[len(U_BOOT_DATA):]
Brandon Maiera657bc62024-06-04 16:16:05 +00004662 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glassd92c8362020-10-26 17:40:25 -06004663 rest = base[len(U_BOOT_DATA):]
4664
4665 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004666 bintool = self.comp_bintools['lz4']
4667 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004668 data1 = rest[:len(expect1)]
4669 section1 = self._decompress(data1)
Brandon Maiera657bc62024-06-04 16:16:05 +00004670 self.assertEqual(expect1, data1)
4671 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glassd92c8362020-10-26 17:40:25 -06004672 rest1 = rest[len(expect1):]
4673
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004674 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004675 data2 = rest1[:len(expect2)]
4676 section2 = self._decompress(data2)
Brandon Maiera657bc62024-06-04 16:16:05 +00004677 self.assertEqual(expect2, data2)
4678 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glassd92c8362020-10-26 17:40:25 -06004679 rest2 = rest1[len(expect2):]
4680
4681 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4682 len(expect2) + len(U_BOOT_DATA))
Brandon Maiera657bc62024-06-04 16:16:05 +00004683 #self.assertEqual(expect_size, len(data))
Simon Glassd92c8362020-10-26 17:40:25 -06004684
Brandon Maiera657bc62024-06-04 16:16:05 +00004685 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glassd92c8362020-10-26 17:40:25 -06004686
4687 self.maxDiff = None
4688 expected = {
4689 'u-boot:offset': 0,
4690 'u-boot:image-pos': 0,
4691 'u-boot:size': len(U_BOOT_DATA),
4692
4693 'base:offset': len(U_BOOT_DATA),
4694 'base:image-pos': len(U_BOOT_DATA),
4695 'base:size': len(data) - len(U_BOOT_DATA),
4696 'base/u-boot:offset': 0,
4697 'base/u-boot:image-pos': len(U_BOOT_DATA),
4698 'base/u-boot:size': len(U_BOOT_DATA),
4699 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4700 len(expect2),
4701 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4702 len(expect2),
4703 'base/u-boot2:size': len(U_BOOT_DATA),
4704
4705 'base/section:offset': len(U_BOOT_DATA),
4706 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4707 'base/section:size': len(expect1),
4708 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4709 'base/section/blob:offset': 0,
4710 'base/section/blob:size': len(COMPRESS_DATA),
4711 'base/section/u-boot:offset': len(COMPRESS_DATA),
4712 'base/section/u-boot:size': len(U_BOOT_DATA),
4713
4714 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4715 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4716 'base/section2:size': len(expect2),
4717 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4718 'base/section2/blob:offset': 0,
4719 'base/section2/blob:size': len(COMPRESS_DATA),
4720 'base/section2/blob2:offset': len(COMPRESS_DATA),
4721 'base/section2/blob2:size': len(COMPRESS_DATA),
4722
4723 'offset': 0,
4724 'image-pos': 0,
4725 'size': len(data),
4726 }
4727 self.assertEqual(expected, props)
4728
Simon Glassecbe4732021-01-06 21:35:15 -07004729 def testSymbolsSubsection(self):
4730 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004731 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004732
Simon Glass3fb25402021-01-06 21:35:16 -07004733 def testReadImageEntryArg(self):
4734 """Test reading an image that would need an entry arg to generate"""
4735 entry_args = {
4736 'cros-ec-rw-path': 'ecrw.bin',
4737 }
4738 data = self.data = self._DoReadFileDtb(
4739 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4740 entry_args=entry_args)
4741
Simon Glass80025522022-01-29 14:14:04 -07004742 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004743 orig_image = control.images['image']
4744
4745 # This should not generate an error about the missing 'cros-ec-rw-path'
4746 # since we are reading the image from a file. Compare with
4747 # testEntryArgsRequired()
4748 image = Image.FromFile(image_fname)
4749 self.assertEqual(orig_image.GetEntries().keys(),
4750 image.GetEntries().keys())
4751
Simon Glassa2af7302021-01-06 21:35:18 -07004752 def testFilesAlign(self):
4753 """Test alignment with files"""
4754 data = self._DoReadFile('190_files_align.dts')
4755
4756 # The first string is 15 bytes so will align to 16
4757 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4758 self.assertEqual(expect, data)
4759
Simon Glassdb84b562021-01-06 21:35:19 -07004760 def testReadImageSkip(self):
4761 """Test reading an image and accessing its FDT map"""
4762 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004763 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004764 orig_image = control.images['image']
4765 image = Image.FromFile(image_fname)
4766 self.assertEqual(orig_image.GetEntries().keys(),
4767 image.GetEntries().keys())
4768
4769 orig_entry = orig_image.GetEntries()['fdtmap']
4770 entry = image.GetEntries()['fdtmap']
4771 self.assertEqual(orig_entry.offset, entry.offset)
4772 self.assertEqual(orig_entry.size, entry.size)
4773 self.assertEqual(16, entry.image_pos)
4774
4775 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4776
Brandon Maiera657bc62024-06-04 16:16:05 +00004777 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glassdb84b562021-01-06 21:35:19 -07004778
Simon Glassc98de972021-03-18 20:24:57 +13004779 def testTplNoDtb(self):
4780 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004781 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004782 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4783 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4784 data[:len(U_BOOT_TPL_NODTB_DATA)])
4785
Simon Glass63f41d42021-03-18 20:24:58 +13004786 def testTplBssPad(self):
4787 """Test that we can pad TPL's BSS with zeros"""
4788 # ELF file with a '__bss_size' symbol
4789 self._SetupTplElf()
4790 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004791 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004792 data)
4793
4794 def testTplBssPadMissing(self):
4795 """Test that a missing symbol is detected"""
4796 self._SetupTplElf('u_boot_ucode_ptr')
4797 with self.assertRaises(ValueError) as e:
4798 self._DoReadFile('193_tpl_bss_pad.dts')
4799 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4800 str(e.exception))
4801
Simon Glass718b5292021-03-18 20:25:07 +13004802 def checkDtbSizes(self, data, pad_len, start):
4803 """Check the size arguments in a dtb embedded in an image
4804
4805 Args:
4806 data: The image data
4807 pad_len: Length of the pad section in the image, in bytes
4808 start: Start offset of the devicetree to examine, within the image
4809
4810 Returns:
4811 Size of the devicetree in bytes
4812 """
4813 dtb_data = data[start:]
4814 dtb = fdt.Fdt.FromData(dtb_data)
4815 fdt_size = dtb.GetFdtObj().totalsize()
4816 dtb.Scan()
4817 props = self._GetPropTree(dtb, 'size')
4818 self.assertEqual({
4819 'size': len(data),
4820 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4821 'u-boot-spl/u-boot-spl-dtb:size': 801,
4822 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4823 'u-boot-spl:size': 860,
4824 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4825 'u-boot/u-boot-dtb:size': 781,
4826 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4827 'u-boot:size': 827,
4828 }, props)
4829 return fdt_size
4830
4831 def testExpanded(self):
4832 """Test that an expanded entry type is selected when needed"""
4833 self._SetupSplElf()
4834 self._SetupTplElf()
4835
4836 # SPL has a devicetree, TPL does not
4837 entry_args = {
4838 'spl-dtb': '1',
4839 'spl-bss-pad': 'y',
4840 'tpl-dtb': '',
4841 }
4842 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4843 entry_args=entry_args)
4844 image = control.images['image']
4845 entries = image.GetEntries()
4846 self.assertEqual(3, len(entries))
4847
4848 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4849 self.assertIn('u-boot', entries)
4850 entry = entries['u-boot']
4851 self.assertEqual('u-boot-expanded', entry.etype)
4852 subent = entry.GetEntries()
4853 self.assertEqual(2, len(subent))
4854 self.assertIn('u-boot-nodtb', subent)
4855 self.assertIn('u-boot-dtb', subent)
4856
4857 # Second, u-boot-spl, which should be expanded into three parts
4858 self.assertIn('u-boot-spl', entries)
4859 entry = entries['u-boot-spl']
4860 self.assertEqual('u-boot-spl-expanded', entry.etype)
4861 subent = entry.GetEntries()
4862 self.assertEqual(3, len(subent))
4863 self.assertIn('u-boot-spl-nodtb', subent)
4864 self.assertIn('u-boot-spl-bss-pad', subent)
4865 self.assertIn('u-boot-spl-dtb', subent)
4866
4867 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4868 # devicetree
4869 self.assertIn('u-boot-tpl', entries)
4870 entry = entries['u-boot-tpl']
4871 self.assertEqual('u-boot-tpl', entry.etype)
4872 self.assertEqual(None, entry.GetEntries())
4873
4874 def testExpandedTpl(self):
4875 """Test that an expanded entry type is selected for TPL when needed"""
4876 self._SetupTplElf()
4877
4878 entry_args = {
4879 'tpl-bss-pad': 'y',
4880 'tpl-dtb': 'y',
4881 }
4882 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4883 entry_args=entry_args)
4884 image = control.images['image']
4885 entries = image.GetEntries()
4886 self.assertEqual(1, len(entries))
4887
4888 # We only have u-boot-tpl, which be expanded
4889 self.assertIn('u-boot-tpl', entries)
4890 entry = entries['u-boot-tpl']
4891 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4892 subent = entry.GetEntries()
4893 self.assertEqual(3, len(subent))
4894 self.assertIn('u-boot-tpl-nodtb', subent)
4895 self.assertIn('u-boot-tpl-bss-pad', subent)
4896 self.assertIn('u-boot-tpl-dtb', subent)
4897
4898 def testExpandedNoPad(self):
4899 """Test an expanded entry without BSS pad enabled"""
4900 self._SetupSplElf()
4901 self._SetupTplElf()
4902
4903 # SPL has a devicetree, TPL does not
4904 entry_args = {
4905 'spl-dtb': 'something',
4906 'spl-bss-pad': 'n',
4907 'tpl-dtb': '',
4908 }
4909 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4910 entry_args=entry_args)
4911 image = control.images['image']
4912 entries = image.GetEntries()
4913
4914 # Just check u-boot-spl, which should be expanded into two parts
4915 self.assertIn('u-boot-spl', entries)
4916 entry = entries['u-boot-spl']
4917 self.assertEqual('u-boot-spl-expanded', entry.etype)
4918 subent = entry.GetEntries()
4919 self.assertEqual(2, len(subent))
4920 self.assertIn('u-boot-spl-nodtb', subent)
4921 self.assertIn('u-boot-spl-dtb', subent)
4922
4923 def testExpandedTplNoPad(self):
4924 """Test that an expanded entry type with padding disabled in TPL"""
4925 self._SetupTplElf()
4926
4927 entry_args = {
4928 'tpl-bss-pad': '',
4929 'tpl-dtb': 'y',
4930 }
4931 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4932 entry_args=entry_args)
4933 image = control.images['image']
4934 entries = image.GetEntries()
4935 self.assertEqual(1, len(entries))
4936
4937 # We only have u-boot-tpl, which be expanded
4938 self.assertIn('u-boot-tpl', entries)
4939 entry = entries['u-boot-tpl']
4940 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4941 subent = entry.GetEntries()
4942 self.assertEqual(2, len(subent))
4943 self.assertIn('u-boot-tpl-nodtb', subent)
4944 self.assertIn('u-boot-tpl-dtb', subent)
4945
4946 def testFdtInclude(self):
4947 """Test that an Fdt is update within all binaries"""
4948 self._SetupSplElf()
4949 self._SetupTplElf()
4950
4951 # SPL has a devicetree, TPL does not
4952 self.maxDiff = None
4953 entry_args = {
4954 'spl-dtb': '1',
4955 'spl-bss-pad': 'y',
4956 'tpl-dtb': '',
4957 }
4958 # Build the image. It includes two separate devicetree binaries, each
4959 # with their own contents, but all contain the binman definition.
4960 data = self._DoReadFileDtb(
4961 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4962 update_dtb=True, entry_args=entry_args)[0]
4963 pad_len = 10
4964
4965 # Check the U-Boot dtb
4966 start = len(U_BOOT_NODTB_DATA)
4967 fdt_size = self.checkDtbSizes(data, pad_len, start)
4968
4969 # Now check SPL
4970 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4971 fdt_size = self.checkDtbSizes(data, pad_len, start)
4972
4973 # TPL has no devicetree
4974 start += fdt_size + len(U_BOOT_TPL_DATA)
4975 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004976
Simon Glass7098b7f2021-03-21 18:24:30 +13004977 def testSymbolsExpanded(self):
4978 """Test binman can assign symbols in expanded entries"""
4979 entry_args = {
4980 'spl-dtb': '1',
4981 }
4982 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4983 U_BOOT_SPL_DTB_DATA, 0x38,
4984 entry_args=entry_args, use_expanded=True)
4985
Simon Glasse1915782021-03-21 18:24:31 +13004986 def testCollection(self):
4987 """Test a collection"""
4988 data = self._DoReadFile('198_collection.dts')
4989 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004990 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4991 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004992 data)
4993
Simon Glass27a7f772021-03-21 18:24:32 +13004994 def testCollectionSection(self):
4995 """Test a collection where a section must be built first"""
4996 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004997 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004998 # building the contents, producing an error is anything is still
4999 # missing.
5000 data = self._DoReadFile('199_collection_section.dts')
5001 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07005002 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
5003 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13005004 data)
5005
Simon Glassf427c5f2021-03-21 18:24:33 +13005006 def testAlignDefault(self):
5007 """Test that default alignment works on sections"""
5008 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07005009 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13005010 U_BOOT_DATA)
5011 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07005012 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13005013 # No alignment within the nested section
5014 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
5015 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07005016 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13005017 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13005018
Bin Mengc0b15742021-05-10 20:23:33 +08005019 def testPackOpenSBI(self):
5020 """Test that an image with an OpenSBI binary can be created"""
5021 data = self._DoReadFile('201_opensbi.dts')
5022 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
5023
Simon Glass76f496d2021-07-06 10:36:37 -06005024 def testSectionsSingleThread(self):
5025 """Test sections without multithreading"""
5026 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07005027 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
5028 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
5029 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06005030 self.assertEqual(expected, data)
5031
5032 def testThreadTimeout(self):
5033 """Test handling a thread that takes too long"""
5034 with self.assertRaises(ValueError) as e:
5035 self._DoTestFile('202_section_timeout.dts',
5036 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06005037 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06005038
Simon Glass748a1d42021-07-06 10:36:41 -06005039 def testTiming(self):
5040 """Test output of timing information"""
5041 data = self._DoReadFile('055_sections.dts')
5042 with test_util.capture_sys_output() as (stdout, stderr):
5043 state.TimingShow()
5044 self.assertIn('read:', stdout.getvalue())
5045 self.assertIn('compress:', stdout.getvalue())
5046
Simon Glassadfb8492021-11-03 21:09:18 -06005047 def testUpdateFdtInElf(self):
5048 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005049 if not elf.ELF_TOOLS:
5050 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005051 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5052 outfile = os.path.join(self._indir, 'u-boot.out')
5053 begin_sym = 'dtb_embed_begin'
5054 end_sym = 'dtb_embed_end'
5055 retcode = self._DoTestFile(
5056 '060_fdt_update.dts', update_dtb=True,
5057 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5058 self.assertEqual(0, retcode)
5059
5060 # Check that the output file does in fact contact a dtb with the binman
5061 # definition in the correct place
5062 syms = elf.GetSymbolFileOffset(infile,
5063 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07005064 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06005065 dtb_data = data[syms['dtb_embed_begin'].offset:
5066 syms['dtb_embed_end'].offset]
5067
5068 dtb = fdt.Fdt.FromData(dtb_data)
5069 dtb.Scan()
5070 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
5071 self.assertEqual({
5072 'image-pos': 0,
5073 'offset': 0,
5074 '_testing:offset': 32,
5075 '_testing:size': 2,
5076 '_testing:image-pos': 32,
5077 'section@0/u-boot:offset': 0,
5078 'section@0/u-boot:size': len(U_BOOT_DATA),
5079 'section@0/u-boot:image-pos': 0,
5080 'section@0:offset': 0,
5081 'section@0:size': 16,
5082 'section@0:image-pos': 0,
5083
5084 'section@1/u-boot:offset': 0,
5085 'section@1/u-boot:size': len(U_BOOT_DATA),
5086 'section@1/u-boot:image-pos': 16,
5087 'section@1:offset': 16,
5088 'section@1:size': 16,
5089 'section@1:image-pos': 16,
5090 'size': 40
5091 }, props)
5092
5093 def testUpdateFdtInElfInvalid(self):
5094 """Test that invalid args are detected with --update-fdt-in-elf"""
5095 with self.assertRaises(ValueError) as e:
5096 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5097 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5098 str(e.exception))
5099
5100 def testUpdateFdtInElfNoSyms(self):
5101 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005102 if not elf.ELF_TOOLS:
5103 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005104 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5105 outfile = ''
5106 begin_sym = 'wrong_begin'
5107 end_sym = 'wrong_end'
5108 with self.assertRaises(ValueError) as e:
5109 self._DoTestFile(
5110 '060_fdt_update.dts',
5111 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5112 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5113 str(e.exception))
5114
5115 def testUpdateFdtInElfTooSmall(self):
5116 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005117 if not elf.ELF_TOOLS:
5118 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005119 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5120 outfile = os.path.join(self._indir, 'u-boot.out')
5121 begin_sym = 'dtb_embed_begin'
5122 end_sym = 'dtb_embed_end'
5123 with self.assertRaises(ValueError) as e:
5124 self._DoTestFile(
5125 '060_fdt_update.dts', update_dtb=True,
5126 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5127 self.assertRegex(
5128 str(e.exception),
5129 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5130
Simon Glass88e04da2021-11-23 11:03:42 -07005131 def testVersion(self):
5132 """Test we can get the binman version"""
5133 version = '(unreleased)'
5134 self.assertEqual(version, state.GetVersion(self._indir))
5135
5136 with self.assertRaises(SystemExit):
5137 with test_util.capture_sys_output() as (_, stderr):
5138 self._DoBinman('-V')
5139 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5140
5141 # Try running the tool too, just to be safe
5142 result = self._RunBinman('-V')
5143 self.assertEqual('Binman %s\n' % version, result.stderr)
5144
5145 # Set up a version file to make sure that works
5146 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005147 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005148 binary=False)
5149 self.assertEqual(version, state.GetVersion(self._indir))
5150
Simon Glass637958f2021-11-23 21:09:50 -07005151 def testAltFormat(self):
5152 """Test that alternative formats can be used to extract"""
5153 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5154
5155 try:
5156 tmpdir, updated_fname = self._SetupImageInTmpdir()
5157 with test_util.capture_sys_output() as (stdout, _):
5158 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5159 self.assertEqual(
5160 '''Flag (-F) Entry type Description
5161fdt fdtmap Extract the devicetree blob from the fdtmap
5162''',
5163 stdout.getvalue())
5164
5165 dtb = os.path.join(tmpdir, 'fdt.dtb')
5166 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5167 dtb, 'fdtmap')
5168
5169 # Check that we can read it and it can be scanning, meaning it does
5170 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005171 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005172 dtb = fdt.Fdt.FromData(data)
5173 dtb.Scan()
5174
5175 # Now check u-boot which has no alt_format
5176 fname = os.path.join(tmpdir, 'fdt.dtb')
5177 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5178 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005179 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005180 self.assertEqual(U_BOOT_DATA, data)
5181
5182 finally:
5183 shutil.rmtree(tmpdir)
5184
Simon Glass0b00ae62021-11-23 21:09:52 -07005185 def testExtblobList(self):
5186 """Test an image with an external blob list"""
5187 data = self._DoReadFile('215_blob_ext_list.dts')
5188 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5189
5190 def testExtblobListMissing(self):
5191 """Test an image with a missing external blob"""
5192 with self.assertRaises(ValueError) as e:
5193 self._DoReadFile('216_blob_ext_list_missing.dts')
5194 self.assertIn("Filename 'missing-file' not found in input path",
5195 str(e.exception))
5196
5197 def testExtblobListMissingOk(self):
5198 """Test an image with an missing external blob that is allowed"""
5199 with test_util.capture_sys_output() as (stdout, stderr):
5200 self._DoTestFile('216_blob_ext_list_missing.dts',
5201 allow_missing=True)
5202 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005203 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005204
Simon Glass3efb2972021-11-23 21:08:59 -07005205 def testFip(self):
5206 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5207 data = self._DoReadFile('203_fip.dts')
5208 hdr, fents = fip_util.decode_fip(data)
5209 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5210 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5211 self.assertEqual(0x123, hdr.flags)
5212
5213 self.assertEqual(2, len(fents))
5214
5215 fent = fents[0]
5216 self.assertEqual(
5217 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5218 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5219 self.assertEqual('soc-fw', fent.fip_type)
5220 self.assertEqual(0x88, fent.offset)
5221 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5222 self.assertEqual(0x123456789abcdef, fent.flags)
5223 self.assertEqual(ATF_BL31_DATA, fent.data)
5224 self.assertEqual(True, fent.valid)
5225
5226 fent = fents[1]
5227 self.assertEqual(
5228 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5229 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5230 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5231 self.assertEqual(0x8c, fent.offset)
5232 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5233 self.assertEqual(0, fent.flags)
5234 self.assertEqual(ATF_BL2U_DATA, fent.data)
5235 self.assertEqual(True, fent.valid)
5236
5237 def testFipOther(self):
5238 """Basic FIP with something that isn't a external blob"""
5239 data = self._DoReadFile('204_fip_other.dts')
5240 hdr, fents = fip_util.decode_fip(data)
5241
5242 self.assertEqual(2, len(fents))
5243 fent = fents[1]
5244 self.assertEqual('rot-cert', fent.fip_type)
5245 self.assertEqual(b'aa', fent.data)
5246
Simon Glass3efb2972021-11-23 21:08:59 -07005247 def testFipNoType(self):
5248 """FIP with an entry of an unknown type"""
5249 with self.assertRaises(ValueError) as e:
5250 self._DoReadFile('205_fip_no_type.dts')
5251 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5252 str(e.exception))
5253
5254 def testFipUuid(self):
5255 """Basic FIP with a manual uuid"""
5256 data = self._DoReadFile('206_fip_uuid.dts')
5257 hdr, fents = fip_util.decode_fip(data)
5258
5259 self.assertEqual(2, len(fents))
5260 fent = fents[1]
5261 self.assertEqual(None, fent.fip_type)
5262 self.assertEqual(
5263 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5264 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5265 fent.uuid)
5266 self.assertEqual(U_BOOT_DATA, fent.data)
5267
5268 def testFipLs(self):
5269 """Test listing a FIP"""
5270 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5271 hdr, fents = fip_util.decode_fip(data)
5272
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005273 tmpdir = None
Simon Glass3efb2972021-11-23 21:08:59 -07005274 try:
5275 tmpdir, updated_fname = self._SetupImageInTmpdir()
5276 with test_util.capture_sys_output() as (stdout, stderr):
5277 self._DoBinman('ls', '-i', updated_fname)
5278 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005279 if tmpdir:
5280 shutil.rmtree(tmpdir)
Simon Glass3efb2972021-11-23 21:08:59 -07005281 lines = stdout.getvalue().splitlines()
5282 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005283'Name Image-pos Size Entry-type Offset Uncomp-size',
5284'--------------------------------------------------------------',
5285'image 0 2d3 section 0',
5286' atf-fip 0 90 atf-fip 0',
5287' soc-fw 88 4 blob-ext 88',
5288' u-boot 8c 4 u-boot 8c',
5289' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005290]
5291 self.assertEqual(expected, lines)
5292
5293 image = control.images['image']
5294 entries = image.GetEntries()
5295 fdtmap = entries['fdtmap']
5296
5297 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5298 magic = fdtmap_data[:8]
5299 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005300 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005301
5302 fdt_data = fdtmap_data[16:]
5303 dtb = fdt.Fdt.FromData(fdt_data)
5304 dtb.Scan()
5305 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5306 self.assertEqual({
5307 'atf-fip/soc-fw:image-pos': 136,
5308 'atf-fip/soc-fw:offset': 136,
5309 'atf-fip/soc-fw:size': 4,
5310 'atf-fip/u-boot:image-pos': 140,
5311 'atf-fip/u-boot:offset': 140,
5312 'atf-fip/u-boot:size': 4,
5313 'atf-fip:image-pos': 0,
5314 'atf-fip:offset': 0,
5315 'atf-fip:size': 144,
5316 'image-pos': 0,
5317 'offset': 0,
5318 'fdtmap:image-pos': fdtmap.image_pos,
5319 'fdtmap:offset': fdtmap.offset,
5320 'fdtmap:size': len(fdtmap_data),
5321 'size': len(data),
5322 }, props)
5323
5324 def testFipExtractOneEntry(self):
5325 """Test extracting a single entry fron an FIP"""
5326 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005327 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005328 fname = os.path.join(self._indir, 'output.extact')
5329 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005330 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005331 self.assertEqual(U_BOOT_DATA, data)
5332
5333 def testFipReplace(self):
5334 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005335 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005336 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005337 updated_fname = tools.get_output_filename('image-updated.bin')
5338 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005339 entry_name = 'atf-fip/u-boot'
5340 control.WriteEntry(updated_fname, entry_name, expected,
5341 allow_resize=True)
5342 actual = control.ReadEntry(updated_fname, entry_name)
5343 self.assertEqual(expected, actual)
5344
Simon Glass80025522022-01-29 14:14:04 -07005345 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005346 hdr, fents = fip_util.decode_fip(new_data)
5347
5348 self.assertEqual(2, len(fents))
5349
5350 # Check that the FIP entry is updated
5351 fent = fents[1]
5352 self.assertEqual(0x8c, fent.offset)
5353 self.assertEqual(len(expected), fent.size)
5354 self.assertEqual(0, fent.flags)
5355 self.assertEqual(expected, fent.data)
5356 self.assertEqual(True, fent.valid)
5357
5358 def testFipMissing(self):
5359 with test_util.capture_sys_output() as (stdout, stderr):
5360 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5361 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005362 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005363
5364 def testFipSize(self):
5365 """Test a FIP with a size property"""
5366 data = self._DoReadFile('210_fip_size.dts')
5367 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5368 hdr, fents = fip_util.decode_fip(data)
5369 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5370 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5371
5372 self.assertEqual(1, len(fents))
5373
5374 fent = fents[0]
5375 self.assertEqual('soc-fw', fent.fip_type)
5376 self.assertEqual(0x60, fent.offset)
5377 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5378 self.assertEqual(ATF_BL31_DATA, fent.data)
5379 self.assertEqual(True, fent.valid)
5380
5381 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005382 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005383
5384 def testFipBadAlign(self):
5385 """Test that an invalid alignment value in a FIP is detected"""
5386 with self.assertRaises(ValueError) as e:
5387 self._DoTestFile('211_fip_bad_align.dts')
5388 self.assertIn(
5389 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5390 str(e.exception))
5391
5392 def testFipCollection(self):
5393 """Test using a FIP in a collection"""
5394 data = self._DoReadFile('212_fip_collection.dts')
5395 entry1 = control.images['image'].GetEntries()['collection']
5396 data1 = data[:entry1.size]
5397 hdr1, fents2 = fip_util.decode_fip(data1)
5398
5399 entry2 = control.images['image'].GetEntries()['atf-fip']
5400 data2 = data[entry2.offset:entry2.offset + entry2.size]
5401 hdr1, fents2 = fip_util.decode_fip(data2)
5402
5403 # The 'collection' entry should have U-Boot included at the end
5404 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5405 self.assertEqual(data1, data2 + U_BOOT_DATA)
5406 self.assertEqual(U_BOOT_DATA, data1[-4:])
5407
5408 # There should be a U-Boot after the final FIP
5409 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005410
Simon Glassccae6862022-01-12 13:10:35 -07005411 def testFakeBlob(self):
5412 """Test handling of faking an external blob"""
5413 with test_util.capture_sys_output() as (stdout, stderr):
5414 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5415 allow_fake_blobs=True)
5416 err = stderr.getvalue()
5417 self.assertRegex(
5418 err,
5419 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005420
Simon Glassceb5f912022-01-09 20:13:46 -07005421 def testExtblobListFaked(self):
5422 """Test an extblob with missing external blob that are faked"""
5423 with test_util.capture_sys_output() as (stdout, stderr):
5424 self._DoTestFile('216_blob_ext_list_missing.dts',
5425 allow_fake_blobs=True)
5426 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005427 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005428
Simon Glass162017b2022-01-09 20:13:57 -07005429 def testListBintools(self):
5430 args = ['tool', '--list']
5431 with test_util.capture_sys_output() as (stdout, _):
5432 self._DoBinman(*args)
5433 out = stdout.getvalue().splitlines()
5434 self.assertTrue(len(out) >= 2)
5435
5436 def testFetchBintools(self):
5437 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005438 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005439 raise urllib.error.URLError('my error')
5440
5441 args = ['tool']
5442 with self.assertRaises(ValueError) as e:
5443 self._DoBinman(*args)
5444 self.assertIn("Invalid arguments to 'tool' subcommand",
5445 str(e.exception))
5446
5447 args = ['tool', '--fetch']
5448 with self.assertRaises(ValueError) as e:
5449 self._DoBinman(*args)
5450 self.assertIn('Please specify bintools to fetch', str(e.exception))
5451
5452 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005453 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005454 side_effect=fail_download):
5455 with test_util.capture_sys_output() as (stdout, _):
5456 self._DoBinman(*args)
5457 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5458
Simon Glass620c4462022-01-09 20:14:11 -07005459 def testBintoolDocs(self):
5460 """Test for creation of bintool documentation"""
5461 with test_util.capture_sys_output() as (stdout, stderr):
5462 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5463 self.assertTrue(len(stdout.getvalue()) > 0)
5464
5465 def testBintoolDocsMissing(self):
5466 """Test handling of missing bintool documentation"""
5467 with self.assertRaises(ValueError) as e:
5468 with test_util.capture_sys_output() as (stdout, stderr):
5469 control.write_bintool_docs(
5470 control.bintool.Bintool.get_tool_list(), 'mkimage')
5471 self.assertIn('Documentation is missing for modules: mkimage',
5472 str(e.exception))
5473
Jan Kiszka58c407f2022-01-28 20:37:53 +01005474 def testListWithGenNode(self):
5475 """Check handling of an FDT map when the section cannot be found"""
5476 entry_args = {
5477 'of-list': 'test-fdt1 test-fdt2',
5478 }
5479 data = self._DoReadFileDtb(
5480 '219_fit_gennode.dts',
5481 entry_args=entry_args,
5482 use_real_dtb=True,
5483 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5484
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005485 tmpdir = None
Jan Kiszka58c407f2022-01-28 20:37:53 +01005486 try:
5487 tmpdir, updated_fname = self._SetupImageInTmpdir()
5488 with test_util.capture_sys_output() as (stdout, stderr):
5489 self._RunBinman('ls', '-i', updated_fname)
5490 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005491 if tmpdir:
5492 shutil.rmtree(tmpdir)
Jan Kiszka58c407f2022-01-28 20:37:53 +01005493
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005494 def testFitSubentryUsesBintool(self):
5495 """Test that binman FIT subentries can use bintools"""
5496 command.test_result = self._HandleGbbCommand
5497 entry_args = {
5498 'keydir': 'devkeys',
5499 'bmpblk': 'bmpblk.bin',
5500 }
5501 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5502 entry_args=entry_args)
5503
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005504 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5505 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005506 self.assertIn(expected, data)
5507
5508 def testFitSubentryMissingBintool(self):
5509 """Test that binman reports missing bintools for FIT subentries"""
5510 entry_args = {
5511 'keydir': 'devkeys',
5512 }
5513 with test_util.capture_sys_output() as (_, stderr):
5514 self._DoTestFile('220_fit_subentry_bintool.dts',
5515 force_missing_bintools='futility', entry_args=entry_args)
5516 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005517 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005518
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005519 def testFitSubentryHashSubnode(self):
5520 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005521 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005522 data, _, _, out_dtb_name = self._DoReadFileDtb(
5523 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5524
5525 mkimage_dtb = fdt.Fdt.FromData(data)
5526 mkimage_dtb.Scan()
5527 binman_dtb = fdt.Fdt(out_dtb_name)
5528 binman_dtb.Scan()
5529
5530 # Check that binman didn't add hash values
5531 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5532 self.assertNotIn('value', fnode.props)
5533
5534 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5535 self.assertNotIn('value', fnode.props)
5536
5537 # Check that mkimage added hash values
5538 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5539 self.assertIn('value', fnode.props)
5540
5541 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5542 self.assertIn('value', fnode.props)
5543
Roger Quadros5cdcea02022-02-19 20:50:04 +02005544 def testPackTeeOs(self):
5545 """Test that an image with an TEE binary can be created"""
5546 data = self._DoReadFile('222_tee_os.dts')
5547 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5548
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305549 def testPackTiDm(self):
5550 """Test that an image with a TI DM binary can be created"""
5551 data = self._DoReadFile('225_ti_dm.dts')
5552 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5553
Simon Glass912339f2022-02-08 11:50:03 -07005554 def testFitFdtOper(self):
5555 """Check handling of a specified FIT operation"""
5556 entry_args = {
5557 'of-list': 'test-fdt1 test-fdt2',
5558 'default-dt': 'test-fdt2',
5559 }
5560 self._DoReadFileDtb(
5561 '223_fit_fdt_oper.dts',
5562 entry_args=entry_args,
5563 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5564
5565 def testFitFdtBadOper(self):
5566 """Check handling of an FDT map when the section cannot be found"""
5567 with self.assertRaises(ValueError) as exc:
5568 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005569 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005570 str(exc.exception))
5571
Simon Glassdd156a42022-03-05 20:18:59 -07005572 def test_uses_expand_size(self):
5573 """Test that the 'expand-size' property cannot be used anymore"""
5574 with self.assertRaises(ValueError) as e:
5575 data = self._DoReadFile('225_expand_size_bad.dts')
5576 self.assertIn(
5577 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5578 str(e.exception))
5579
Simon Glass5f423422022-03-05 20:19:12 -07005580 def testFitSplitElf(self):
5581 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005582 if not elf.ELF_TOOLS:
5583 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005584 entry_args = {
5585 'of-list': 'test-fdt1 test-fdt2',
5586 'default-dt': 'test-fdt2',
5587 'atf-bl31-path': 'bl31.elf',
5588 'tee-os-path': 'tee.elf',
5589 }
5590 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5591 data = self._DoReadFileDtb(
5592 '226_fit_split_elf.dts',
5593 entry_args=entry_args,
5594 extra_indirs=[test_subdir])[0]
5595
5596 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5597 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5598
5599 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5600 'data', 'load'}
5601 dtb = fdt.Fdt.FromData(fit_data)
5602 dtb.Scan()
5603
5604 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5605 segments, entry = elf.read_loadable_segments(elf_data)
5606
5607 # We assume there are two segments
Brandon Maiera657bc62024-06-04 16:16:05 +00005608 self.assertEqual(2, len(segments))
Simon Glass5f423422022-03-05 20:19:12 -07005609
5610 atf1 = dtb.GetNode('/images/atf-1')
5611 _, start, data = segments[0]
5612 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5613 self.assertEqual(entry,
5614 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5615 self.assertEqual(start,
5616 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5617 self.assertEqual(data, atf1.props['data'].bytes)
5618
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005619 hash_node = atf1.FindNode('hash')
5620 self.assertIsNotNone(hash_node)
5621 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5622
Simon Glass5f423422022-03-05 20:19:12 -07005623 atf2 = dtb.GetNode('/images/atf-2')
5624 self.assertEqual(base_keys, atf2.props.keys())
5625 _, start, data = segments[1]
5626 self.assertEqual(start,
5627 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5628 self.assertEqual(data, atf2.props['data'].bytes)
5629
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005630 hash_node = atf2.FindNode('hash')
5631 self.assertIsNotNone(hash_node)
5632 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5633
5634 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5635 self.assertIsNotNone(hash_node)
5636 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5637
Simon Glass5f423422022-03-05 20:19:12 -07005638 conf = dtb.GetNode('/configurations')
5639 self.assertEqual({'default'}, conf.props.keys())
5640
5641 for subnode in conf.subnodes:
5642 self.assertEqual({'description', 'fdt', 'loadables'},
5643 subnode.props.keys())
5644 self.assertEqual(
5645 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5646 fdt_util.GetStringList(subnode, 'loadables'))
5647
5648 def _check_bad_fit(self, dts):
5649 """Check a bad FIT
5650
5651 This runs with the given dts and returns the assertion raised
5652
5653 Args:
5654 dts (str): dts filename to use
5655
5656 Returns:
5657 str: Assertion string raised
5658 """
5659 entry_args = {
5660 'of-list': 'test-fdt1 test-fdt2',
5661 'default-dt': 'test-fdt2',
5662 'atf-bl31-path': 'bl31.elf',
5663 'tee-os-path': 'tee.elf',
5664 }
5665 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5666 with self.assertRaises(ValueError) as exc:
5667 self._DoReadFileDtb(dts, entry_args=entry_args,
5668 extra_indirs=[test_subdir])[0]
5669 return str(exc.exception)
5670
5671 def testFitSplitElfBadElf(self):
5672 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005673 if not elf.ELF_TOOLS:
5674 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005675 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5676 entry_args = {
5677 'of-list': 'test-fdt1 test-fdt2',
5678 'default-dt': 'test-fdt2',
5679 'atf-bl31-path': 'bad.elf',
5680 'tee-os-path': 'tee.elf',
5681 }
5682 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5683 with self.assertRaises(ValueError) as exc:
5684 self._DoReadFileDtb(
5685 '226_fit_split_elf.dts',
5686 entry_args=entry_args,
5687 extra_indirs=[test_subdir])[0]
5688 self.assertIn(
5689 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5690 str(exc.exception))
5691
Simon Glass5f423422022-03-05 20:19:12 -07005692 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005693 """Test an split-elf FIT with a missing ELF file
5694
5695 Args:
5696 kwargs (dict of str): Arguments to pass to _DoTestFile()
5697
5698 Returns:
5699 tuple:
5700 str: stdout result
5701 str: stderr result
5702 """
Simon Glass5f423422022-03-05 20:19:12 -07005703 entry_args = {
5704 'of-list': 'test-fdt1 test-fdt2',
5705 'default-dt': 'test-fdt2',
5706 'atf-bl31-path': 'bl31.elf',
5707 'tee-os-path': 'missing.elf',
5708 }
5709 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5710 with test_util.capture_sys_output() as (stdout, stderr):
5711 self._DoTestFile(
5712 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005713 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5714 out = stdout.getvalue()
5715 err = stderr.getvalue()
5716 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005717
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005718 def testFitSplitElfBadDirective(self):
5719 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5720 if not elf.ELF_TOOLS:
5721 self.skipTest('Python elftools not available')
5722 err = self._check_bad_fit('227_fit_bad_dir.dts')
5723 self.assertIn(
5724 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5725 err)
5726
5727 def testFitSplitElfBadDirectiveConfig(self):
5728 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5729 if not elf.ELF_TOOLS:
5730 self.skipTest('Python elftools not available')
5731 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5732 self.assertEqual(
5733 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5734 err)
5735
5736
Simon Glass5f423422022-03-05 20:19:12 -07005737 def testFitSplitElfMissing(self):
5738 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005739 if not elf.ELF_TOOLS:
5740 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005741 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005742 self.assertRegex(
5743 err,
5744 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005745 self.assertNotRegex(out, '.*Faked blob.*')
5746 fname = tools.get_output_filename('binman-fake/missing.elf')
5747 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005748
5749 def testFitSplitElfFaked(self):
5750 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005751 if not elf.ELF_TOOLS:
5752 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005753 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005754 self.assertRegex(
5755 err,
5756 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005757 self.assertRegex(
5758 out,
5759 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5760 fname = tools.get_output_filename('binman-fake/missing.elf')
5761 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005762
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005763 def testMkimageMissingBlob(self):
5764 """Test using mkimage to build an image"""
5765 with test_util.capture_sys_output() as (stdout, stderr):
5766 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5767 allow_fake_blobs=True)
5768 err = stderr.getvalue()
5769 self.assertRegex(
5770 err,
5771 "Image '.*' has faked external blobs and is non-functional: .*")
5772
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005773 def testPreLoad(self):
5774 """Test an image with a pre-load header"""
5775 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005776 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005777 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005778 data = self._DoReadFileDtb(
5779 '230_pre_load.dts', entry_args=entry_args,
5780 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005781 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5782 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5783 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Simon Glasse2dfb962023-07-24 09:19:57 -06005784
5785 def testPreLoadNoKey(self):
5786 """Test an image with a pre-load heade0r with missing key"""
5787 with self.assertRaises(FileNotFoundError) as exc:
5788 self._DoReadFile('230_pre_load.dts')
5789 self.assertIn("No such file or directory: 'dev.key'",
5790 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005791
5792 def testPreLoadPkcs(self):
5793 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005794 entry_args = {
5795 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5796 }
5797 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5798 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005799 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5800 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5801 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5802
5803 def testPreLoadPss(self):
5804 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005805 entry_args = {
5806 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5807 }
5808 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5809 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005810 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5811 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5812 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5813
5814 def testPreLoadInvalidPadding(self):
5815 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005816 entry_args = {
5817 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5818 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005819 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005820 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5821 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005822
5823 def testPreLoadInvalidSha(self):
5824 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005825 entry_args = {
5826 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5827 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005828 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005829 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5830 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005831
5832 def testPreLoadInvalidAlgo(self):
5833 """Test an image with a pre-load header with an invalid algo"""
5834 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005835 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005836
5837 def testPreLoadInvalidKey(self):
5838 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005839 entry_args = {
5840 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5841 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005842 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005843 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5844 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005845
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005846 def _CheckSafeUniqueNames(self, *images):
5847 """Check all entries of given images for unsafe unique names"""
5848 for image in images:
5849 entries = {}
5850 image._CollectEntries(entries, {}, image)
5851 for entry in entries.values():
5852 uniq = entry.GetUniqueName()
5853
5854 # Used as part of a filename, so must not be absolute paths.
5855 self.assertFalse(os.path.isabs(uniq))
5856
5857 def testSafeUniqueNames(self):
5858 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005859 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005860
5861 orig_image = control.images['image']
5862 image_fname = tools.get_output_filename('image.bin')
5863 image = Image.FromFile(image_fname)
5864
5865 self._CheckSafeUniqueNames(orig_image, image)
5866
5867 def testSafeUniqueNamesMulti(self):
5868 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005869 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005870
5871 orig_image = control.images['image']
5872 image_fname = tools.get_output_filename('image.bin')
5873 image = Image.FromFile(image_fname)
5874
5875 self._CheckSafeUniqueNames(orig_image, image)
5876
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005877 def testReplaceCmdWithBintool(self):
5878 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005879 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005880 expected = U_BOOT_DATA + b'aa'
5881 self.assertEqual(expected, data[:len(expected)])
5882
5883 try:
5884 tmpdir, updated_fname = self._SetupImageInTmpdir()
5885 fname = os.path.join(tmpdir, 'update-testing.bin')
5886 tools.write_file(fname, b'zz')
5887 self._DoBinman('replace', '-i', updated_fname,
5888 '_testing', '-f', fname)
5889
5890 data = tools.read_file(updated_fname)
5891 expected = U_BOOT_DATA + b'zz'
5892 self.assertEqual(expected, data[:len(expected)])
5893 finally:
5894 shutil.rmtree(tmpdir)
5895
5896 def testReplaceCmdOtherWithBintool(self):
5897 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005898 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005899 expected = U_BOOT_DATA + b'aa'
5900 self.assertEqual(expected, data[:len(expected)])
5901
5902 try:
5903 tmpdir, updated_fname = self._SetupImageInTmpdir()
5904 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5905 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5906 self._DoBinman('replace', '-i', updated_fname,
5907 'u-boot', '-f', fname)
5908
5909 data = tools.read_file(updated_fname)
5910 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5911 self.assertEqual(expected, data[:len(expected)])
5912 finally:
5913 shutil.rmtree(tmpdir)
5914
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005915 def testReplaceResizeNoRepackSameSize(self):
5916 """Test replacing entries with same-size data without repacking"""
5917 expected = b'x' * len(U_BOOT_DATA)
5918 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5919 self.assertEqual(expected, data)
5920
5921 path, fdtmap = state.GetFdtContents('fdtmap')
5922 self.assertIsNotNone(path)
5923 self.assertEqual(expected_fdtmap, fdtmap)
5924
5925 def testReplaceResizeNoRepackSmallerSize(self):
5926 """Test replacing entries with smaller-size data without repacking"""
5927 new_data = b'x'
5928 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5929 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5930 self.assertEqual(expected, data)
5931
5932 path, fdtmap = state.GetFdtContents('fdtmap')
5933 self.assertIsNotNone(path)
5934 self.assertEqual(expected_fdtmap, fdtmap)
5935
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005936 def testExtractFit(self):
5937 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005938 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005939 image_fname = tools.get_output_filename('image.bin')
5940
5941 fit_data = control.ReadEntry(image_fname, 'fit')
5942 fit = fdt.Fdt.FromData(fit_data)
5943 fit.Scan()
5944
5945 # Check subentry data inside the extracted fit
5946 for node_path, expected in [
5947 ('/images/kernel', U_BOOT_DATA),
5948 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5949 ('/images/scr-1', COMPRESS_DATA),
5950 ]:
5951 node = fit.GetNode(node_path)
5952 data = fit.GetProps(node)['data'].bytes
5953 self.assertEqual(expected, data)
5954
5955 def testExtractFitSubentries(self):
5956 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005957 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005958 image_fname = tools.get_output_filename('image.bin')
5959
5960 for entry_path, expected in [
5961 ('fit/kernel', U_BOOT_DATA),
5962 ('fit/kernel/u-boot', U_BOOT_DATA),
5963 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5964 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5965 ('fit/scr-1', COMPRESS_DATA),
5966 ('fit/scr-1/blob', COMPRESS_DATA),
5967 ]:
5968 data = control.ReadEntry(image_fname, entry_path)
5969 self.assertEqual(expected, data)
5970
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005971 def testReplaceFitSubentryLeafSameSize(self):
5972 """Test replacing a FIT leaf subentry with same-size data"""
5973 new_data = b'x' * len(U_BOOT_DATA)
5974 data, expected_fdtmap, _ = self._RunReplaceCmd(
5975 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005976 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005977 self.assertEqual(new_data, data)
5978
5979 path, fdtmap = state.GetFdtContents('fdtmap')
5980 self.assertIsNotNone(path)
5981 self.assertEqual(expected_fdtmap, fdtmap)
5982
5983 def testReplaceFitSubentryLeafBiggerSize(self):
5984 """Test replacing a FIT leaf subentry with bigger-size data"""
5985 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5986 data, expected_fdtmap, _ = self._RunReplaceCmd(
5987 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005988 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005989 self.assertEqual(new_data, data)
5990
5991 # Will be repacked, so fdtmap must change
5992 path, fdtmap = state.GetFdtContents('fdtmap')
5993 self.assertIsNotNone(path)
5994 self.assertNotEqual(expected_fdtmap, fdtmap)
5995
5996 def testReplaceFitSubentryLeafSmallerSize(self):
5997 """Test replacing a FIT leaf subentry with smaller-size data"""
5998 new_data = b'x'
5999 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
6000 data, expected_fdtmap, _ = self._RunReplaceCmd(
6001 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006002 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006003 self.assertEqual(expected, data)
6004
6005 path, fdtmap = state.GetFdtContents('fdtmap')
6006 self.assertIsNotNone(path)
6007 self.assertEqual(expected_fdtmap, fdtmap)
6008
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006009 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07006010 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006011 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07006012 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6013 new_data, dts='241_replace_section_simple.dts')
6014 self.assertEqual(new_data, data)
6015
6016 entries = image.GetEntries()
6017 self.assertIn('section', entries)
6018 entry = entries['section']
6019 self.assertEqual(len(new_data), entry.size)
6020
6021 def testReplaceSectionLarger(self):
6022 """Test replacing a simple section with larger data"""
6023 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6024 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6025 new_data, dts='241_replace_section_simple.dts')
6026 self.assertEqual(new_data, data)
6027
6028 entries = image.GetEntries()
6029 self.assertIn('section', entries)
6030 entry = entries['section']
6031 self.assertEqual(len(new_data), entry.size)
6032 fentry = entries['fdtmap']
6033 self.assertEqual(entry.offset + entry.size, fentry.offset)
6034
6035 def testReplaceSectionSmaller(self):
6036 """Test replacing a simple section with smaller data"""
6037 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
6038 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6039 new_data, dts='241_replace_section_simple.dts')
6040 self.assertEqual(new_data, data)
6041
6042 # The new size is the same as the old, just with a pad byte at the end
6043 entries = image.GetEntries()
6044 self.assertIn('section', entries)
6045 entry = entries['section']
6046 self.assertEqual(len(new_data), entry.size)
6047
6048 def testReplaceSectionSmallerAllow(self):
6049 """Test failing to replace a simple section with smaller data"""
6050 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
6051 try:
6052 state.SetAllowEntryContraction(True)
6053 with self.assertRaises(ValueError) as exc:
6054 self._RunReplaceCmd('section', new_data,
6055 dts='241_replace_section_simple.dts')
6056 finally:
6057 state.SetAllowEntryContraction(False)
6058
6059 # Since we have no information about the position of things within the
6060 # section, we cannot adjust the position of /section-u-boot so it ends
6061 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06006062 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07006063 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
6064 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06006065 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006066
Simon Glass8fbca772022-08-13 11:40:48 -06006067 def testMkimageImagename(self):
6068 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006069 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006070 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06006071
6072 # Check that the data appears in the file somewhere
6073 self.assertIn(U_BOOT_SPL_DATA, data)
6074
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006075 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06006076 name = data[0x20:0x40]
6077
6078 # Build the filename that we expect to be placed in there, by virtue of
6079 # the -n paraameter
6080 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6081
6082 # Check that the image name is set to the temporary filename used
6083 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6084
Simon Glassb1669752022-08-13 11:40:49 -06006085 def testMkimageImage(self):
6086 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006087 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006088 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006089
6090 # Check that the data appears in the file somewhere
6091 self.assertIn(U_BOOT_SPL_DATA, data)
6092
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006093 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006094 name = data[0x20:0x40]
6095
6096 # Build the filename that we expect to be placed in there, by virtue of
6097 # the -n paraameter
6098 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6099
6100 # Check that the image name is set to the temporary filename used
6101 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6102
6103 # Check the corect data is in the imagename file
6104 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6105
6106 def testMkimageImageNoContent(self):
6107 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006108 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006109 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006110 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006111 self.assertIn('Could not complete processing of contents',
6112 str(exc.exception))
6113
6114 def testMkimageImageBad(self):
6115 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006116 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006117 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006118 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006119 self.assertIn('Cannot use both imagename node and data-to-imagename',
6120 str(exc.exception))
6121
Simon Glassbd5cd882022-08-13 11:40:50 -06006122 def testCollectionOther(self):
6123 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006124 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006125 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6126 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6127 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6128 data)
6129
6130 def testMkimageCollection(self):
6131 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006132 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006133 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006134 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6135 self.assertEqual(expect, data[:len(expect)])
6136
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006137 def testCompressDtbPrependInvalid(self):
6138 """Test that invalid header is detected"""
6139 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006140 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006141 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6142 "'u-boot-dtb': 'invalid'", str(e.exception))
6143
6144 def testCompressDtbPrependLength(self):
6145 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006146 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006147 image = control.images['image']
6148 entries = image.GetEntries()
6149 self.assertIn('u-boot-dtb', entries)
6150 u_boot_dtb = entries['u-boot-dtb']
6151 self.assertIn('fdtmap', entries)
6152 fdtmap = entries['fdtmap']
6153
6154 image_fname = tools.get_output_filename('image.bin')
6155 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6156 dtb = fdt.Fdt.FromData(orig)
6157 dtb.Scan()
6158 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6159 expected = {
6160 'u-boot:size': len(U_BOOT_DATA),
6161 'u-boot-dtb:uncomp-size': len(orig),
6162 'u-boot-dtb:size': u_boot_dtb.size,
6163 'fdtmap:size': fdtmap.size,
6164 'size': len(data),
6165 }
6166 self.assertEqual(expected, props)
6167
6168 # Check implementation
6169 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6170 rest = data[len(U_BOOT_DATA):]
6171 comp_data_len = struct.unpack('<I', rest[:4])[0]
6172 comp_data = rest[4:4 + comp_data_len]
6173 orig2 = self._decompress(comp_data)
6174 self.assertEqual(orig, orig2)
6175
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006176 def testInvalidCompress(self):
6177 """Test that invalid compress algorithm is detected"""
6178 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006179 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006180 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6181
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006182 def testCompUtilCompressions(self):
6183 """Test compression algorithms"""
6184 for bintool in self.comp_bintools.values():
6185 self._CheckBintool(bintool)
6186 data = bintool.compress(COMPRESS_DATA)
6187 self.assertNotEqual(COMPRESS_DATA, data)
6188 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006189 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006190
6191 def testCompUtilVersions(self):
6192 """Test tool version of compression algorithms"""
6193 for bintool in self.comp_bintools.values():
6194 self._CheckBintool(bintool)
6195 version = bintool.version()
6196 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6197
6198 def testCompUtilPadding(self):
6199 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006200 # Skip zstd because it doesn't support padding
6201 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006202 self._CheckBintool(bintool)
6203 data = bintool.compress(COMPRESS_DATA)
6204 self.assertNotEqual(COMPRESS_DATA, data)
6205 data += tools.get_bytes(0, 64)
6206 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006207 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006208
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006209 def testCompressDtbZstd(self):
6210 """Test that zstd compress of device-tree files failed"""
6211 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006212 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006213 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6214 "requires a length header", str(e.exception))
6215
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006216 def testMkimageMultipleDataFiles(self):
6217 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006218 self._SetupSplElf()
6219 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006220 data = self._DoReadFile('252_mkimage_mult_data.dts')
6221 # Size of files are packed in their 4B big-endian format
6222 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6223 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6224 # Size info is always followed by a 4B zero value.
6225 expect += tools.get_bytes(0, 4)
6226 expect += U_BOOT_TPL_DATA
6227 # All but last files are 4B-aligned
6228 align_pad = len(U_BOOT_TPL_DATA) % 4
6229 if align_pad:
6230 expect += tools.get_bytes(0, align_pad)
6231 expect += U_BOOT_SPL_DATA
6232 self.assertEqual(expect, data[-len(expect):])
6233
Marek Vasutf7413f02023-07-18 07:23:58 -06006234 def testMkimageMultipleExpanded(self):
6235 """Test passing multiple files to mkimage in a mkimage entry"""
6236 self._SetupSplElf()
6237 self._SetupTplElf()
6238 entry_args = {
6239 'spl-bss-pad': 'y',
6240 'spl-dtb': 'y',
6241 }
6242 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6243 use_expanded=True, entry_args=entry_args)[0]
6244 pad_len = 10
6245 tpl_expect = U_BOOT_TPL_DATA
6246 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6247 spl_expect += U_BOOT_SPL_DTB_DATA
6248
6249 content = data[0x40:]
6250 lens = struct.unpack('>III', content[:12])
6251
6252 # Size of files are packed in their 4B big-endian format
6253 # Size info is always followed by a 4B zero value.
6254 self.assertEqual(len(tpl_expect), lens[0])
6255 self.assertEqual(len(spl_expect), lens[1])
6256 self.assertEqual(0, lens[2])
6257
6258 rest = content[12:]
6259 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6260
6261 rest = rest[len(tpl_expect):]
6262 align_pad = len(tpl_expect) % 4
6263 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6264 rest = rest[align_pad:]
6265 self.assertEqual(spl_expect, rest)
6266
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006267 def testMkimageMultipleNoContent(self):
6268 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006269 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006270 with self.assertRaises(ValueError) as exc:
6271 self._DoReadFile('253_mkimage_mult_no_content.dts')
6272 self.assertIn('Could not complete processing of contents',
6273 str(exc.exception))
6274
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006275 def testMkimageFilename(self):
6276 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006277 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006278 retcode = self._DoTestFile('254_mkimage_filename.dts')
6279 self.assertEqual(0, retcode)
6280 fname = tools.get_output_filename('mkimage-test.bin')
6281 self.assertTrue(os.path.exists(fname))
6282
Simon Glass56d05412022-02-28 07:16:54 -07006283 def testVpl(self):
6284 """Test that an image with VPL and its device tree can be created"""
6285 # ELF file with a '__bss_size' symbol
6286 self._SetupVplElf()
6287 data = self._DoReadFile('255_u_boot_vpl.dts')
6288 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6289
6290 def testVplNoDtb(self):
6291 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6292 self._SetupVplElf()
6293 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6294 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6295 data[:len(U_BOOT_VPL_NODTB_DATA)])
6296
6297 def testExpandedVpl(self):
6298 """Test that an expanded entry type is selected for TPL when needed"""
6299 self._SetupVplElf()
6300
6301 entry_args = {
6302 'vpl-bss-pad': 'y',
6303 'vpl-dtb': 'y',
6304 }
6305 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6306 entry_args=entry_args)
6307 image = control.images['image']
6308 entries = image.GetEntries()
6309 self.assertEqual(1, len(entries))
6310
6311 # We only have u-boot-vpl, which be expanded
6312 self.assertIn('u-boot-vpl', entries)
6313 entry = entries['u-boot-vpl']
6314 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6315 subent = entry.GetEntries()
6316 self.assertEqual(3, len(subent))
6317 self.assertIn('u-boot-vpl-nodtb', subent)
6318 self.assertIn('u-boot-vpl-bss-pad', subent)
6319 self.assertIn('u-boot-vpl-dtb', subent)
6320
6321 def testVplBssPadMissing(self):
6322 """Test that a missing symbol is detected"""
6323 self._SetupVplElf('u_boot_ucode_ptr')
6324 with self.assertRaises(ValueError) as e:
6325 self._DoReadFile('258_vpl_bss_pad.dts')
6326 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6327 str(e.exception))
6328
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306329 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306330 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306331 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6332 self.assertEqual(0, retcode)
6333 image = control.images['test_image']
6334 fname = tools.get_output_filename('test_image.bin')
6335 sname = tools.get_output_filename('symlink_to_test.bin')
6336 self.assertTrue(os.path.islink(sname))
6337 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006338
Andrew Davis6b463da2023-07-22 00:14:44 +05306339 def testSymlinkOverwrite(self):
6340 """Test that symlinked images can be overwritten"""
6341 testdir = TestFunctional._MakeInputDir('symlinktest')
6342 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6343 # build the same image again in the same directory so that existing symlink is present
6344 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6345 fname = tools.get_output_filename('test_image.bin')
6346 sname = tools.get_output_filename('symlink_to_test.bin')
6347 self.assertTrue(os.path.islink(sname))
6348 self.assertEqual(os.readlink(sname), fname)
6349
Simon Glass37f85de2022-10-20 18:22:47 -06006350 def testSymbolsElf(self):
6351 """Test binman can assign symbols embedded in an ELF file"""
6352 if not elf.ELF_TOOLS:
6353 self.skipTest('Python elftools not available')
6354 self._SetupTplElf('u_boot_binman_syms')
6355 self._SetupVplElf('u_boot_binman_syms')
6356 self._SetupSplElf('u_boot_binman_syms')
6357 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6358 image_fname = tools.get_output_filename('image.bin')
6359
6360 image = control.images['image']
6361 entries = image.GetEntries()
6362
6363 for entry in entries.values():
6364 # No symbols in u-boot and it has faked contents anyway
6365 if entry.name == 'u-boot':
6366 continue
6367 edata = data[entry.image_pos:entry.image_pos + entry.size]
6368 efname = tools.get_output_filename(f'edata-{entry.name}')
6369 tools.write_file(efname, edata)
6370
6371 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6372 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6373 for name, sym in syms.items():
6374 msg = 'test'
6375 val = elf.GetSymbolValue(sym, edata, msg)
6376 entry_m = re_name.match(name)
6377 if entry_m:
6378 ename, prop = entry_m.group(1), entry_m.group(3)
6379 entry, entry_name, prop_name = image.LookupEntry(entries,
6380 name, msg)
6381 if prop_name == 'offset':
6382 expect_val = entry.offset
6383 elif prop_name == 'image_pos':
6384 expect_val = entry.image_pos
6385 elif prop_name == 'size':
6386 expect_val = entry.size
6387 self.assertEqual(expect_val, val)
6388
6389 def testSymbolsElfBad(self):
6390 """Check error when trying to write symbols without the elftools lib"""
6391 if not elf.ELF_TOOLS:
6392 self.skipTest('Python elftools not available')
6393 self._SetupTplElf('u_boot_binman_syms')
6394 self._SetupVplElf('u_boot_binman_syms')
6395 self._SetupSplElf('u_boot_binman_syms')
6396 try:
6397 elf.ELF_TOOLS = False
6398 with self.assertRaises(ValueError) as exc:
6399 self._DoReadFileDtb('260_symbols_elf.dts')
6400 finally:
6401 elf.ELF_TOOLS = True
6402 self.assertIn(
6403 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6404 'Cannot write symbols to an ELF file without Python elftools',
6405 str(exc.exception))
6406
Simon Glassde244162023-01-07 14:07:08 -07006407 def testSectionFilename(self):
6408 """Check writing of section contents to a file"""
6409 data = self._DoReadFile('261_section_fname.dts')
6410 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6411 tools.get_bytes(ord('!'), 7) +
6412 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6413 self.assertEqual(expected, data)
6414
6415 sect_fname = tools.get_output_filename('outfile.bin')
6416 self.assertTrue(os.path.exists(sect_fname))
6417 sect_data = tools.read_file(sect_fname)
6418 self.assertEqual(U_BOOT_DATA, sect_data)
6419
Simon Glass1e9e61c2023-01-07 14:07:12 -07006420 def testAbsent(self):
6421 """Check handling of absent entries"""
6422 data = self._DoReadFile('262_absent.dts')
6423 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6424
Simon Glassad5cfe12023-01-07 14:07:14 -07006425 def testPackTeeOsOptional(self):
6426 """Test that an image with an optional TEE binary can be created"""
6427 entry_args = {
6428 'tee-os-path': 'tee.elf',
6429 }
6430 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6431 entry_args=entry_args)[0]
6432 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6433
6434 def checkFitTee(self, dts, tee_fname):
6435 """Check that a tee-os entry works and returns data
6436
6437 Args:
6438 dts (str): Device tree filename to use
6439 tee_fname (str): filename containing tee-os
6440
6441 Returns:
6442 bytes: Image contents
6443 """
6444 if not elf.ELF_TOOLS:
6445 self.skipTest('Python elftools not available')
6446 entry_args = {
6447 'of-list': 'test-fdt1 test-fdt2',
6448 'default-dt': 'test-fdt2',
6449 'tee-os-path': tee_fname,
6450 }
6451 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6452 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6453 extra_indirs=[test_subdir])[0]
6454 return data
6455
6456 def testFitTeeOsOptionalFit(self):
6457 """Test an image with a FIT with an optional OP-TEE binary"""
6458 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6459
6460 # There should be only one node, holding the data set up in SetUpClass()
6461 # for tee.bin
6462 dtb = fdt.Fdt.FromData(data)
6463 dtb.Scan()
6464 node = dtb.GetNode('/images/tee-1')
6465 self.assertEqual(TEE_ADDR,
6466 fdt_util.fdt32_to_cpu(node.props['load'].value))
6467 self.assertEqual(TEE_ADDR,
6468 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6469 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6470
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006471 with test_util.capture_sys_output() as (stdout, stderr):
6472 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6473 err = stderr.getvalue()
6474 self.assertRegex(
6475 err,
6476 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6477
Simon Glassad5cfe12023-01-07 14:07:14 -07006478 def testFitTeeOsOptionalFitBad(self):
6479 """Test an image with a FIT with an optional OP-TEE binary"""
6480 with self.assertRaises(ValueError) as exc:
6481 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6482 self.assertIn(
6483 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6484 str(exc.exception))
6485
6486 def testFitTeeOsBad(self):
6487 """Test an OP-TEE binary with wrong formats"""
6488 self.make_tee_bin('tee.bad1', 123)
6489 with self.assertRaises(ValueError) as exc:
6490 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6491 self.assertIn(
6492 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6493 str(exc.exception))
6494
6495 self.make_tee_bin('tee.bad2', 0, b'extra data')
6496 with self.assertRaises(ValueError) as exc:
6497 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6498 self.assertIn(
6499 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6500 str(exc.exception))
6501
Simon Glass63328f12023-01-07 14:07:15 -07006502 def testExtblobOptional(self):
6503 """Test an image with an external blob that is optional"""
6504 with test_util.capture_sys_output() as (stdout, stderr):
6505 data = self._DoReadFile('266_blob_ext_opt.dts')
6506 self.assertEqual(REFCODE_DATA, data)
6507 err = stderr.getvalue()
6508 self.assertRegex(
6509 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006510 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006511
Simon Glass7447a9d2023-01-11 16:10:12 -07006512 def testSectionInner(self):
6513 """Test an inner section with a size"""
6514 data = self._DoReadFile('267_section_inner.dts')
6515 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6516 self.assertEqual(expected, data)
6517
Simon Glassa4948b22023-01-11 16:10:14 -07006518 def testNull(self):
6519 """Test an image with a null entry"""
6520 data = self._DoReadFile('268_null.dts')
6521 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6522
Simon Glassf1ee03b2023-01-11 16:10:16 -07006523 def testOverlap(self):
6524 """Test an image with a overlapping entry"""
6525 data = self._DoReadFile('269_overlap.dts')
6526 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6527
6528 image = control.images['image']
6529 entries = image.GetEntries()
6530
6531 self.assertIn('inset', entries)
6532 inset = entries['inset']
6533 self.assertEqual(1, inset.offset);
6534 self.assertEqual(1, inset.image_pos);
6535 self.assertEqual(2, inset.size);
6536
6537 def testOverlapNull(self):
6538 """Test an image with a null overlap"""
6539 data = self._DoReadFile('270_overlap_null.dts')
6540 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6541
6542 # Check the FMAP
6543 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6544 self.assertEqual(4, fhdr.nareas)
6545 fiter = iter(fentries)
6546
6547 fentry = next(fiter)
6548 self.assertEqual(b'SECTION', fentry.name)
6549 self.assertEqual(0, fentry.offset)
6550 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6551 self.assertEqual(0, fentry.flags)
6552
6553 fentry = next(fiter)
6554 self.assertEqual(b'U_BOOT', fentry.name)
6555 self.assertEqual(0, fentry.offset)
6556 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6557 self.assertEqual(0, fentry.flags)
6558
6559 # Make sure that the NULL entry appears in the FMAP
6560 fentry = next(fiter)
6561 self.assertEqual(b'NULL', fentry.name)
6562 self.assertEqual(1, fentry.offset)
6563 self.assertEqual(2, fentry.size)
6564 self.assertEqual(0, fentry.flags)
6565
6566 fentry = next(fiter)
6567 self.assertEqual(b'FMAP', fentry.name)
6568 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6569
6570 def testOverlapBad(self):
6571 """Test an image with a bad overlapping entry"""
6572 with self.assertRaises(ValueError) as exc:
6573 self._DoReadFile('271_overlap_bad.dts')
6574 self.assertIn(
6575 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6576 str(exc.exception))
6577
6578 def testOverlapNoOffset(self):
6579 """Test an image with a bad overlapping entry"""
6580 with self.assertRaises(ValueError) as exc:
6581 self._DoReadFile('272_overlap_no_size.dts')
6582 self.assertIn(
6583 "Node '/binman/inset': 'fill' entry is missing properties: size",
6584 str(exc.exception))
6585
Simon Glasse0035c92023-01-11 16:10:17 -07006586 def testBlobSymbol(self):
6587 """Test a blob with symbols read from an ELF file"""
6588 elf_fname = self.ElfTestFile('blob_syms')
6589 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6590 TestFunctional._MakeInputFile('blob_syms.bin',
6591 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6592
6593 data = self._DoReadFile('273_blob_symbol.dts')
6594
6595 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6596 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6597 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6598 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6599 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6600
6601 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6602 expected = sym_values
6603 self.assertEqual(expected, data[:len(expected)])
6604
Simon Glass49e9c002023-01-11 16:10:19 -07006605 def testOffsetFromElf(self):
6606 """Test a blob with symbols read from an ELF file"""
6607 elf_fname = self.ElfTestFile('blob_syms')
6608 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6609 TestFunctional._MakeInputFile('blob_syms.bin',
6610 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6611
6612 data = self._DoReadFile('274_offset_from_elf.dts')
6613
6614 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6615 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6616
6617 image = control.images['image']
6618 entries = image.GetEntries()
6619
6620 self.assertIn('inset', entries)
6621 inset = entries['inset']
6622
6623 self.assertEqual(base + 4, inset.offset);
6624 self.assertEqual(base + 4, inset.image_pos);
6625 self.assertEqual(4, inset.size);
6626
6627 self.assertIn('inset2', entries)
6628 inset = entries['inset2']
6629 self.assertEqual(base + 8, inset.offset);
6630 self.assertEqual(base + 8, inset.image_pos);
6631 self.assertEqual(4, inset.size);
6632
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006633 def testFitAlign(self):
6634 """Test an image with an FIT with aligned external data"""
6635 data = self._DoReadFile('275_fit_align.dts')
6636 self.assertEqual(4096, len(data))
6637
6638 dtb = fdt.Fdt.FromData(data)
6639 dtb.Scan()
6640
6641 props = self._GetPropTree(dtb, ['data-position'])
6642 expected = {
6643 'u-boot:data-position': 1024,
6644 'fdt-1:data-position': 2048,
6645 'fdt-2:data-position': 3072,
6646 }
6647 self.assertEqual(expected, props)
6648
Jonas Karlman490f73c2023-01-21 19:02:12 +00006649 def testFitFirmwareLoadables(self):
6650 """Test an image with an FIT that use fit,firmware"""
6651 if not elf.ELF_TOOLS:
6652 self.skipTest('Python elftools not available')
6653 entry_args = {
6654 'of-list': 'test-fdt1',
6655 'default-dt': 'test-fdt1',
6656 'atf-bl31-path': 'bl31.elf',
6657 'tee-os-path': 'missing.bin',
6658 }
6659 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006660 with test_util.capture_sys_output() as (stdout, stderr):
6661 data = self._DoReadFileDtb(
6662 '276_fit_firmware_loadables.dts',
6663 entry_args=entry_args,
6664 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006665
6666 dtb = fdt.Fdt.FromData(data)
6667 dtb.Scan()
6668
6669 node = dtb.GetNode('/configurations/conf-uboot-1')
6670 self.assertEqual('u-boot', node.props['firmware'].value)
6671 self.assertEqual(['atf-1', 'atf-2'],
6672 fdt_util.GetStringList(node, 'loadables'))
6673
6674 node = dtb.GetNode('/configurations/conf-atf-1')
6675 self.assertEqual('atf-1', node.props['firmware'].value)
6676 self.assertEqual(['u-boot', 'atf-2'],
6677 fdt_util.GetStringList(node, 'loadables'))
6678
6679 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6680 self.assertEqual('u-boot', node.props['firmware'].value)
6681 self.assertEqual(['atf-1', 'atf-2'],
6682 fdt_util.GetStringList(node, 'loadables'))
6683
6684 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6685 self.assertEqual('atf-1', node.props['firmware'].value)
6686 self.assertEqual(['u-boot', 'atf-2'],
6687 fdt_util.GetStringList(node, 'loadables'))
6688
6689 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6690 self.assertEqual('atf-1', node.props['firmware'].value)
6691 self.assertEqual(['u-boot', 'atf-2'],
6692 fdt_util.GetStringList(node, 'loadables'))
6693
Simon Glass9a1c7262023-02-22 12:14:49 -07006694 def testTooldir(self):
6695 """Test that we can specify the tooldir"""
6696 with test_util.capture_sys_output() as (stdout, stderr):
6697 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6698 'tool', '-l'))
6699 self.assertEqual('fred', bintool.Bintool.tooldir)
6700
6701 # Check that the toolpath is updated correctly
6702 self.assertEqual(['fred'], tools.tool_search_paths)
6703
6704 # Try with a few toolpaths; the tooldir should be at the end
6705 with test_util.capture_sys_output() as (stdout, stderr):
6706 self.assertEqual(0, self._DoBinman(
6707 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6708 'tool', '-l'))
6709 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6710
Simon Glass49b77e82023-03-02 17:02:44 -07006711 def testReplaceSectionEntry(self):
6712 """Test replacing an entry in a section"""
6713 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6714 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6715 expect_data, dts='241_replace_section_simple.dts')
6716 self.assertEqual(expect_data, entry_data)
6717
6718 entries = image.GetEntries()
6719 self.assertIn('section', entries)
6720 section = entries['section']
6721
6722 sect_entries = section.GetEntries()
6723 self.assertIn('blob', sect_entries)
6724 entry = sect_entries['blob']
6725 self.assertEqual(len(expect_data), entry.size)
6726
6727 fname = tools.get_output_filename('image-updated.bin')
6728 data = tools.read_file(fname)
6729
6730 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6731 self.assertEqual(expect_data, new_blob_data)
6732
6733 self.assertEqual(U_BOOT_DATA,
6734 data[entry.image_pos + len(expect_data):]
6735 [:len(U_BOOT_DATA)])
6736
6737 def testReplaceSectionDeep(self):
6738 """Test replacing an entry in two levels of sections"""
6739 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6740 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6741 'section/section/blob', expect_data,
6742 dts='278_replace_section_deep.dts')
6743 self.assertEqual(expect_data, entry_data)
6744
6745 entries = image.GetEntries()
6746 self.assertIn('section', entries)
6747 section = entries['section']
6748
6749 subentries = section.GetEntries()
6750 self.assertIn('section', subentries)
6751 section = subentries['section']
6752
6753 sect_entries = section.GetEntries()
6754 self.assertIn('blob', sect_entries)
6755 entry = sect_entries['blob']
6756 self.assertEqual(len(expect_data), entry.size)
6757
6758 fname = tools.get_output_filename('image-updated.bin')
6759 data = tools.read_file(fname)
6760
6761 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6762 self.assertEqual(expect_data, new_blob_data)
6763
6764 self.assertEqual(U_BOOT_DATA,
6765 data[entry.image_pos + len(expect_data):]
6766 [:len(U_BOOT_DATA)])
6767
6768 def testReplaceFitSibling(self):
6769 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006770 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006771 fname = TestFunctional._MakeInputFile('once', b'available once')
6772 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6773 os.remove(fname)
6774
6775 try:
6776 tmpdir, updated_fname = self._SetupImageInTmpdir()
6777
6778 fname = os.path.join(tmpdir, 'update-blob')
6779 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6780 tools.write_file(fname, expected)
6781
6782 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6783 data = tools.read_file(updated_fname)
6784 start = len(U_BOOT_DTB_DATA)
6785 self.assertEqual(expected, data[start:start + len(expected)])
6786 map_fname = os.path.join(tmpdir, 'image-updated.map')
6787 self.assertFalse(os.path.exists(map_fname))
6788 finally:
6789 shutil.rmtree(tmpdir)
6790
Simon Glassc3fe97f2023-03-02 17:02:45 -07006791 def testX509Cert(self):
6792 """Test creating an X509 certificate"""
6793 keyfile = self.TestFile('key.key')
6794 entry_args = {
6795 'keyfile': keyfile,
6796 }
6797 data = self._DoReadFileDtb('279_x509_cert.dts',
6798 entry_args=entry_args)[0]
6799 cert = data[:-4]
6800 self.assertEqual(U_BOOT_DATA, data[-4:])
6801
6802 # TODO: verify the signature
6803
6804 def testX509CertMissing(self):
6805 """Test that binman still produces an image if openssl is missing"""
6806 keyfile = self.TestFile('key.key')
6807 entry_args = {
6808 'keyfile': 'keyfile',
6809 }
6810 with test_util.capture_sys_output() as (_, stderr):
6811 self._DoTestFile('279_x509_cert.dts',
6812 force_missing_bintools='openssl',
6813 entry_args=entry_args)
6814 err = stderr.getvalue()
6815 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6816
Jonas Karlman35305492023-02-25 19:01:33 +00006817 def testPackRockchipTpl(self):
6818 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006819 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006820 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6821
Jonas Karlman1016ec72023-02-25 19:01:35 +00006822 def testMkimageMissingBlobMultiple(self):
6823 """Test missing blob with mkimage entry and multiple-data-files"""
6824 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006825 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006826 err = stderr.getvalue()
6827 self.assertIn("is missing external blobs and is non-functional", err)
6828
6829 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006830 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006831 self.assertIn("not found in input path", str(e.exception))
6832
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006833 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6834 """Prepare sign environment
6835
6836 Create private and public keys, add pubkey into dtb.
6837
6838 Returns:
6839 Tuple:
6840 FIT container
6841 Image name
6842 Private key
6843 DTB
6844 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006845 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006846 data = self._DoReadFileRealDtb(dts)
6847 updated_fname = tools.get_output_filename('image-updated.bin')
6848 tools.write_file(updated_fname, data)
6849 dtb = tools.get_output_filename('source.dtb')
6850 private_key = tools.get_output_filename('test_key.key')
6851 public_key = tools.get_output_filename('test_key.crt')
6852 fit = tools.get_output_filename('fit.fit')
6853 key_dir = tools.get_output_dir()
6854
6855 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6856 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6857 private_key, '-out', public_key)
6858 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6859 '-n', 'test_key', '-r', 'conf', dtb)
6860
6861 return fit, updated_fname, private_key, dtb
6862
6863 def testSignSimple(self):
6864 """Test that a FIT container can be signed in image"""
6865 is_signed = False
6866 fit, fname, private_key, dtb = self._PrepareSignEnv()
6867
6868 # do sign with private key
6869 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6870 ['fit'])
6871 is_signed = self._CheckSign(fit, dtb)
6872
6873 self.assertEqual(is_signed, True)
6874
6875 def testSignExactFIT(self):
6876 """Test that a FIT container can be signed and replaced in image"""
6877 is_signed = False
6878 fit, fname, private_key, dtb = self._PrepareSignEnv()
6879
6880 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6881 args = []
6882 if self.toolpath:
6883 for path in self.toolpath:
6884 args += ['--toolpath', path]
6885
6886 # do sign with private key
6887 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6888 'sha256,rsa4096', '-f', fit, 'fit')
6889 is_signed = self._CheckSign(fit, dtb)
6890
6891 self.assertEqual(is_signed, True)
6892
6893 def testSignNonFit(self):
6894 """Test a non-FIT entry cannot be signed"""
6895 is_signed = False
6896 fit, fname, private_key, _ = self._PrepareSignEnv(
6897 '281_sign_non_fit.dts')
6898
6899 # do sign with private key
6900 with self.assertRaises(ValueError) as e:
6901 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6902 'sha256,rsa4096', '-f', fit, 'u-boot')
6903 self.assertIn(
6904 "Node '/u-boot': Updating signatures is not supported with this entry type",
6905 str(e.exception))
6906
6907 def testSignMissingMkimage(self):
6908 """Test that FIT signing handles a missing mkimage tool"""
6909 fit, fname, private_key, _ = self._PrepareSignEnv()
6910
6911 # try to sign with a missing mkimage tool
6912 bintool.Bintool.set_missing_list(['mkimage'])
6913 with self.assertRaises(ValueError) as e:
6914 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6915 ['fit'])
6916 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6917
Simon Glass4abf7842023-07-18 07:23:54 -06006918 def testSymbolNoWrite(self):
6919 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006920 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006921 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6922 no_write_symbols=True)
6923
6924 def testSymbolNoWriteExpanded(self):
6925 """Test disabling of symbol writing in expanded entries"""
6926 entry_args = {
6927 'spl-dtb': '1',
6928 }
6929 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6930 U_BOOT_SPL_DTB_DATA, 0x38,
6931 entry_args=entry_args, use_expanded=True,
6932 no_write_symbols=True)
6933
Marek Vasutf7413f02023-07-18 07:23:58 -06006934 def testMkimageSpecial(self):
6935 """Test mkimage ignores special hash-1 node"""
6936 data = self._DoReadFile('283_mkimage_special.dts')
6937
6938 # Just check that the data appears in the file somewhere
6939 self.assertIn(U_BOOT_DATA, data)
6940
Simon Glass2d94c422023-07-18 07:23:59 -06006941 def testFitFdtList(self):
6942 """Test an image with an FIT with the fit,fdt-list-val option"""
6943 entry_args = {
6944 'default-dt': 'test-fdt2',
6945 }
6946 data = self._DoReadFileDtb(
6947 '284_fit_fdt_list.dts',
6948 entry_args=entry_args,
6949 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6950 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6951 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6952
Simon Glass83b8bfe2023-07-18 07:24:01 -06006953 def testSplEmptyBss(self):
6954 """Test an expanded SPL with a zero-size BSS"""
6955 # ELF file with a '__bss_size' symbol
6956 self._SetupSplElf(src_fname='bss_data_zero')
6957
6958 entry_args = {
6959 'spl-bss-pad': 'y',
6960 'spl-dtb': 'y',
6961 }
6962 data = self._DoReadFileDtb('285_spl_expand.dts',
6963 use_expanded=True, entry_args=entry_args)[0]
6964
Simon Glassfc792842023-07-18 07:24:04 -06006965 def testTemplate(self):
6966 """Test using a template"""
6967 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6968 data = self._DoReadFile('286_template.dts')
6969 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6970 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6971 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6972
Simon Glass09490b02023-07-22 21:43:52 -06006973 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6974 self.assertTrue(os.path.exists(dtb_fname1))
6975 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6976 dtb.Scan()
6977 node1 = dtb.GetNode('/binman/template')
6978 self.assertTrue(node1)
6979 vga = dtb.GetNode('/binman/first/intel-vga')
6980 self.assertTrue(vga)
6981
Simon Glass54825e12023-07-22 21:43:56 -06006982 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6983 self.assertTrue(os.path.exists(dtb_fname2))
6984 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6985 dtb2.Scan()
6986 node2 = dtb2.GetNode('/binman/template')
6987 self.assertFalse(node2)
6988
Simon Glass9909c112023-07-18 07:24:05 -06006989 def testTemplateBlobMulti(self):
6990 """Test using a template with 'multiple-images' enabled"""
6991 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6992 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6993 retcode = self._DoTestFile('287_template_multi.dts')
6994
6995 self.assertEqual(0, retcode)
6996 image = control.images['image']
6997 image_fname = tools.get_output_filename('my-image.bin')
6998 data = tools.read_file(image_fname)
6999 self.assertEqual(b'blob@@@@other', data)
7000
Simon Glass5dc511b2023-07-18 07:24:06 -06007001 def testTemplateFit(self):
7002 """Test using a template in a FIT"""
7003 fit_data = self._DoReadFile('288_template_fit.dts')
7004 fname = os.path.join(self._indir, 'fit_data.fit')
7005 tools.write_file(fname, fit_data)
7006 out = tools.run('dumpimage', '-l', fname)
7007
Simon Glassaa6e0552023-07-18 07:24:07 -06007008 def testTemplateSection(self):
7009 """Test using a template in a section (not at top level)"""
7010 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
7011 data = self._DoReadFile('289_template_section.dts')
7012 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
7013 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
7014 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
7015
Simon Glassf53a7bc2023-07-18 07:24:08 -06007016 def testMkimageSymbols(self):
7017 """Test using mkimage to build an image with symbols in it"""
7018 self._SetupSplElf('u_boot_binman_syms')
7019 data = self._DoReadFile('290_mkimage_sym.dts')
7020
7021 image = control.images['image']
7022 entries = image.GetEntries()
7023 self.assertIn('u-boot', entries)
7024 u_boot = entries['u-boot']
7025
7026 mkim = entries['mkimage']
7027 mkim_entries = mkim.GetEntries()
7028 self.assertIn('u-boot-spl', mkim_entries)
7029 spl = mkim_entries['u-boot-spl']
7030 self.assertIn('u-boot-spl2', mkim_entries)
7031 spl2 = mkim_entries['u-boot-spl2']
7032
7033 # skip the mkimage header and the area sizes
7034 mk_data = data[mkim.offset + 0x40:]
7035 size, term = struct.unpack('>LL', mk_data[:8])
7036
7037 # There should be only one image, so check that the zero terminator is
7038 # present
7039 self.assertEqual(0, term)
7040
7041 content = mk_data[8:8 + size]
7042
7043 # The image should contain the symbols from u_boot_binman_syms.c
7044 # Note that image_pos is adjusted by the base address of the image,
7045 # which is 0x10 in our test image
7046 spl_data = content[:0x18]
7047 content = content[0x1b:]
7048
7049 # After the header is a table of offsets for each image. There should
7050 # only be one image, then a 0 terminator, so figure out the real start
7051 # of the image data
7052 base = 0x40 + 8
7053
7054 # Check symbols in both u-boot-spl and u-boot-spl2
7055 for i in range(2):
7056 vals = struct.unpack('<LLQLL', spl_data)
7057
7058 # The image should contain the symbols from u_boot_binman_syms.c
7059 # Note that image_pos is adjusted by the base address of the image,
7060 # which is 0x10 in our 'u_boot_binman_syms' test image
7061 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
7062 self.assertEqual(base, vals[1])
7063 self.assertEqual(spl2.offset, vals[2])
7064 # figure out the internal positions of its components
7065 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
7066
7067 # Check that spl and spl2 are actually at the indicated positions
7068 self.assertEqual(
7069 elf.BINMAN_SYM_MAGIC_VALUE,
7070 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
7071 self.assertEqual(
7072 elf.BINMAN_SYM_MAGIC_VALUE,
7073 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
7074
7075 self.assertEqual(len(U_BOOT_DATA), vals[4])
7076
7077 # Move to next
7078 spl_data = content[:0x18]
7079
Simon Glass86b3e472023-07-22 21:43:57 -06007080 def testTemplatePhandle(self):
7081 """Test using a template in a node containing a phandle"""
7082 entry_args = {
7083 'atf-bl31-path': 'bl31.elf',
7084 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06007085 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007086 entry_args=entry_args)
7087 fname = tools.get_output_filename('image.bin')
7088 out = tools.run('dumpimage', '-l', fname)
7089
7090 # We should see the FIT description and one for each of the two images
7091 lines = out.splitlines()
7092 descs = [line.split()[-1] for line in lines if 'escription' in line]
7093 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7094
7095 def testTemplatePhandleDup(self):
7096 """Test using a template in a node containing a phandle"""
7097 entry_args = {
7098 'atf-bl31-path': 'bl31.elf',
7099 }
7100 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007101 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007102 entry_args=entry_args)
7103 self.assertIn(
7104 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7105 str(e.exception))
7106
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307107 def testTIBoardConfig(self):
7108 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007109 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307110 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7111
Neha Malcom Francis8cd04512024-01-05 17:09:17 +05307112 def testTIBoardConfigLint(self):
7113 """Test that an incorrectly linted config file would generate error"""
7114 with self.assertRaises(ValueError) as e:
7115 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7116 self.assertIn("Yamllint error", str(e.exception))
7117
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307118 def testTIBoardConfigCombined(self):
7119 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007120 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307121 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7122 self.assertGreater(data, configlen_noheader)
7123
7124 def testTIBoardConfigNoDataType(self):
7125 """Test that error is thrown when data type is not supported"""
7126 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007127 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307128 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007129
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307130 def testPackTiSecure(self):
7131 """Test that an image with a TI secured binary can be created"""
7132 keyfile = self.TestFile('key.key')
7133 entry_args = {
7134 'keyfile': keyfile,
7135 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007136 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307137 entry_args=entry_args)[0]
7138 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7139
Manorit Chawdhry2e523b02023-12-29 16:16:27 +05307140 def testPackTiSecureFirewall(self):
7141 """Test that an image with a TI secured binary can be created"""
7142 keyfile = self.TestFile('key.key')
7143 entry_args = {
7144 'keyfile': keyfile,
7145 }
7146 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7147 entry_args=entry_args)[0]
7148 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7149 entry_args=entry_args)[0]
7150 self.assertGreater(len(data_firewall),len(data_no_firewall))
7151
7152 def testPackTiSecureFirewallMissingProperty(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 }
7158 with self.assertRaises(ValueError) as e:
7159 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7160 entry_args=entry_args)[0]
7161 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7162
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307163 def testPackTiSecureMissingTool(self):
7164 """Test that an image with a TI secured binary (non-functional) can be created
7165 when openssl is missing"""
7166 keyfile = self.TestFile('key.key')
7167 entry_args = {
7168 'keyfile': keyfile,
7169 }
7170 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007171 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307172 force_missing_bintools='openssl',
7173 entry_args=entry_args)
7174 err = stderr.getvalue()
7175 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7176
7177 def testPackTiSecureROM(self):
7178 """Test that a ROM image with a TI secured binary can be created"""
7179 keyfile = self.TestFile('key.key')
7180 entry_args = {
7181 'keyfile': keyfile,
7182 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007183 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307184 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007185 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307186 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007187 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307188 entry_args=entry_args)[0]
7189 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7190 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7191 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7192
7193 def testPackTiSecureROMCombined(self):
7194 """Test that a ROM image with a TI secured binary can be created"""
7195 keyfile = self.TestFile('key.key')
7196 entry_args = {
7197 'keyfile': keyfile,
7198 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007199 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307200 entry_args=entry_args)[0]
7201 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7202
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007203 def testEncryptedNoAlgo(self):
7204 """Test encrypted node with missing required properties"""
7205 with self.assertRaises(ValueError) as e:
7206 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7207 self.assertIn(
7208 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7209 str(e.exception))
7210
7211 def testEncryptedInvalidIvfile(self):
7212 """Test encrypted node with invalid iv file"""
7213 with self.assertRaises(ValueError) as e:
7214 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7215 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7216 str(e.exception))
7217
7218 def testEncryptedMissingKey(self):
7219 """Test encrypted node with missing key properties"""
7220 with self.assertRaises(ValueError) as e:
7221 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7222 self.assertIn(
7223 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7224 str(e.exception))
7225
7226 def testEncryptedKeySource(self):
7227 """Test encrypted node with key-source property"""
7228 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7229
7230 dtb = fdt.Fdt.FromData(data)
7231 dtb.Scan()
7232
7233 node = dtb.GetNode('/images/u-boot/cipher')
7234 self.assertEqual('algo-name', node.props['algo'].value)
7235 self.assertEqual('key-source-value', node.props['key-source'].value)
7236 self.assertEqual(ENCRYPTED_IV_DATA,
7237 tools.to_bytes(''.join(node.props['iv'].value)))
7238 self.assertNotIn('key', node.props)
7239
7240 def testEncryptedKeyFile(self):
7241 """Test encrypted node with key-filename property"""
7242 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7243
7244 dtb = fdt.Fdt.FromData(data)
7245 dtb.Scan()
7246
7247 node = dtb.GetNode('/images/u-boot/cipher')
7248 self.assertEqual('algo-name', node.props['algo'].value)
7249 self.assertEqual(ENCRYPTED_IV_DATA,
7250 tools.to_bytes(''.join(node.props['iv'].value)))
7251 self.assertEqual(ENCRYPTED_KEY_DATA,
7252 tools.to_bytes(''.join(node.props['key'].value)))
7253 self.assertNotIn('key-source', node.props)
7254
Lukas Funkee901faf2023-07-18 13:53:13 +02007255
7256 def testSplPubkeyDtb(self):
Simon Glass4b861272024-07-20 11:49:41 +01007257 """Test u_boot_spl_pubkey_dtb etype"""
7258 data = tools.read_file(self.TestFile("key.pem"))
7259 self._MakeInputFile("key.crt", data)
7260 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7261 image = control.images['image']
7262 entries = image.GetEntries()
7263 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7264 dtb_data = dtb_entry.GetData()
7265 dtb = fdt.Fdt.FromData(dtb_data)
7266 dtb.Scan()
Lukas Funkee901faf2023-07-18 13:53:13 +02007267
Simon Glass4b861272024-07-20 11:49:41 +01007268 signature_node = dtb.GetNode('/signature')
7269 self.assertIsNotNone(signature_node)
7270 key_node = signature_node.FindNode("key-key")
7271 self.assertIsNotNone(key_node)
7272 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7273 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7274 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007275
Lukas Funke712e1062023-08-03 17:22:14 +02007276 def testXilinxBootgenSigning(self):
7277 """Test xilinx-bootgen etype"""
7278 bootgen = bintool.Bintool.create('bootgen')
7279 self._CheckBintool(bootgen)
7280 data = tools.read_file(self.TestFile("key.key"))
7281 self._MakeInputFile("psk.pem", data)
7282 self._MakeInputFile("ssk.pem", data)
7283 self._SetupPmuFwlElf()
7284 self._SetupSplElf()
7285 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7286 image_fname = tools.get_output_filename('image.bin')
7287
7288 # Read partition header table and check if authentication is enabled
7289 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7290 "-read", image_fname, "pht").splitlines()
7291 attributes = {"authentication": None,
7292 "core": None,
7293 "encryption": None}
7294
7295 for l in bootgen_out:
7296 for a in attributes.keys():
7297 if a in l:
7298 m = re.match(fr".*{a} \[([^]]+)\]", l)
7299 attributes[a] = m.group(1)
7300
7301 self.assertTrue(attributes['authentication'] == "rsa")
7302 self.assertTrue(attributes['core'] == "a53-0")
7303 self.assertTrue(attributes['encryption'] == "no")
7304
7305 def testXilinxBootgenSigningEncryption(self):
7306 """Test xilinx-bootgen etype"""
7307 bootgen = bintool.Bintool.create('bootgen')
7308 self._CheckBintool(bootgen)
7309 data = tools.read_file(self.TestFile("key.key"))
7310 self._MakeInputFile("psk.pem", data)
7311 self._MakeInputFile("ssk.pem", data)
7312 self._SetupPmuFwlElf()
7313 self._SetupSplElf()
7314 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7315 image_fname = tools.get_output_filename('image.bin')
7316
7317 # Read boot header in order to verify encryption source and
7318 # encryption parameter
7319 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7320 "-read", image_fname, "bh").splitlines()
7321 attributes = {"auth_only":
7322 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7323 "encryption_keystore":
7324 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7325 "value": None},
7326 }
7327
7328 for l in bootgen_out:
7329 for a in attributes.keys():
7330 if a in l:
7331 m = re.match(attributes[a]['re'], l)
7332 attributes[a] = m.group(1)
7333
7334 # Check if fsbl-attribute is set correctly
7335 self.assertTrue(attributes['auth_only'] == "true")
7336 # Check if key is stored in efuse
7337 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7338
7339 def testXilinxBootgenMissing(self):
7340 """Test that binman still produces an image if bootgen is missing"""
7341 data = tools.read_file(self.TestFile("key.key"))
7342 self._MakeInputFile("psk.pem", data)
7343 self._MakeInputFile("ssk.pem", data)
7344 self._SetupPmuFwlElf()
7345 self._SetupSplElf()
7346 with test_util.capture_sys_output() as (_, stderr):
7347 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7348 force_missing_bintools='bootgen')
7349 err = stderr.getvalue()
7350 self.assertRegex(err,
7351 "Image 'image'.*missing bintools.*: bootgen")
7352
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307353 def _GetCapsuleHeaders(self, data):
7354 """Get the capsule header contents
7355
7356 Args:
7357 data: Capsule file contents
7358
7359 Returns:
7360 Dict:
7361 key: Capsule Header name (str)
7362 value: Header field value (str)
7363 """
7364 capsule_file = os.path.join(self._indir, 'test.capsule')
7365 tools.write_file(capsule_file, data)
7366
7367 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7368 lines = out.splitlines()
7369
7370 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7371 vals = {}
7372 for line in lines:
7373 mat = re_line.match(line)
7374 if mat:
7375 vals[mat.group(1)] = mat.group(2)
7376
7377 return vals
7378
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307379 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7380 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307381 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7382 fmp_size = "00000010"
7383 fmp_fw_version = "00000002"
7384 capsule_image_index = "00000001"
7385 oemflag = "00018000"
7386 auth_hdr_revision = "00000200"
7387 auth_hdr_cert_type = "00000EF1"
7388
7389 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307390
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307391 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307392
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307393 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307394
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307395 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7396 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7397 self.assertEqual(capsule_image_index,
7398 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307399
7400 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307401 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7402
7403 if signed_capsule:
7404 self.assertEqual(auth_hdr_revision,
7405 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7406 self.assertEqual(auth_hdr_cert_type,
7407 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7408 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7409 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7410
7411 if version_check:
7412 self.assertEqual(fmp_signature,
7413 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7414 self.assertEqual(fmp_size,
7415 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7416 self.assertEqual(fmp_fw_version,
7417 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7418
7419 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307420
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307421 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7422 if accept_capsule:
7423 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7424 else:
7425 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7426
7427 hdr = self._GetCapsuleHeaders(data)
7428
7429 self.assertEqual(capsule_hdr_guid.upper(),
7430 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7431
7432 if accept_capsule:
7433 capsule_size = "0000002C"
7434 else:
7435 capsule_size = "0000001C"
7436 self.assertEqual(capsule_size,
7437 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7438
7439 if accept_capsule:
7440 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7441
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307442 def testCapsuleGen(self):
7443 """Test generation of EFI capsule"""
7444 data = self._DoReadFile('311_capsule.dts')
7445
7446 self._CheckCapsule(data)
7447
7448 def testSignedCapsuleGen(self):
7449 """Test generation of EFI capsule"""
7450 data = tools.read_file(self.TestFile("key.key"))
7451 self._MakeInputFile("key.key", data)
7452 data = tools.read_file(self.TestFile("key.pem"))
7453 self._MakeInputFile("key.crt", data)
7454
7455 data = self._DoReadFile('312_capsule_signed.dts')
7456
7457 self._CheckCapsule(data, signed_capsule=True)
7458
7459 def testCapsuleGenVersionSupport(self):
7460 """Test generation of EFI capsule with version support"""
7461 data = self._DoReadFile('313_capsule_version.dts')
7462
7463 self._CheckCapsule(data, version_check=True)
7464
7465 def testCapsuleGenSignedVer(self):
7466 """Test generation of signed EFI capsule with version information"""
7467 data = tools.read_file(self.TestFile("key.key"))
7468 self._MakeInputFile("key.key", data)
7469 data = tools.read_file(self.TestFile("key.pem"))
7470 self._MakeInputFile("key.crt", data)
7471
7472 data = self._DoReadFile('314_capsule_signed_ver.dts')
7473
7474 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7475
7476 def testCapsuleGenCapOemFlags(self):
7477 """Test generation of EFI capsule with OEM Flags set"""
7478 data = self._DoReadFile('315_capsule_oemflags.dts')
7479
7480 self._CheckCapsule(data, capoemflags=True)
7481
7482 def testCapsuleGenKeyMissing(self):
7483 """Test that binman errors out on missing key"""
7484 with self.assertRaises(ValueError) as e:
7485 self._DoReadFile('316_capsule_missing_key.dts')
7486
7487 self.assertIn("Both private key and public key certificate need to be provided",
7488 str(e.exception))
7489
7490 def testCapsuleGenIndexMissing(self):
7491 """Test that binman errors out on missing image index"""
7492 with self.assertRaises(ValueError) as e:
7493 self._DoReadFile('317_capsule_missing_index.dts')
7494
7495 self.assertIn("entry is missing properties: image-index",
7496 str(e.exception))
7497
7498 def testCapsuleGenGuidMissing(self):
7499 """Test that binman errors out on missing image GUID"""
7500 with self.assertRaises(ValueError) as e:
7501 self._DoReadFile('318_capsule_missing_guid.dts')
7502
7503 self.assertIn("entry is missing properties: image-guid",
7504 str(e.exception))
7505
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307506 def testCapsuleGenAcceptCapsule(self):
7507 """Test generationg of accept EFI capsule"""
7508 data = self._DoReadFile('319_capsule_accept.dts')
7509
7510 self._CheckEmptyCapsule(data, accept_capsule=True)
7511
7512 def testCapsuleGenRevertCapsule(self):
7513 """Test generationg of revert EFI capsule"""
7514 data = self._DoReadFile('320_capsule_revert.dts')
7515
7516 self._CheckEmptyCapsule(data)
7517
7518 def testCapsuleGenAcceptGuidMissing(self):
7519 """Test that binman errors out on missing image GUID for accept capsule"""
7520 with self.assertRaises(ValueError) as e:
7521 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7522
7523 self.assertIn("Image GUID needed for generating accept capsule",
7524 str(e.exception))
7525
7526 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7527 """Test that capsule-type is specified"""
7528 with self.assertRaises(ValueError) as e:
7529 self._DoReadFile('322_empty_capsule_type_missing.dts')
7530
7531 self.assertIn("entry is missing properties: capsule-type",
7532 str(e.exception))
7533
7534 def testCapsuleGenAcceptOrRevertMissing(self):
7535 """Test that both accept and revert capsule are not specified"""
7536 with self.assertRaises(ValueError) as e:
7537 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7538
Simon Glassa360b8f2024-06-23 11:55:06 -06007539 def test_assume_size(self):
7540 """Test handling of the assume-size property for external blob"""
7541 with self.assertRaises(ValueError) as e:
7542 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7543 allow_fake_blobs=True)
7544 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7545 str(e.exception))
7546
7547 def test_assume_size_ok(self):
7548 """Test handling of the assume-size where it fits OK"""
7549 with test_util.capture_sys_output() as (stdout, stderr):
7550 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7551 allow_fake_blobs=True)
7552 err = stderr.getvalue()
7553 self.assertRegex(
7554 err,
7555 "Image '.*' has faked external blobs and is non-functional: .*")
7556
7557 def test_assume_size_no_fake(self):
7558 """Test handling of the assume-size where it fits OK"""
7559 with test_util.capture_sys_output() as (stdout, stderr):
7560 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7561 err = stderr.getvalue()
7562 self.assertRegex(
7563 err,
7564 "Image '.*' is missing external blobs and is non-functional: .*")
7565
Simon Glass5f7aadf2024-07-20 11:49:47 +01007566 def SetupAlternateDts(self):
7567 """Compile the .dts test files for alternative-fdt
7568
7569 Returns:
7570 tuple:
7571 str: Test directory created
7572 list of str: '.bin' files which we expect Binman to create
7573 """
7574 testdir = TestFunctional._MakeInputDir('dtb')
7575 dtb_list = []
7576 for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
7577 tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
7578 base = os.path.splitext(os.path.basename(fname))[0]
7579 dtb_list.append(base + '.bin')
7580 shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
7581
7582 return testdir, dtb_list
7583
Simon Glassf3598922024-07-20 11:49:45 +01007584 def CheckAlternates(self, dts, phase, xpl_data):
7585 """Run the test for the alterative-fdt etype
7586
7587 Args:
7588 dts (str): Devicetree file to process
7589 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7590 xpl_data (bytes): Expected data for the phase's binary
7591
7592 Returns:
7593 dict of .dtb files produced
7594 key: str filename
7595 value: Fdt object
7596 """
Simon Glass5f7aadf2024-07-20 11:49:47 +01007597 dtb_list = self.SetupAlternateDts()[1]
Simon Glassf3598922024-07-20 11:49:45 +01007598
7599 entry_args = {
7600 f'{phase}-dtb': '1',
7601 f'{phase}-bss-pad': 'y',
7602 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7603 }
7604 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7605 use_expanded=True, entry_args=entry_args)[0]
7606 self.assertEqual(xpl_data, data[:len(xpl_data)])
7607 rest = data[len(xpl_data):]
7608 pad_len = 10
7609 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7610
7611 # Check the dtb is using the test file
7612 dtb_data = rest[pad_len:]
7613 dtb = fdt.Fdt.FromData(dtb_data)
7614 dtb.Scan()
7615 fdt_size = dtb.GetFdtObj().totalsize()
7616 self.assertEqual('model-not-set',
7617 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7618
7619 pad_len = 10
7620
7621 # Check the other output files
7622 dtbs = {}
7623 for fname in dtb_list:
7624 pathname = tools.get_output_filename(fname)
7625 self.assertTrue(os.path.exists(pathname))
7626
7627 data = tools.read_file(pathname)
7628 self.assertEqual(xpl_data, data[:len(xpl_data)])
7629 rest = data[len(xpl_data):]
7630
7631 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7632 rest = rest[pad_len:]
7633
7634 dtb = fdt.Fdt.FromData(rest)
7635 dtb.Scan()
7636 dtbs[fname] = dtb
7637
7638 expected = 'one' if '1' in fname else 'two'
7639 self.assertEqual(f'u-boot,model-{expected}',
7640 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7641
7642 # Make sure the FDT is the same size as the 'main' one
7643 rest = rest[fdt_size:]
7644
7645 self.assertEqual(b'', rest)
7646 return dtbs
7647
7648 def testAlternatesFdt(self):
7649 """Test handling of alternates-fdt etype"""
7650 self._SetupTplElf()
7651 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7652 U_BOOT_TPL_NODTB_DATA)
7653 for dtb in dtbs.values():
7654 # Check for the node with the tag
7655 node = dtb.GetNode('/node')
7656 self.assertIsNotNone(node)
7657 self.assertEqual(5, len(node.props.keys()))
7658
7659 # Make sure the other node is still there
7660 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7661
7662 def testAlternatesFdtgrep(self):
7663 """Test handling of alternates-fdt etype using fdtgrep"""
7664 self._SetupTplElf()
7665 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7666 U_BOOT_TPL_NODTB_DATA)
7667 for dtb in dtbs.values():
7668 # Check for the node with the tag
7669 node = dtb.GetNode('/node')
7670 self.assertIsNotNone(node)
7671 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7672 node.props.keys())
7673
7674 # Make sure the other node is gone
7675 self.assertIsNone(dtb.GetNode('/node/other-node'))
7676
7677 def testAlternatesFdtgrepVpl(self):
7678 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7679 self._SetupVplElf()
7680 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7681 U_BOOT_VPL_NODTB_DATA)
7682
7683 def testAlternatesFdtgrepSpl(self):
7684 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7685 self._SetupSplElf()
7686 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7687 U_BOOT_SPL_NODTB_DATA)
7688
7689 def testAlternatesFdtgrepInval(self):
7690 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7691 self._SetupSplElf()
7692 with self.assertRaises(ValueError) as e:
7693 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7694 U_BOOT_SPL_NODTB_DATA)
7695 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7696 str(e.exception))
7697
Simon Glasscd2783e2024-07-20 11:49:46 +01007698 def testFitFdtListDir(self):
7699 """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
Simon Glass1bba8942024-08-26 13:11:34 -06007700 old_dir = os.getcwd()
7701 try:
7702 os.chdir(self._indir)
7703 self.CheckFitFdt('333_fit_fdt_dir.dts', False)
7704 finally:
7705 os.chdir(old_dir)
Simon Glasscd2783e2024-07-20 11:49:46 +01007706
Simon Glassd2a9d6e2024-08-26 13:11:37 -06007707 def testFitFdtListDirDefault(self):
7708 """Test an FIT fit,fdt-list-dir where the default DT in is a subdir"""
7709 old_dir = os.getcwd()
7710 try:
7711 os.chdir(self._indir)
7712 self.CheckFitFdt('333_fit_fdt_dir.dts', False,
7713 default_dt='rockchip/test-fdt2')
7714 finally:
7715 os.chdir(old_dir)
7716
Simon Glass5f7aadf2024-07-20 11:49:47 +01007717 def testFitFdtCompat(self):
7718 """Test an image with an FIT with compatible in the config nodes"""
7719 entry_args = {
7720 'of-list': 'model1 model2',
7721 'default-dt': 'model2',
7722 }
7723 testdir, dtb_list = self.SetupAlternateDts()
7724 data = self._DoReadFileDtb(
7725 '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
7726 entry_args=entry_args, extra_indirs=[testdir])[0]
7727
7728 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7729
7730 fit = fdt.Fdt.FromData(fit_data)
7731 fit.Scan()
7732
7733 cnode = fit.GetNode('/configurations')
7734 self.assertIn('default', cnode.props)
7735 self.assertEqual('config-2', cnode.props['default'].value)
7736
7737 for seq in range(1, 2):
7738 name = f'config-{seq}'
7739 fnode = fit.GetNode('/configurations/%s' % name)
7740 self.assertIsNotNone(fnode)
7741 self.assertIn('compatible', fnode.props.keys())
7742 expected = 'one' if seq == 1 else 'two'
7743 self.assertEqual(f'u-boot,model-{expected}',
7744 fnode.props['compatible'].value)
7745
Simon Glassa04b9942024-07-20 11:49:48 +01007746 def testFitFdtPhase(self):
7747 """Test an image with an FIT with fdt-phase in the fdt nodes"""
7748 phase = 'tpl'
7749 entry_args = {
7750 f'{phase}-dtb': '1',
7751 f'{phase}-bss-pad': 'y',
7752 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7753 'of-list': 'model1 model2',
7754 'default-dt': 'model2',
7755 }
7756 testdir, dtb_list = self.SetupAlternateDts()
7757 data = self._DoReadFileDtb(
7758 '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
7759 entry_args=entry_args, extra_indirs=[testdir])[0]
7760 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7761 fit = fdt.Fdt.FromData(fit_data)
7762 fit.Scan()
7763
7764 # Check that each FDT has only the expected properties for the phase
7765 for seq in range(1, 2):
7766 fnode = fit.GetNode(f'/images/fdt-{seq}')
7767 self.assertIsNotNone(fnode)
7768 dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
7769 dtb.Scan()
7770
7771 # Make sure that the 'bootph-pre-sram' tag in /node protects it from
7772 # removal
7773 node = dtb.GetNode('/node')
7774 self.assertIsNotNone(node)
7775 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7776 node.props.keys())
7777
7778 # Make sure the other node is gone
7779 self.assertIsNone(dtb.GetNode('/node/other-node'))
7780
Simon Glassb553e8a2024-08-26 13:11:29 -06007781 def testMkeficapsuleMissing(self):
7782 """Test that binman complains if mkeficapsule is missing"""
7783 with self.assertRaises(ValueError) as e:
7784 self._DoTestFile('311_capsule.dts',
7785 force_missing_bintools='mkeficapsule')
7786 self.assertIn("Node '/binman/efi-capsule': Missing tool: 'mkeficapsule'",
7787 str(e.exception))
7788
7789 def testMkeficapsuleMissingOk(self):
7790 """Test that binman deals with mkeficapsule being missing"""
7791 with test_util.capture_sys_output() as (stdout, stderr):
7792 ret = self._DoTestFile('311_capsule.dts',
7793 force_missing_bintools='mkeficapsule',
7794 allow_missing=True)
7795 self.assertEqual(103, ret)
7796 err = stderr.getvalue()
7797 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkeficapsule")
7798
Simon Glass4b0f4142024-08-26 13:11:40 -06007799 def testSymbolsBase(self):
7800 """Test handling of symbols-base"""
7801 self.checkSymbols('336_symbols_base.dts', U_BOOT_SPL_DATA, 0x1c,
7802 symbols_base=0)
7803
7804 def testSymbolsBaseExpanded(self):
7805 """Test handling of symbols-base with expanded entries"""
7806 entry_args = {
7807 'spl-dtb': '1',
7808 }
7809 self.checkSymbols('337_symbols_base_expand.dts', U_BOOT_SPL_NODTB_DATA +
7810 U_BOOT_SPL_DTB_DATA, 0x38,
7811 entry_args=entry_args, use_expanded=True,
7812 symbols_base=0)
7813
Simon Glass3eb30a42024-08-26 13:11:42 -06007814 def testSymbolsCompressed(self):
7815 """Test binman complains about symbols from a compressed section"""
7816 with test_util.capture_sys_output() as (stdout, stderr):
7817 self.checkSymbols('338_symbols_comp.dts', U_BOOT_SPL_DATA, None)
7818 out = stdout.getvalue()
7819 self.assertIn('Symbol-writing: no value for /binman/section/u-boot',
7820 out)
7821
Simon Glass9c25ef22024-08-26 13:11:43 -06007822 def testNxpImx8Image(self):
7823 """Test that binman can produce an iMX8 image"""
7824 self._DoTestFile('339_nxp_imx8.dts')
7825
Alexander Kochetkova730a282024-09-16 11:24:46 +03007826 def testFitSignSimple(self):
7827 """Test that image with FIT and signature nodes can be signed"""
7828 if not elf.ELF_TOOLS:
7829 self.skipTest('Python elftools not available')
7830 entry_args = {
7831 'of-list': 'test-fdt1',
7832 'default-dt': 'test-fdt1',
7833 'atf-bl31-path': 'bl31.elf',
7834 }
7835 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7836 self._MakeInputFile("keys/rsa2048.key", data)
7837
7838 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7839 keys_subdir = os.path.join(self._indir, "keys")
7840 data = self._DoReadFileDtb(
7841 '340_fit_signature.dts',
7842 entry_args=entry_args,
7843 extra_indirs=[test_subdir, keys_subdir])[0]
7844
7845 dtb = fdt.Fdt.FromData(data)
7846 dtb.Scan()
7847
7848 conf = dtb.GetNode('/configurations/conf-uboot-1')
7849 self.assertIsNotNone(conf)
7850 signature = conf.FindNode('signature')
7851 self.assertIsNotNone(signature)
7852 self.assertIsNotNone(signature.props.get('value'))
7853
7854 images = dtb.GetNode('/images')
7855 self.assertIsNotNone(images)
7856 for subnode in images.subnodes:
7857 signature = subnode.FindNode('signature')
7858 self.assertIsNotNone(signature)
7859 self.assertIsNotNone(signature.props.get('value'))
7860
7861 def testFitSignKeyNotFound(self):
7862 """Test that missing keys raise an error"""
7863 if not elf.ELF_TOOLS:
7864 self.skipTest('Python elftools not available')
7865 entry_args = {
7866 'of-list': 'test-fdt1',
7867 'default-dt': 'test-fdt1',
7868 'atf-bl31-path': 'bl31.elf',
7869 }
7870 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7871 with self.assertRaises(ValueError) as e:
7872 self._DoReadFileDtb(
7873 '340_fit_signature.dts',
7874 entry_args=entry_args,
7875 extra_indirs=[test_subdir])[0]
7876 self.assertIn(
7877 'Filename \'rsa2048.key\' not found in input path',
7878 str(e.exception))
7879
7880 def testFitSignMultipleKeyPaths(self):
7881 """Test that keys found in multiple paths raise an error"""
7882 if not elf.ELF_TOOLS:
7883 self.skipTest('Python elftools not available')
7884 entry_args = {
7885 'of-list': 'test-fdt1',
7886 'default-dt': 'test-fdt1',
7887 'atf-bl31-path': 'bl31.elf',
7888 }
7889 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7890 self._MakeInputFile("keys1/rsa2048.key", data)
7891 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7892 self._MakeInputFile("keys2/conf-rsa2048.key", data)
7893
7894 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7895 keys_subdir1 = os.path.join(self._indir, "keys1")
7896 keys_subdir2 = os.path.join(self._indir, "keys2")
7897 with self.assertRaises(ValueError) as e:
7898 self._DoReadFileDtb(
7899 '341_fit_signature.dts',
7900 entry_args=entry_args,
7901 extra_indirs=[test_subdir, keys_subdir1, keys_subdir2])[0]
7902 self.assertIn(
7903 'Node \'/binman/fit\': multiple key paths found',
7904 str(e.exception))
7905
7906 def testFitSignNoSingatureNodes(self):
7907 """Test that fit,sign doens't raise error if no signature nodes found"""
7908 if not elf.ELF_TOOLS:
7909 self.skipTest('Python elftools not available')
7910 entry_args = {
7911 'of-list': 'test-fdt1',
7912 'default-dt': 'test-fdt1',
7913 'atf-bl31-path': 'bl31.elf',
7914 }
7915 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7916 self._DoReadFileDtb(
7917 '342_fit_signature.dts',
7918 entry_args=entry_args,
7919 extra_indirs=[test_subdir])[0]
7920
Simon Glassa360b8f2024-06-23 11:55:06 -06007921
Paul HENRYSff318462024-11-25 18:47:17 +01007922 def testSimpleFitEncryptedData(self):
7923 """Test an image with a FIT containing data to be encrypted"""
7924 data = tools.read_file(self.TestFile("aes256.bin"))
7925 self._MakeInputFile("keys/aes256.bin", data)
7926
7927 keys_subdir = os.path.join(self._indir, "keys")
7928 data = self._DoReadFileDtb(
7929 '343_fit_encrypt_data.dts',
7930 extra_indirs=[keys_subdir])[0]
7931
7932 fit = fdt.Fdt.FromData(data)
7933 fit.Scan()
7934
7935 # Extract the encrypted data and the Initialization Vector from the FIT
7936 node = fit.GetNode('/images/u-boot')
7937 subnode = fit.GetNode('/images/u-boot/cipher')
7938 data_size_unciphered = int.from_bytes(fit.GetProps(node)['data-size-unciphered'].bytes,
7939 byteorder='big')
7940 self.assertEqual(data_size_unciphered, len(U_BOOT_NODTB_DATA))
7941
7942 # Retrieve the key name from the FIT removing any null byte
7943 key_name = fit.GetProps(subnode)['key-name-hint'].bytes.replace(b'\x00', b'')
7944 with open(self.TestFile(key_name.decode('ascii') + '.bin'), 'rb') as file:
7945 key = file.read()
7946 iv = fit.GetProps(subnode)['iv'].bytes.hex()
7947 enc_data = fit.GetProps(node)['data'].bytes
7948 outdir = tools.get_output_dir()
7949 enc_data_file = os.path.join(outdir, 'encrypted_data.bin')
7950 tools.write_file(enc_data_file, enc_data)
7951 data_file = os.path.join(outdir, 'data.bin')
7952
7953 # Decrypt the encrypted data from the FIT and compare the data
7954 tools.run('openssl', 'enc', '-aes-256-cbc', '-nosalt', '-d', '-in',
7955 enc_data_file, '-out', data_file, '-K', key.hex(), '-iv', iv)
7956 with open(data_file, 'r') as file:
7957 dec_data = file.read()
7958 self.assertEqual(U_BOOT_NODTB_DATA, dec_data.encode('ascii'))
7959
7960 def testSimpleFitEncryptedDataMissingKey(self):
7961 """Test an image with a FIT containing data to be encrypted but with a missing key"""
7962 with self.assertRaises(ValueError) as e:
7963 self._DoReadFile('344_fit_encrypt_data_no_key.dts')
7964
7965 self.assertIn("Filename 'aes256.bin' not found in input path", str(e.exception))
7966
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01007967 def testFitFdtName(self):
7968 """Test an image with an FIT with multiple FDT images using NAME"""
7969 self.CheckFitFdt('345_fit_fdt_name.dts', use_seq_num=False)
7970
Simon Glassac599912017-11-12 21:52:22 -07007971if __name__ == "__main__":
7972 unittest.main()