blob: 7b4454bd342f40a095eb654522ed3983f2dda59a [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,
508 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600509 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700510 """Run binman and return the resulting image
511
512 This runs binman with a given test file and then reads the resulting
513 output file. It is a shortcut function since most tests need to do
514 these steps.
515
516 Raises an assertion failure if binman returns a non-zero exit code.
517
518 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600519 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700520 use_real_dtb: True to use the test file as the contents of
521 the u-boot-dtb entry. Normally this is not needed and the
522 test contents (the U_BOOT_DTB_DATA string) can be used.
523 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300524 use_expanded: True to use expanded entries where available, e.g.
525 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600526 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600527 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600528 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600529 entry_args: Dict of entry args to supply to binman
530 key: arg name
531 value: value of that arg
532 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
533 function. If reset_dtbs is True, then the original test dtb
534 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600535 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600536 threads: Number of threads to use (None for default, 0 for
537 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700538
539 Returns:
540 Tuple:
541 Resulting image contents
542 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600543 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600544 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700545 """
Simon Glass72232452016-11-25 20:15:53 -0700546 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700547 # Use the compiled test file as the u-boot-dtb input
548 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700549 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600550
551 # For testing purposes, make a copy of the DT for SPL and TPL. Add
Simon Glassd9e01d22024-07-20 11:49:40 +0100552 # a node indicating which it is, to aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700553 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600554 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
555 outfile = os.path.join(self._indir, dtb_fname)
556 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700557 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700558
559 try:
Simon Glass91710b32018-07-17 13:25:32 -0600560 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600561 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600562 use_expanded=use_expanded, extra_indirs=extra_indirs,
563 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700564 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700565 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700566
567 # Find the (only) image, read it and return its contents
568 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700569 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600570 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600571 if map:
Simon Glass80025522022-01-29 14:14:04 -0700572 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600573 with open(map_fname) as fd:
574 map_data = fd.read()
575 else:
576 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600577 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600578 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700579 finally:
580 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600581 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600582 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700583
Simon Glass5b4bce32019-07-08 14:25:26 -0600584 def _DoReadFileRealDtb(self, fname):
585 """Run binman with a real .dtb file and return the resulting data
586
587 Args:
588 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
589
590 Returns:
591 Resulting image contents
592 """
593 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
594
Simon Glass72232452016-11-25 20:15:53 -0700595 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600596 """Helper function which discards the device-tree binary
597
598 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600599 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600600 use_real_dtb: True to use the test file as the contents of
601 the u-boot-dtb entry. Normally this is not needed and the
602 test contents (the U_BOOT_DTB_DATA string) can be used.
603 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600604
605 Returns:
606 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600607 """
Simon Glass72232452016-11-25 20:15:53 -0700608 return self._DoReadFileDtb(fname, use_real_dtb)[0]
609
Simon Glass57454f42016-11-25 20:15:52 -0700610 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600611 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700612 """Create a new test input file, creating directories as needed
613
614 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600615 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700616 contents: File contents to write in to the file
617 Returns:
618 Full pathname of file created
619 """
Simon Glass862f8e22019-08-24 07:22:43 -0600620 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700621 dirname = os.path.dirname(pathname)
622 if dirname and not os.path.exists(dirname):
623 os.makedirs(dirname)
624 with open(pathname, 'wb') as fd:
625 fd.write(contents)
626 return pathname
627
628 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600629 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600630 """Create a new test input directory, creating directories as needed
631
632 Args:
633 dirname: Directory name to create
634
635 Returns:
636 Full pathname of directory created
637 """
Simon Glass862f8e22019-08-24 07:22:43 -0600638 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600639 if not os.path.exists(pathname):
640 os.makedirs(pathname)
641 return pathname
642
643 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600644 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600645 """Set up an ELF file with a '_dt_ucode_base_size' symbol
646
647 Args:
648 Filename of ELF file to use as SPL
649 """
Simon Glass93a806f2019-08-24 07:22:59 -0600650 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700651 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600652
653 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600654 def _SetupTplElf(cls, src_fname='bss_data'):
655 """Set up an ELF file with a '_dt_ucode_base_size' symbol
656
657 Args:
658 Filename of ELF file to use as TPL
659 """
660 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700661 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600662
663 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700664 def _SetupVplElf(cls, src_fname='bss_data'):
665 """Set up an ELF file with a '_dt_ucode_base_size' symbol
666
667 Args:
668 Filename of ELF file to use as VPL
669 """
670 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
671 tools.read_file(cls.ElfTestFile(src_fname)))
672
673 @classmethod
Lukas Funkee901faf2023-07-18 13:53:13 +0200674 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
675 """Set up an ELF file with a '_dt_ucode_base_size' symbol
676
677 Args:
678 Filename of ELF file to use as VPL
679 """
680 TestFunctional._MakeInputFile('pmu-firmware.elf',
681 tools.read_file(cls.ElfTestFile(src_fname)))
682
683 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600684 def _SetupDescriptor(cls):
685 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
686 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
687
688 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600689 def TestFile(cls, fname):
690 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700691
Simon Glassf6290892019-08-24 07:22:53 -0600692 @classmethod
693 def ElfTestFile(cls, fname):
694 return os.path.join(cls._elf_testdir, fname)
695
Simon Glassad5cfe12023-01-07 14:07:14 -0700696 @classmethod
697 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
698 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
699 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
700 dummy, paged_sz) + U_BOOT_DATA
701 data += extra_data
702 TestFunctional._MakeInputFile(fname, data)
703
Simon Glass57454f42016-11-25 20:15:52 -0700704 def AssertInList(self, grep_list, target):
705 """Assert that at least one of a list of things is in a target
706
707 Args:
708 grep_list: List of strings to check
709 target: Target string
710 """
711 for grep in grep_list:
712 if grep in target:
713 return
Simon Glass848cdb52019-05-17 22:00:50 -0600714 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700715
716 def CheckNoGaps(self, entries):
717 """Check that all entries fit together without gaps
718
719 Args:
720 entries: List of entries to check
721 """
Simon Glasse8561af2018-08-01 15:22:37 -0600722 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700723 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600724 self.assertEqual(offset, entry.offset)
725 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700726
Simon Glass72232452016-11-25 20:15:53 -0700727 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600728 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700729
730 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600731 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700732
733 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600734 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700735 """
736 return struct.unpack('>L', dtb[4:8])[0]
737
Simon Glass0f621332019-07-08 14:25:27 -0600738 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600739 def AddNode(node, path):
740 if node.name != '/':
741 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600742 for prop in node.props.values():
743 if prop.name in prop_names:
744 prop_path = path + ':' + prop.name
745 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
746 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600747 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600748 AddNode(subnode, path)
749
750 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600751 AddNode(dtb.GetRoot(), '')
752 return tree
753
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000754 def _CheckSign(self, fit, key):
755 try:
756 tools.run('fit_check_sign', '-k', key, '-f', fit)
757 except:
758 self.fail('Expected signed FIT container')
759 return False
760 return True
761
Simon Glass57454f42016-11-25 20:15:52 -0700762 def testRun(self):
763 """Test a basic run with valid args"""
764 result = self._RunBinman('-h')
765
766 def testFullHelp(self):
767 """Test that the full help is displayed with -H"""
768 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300769 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500770 # Remove possible extraneous strings
771 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
772 gothelp = result.stdout.replace(extra, '')
773 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700774 self.assertEqual(0, len(result.stderr))
775 self.assertEqual(0, result.return_code)
776
777 def testFullHelpInternal(self):
778 """Test that the full help is displayed with -H"""
779 try:
780 command.test_result = command.CommandResult()
781 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300782 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700783 finally:
784 command.test_result = None
785
786 def testHelp(self):
787 """Test that the basic help is displayed with -h"""
788 result = self._RunBinman('-h')
789 self.assertTrue(len(result.stdout) > 200)
790 self.assertEqual(0, len(result.stderr))
791 self.assertEqual(0, result.return_code)
792
Simon Glass57454f42016-11-25 20:15:52 -0700793 def testBoard(self):
794 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600795 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700796 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300797 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700798 self.assertEqual(0, result)
799
800 def testNeedBoard(self):
801 """Test that we get an error when no board ius supplied"""
802 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600803 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700804 self.assertIn("Must provide a board to process (use -b <board>)",
805 str(e.exception))
806
807 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600808 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700809 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600810 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700811 # We get one error from libfdt, and a different one from fdtget.
812 self.AssertInList(["Couldn't open blob from 'missing_file'",
813 'No such file or directory'], str(e.exception))
814
815 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600816 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700817
818 Since this is a source file it should be compiled and the error
819 will come from the device-tree compiler (dtc).
820 """
821 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600822 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700823 self.assertIn("FATAL ERROR: Unable to parse input tree",
824 str(e.exception))
825
826 def testMissingNode(self):
827 """Test that a device tree without a 'binman' node generates an error"""
828 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600829 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700830 self.assertIn("does not have a 'binman' node", str(e.exception))
831
832 def testEmpty(self):
833 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600834 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700835 self.assertEqual(0, len(result.stderr))
836 self.assertEqual(0, result.return_code)
837
838 def testInvalidEntry(self):
839 """Test that an invalid entry is flagged"""
840 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600841 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600842 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700843 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
844 "'/binman/not-a-valid-type'", str(e.exception))
845
846 def testSimple(self):
847 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600848 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700849 self.assertEqual(U_BOOT_DATA, data)
850
Simon Glass075a45c2017-11-13 18:55:00 -0700851 def testSimpleDebug(self):
852 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600853 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700854
Simon Glass57454f42016-11-25 20:15:52 -0700855 def testDual(self):
856 """Test that we can handle creating two images
857
858 This also tests image padding.
859 """
Simon Glass511f6582018-10-01 12:22:30 -0600860 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700861 self.assertEqual(0, retcode)
862
863 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600864 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700865 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700866 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600867 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700868 data = fd.read()
869 self.assertEqual(U_BOOT_DATA, data)
870
871 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600872 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700873 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700874 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600875 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700876 data = fd.read()
877 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700878 self.assertEqual(tools.get_bytes(0, 3), data[:3])
879 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700880
881 def testBadAlign(self):
882 """Test that an invalid alignment value is detected"""
883 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600884 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700885 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
886 "of two", str(e.exception))
887
888 def testPackSimple(self):
889 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600890 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700891 self.assertEqual(0, retcode)
892 self.assertIn('image', control.images)
893 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600894 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700895 self.assertEqual(5, len(entries))
896
897 # First u-boot
898 self.assertIn('u-boot', entries)
899 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600900 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700901 self.assertEqual(len(U_BOOT_DATA), entry.size)
902
903 # Second u-boot, aligned to 16-byte boundary
904 self.assertIn('u-boot-align', entries)
905 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600906 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700907 self.assertEqual(len(U_BOOT_DATA), entry.size)
908
909 # Third u-boot, size 23 bytes
910 self.assertIn('u-boot-size', entries)
911 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600912 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700913 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
914 self.assertEqual(23, entry.size)
915
916 # Fourth u-boot, placed immediate after the above
917 self.assertIn('u-boot-next', entries)
918 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600919 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700920 self.assertEqual(len(U_BOOT_DATA), entry.size)
921
Simon Glasse8561af2018-08-01 15:22:37 -0600922 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700923 self.assertIn('u-boot-fixed', entries)
924 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600925 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700926 self.assertEqual(len(U_BOOT_DATA), entry.size)
927
Simon Glass39dd2152019-07-08 14:25:47 -0600928 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700929
930 def testPackExtra(self):
931 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600932 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
933 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700934
Simon Glass57454f42016-11-25 20:15:52 -0700935 self.assertIn('image', control.images)
936 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600937 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600938 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700939
Samuel Hollande2574022023-01-21 17:25:16 -0600940 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700941 self.assertIn('u-boot', entries)
942 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600943 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700944 self.assertEqual(3, entry.pad_before)
945 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600946 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700947 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
948 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600949 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700950
951 # Second u-boot has an aligned size, but it has no effect
952 self.assertIn('u-boot-align-size-nop', entries)
953 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600954 self.assertEqual(pos, entry.offset)
955 self.assertEqual(len(U_BOOT_DATA), entry.size)
956 self.assertEqual(U_BOOT_DATA, entry.data)
957 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
958 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700959
960 # Third u-boot has an aligned size too
961 self.assertIn('u-boot-align-size', entries)
962 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600963 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700964 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600965 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700966 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600967 data[pos:pos + entry.size])
968 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700969
970 # Fourth u-boot has an aligned end
971 self.assertIn('u-boot-align-end', entries)
972 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600973 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700974 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600975 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700976 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600977 data[pos:pos + entry.size])
978 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700979
980 # Fifth u-boot immediately afterwards
981 self.assertIn('u-boot-align-both', entries)
982 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600983 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700984 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600985 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700986 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600987 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700988
Samuel Hollande2574022023-01-21 17:25:16 -0600989 # Sixth u-boot with both minimum size and aligned size
990 self.assertIn('u-boot-min-size', entries)
991 entry = entries['u-boot-min-size']
992 self.assertEqual(128, entry.offset)
993 self.assertEqual(32, entry.size)
994 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
995 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
996 data[pos:pos + entry.size])
997
Simon Glass57454f42016-11-25 20:15:52 -0700998 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -0600999 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001000
Simon Glassafb9caa2020-10-26 17:40:10 -06001001 dtb = fdt.Fdt(out_dtb_fname)
1002 dtb.Scan()
1003 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
1004 expected = {
1005 'image-pos': 0,
1006 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -06001007 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -06001008
1009 'u-boot:image-pos': 0,
1010 'u-boot:offset': 0,
1011 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1012
1013 'u-boot-align-size-nop:image-pos': 12,
1014 'u-boot-align-size-nop:offset': 12,
1015 'u-boot-align-size-nop:size': 4,
1016
1017 'u-boot-align-size:image-pos': 16,
1018 'u-boot-align-size:offset': 16,
1019 'u-boot-align-size:size': 32,
1020
1021 'u-boot-align-end:image-pos': 48,
1022 'u-boot-align-end:offset': 48,
1023 'u-boot-align-end:size': 16,
1024
1025 'u-boot-align-both:image-pos': 64,
1026 'u-boot-align-both:offset': 64,
1027 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -06001028
1029 'u-boot-min-size:image-pos': 128,
1030 'u-boot-min-size:offset': 128,
1031 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -06001032 }
1033 self.assertEqual(expected, props)
1034
Simon Glass57454f42016-11-25 20:15:52 -07001035 def testPackAlignPowerOf2(self):
1036 """Test that invalid entry alignment is detected"""
1037 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001038 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001039 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1040 "of two", str(e.exception))
1041
1042 def testPackAlignSizePowerOf2(self):
1043 """Test that invalid entry size alignment is detected"""
1044 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001045 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001046 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1047 "power of two", str(e.exception))
1048
1049 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001050 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001051 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001052 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001053 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001054 "align 0x4 (4)", str(e.exception))
1055
1056 def testPackInvalidSizeAlign(self):
1057 """Test that invalid entry size alignment is detected"""
1058 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001059 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001060 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1061 "align-size 0x4 (4)", str(e.exception))
1062
1063 def testPackOverlap(self):
1064 """Test that overlapping regions are detected"""
1065 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001066 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001067 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001068 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1069 str(e.exception))
1070
1071 def testPackEntryOverflow(self):
1072 """Test that entries that overflow their size are detected"""
1073 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001074 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001075 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1076 "but entry size is 0x3 (3)", str(e.exception))
1077
1078 def testPackImageOverflow(self):
1079 """Test that entries which overflow the image size are detected"""
1080 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001081 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001082 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001083 "size 0x3 (3)", str(e.exception))
1084
1085 def testPackImageSize(self):
1086 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001087 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001088 self.assertEqual(0, retcode)
1089 self.assertIn('image', control.images)
1090 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001091 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001092
1093 def testPackImageSizeAlign(self):
1094 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001095 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001096 self.assertEqual(0, retcode)
1097 self.assertIn('image', control.images)
1098 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001099 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001100
1101 def testPackInvalidImageAlign(self):
1102 """Test that invalid image alignment is detected"""
1103 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001104 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001105 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001106 "align-size 0x8 (8)", str(e.exception))
1107
Simon Glass2a0fa982022-02-11 13:23:21 -07001108 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001109 """Test that invalid image alignment is detected"""
1110 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001111 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001112 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001113 "two", str(e.exception))
1114
1115 def testImagePadByte(self):
1116 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001117 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001118 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001119 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001120 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001121
1122 def testImageName(self):
1123 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001124 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001125 self.assertEqual(0, retcode)
1126 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001127 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001128 self.assertTrue(os.path.exists(fname))
1129
1130 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001131 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001132 self.assertTrue(os.path.exists(fname))
1133
1134 def testBlobFilename(self):
1135 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001136 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001137 self.assertEqual(BLOB_DATA, data)
1138
1139 def testPackSorted(self):
1140 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001141 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001142 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001143 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1144 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001145
Simon Glasse8561af2018-08-01 15:22:37 -06001146 def testPackZeroOffset(self):
1147 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001148 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001149 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001150 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001151 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001152 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1153 str(e.exception))
1154
1155 def testPackUbootDtb(self):
1156 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001157 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001158 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001159
1160 def testPackX86RomNoSize(self):
1161 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001162 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001163 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001164 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001165 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001166 "using end-at-4gb", str(e.exception))
1167
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301168 def test4gbAndSkipAtStartTogether(self):
1169 """Test that the end-at-4gb and skip-at-size property can't be used
1170 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001171 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301172 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001173 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001174 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301175 "'skip-at-start'", str(e.exception))
1176
Simon Glass72232452016-11-25 20:15:53 -07001177 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001178 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001179 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001180 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001181 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001182 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1183 "is outside the section '/binman' starting at "
1184 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001185 str(e.exception))
1186
1187 def testPackX86Rom(self):
1188 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001189 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001190 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001191 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1192 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001193
1194 def testPackX86RomMeNoDesc(self):
1195 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001196 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001197 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001198 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001199 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001200 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1201 str(e.exception))
1202 finally:
1203 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001204
1205 def testPackX86RomBadDesc(self):
1206 """Test that the Intel requires a descriptor entry"""
1207 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001208 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001209 self.assertIn("Node '/binman/intel-me': No offset set with "
1210 "offset-unset: should another entry provide this correct "
1211 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001212
1213 def testPackX86RomMe(self):
1214 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001215 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001216 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001217 if data[:0x1000] != expected_desc:
1218 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001219 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1220
1221 def testPackVga(self):
1222 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001223 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001224 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1225
1226 def testPackStart16(self):
1227 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001228 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001229 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1230
Jagdish Gediya311d4842018-09-03 21:35:08 +05301231 def testPackPowerpcMpc85xxBootpgResetvec(self):
1232 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1233 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001234 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301235 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1236
Simon Glass6ba679c2018-07-06 10:27:17 -06001237 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001238 """Handle running a test for insertion of microcode
1239
1240 Args:
1241 dts_fname: Name of test .dts file
1242 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001243 ucode_second: True if the microsecond entry is second instead of
1244 third
Simon Glass820af1d2018-07-06 10:27:16 -06001245
1246 Returns:
1247 Tuple:
1248 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001249 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001250 in the above (two 4-byte words)
1251 """
Simon Glass3d274232017-11-12 21:52:27 -07001252 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001253
1254 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001255 if ucode_second:
1256 ucode_content = data[len(nodtb_data):]
1257 ucode_pos = len(nodtb_data)
1258 dtb_with_ucode = ucode_content[16:]
1259 fdt_len = self.GetFdtLen(dtb_with_ucode)
1260 else:
1261 dtb_with_ucode = data[len(nodtb_data):]
1262 fdt_len = self.GetFdtLen(dtb_with_ucode)
1263 ucode_content = dtb_with_ucode[fdt_len:]
1264 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001265 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001266 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001267 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001268 dtb = fdt.FdtScan(fname)
1269 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001270 self.assertTrue(ucode)
1271 for node in ucode.subnodes:
1272 self.assertFalse(node.props.get('data'))
1273
Simon Glass72232452016-11-25 20:15:53 -07001274 # Check that the microcode appears immediately after the Fdt
1275 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001276 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001277 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1278 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001279 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001280
1281 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001282 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001283 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1284 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001285 u_boot = data[:len(nodtb_data)]
1286 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001287
1288 def testPackUbootMicrocode(self):
1289 """Test that x86 microcode can be handled correctly
1290
1291 We expect to see the following in the image, in order:
1292 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1293 place
1294 u-boot.dtb with the microcode removed
1295 the microcode
1296 """
Simon Glass511f6582018-10-01 12:22:30 -06001297 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001298 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001299 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1300 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001301
Simon Glassbac25c82017-05-27 07:38:26 -06001302 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001303 """Test that x86 microcode can be handled correctly
1304
1305 We expect to see the following in the image, in order:
1306 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1307 place
1308 u-boot.dtb with the microcode
1309 an empty microcode region
1310 """
1311 # We need the libfdt library to run this test since only that allows
1312 # finding the offset of a property. This is required by
1313 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001314 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001315
1316 second = data[len(U_BOOT_NODTB_DATA):]
1317
1318 fdt_len = self.GetFdtLen(second)
1319 third = second[fdt_len:]
1320 second = second[:fdt_len]
1321
Simon Glassbac25c82017-05-27 07:38:26 -06001322 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1323 self.assertIn(ucode_data, second)
1324 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001325
Simon Glassbac25c82017-05-27 07:38:26 -06001326 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001327 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001328 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1329 len(ucode_data))
1330 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001331 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1332 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001333
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001334 def testPackUbootSingleMicrocode(self):
1335 """Test that x86 microcode can be handled correctly with fdt_normal.
1336 """
Simon Glassbac25c82017-05-27 07:38:26 -06001337 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001338
Simon Glass996021e2016-11-25 20:15:54 -07001339 def testUBootImg(self):
1340 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001341 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001342 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001343
1344 def testNoMicrocode(self):
1345 """Test that a missing microcode region is detected"""
1346 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001347 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001348 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1349 "node found in ", str(e.exception))
1350
1351 def testMicrocodeWithoutNode(self):
1352 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1353 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001354 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001355 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1356 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1357
1358 def testMicrocodeWithoutNode2(self):
1359 """Test that a missing u-boot-ucode node is detected"""
1360 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001361 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001362 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1363 "microcode region u-boot-ucode", str(e.exception))
1364
1365 def testMicrocodeWithoutPtrInElf(self):
1366 """Test that a U-Boot binary without the microcode symbol is detected"""
1367 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001368 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001369 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001370 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001371
1372 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001373 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001374 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1375 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1376
1377 finally:
1378 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001379 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001380 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001381
1382 def testMicrocodeNotInImage(self):
1383 """Test that microcode must be placed within the image"""
1384 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001385 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001386 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1387 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001388 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001389
1390 def testWithoutMicrocode(self):
1391 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001392 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001393 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001394 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001395
1396 # Now check the device tree has no microcode
1397 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1398 second = data[len(U_BOOT_NODTB_DATA):]
1399
1400 fdt_len = self.GetFdtLen(second)
1401 self.assertEqual(dtb, second[:fdt_len])
1402
1403 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1404 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001405 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001406
1407 def testUnknownPosSize(self):
1408 """Test that microcode must be placed within the image"""
1409 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001410 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001411 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001412 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001413
1414 def testPackFsp(self):
1415 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001416 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001417 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1418
1419 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001420 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001421 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001422 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001423
1424 def testPackVbt(self):
1425 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001426 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001427 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001428
Simon Glass7f94e832017-11-12 21:52:25 -07001429 def testSplBssPad(self):
1430 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001431 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001432 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001433 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001434 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001435 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001436
Simon Glass04cda032018-10-01 21:12:42 -06001437 def testSplBssPadMissing(self):
1438 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001439 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001440 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001441 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001442 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1443 str(e.exception))
1444
Simon Glasse83679d2017-11-12 21:52:26 -07001445 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001446 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001447 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001448 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1449
Simon Glass6ba679c2018-07-06 10:27:17 -06001450 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1451 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001452
1453 We expect to see the following in the image, in order:
1454 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1455 correct place
1456 u-boot.dtb with the microcode removed
1457 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001458
1459 Args:
1460 dts: Device tree file to use for test
1461 ucode_second: True if the microsecond entry is second instead of
1462 third
Simon Glass3d274232017-11-12 21:52:27 -07001463 """
Simon Glass7057d022018-10-01 21:12:47 -06001464 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001465 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1466 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001467 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1468 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001469
Simon Glass6ba679c2018-07-06 10:27:17 -06001470 def testPackUbootSplMicrocode(self):
1471 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001472 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001473 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001474
1475 def testPackUbootSplMicrocodeReorder(self):
1476 """Test that order doesn't matter for microcode entries
1477
1478 This is the same as testPackUbootSplMicrocode but when we process the
1479 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1480 entry, so we reply on binman to try later.
1481 """
Simon Glass511f6582018-10-01 12:22:30 -06001482 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001483 ucode_second=True)
1484
Simon Glassa409c932017-11-12 21:52:28 -07001485 def testPackMrc(self):
1486 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001487 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001488 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1489
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001490 def testSplDtb(self):
1491 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001492 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001493 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001494 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1495
Simon Glass0a6da312017-11-13 18:54:56 -07001496 def testSplNoDtb(self):
1497 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001498 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001499 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001500 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1501
Simon Glass7098b7f2021-03-21 18:24:30 +13001502 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4abf7842023-07-18 07:23:54 -06001503 use_expanded=False, no_write_symbols=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001504 """Check the image contains the expected symbol values
1505
1506 Args:
1507 dts: Device tree file to use for test
1508 base_data: Data before and after 'u-boot' section
1509 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001510 entry_args: Dict of entry args to supply to binman
1511 key: arg name
1512 value: value of that arg
1513 use_expanded: True to use expanded entries where available, e.g.
1514 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001515 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001516 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001517 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1518 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001519 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001520 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001521 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001522
Simon Glass7057d022018-10-01 21:12:47 -06001523 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001524 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1525 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001526 # The image should contain the symbols from u_boot_binman_syms.c
1527 # Note that image_pos is adjusted by the base address of the image,
1528 # which is 0x10 in our test image
Simon Glass4b4049e2024-08-26 13:11:39 -06001529 vals = (elf.BINMAN_SYM_MAGIC_VALUE, 0x00,
1530 u_boot_offset + len(U_BOOT_DATA),
1531 0x10 + u_boot_offset, 0x04)
1532 sym_values = struct.pack('<LLQLL', *vals)
Simon Glass4abf7842023-07-18 07:23:54 -06001533 if no_write_symbols:
Simon Glass4b4049e2024-08-26 13:11:39 -06001534 self.assertEqual(
1535 base_data +
1536 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1537 U_BOOT_DATA + base_data, data)
Simon Glass4abf7842023-07-18 07:23:54 -06001538 else:
Simon Glass4b4049e2024-08-26 13:11:39 -06001539 got_vals = struct.unpack('<LLQLL', data[:24])
1540
1541 # For debugging:
1542 #print('expect:', list(f'{v:x}' for v in vals))
1543 #print(' got:', list(f'{v:x}' for v in got_vals))
1544
1545 self.assertEqual(vals, got_vals)
1546 self.assertEqual(sym_values, data[:24])
1547
1548 blen = len(base_data)
1549 self.assertEqual(base_data[24:], data[24:blen])
1550 self.assertEqual(0xff, data[blen])
1551
1552 ofs = blen + 1 + len(U_BOOT_DATA)
1553 self.assertEqual(U_BOOT_DATA, data[blen + 1:ofs])
1554
1555 self.assertEqual(sym_values, data[ofs:ofs + 24])
1556 self.assertEqual(base_data[24:], data[ofs + 24:])
1557
1558 # Just repeating the above asserts all at once, for clarity
Simon Glass4abf7842023-07-18 07:23:54 -06001559 expected = (sym_values + base_data[24:] +
1560 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1561 base_data[24:])
Simon Glass4b4049e2024-08-26 13:11:39 -06001562 self.assertEqual(expected, data)
Simon Glass4ca8e042017-11-13 18:55:01 -07001563
Simon Glass31e04cb2021-03-18 20:24:56 +13001564 def testSymbols(self):
1565 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001566 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001567
1568 def testSymbolsNoDtb(self):
1569 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001570 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001571 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1572 0x38)
1573
Simon Glasse76a3e62018-06-01 09:38:11 -06001574 def testPackUnitAddress(self):
1575 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001576 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001577 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1578
Simon Glassa91e1152018-06-01 09:38:16 -06001579 def testSections(self):
1580 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001581 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001582 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1583 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1584 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001585 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001586
Simon Glass30732662018-06-01 09:38:20 -06001587 def testMap(self):
1588 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001589 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001590 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700159100000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600159200000000 00000000 00000010 section@0
159300000000 00000000 00000004 u-boot
159400000010 00000010 00000010 section@1
159500000010 00000000 00000004 u-boot
159600000020 00000020 00000004 section@2
159700000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001598''', map_data)
1599
Simon Glass3b78d532018-06-01 09:38:21 -06001600 def testNamePrefix(self):
1601 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001602 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001603 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700160400000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600160500000000 00000000 00000010 section@0
160600000000 00000000 00000004 ro-u-boot
160700000010 00000010 00000010 section@1
160800000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001609''', map_data)
1610
Simon Glass6ba679c2018-07-06 10:27:17 -06001611 def testUnknownContents(self):
1612 """Test that obtaining the contents works as expected"""
1613 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001614 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001615 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001616 "processing of contents: remaining ["
1617 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001618
Simon Glass2e1169f2018-07-06 10:27:19 -06001619 def testBadChangeSize(self):
1620 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001621 try:
1622 state.SetAllowEntryExpansion(False)
1623 with self.assertRaises(ValueError) as e:
1624 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001625 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001626 str(e.exception))
1627 finally:
1628 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001629
Simon Glassa87014e2018-07-06 10:27:42 -06001630 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001631 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001632 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001633 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001634 dtb = fdt.Fdt(out_dtb_fname)
1635 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001636 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001637 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001638 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001639 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001640 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001641 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001642 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001643 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001644 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001645 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001646 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001647 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001648 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001649
Simon Glasse8561af2018-08-01 15:22:37 -06001650 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001651 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001652 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001653 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001654 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001655 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001656 'size': 40
1657 }, props)
1658
1659 def testUpdateFdtBad(self):
1660 """Test that we detect when ProcessFdt never completes"""
1661 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001662 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001663 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001664 '[<binman.etype._testing.Entry__testing',
1665 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001666
Simon Glass91710b32018-07-17 13:25:32 -06001667 def testEntryArgs(self):
1668 """Test passing arguments to entries from the command line"""
1669 entry_args = {
1670 'test-str-arg': 'test1',
1671 'test-int-arg': '456',
1672 }
Simon Glass511f6582018-10-01 12:22:30 -06001673 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001674 self.assertIn('image', control.images)
1675 entry = control.images['image'].GetEntries()['_testing']
1676 self.assertEqual('test0', entry.test_str_fdt)
1677 self.assertEqual('test1', entry.test_str_arg)
1678 self.assertEqual(123, entry.test_int_fdt)
1679 self.assertEqual(456, entry.test_int_arg)
1680
1681 def testEntryArgsMissing(self):
1682 """Test missing arguments and properties"""
1683 entry_args = {
1684 'test-int-arg': '456',
1685 }
Simon Glass511f6582018-10-01 12:22:30 -06001686 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001687 entry = control.images['image'].GetEntries()['_testing']
1688 self.assertEqual('test0', entry.test_str_fdt)
1689 self.assertEqual(None, entry.test_str_arg)
1690 self.assertEqual(None, entry.test_int_fdt)
1691 self.assertEqual(456, entry.test_int_arg)
1692
1693 def testEntryArgsRequired(self):
1694 """Test missing arguments and properties"""
1695 entry_args = {
1696 'test-int-arg': '456',
1697 }
1698 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001699 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001700 self.assertIn("Node '/binman/_testing': "
1701 'Missing required properties/entry args: test-str-arg, '
1702 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001703 str(e.exception))
1704
1705 def testEntryArgsInvalidFormat(self):
1706 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001707 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1708 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001709 with self.assertRaises(ValueError) as e:
1710 self._DoBinman(*args)
1711 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1712
1713 def testEntryArgsInvalidInteger(self):
1714 """Test that an invalid entry-argument integer is detected"""
1715 entry_args = {
1716 'test-int-arg': 'abc',
1717 }
1718 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001719 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001720 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1721 "'test-int-arg' (value 'abc') to integer",
1722 str(e.exception))
1723
1724 def testEntryArgsInvalidDatatype(self):
1725 """Test that an invalid entry-argument datatype is detected
1726
1727 This test could be written in entry_test.py except that it needs
1728 access to control.entry_args, which seems more than that module should
1729 be able to see.
1730 """
1731 entry_args = {
1732 'test-bad-datatype-arg': '12',
1733 }
1734 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001735 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001736 entry_args=entry_args)
1737 self.assertIn('GetArg() internal error: Unknown data type ',
1738 str(e.exception))
1739
Simon Glass2ca52032018-07-17 13:25:33 -06001740 def testText(self):
1741 """Test for a text entry type"""
1742 entry_args = {
1743 'test-id': TEXT_DATA,
1744 'test-id2': TEXT_DATA2,
1745 'test-id3': TEXT_DATA3,
1746 }
Simon Glass511f6582018-10-01 12:22:30 -06001747 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001748 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001749 expected = (tools.to_bytes(TEXT_DATA) +
1750 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1751 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001752 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001753 self.assertEqual(expected, data)
1754
Simon Glass969616c2018-07-17 13:25:36 -06001755 def testEntryDocs(self):
1756 """Test for creation of entry documentation"""
1757 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001758 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001759 self.assertTrue(len(stdout.getvalue()) > 0)
1760
1761 def testEntryDocsMissing(self):
1762 """Test handling of missing entry documentation"""
1763 with self.assertRaises(ValueError) as e:
1764 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001765 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001766 self.assertIn('Documentation is missing for modules: u_boot',
1767 str(e.exception))
1768
Simon Glass704784b2018-07-17 13:25:38 -06001769 def testFmap(self):
1770 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001771 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001772 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001773 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1774 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001775 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001776 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001777 self.assertEqual(1, fhdr.ver_major)
1778 self.assertEqual(0, fhdr.ver_minor)
1779 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001780 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001781 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001782 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001783 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001784 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001785
Simon Glass82059c22021-04-03 11:05:09 +13001786 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001787 self.assertEqual(b'SECTION0', fentry.name)
1788 self.assertEqual(0, fentry.offset)
1789 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001790 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001791
1792 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001793 self.assertEqual(b'RO_U_BOOT', fentry.name)
1794 self.assertEqual(0, fentry.offset)
1795 self.assertEqual(4, fentry.size)
1796 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001797
Simon Glass82059c22021-04-03 11:05:09 +13001798 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001799 self.assertEqual(b'SECTION1', fentry.name)
1800 self.assertEqual(16, fentry.offset)
1801 self.assertEqual(16, fentry.size)
1802 self.assertEqual(0, fentry.flags)
1803
1804 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001805 self.assertEqual(b'RW_U_BOOT', fentry.name)
1806 self.assertEqual(16, fentry.offset)
1807 self.assertEqual(4, fentry.size)
1808 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001809
Simon Glass82059c22021-04-03 11:05:09 +13001810 fentry = next(fiter)
1811 self.assertEqual(b'FMAP', fentry.name)
1812 self.assertEqual(32, fentry.offset)
1813 self.assertEqual(expect_size, fentry.size)
1814 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001815
Simon Glassdb168d42018-07-17 13:25:39 -06001816 def testBlobNamedByArg(self):
1817 """Test we can add a blob with the filename coming from an entry arg"""
1818 entry_args = {
1819 'cros-ec-rw-path': 'ecrw.bin',
1820 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001821 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001822
Simon Glass53f53992018-07-17 13:25:40 -06001823 def testFill(self):
1824 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001825 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001826 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001827 self.assertEqual(expected, data)
1828
1829 def testFillNoSize(self):
1830 """Test for an fill entry type with no size"""
1831 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001832 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001833 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001834 str(e.exception))
1835
Simon Glassc1ae83c2018-07-17 13:25:44 -06001836 def _HandleGbbCommand(self, pipe_list):
1837 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001838 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001839 fname = pipe_list[0][-1]
1840 # Append our GBB data to the file, which will happen every time the
1841 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001842 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001843 fd.write(GBB_DATA)
1844 return command.CommandResult()
1845
1846 def testGbb(self):
1847 """Test for the Chromium OS Google Binary Block"""
1848 command.test_result = self._HandleGbbCommand
1849 entry_args = {
1850 'keydir': 'devkeys',
1851 'bmpblk': 'bmpblk.bin',
1852 }
Simon Glass511f6582018-10-01 12:22:30 -06001853 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001854
1855 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001856 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1857 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001858 self.assertEqual(expected, data)
1859
1860 def testGbbTooSmall(self):
1861 """Test for the Chromium OS Google Binary Block being large enough"""
1862 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001863 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001864 self.assertIn("Node '/binman/gbb': GBB is too small",
1865 str(e.exception))
1866
1867 def testGbbNoSize(self):
1868 """Test for the Chromium OS Google Binary Block having a size"""
1869 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001870 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001871 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1872 str(e.exception))
1873
Simon Glass66152ce2022-01-09 20:14:09 -07001874 def testGbbMissing(self):
1875 """Test that binman still produces an image if futility is missing"""
1876 entry_args = {
1877 'keydir': 'devkeys',
1878 }
1879 with test_util.capture_sys_output() as (_, stderr):
1880 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1881 entry_args=entry_args)
1882 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001883 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001884
Simon Glass5c350162018-07-17 13:25:47 -06001885 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001886 """Fake calls to the futility utility
1887
1888 The expected pipe is:
1889
1890 [('futility', 'vbutil_firmware', '--vblock',
1891 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1892 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1893 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1894 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1895
1896 This writes to the output file (here, 'vblock.vblock'). If
1897 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1898 of the input data (here, 'input.vblock').
1899 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001900 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001901 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001902 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001903 if self._hash_data:
1904 infile = pipe_list[0][11]
1905 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001906 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001907 m.update(data)
1908 fd.write(m.digest())
1909 else:
1910 fd.write(VBLOCK_DATA)
1911
Simon Glass5c350162018-07-17 13:25:47 -06001912 return command.CommandResult()
1913
1914 def testVblock(self):
1915 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001916 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001917 command.test_result = self._HandleVblockCommand
1918 entry_args = {
1919 'keydir': 'devkeys',
1920 }
Simon Glass511f6582018-10-01 12:22:30 -06001921 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001922 entry_args=entry_args)
1923 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1924 self.assertEqual(expected, data)
1925
1926 def testVblockNoContent(self):
1927 """Test we detect a vblock which has no content to sign"""
1928 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001929 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001930 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001931 'property', str(e.exception))
1932
1933 def testVblockBadPhandle(self):
1934 """Test that we detect a vblock with an invalid phandle in contents"""
1935 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001936 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001937 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1938 '1000', str(e.exception))
1939
1940 def testVblockBadEntry(self):
1941 """Test that we detect an entry that points to a non-entry"""
1942 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001943 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001944 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1945 "'other'", str(e.exception))
1946
Simon Glass220c6222021-01-06 21:35:17 -07001947 def testVblockContent(self):
1948 """Test that the vblock signs the right data"""
1949 self._hash_data = True
1950 command.test_result = self._HandleVblockCommand
1951 entry_args = {
1952 'keydir': 'devkeys',
1953 }
1954 data = self._DoReadFileDtb(
1955 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1956 entry_args=entry_args)[0]
1957 hashlen = 32 # SHA256 hash is 32 bytes
1958 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1959 hashval = data[-hashlen:]
1960 dtb = data[len(U_BOOT_DATA):-hashlen]
1961
1962 expected_data = U_BOOT_DATA + dtb
1963
1964 # The hashval should be a hash of the dtb
1965 m = hashlib.sha256()
1966 m.update(expected_data)
1967 expected_hashval = m.digest()
1968 self.assertEqual(expected_hashval, hashval)
1969
Simon Glass66152ce2022-01-09 20:14:09 -07001970 def testVblockMissing(self):
1971 """Test that binman still produces an image if futility is missing"""
1972 entry_args = {
1973 'keydir': 'devkeys',
1974 }
1975 with test_util.capture_sys_output() as (_, stderr):
1976 self._DoTestFile('074_vblock.dts',
1977 force_missing_bintools='futility',
1978 entry_args=entry_args)
1979 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001980 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001981
Simon Glass8425a1f2018-07-17 13:25:48 -06001982 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001983 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001984 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001985 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001986 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001987 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1988
Simon Glass24b97442018-07-17 13:25:51 -06001989 def testUsesPos(self):
1990 """Test that the 'pos' property cannot be used anymore"""
1991 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001992 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001993 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1994 "'pos'", str(e.exception))
1995
Simon Glass274bf092018-09-14 04:57:08 -06001996 def testFillZero(self):
1997 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001998 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001999 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06002000
Simon Glass267de432018-09-14 04:57:09 -06002001 def testTextMissing(self):
2002 """Test for a text entry type where there is no text"""
2003 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002004 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06002005 self.assertIn("Node '/binman/text': No value provided for text label "
2006 "'test-id'", str(e.exception))
2007
Simon Glassed40e962018-09-14 04:57:10 -06002008 def testPackStart16Tpl(self):
2009 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06002010 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06002011 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
2012
Simon Glass3b376c32018-09-14 04:57:12 -06002013 def testSelectImage(self):
2014 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06002015 expected = 'Skipping images: image1'
2016
2017 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06002018 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06002019 with test_util.capture_sys_output() as (stdout, stderr):
2020 retcode = self._DoTestFile('006_dual_image.dts',
2021 verbosity=verbosity,
2022 images=['image2'])
2023 self.assertEqual(0, retcode)
2024 if verbosity:
2025 self.assertIn(expected, stdout.getvalue())
2026 else:
2027 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06002028
Simon Glass80025522022-01-29 14:14:04 -07002029 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2030 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06002031 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06002032
Simon Glasse219aa42018-09-14 04:57:24 -06002033 def testUpdateFdtAll(self):
2034 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06002035 self._SetupSplElf()
2036 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06002037 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06002038
2039 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06002040 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002041 'image-pos': 0,
2042 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06002043 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002044 'section:image-pos': 0,
2045 'section:size': 565,
2046 'section/u-boot-dtb:offset': 0,
2047 'section/u-boot-dtb:image-pos': 0,
2048 'section/u-boot-dtb:size': 565,
2049 'u-boot-spl-dtb:offset': 565,
2050 'u-boot-spl-dtb:image-pos': 565,
2051 'u-boot-spl-dtb:size': 585,
2052 'u-boot-tpl-dtb:offset': 1150,
2053 'u-boot-tpl-dtb:image-pos': 1150,
2054 'u-boot-tpl-dtb:size': 585,
2055 'u-boot-vpl-dtb:image-pos': 1735,
2056 'u-boot-vpl-dtb:offset': 1735,
2057 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002058 }
2059
2060 # We expect three device-tree files in the output, one after the other.
2061 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2062 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2063 # main U-Boot tree. All three should have the same postions and offset.
2064 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002065 self.maxDiff = None
2066 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002067 dtb = fdt.Fdt.FromData(data[start:])
2068 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002069 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002070 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002071 expected = dict(base_expected)
2072 if item:
2073 expected[item] = 0
2074 self.assertEqual(expected, props)
2075 start += dtb._fdt_obj.totalsize()
2076
2077 def testUpdateFdtOutput(self):
2078 """Test that output DTB files are updated"""
2079 try:
Simon Glass511f6582018-10-01 12:22:30 -06002080 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002081 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2082
2083 # Unfortunately, compiling a source file always results in a file
2084 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002085 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002086 # binman as a file called u-boot.dtb. To fix this, copy the file
2087 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002088 start = 0
2089 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002090 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002091 dtb = fdt.Fdt.FromData(data[start:])
2092 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002093 pathname = tools.get_output_filename(os.path.split(fname)[1])
2094 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002095 name = os.path.split(fname)[0]
2096
2097 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002098 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002099 else:
2100 orig_indata = dtb_data
2101 self.assertNotEqual(outdata, orig_indata,
2102 "Expected output file '%s' be updated" % pathname)
2103 self.assertEqual(outdata, data[start:start + size],
2104 "Expected output file '%s' to match output image" %
2105 pathname)
2106 start += size
2107 finally:
2108 self._ResetDtbs()
2109
Simon Glass7ba33592018-09-14 04:57:26 -06002110 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002111 bintool = self.comp_bintools['lz4']
2112 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002113
2114 def testCompress(self):
2115 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002116 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002117 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002118 use_real_dtb=True, update_dtb=True)
2119 dtb = fdt.Fdt(out_dtb_fname)
2120 dtb.Scan()
2121 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2122 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00002123 self.assertEqual(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002124
2125 # Do a sanity check on various fields
2126 image = control.images['image']
2127 entries = image.GetEntries()
2128 self.assertEqual(1, len(entries))
2129
2130 entry = entries['blob']
2131 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2132 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2133 orig = self._decompress(entry.data)
2134 self.assertEqual(orig, entry.uncomp_data)
2135
Simon Glass72eeff12020-10-26 17:40:16 -06002136 self.assertEqual(image.data, entry.data)
2137
Simon Glass7ba33592018-09-14 04:57:26 -06002138 expected = {
2139 'blob:uncomp-size': len(COMPRESS_DATA),
2140 'blob:size': len(data),
2141 'size': len(data),
2142 }
2143 self.assertEqual(expected, props)
2144
Simon Glassac6328c2018-09-14 04:57:28 -06002145 def testFiles(self):
2146 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002147 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002148 self.assertEqual(FILES_DATA, data)
2149
2150 def testFilesCompress(self):
2151 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002152 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002153 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002154
2155 image = control.images['image']
2156 entries = image.GetEntries()
2157 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002158 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002159
Simon Glass303f62f2019-05-17 22:00:46 -06002160 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002161 for i in range(1, 3):
2162 key = '%d.dat' % i
2163 start = entries[key].image_pos
2164 len = entries[key].size
2165 chunk = data[start:start + len]
2166 orig += self._decompress(chunk)
2167
2168 self.assertEqual(FILES_DATA, orig)
2169
2170 def testFilesMissing(self):
2171 """Test missing files"""
2172 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002173 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002174 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2175 'no files', str(e.exception))
2176
2177 def testFilesNoPattern(self):
2178 """Test missing files"""
2179 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002180 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002181 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2182 str(e.exception))
2183
Simon Glassdd156a42022-03-05 20:18:59 -07002184 def testExtendSize(self):
2185 """Test an extending entry"""
2186 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002187 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002188 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2189 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2190 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2191 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002192 self.assertEqual(expect, data)
2193 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700219400000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600219500000000 00000000 00000008 fill
219600000008 00000008 00000004 u-boot
21970000000c 0000000c 00000004 section
21980000000c 00000000 00000003 intel-mrc
219900000010 00000010 00000004 u-boot2
220000000014 00000014 0000000c section2
220100000014 00000000 00000008 fill
22020000001c 00000008 00000004 u-boot
220300000020 00000020 00000008 fill2
2204''', map_data)
2205
Simon Glassdd156a42022-03-05 20:18:59 -07002206 def testExtendSizeBad(self):
2207 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002208 with test_util.capture_sys_output() as (stdout, stderr):
2209 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002210 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002211 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2212 'expanding entry', str(e.exception))
2213
Simon Glassae7cf032018-09-14 04:57:31 -06002214 def testHash(self):
2215 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002216 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002217 use_real_dtb=True, update_dtb=True)
2218 dtb = fdt.Fdt(out_dtb_fname)
2219 dtb.Scan()
2220 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2221 m = hashlib.sha256()
2222 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002223 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002224
2225 def testHashNoAlgo(self):
2226 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002227 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002228 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2229 'hash node', str(e.exception))
2230
2231 def testHashBadAlgo(self):
2232 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002233 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002234 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002235 str(e.exception))
2236
2237 def testHashSection(self):
2238 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002239 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002240 use_real_dtb=True, update_dtb=True)
2241 dtb = fdt.Fdt(out_dtb_fname)
2242 dtb.Scan()
2243 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2244 m = hashlib.sha256()
2245 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002246 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002247 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002248
Simon Glass3fb4f422018-09-14 04:57:32 -06002249 def testPackUBootTplMicrocode(self):
2250 """Test that x86 microcode can be handled correctly in TPL
2251
2252 We expect to see the following in the image, in order:
2253 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2254 place
2255 u-boot-tpl.dtb with the microcode removed
2256 the microcode
2257 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002258 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002259 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002260 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002261 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2262 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002263
Simon Glassc64aea52018-09-14 04:57:34 -06002264 def testFmapX86(self):
2265 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002266 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002267 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002268 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002269 self.assertEqual(expected, data[:32])
2270 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2271
2272 self.assertEqual(0x100, fhdr.image_size)
2273
2274 self.assertEqual(0, fentries[0].offset)
2275 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002276 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002277
2278 self.assertEqual(4, fentries[1].offset)
2279 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002280 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002281
2282 self.assertEqual(32, fentries[2].offset)
2283 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2284 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002285 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002286
2287 def testFmapX86Section(self):
2288 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002289 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002290 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002291 self.assertEqual(expected, data[:32])
2292 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2293
Simon Glassb1d414c2021-04-03 11:05:10 +13002294 self.assertEqual(0x180, fhdr.image_size)
2295 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002296 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002297
Simon Glass82059c22021-04-03 11:05:09 +13002298 fentry = next(fiter)
2299 self.assertEqual(b'U_BOOT', fentry.name)
2300 self.assertEqual(0, fentry.offset)
2301 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002302
Simon Glass82059c22021-04-03 11:05:09 +13002303 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002304 self.assertEqual(b'SECTION', fentry.name)
2305 self.assertEqual(4, fentry.offset)
2306 self.assertEqual(0x20 + expect_size, fentry.size)
2307
2308 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002309 self.assertEqual(b'INTEL_MRC', fentry.name)
2310 self.assertEqual(4, fentry.offset)
2311 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002312
Simon Glass82059c22021-04-03 11:05:09 +13002313 fentry = next(fiter)
2314 self.assertEqual(b'FMAP', fentry.name)
2315 self.assertEqual(36, fentry.offset)
2316 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002317
Simon Glassb1714232018-09-14 04:57:35 -06002318 def testElf(self):
2319 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002320 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002321 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002322 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002323 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002324 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002325
Simon Glass0d673792019-07-08 13:18:25 -06002326 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002327 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002328 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002329 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002330 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002331 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002332
Simon Glasscd817d52018-09-14 04:57:36 -06002333 def testPackOverlapMap(self):
2334 """Test that overlapping regions are detected"""
2335 with test_util.capture_sys_output() as (stdout, stderr):
2336 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002337 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002338 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002339 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2340 stdout.getvalue())
2341
2342 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002343 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002344 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002345 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002346 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002347<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002348<none> 00000000 00000004 u-boot
2349<none> 00000003 00000004 u-boot-align
2350''', map_data)
2351
Simon Glass0d673792019-07-08 13:18:25 -06002352 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002353 """Test that an image with an Intel Reference code binary works"""
2354 data = self._DoReadFile('100_intel_refcode.dts')
2355 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2356
Simon Glasseb023b32019-04-25 21:58:39 -06002357 def testSectionOffset(self):
2358 """Tests use of a section with an offset"""
2359 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2360 map=True)
2361 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700236200000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600236300000004 00000004 00000010 section@0
236400000004 00000000 00000004 u-boot
236500000018 00000018 00000010 section@1
236600000018 00000000 00000004 u-boot
23670000002c 0000002c 00000004 section@2
23680000002c 00000000 00000004 u-boot
2369''', map_data)
2370 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002371 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2372 tools.get_bytes(0x21, 12) +
2373 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2374 tools.get_bytes(0x61, 12) +
2375 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2376 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002377
Simon Glass1de34482019-07-08 13:18:53 -06002378 def testCbfsRaw(self):
2379 """Test base handling of a Coreboot Filesystem (CBFS)
2380
2381 The exact contents of the CBFS is verified by similar tests in
2382 cbfs_util_test.py. The tests here merely check that the files added to
2383 the CBFS can be found in the final image.
2384 """
2385 data = self._DoReadFile('102_cbfs_raw.dts')
2386 size = 0xb0
2387
2388 cbfs = cbfs_util.CbfsReader(data)
2389 self.assertEqual(size, cbfs.rom_size)
2390
2391 self.assertIn('u-boot-dtb', cbfs.files)
2392 cfile = cbfs.files['u-boot-dtb']
2393 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2394
2395 def testCbfsArch(self):
2396 """Test on non-x86 architecture"""
2397 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2398 size = 0x100
2399
2400 cbfs = cbfs_util.CbfsReader(data)
2401 self.assertEqual(size, cbfs.rom_size)
2402
2403 self.assertIn('u-boot-dtb', cbfs.files)
2404 cfile = cbfs.files['u-boot-dtb']
2405 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2406
2407 def testCbfsStage(self):
2408 """Tests handling of a Coreboot Filesystem (CBFS)"""
2409 if not elf.ELF_TOOLS:
2410 self.skipTest('Python elftools not available')
2411 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2412 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2413 size = 0xb0
2414
2415 data = self._DoReadFile('104_cbfs_stage.dts')
2416 cbfs = cbfs_util.CbfsReader(data)
2417 self.assertEqual(size, cbfs.rom_size)
2418
2419 self.assertIn('u-boot', cbfs.files)
2420 cfile = cbfs.files['u-boot']
2421 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2422
2423 def testCbfsRawCompress(self):
2424 """Test handling of compressing raw files"""
2425 self._CheckLz4()
2426 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2427 size = 0x140
2428
2429 cbfs = cbfs_util.CbfsReader(data)
2430 self.assertIn('u-boot', cbfs.files)
2431 cfile = cbfs.files['u-boot']
2432 self.assertEqual(COMPRESS_DATA, cfile.data)
2433
2434 def testCbfsBadArch(self):
2435 """Test handling of a bad architecture"""
2436 with self.assertRaises(ValueError) as e:
2437 self._DoReadFile('106_cbfs_bad_arch.dts')
2438 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2439
2440 def testCbfsNoSize(self):
2441 """Test handling of a missing size property"""
2442 with self.assertRaises(ValueError) as e:
2443 self._DoReadFile('107_cbfs_no_size.dts')
2444 self.assertIn('entry must have a size property', str(e.exception))
2445
Simon Glass3e28f4f2021-11-23 11:03:54 -07002446 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002447 """Test handling of a CBFS entry which does not provide contentsy"""
2448 with self.assertRaises(ValueError) as e:
2449 self._DoReadFile('108_cbfs_no_contents.dts')
2450 self.assertIn('Could not complete processing of contents',
2451 str(e.exception))
2452
2453 def testCbfsBadCompress(self):
2454 """Test handling of a bad architecture"""
2455 with self.assertRaises(ValueError) as e:
2456 self._DoReadFile('109_cbfs_bad_compress.dts')
2457 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2458 str(e.exception))
2459
2460 def testCbfsNamedEntries(self):
2461 """Test handling of named entries"""
2462 data = self._DoReadFile('110_cbfs_name.dts')
2463
2464 cbfs = cbfs_util.CbfsReader(data)
2465 self.assertIn('FRED', cbfs.files)
2466 cfile1 = cbfs.files['FRED']
2467 self.assertEqual(U_BOOT_DATA, cfile1.data)
2468
2469 self.assertIn('hello', cbfs.files)
2470 cfile2 = cbfs.files['hello']
2471 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2472
Simon Glass759af872019-07-08 13:18:54 -06002473 def _SetupIfwi(self, fname):
2474 """Set up to run an IFWI test
2475
2476 Args:
2477 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2478 """
2479 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002480 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002481
2482 # Intel Integrated Firmware Image (IFWI) file
2483 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2484 data = fd.read()
2485 TestFunctional._MakeInputFile(fname,data)
2486
2487 def _CheckIfwi(self, data):
2488 """Check that an image with an IFWI contains the correct output
2489
2490 Args:
2491 data: Conents of output file
2492 """
Simon Glass80025522022-01-29 14:14:04 -07002493 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002494 if data[:0x1000] != expected_desc:
2495 self.fail('Expected descriptor binary at start of image')
2496
2497 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002498 image_fname = tools.get_output_filename('image.bin')
2499 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002500 ifwitool = bintool.Bintool.create('ifwitool')
2501 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002502
Simon Glass80025522022-01-29 14:14:04 -07002503 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002504 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002505
2506 def testPackX86RomIfwi(self):
2507 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2508 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002509 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002510 self._CheckIfwi(data)
2511
2512 def testPackX86RomIfwiNoDesc(self):
2513 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2514 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002515 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002516 self._CheckIfwi(data)
2517
2518 def testPackX86RomIfwiNoData(self):
2519 """Test that an x86 ROM with IFWI handles missing data"""
2520 self._SetupIfwi('ifwi.bin')
2521 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002522 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002523 self.assertIn('Could not complete processing of contents',
2524 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002525
Simon Glass66152ce2022-01-09 20:14:09 -07002526 def testIfwiMissing(self):
2527 """Test that binman still produces an image if ifwitool is missing"""
2528 self._SetupIfwi('fitimage.bin')
2529 with test_util.capture_sys_output() as (_, stderr):
2530 self._DoTestFile('111_x86_rom_ifwi.dts',
2531 force_missing_bintools='ifwitool')
2532 err = stderr.getvalue()
2533 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002534 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002535
Simon Glassc2f1aed2019-07-08 13:18:56 -06002536 def testCbfsOffset(self):
2537 """Test a CBFS with files at particular offsets
2538
2539 Like all CFBS tests, this is just checking the logic that calls
2540 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2541 """
2542 data = self._DoReadFile('114_cbfs_offset.dts')
2543 size = 0x200
2544
2545 cbfs = cbfs_util.CbfsReader(data)
2546 self.assertEqual(size, cbfs.rom_size)
2547
2548 self.assertIn('u-boot', cbfs.files)
2549 cfile = cbfs.files['u-boot']
2550 self.assertEqual(U_BOOT_DATA, cfile.data)
2551 self.assertEqual(0x40, cfile.cbfs_offset)
2552
2553 self.assertIn('u-boot-dtb', cbfs.files)
2554 cfile2 = cbfs.files['u-boot-dtb']
2555 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2556 self.assertEqual(0x140, cfile2.cbfs_offset)
2557
Simon Glass0f621332019-07-08 14:25:27 -06002558 def testFdtmap(self):
2559 """Test an FDT map can be inserted in the image"""
2560 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2561 fdtmap_data = data[len(U_BOOT_DATA):]
2562 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002563 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002564 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002565
2566 fdt_data = fdtmap_data[16:]
2567 dtb = fdt.Fdt.FromData(fdt_data)
2568 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002569 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002570 self.assertEqual({
2571 'image-pos': 0,
2572 'offset': 0,
2573 'u-boot:offset': 0,
2574 'u-boot:size': len(U_BOOT_DATA),
2575 'u-boot:image-pos': 0,
2576 'fdtmap:image-pos': 4,
2577 'fdtmap:offset': 4,
2578 'fdtmap:size': len(fdtmap_data),
2579 'size': len(data),
2580 }, props)
2581
2582 def testFdtmapNoMatch(self):
2583 """Check handling of an FDT map when the section cannot be found"""
2584 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2585
2586 # Mangle the section name, which should cause a mismatch between the
2587 # correct FDT path and the one expected by the section
2588 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002589 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002590 entries = image.GetEntries()
2591 fdtmap = entries['fdtmap']
2592 with self.assertRaises(ValueError) as e:
2593 fdtmap._GetFdtmap()
2594 self.assertIn("Cannot locate node for path '/binman-suffix'",
2595 str(e.exception))
2596
Simon Glasscec34ba2019-07-08 14:25:28 -06002597 def testFdtmapHeader(self):
2598 """Test an FDT map and image header can be inserted in the image"""
2599 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2600 fdtmap_pos = len(U_BOOT_DATA)
2601 fdtmap_data = data[fdtmap_pos:]
2602 fdt_data = fdtmap_data[16:]
2603 dtb = fdt.Fdt.FromData(fdt_data)
2604 fdt_size = dtb.GetFdtObj().totalsize()
2605 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002606 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002607 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2608 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2609
2610 def testFdtmapHeaderStart(self):
2611 """Test an image header can be inserted at the image start"""
2612 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2613 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2614 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002615 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002616 offset = struct.unpack('<I', hdr_data[4:])[0]
2617 self.assertEqual(fdtmap_pos, offset)
2618
2619 def testFdtmapHeaderPos(self):
2620 """Test an image header can be inserted at a chosen position"""
2621 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2622 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2623 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002624 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002625 offset = struct.unpack('<I', hdr_data[4:])[0]
2626 self.assertEqual(fdtmap_pos, offset)
2627
2628 def testHeaderMissingFdtmap(self):
2629 """Test an image header requires an fdtmap"""
2630 with self.assertRaises(ValueError) as e:
2631 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2632 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2633 str(e.exception))
2634
2635 def testHeaderNoLocation(self):
2636 """Test an image header with a no specified location is detected"""
2637 with self.assertRaises(ValueError) as e:
2638 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2639 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2640 str(e.exception))
2641
Simon Glasse61b6f62019-07-08 14:25:37 -06002642 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002643 """Test extending an entry after it is packed"""
2644 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002645 self.assertEqual(b'aaa', data[:3])
2646 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2647 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002648
Simon Glassdd156a42022-03-05 20:18:59 -07002649 def testEntryExtendBad(self):
2650 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002651 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002652 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002653 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002654 str(e.exception))
2655
Simon Glassdd156a42022-03-05 20:18:59 -07002656 def testEntryExtendSection(self):
2657 """Test extending an entry within a section after it is packed"""
2658 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002659 self.assertEqual(b'aaa', data[:3])
2660 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2661 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002662
Simon Glass90d29682019-07-08 14:25:38 -06002663 def testCompressDtb(self):
2664 """Test that compress of device-tree files is supported"""
2665 self._CheckLz4()
2666 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2667 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2668 comp_data = data[len(U_BOOT_DATA):]
2669 orig = self._decompress(comp_data)
2670 dtb = fdt.Fdt.FromData(orig)
2671 dtb.Scan()
2672 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2673 expected = {
2674 'u-boot:size': len(U_BOOT_DATA),
2675 'u-boot-dtb:uncomp-size': len(orig),
2676 'u-boot-dtb:size': len(comp_data),
2677 'size': len(data),
2678 }
2679 self.assertEqual(expected, props)
2680
Simon Glass151bbbf2019-07-08 14:25:41 -06002681 def testCbfsUpdateFdt(self):
2682 """Test that we can update the device tree with CBFS offset/size info"""
2683 self._CheckLz4()
2684 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2685 update_dtb=True)
2686 dtb = fdt.Fdt(out_dtb_fname)
2687 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002688 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002689 del props['cbfs/u-boot:size']
2690 self.assertEqual({
2691 'offset': 0,
2692 'size': len(data),
2693 'image-pos': 0,
2694 'cbfs:offset': 0,
2695 'cbfs:size': len(data),
2696 'cbfs:image-pos': 0,
Simon Glassfa144222023-10-14 14:40:28 -06002697 'cbfs/u-boot:offset': 0x30,
Simon Glass151bbbf2019-07-08 14:25:41 -06002698 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002699 'cbfs/u-boot:image-pos': 0x30,
2700 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002701 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002702 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002703 }, props)
2704
Simon Glass3c9b4f22019-07-08 14:25:42 -06002705 def testCbfsBadType(self):
2706 """Test an image header with a no specified location is detected"""
2707 with self.assertRaises(ValueError) as e:
2708 self._DoReadFile('126_cbfs_bad_type.dts')
2709 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2710
Simon Glass6b156f82019-07-08 14:25:43 -06002711 def testList(self):
2712 """Test listing the files in an image"""
2713 self._CheckLz4()
2714 data = self._DoReadFile('127_list.dts')
2715 image = control.images['image']
2716 entries = image.BuildEntryList()
2717 self.assertEqual(7, len(entries))
2718
2719 ent = entries[0]
2720 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002721 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002722 self.assertEqual('section', ent.etype)
2723 self.assertEqual(len(data), ent.size)
2724 self.assertEqual(0, ent.image_pos)
2725 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002726 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002727
2728 ent = entries[1]
2729 self.assertEqual(1, ent.indent)
2730 self.assertEqual('u-boot', ent.name)
2731 self.assertEqual('u-boot', ent.etype)
2732 self.assertEqual(len(U_BOOT_DATA), ent.size)
2733 self.assertEqual(0, ent.image_pos)
2734 self.assertEqual(None, ent.uncomp_size)
2735 self.assertEqual(0, ent.offset)
2736
2737 ent = entries[2]
2738 self.assertEqual(1, ent.indent)
2739 self.assertEqual('section', ent.name)
2740 self.assertEqual('section', ent.etype)
2741 section_size = ent.size
2742 self.assertEqual(0x100, ent.image_pos)
2743 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002744 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002745
2746 ent = entries[3]
2747 self.assertEqual(2, ent.indent)
2748 self.assertEqual('cbfs', ent.name)
2749 self.assertEqual('cbfs', ent.etype)
2750 self.assertEqual(0x400, ent.size)
2751 self.assertEqual(0x100, ent.image_pos)
2752 self.assertEqual(None, ent.uncomp_size)
2753 self.assertEqual(0, ent.offset)
2754
2755 ent = entries[4]
2756 self.assertEqual(3, 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(0x138, ent.image_pos)
2761 self.assertEqual(None, ent.uncomp_size)
2762 self.assertEqual(0x38, ent.offset)
2763
2764 ent = entries[5]
2765 self.assertEqual(3, ent.indent)
2766 self.assertEqual('u-boot-dtb', ent.name)
2767 self.assertEqual('text', ent.etype)
2768 self.assertGreater(len(COMPRESS_DATA), ent.size)
2769 self.assertEqual(0x178, ent.image_pos)
2770 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2771 self.assertEqual(0x78, ent.offset)
2772
2773 ent = entries[6]
2774 self.assertEqual(2, ent.indent)
2775 self.assertEqual('u-boot-dtb', ent.name)
2776 self.assertEqual('u-boot-dtb', ent.etype)
2777 self.assertEqual(0x500, ent.image_pos)
2778 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2779 dtb_size = ent.size
2780 # Compressing this data expands it since headers are added
2781 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2782 self.assertEqual(0x400, ent.offset)
2783
2784 self.assertEqual(len(data), 0x100 + section_size)
2785 self.assertEqual(section_size, 0x400 + dtb_size)
2786
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002787 def testFindFdtmap(self):
2788 """Test locating an FDT map in an image"""
2789 self._CheckLz4()
2790 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2791 image = control.images['image']
2792 entries = image.GetEntries()
2793 entry = entries['fdtmap']
2794 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2795
2796 def testFindFdtmapMissing(self):
2797 """Test failing to locate an FDP map"""
2798 data = self._DoReadFile('005_simple.dts')
2799 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2800
Simon Glassed39a3c2019-07-08 14:25:45 -06002801 def testFindImageHeader(self):
2802 """Test locating a image header"""
2803 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002804 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002805 image = control.images['image']
2806 entries = image.GetEntries()
2807 entry = entries['fdtmap']
2808 # The header should point to the FDT map
2809 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2810
2811 def testFindImageHeaderStart(self):
2812 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002813 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002814 image = control.images['image']
2815 entries = image.GetEntries()
2816 entry = entries['fdtmap']
2817 # The header should point to the FDT map
2818 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2819
2820 def testFindImageHeaderMissing(self):
2821 """Test failing to locate an image header"""
2822 data = self._DoReadFile('005_simple.dts')
2823 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2824
Simon Glassb8424fa2019-07-08 14:25:46 -06002825 def testReadImage(self):
2826 """Test reading an image and accessing its FDT map"""
2827 self._CheckLz4()
2828 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002829 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002830 orig_image = control.images['image']
2831 image = Image.FromFile(image_fname)
2832 self.assertEqual(orig_image.GetEntries().keys(),
2833 image.GetEntries().keys())
2834
2835 orig_entry = orig_image.GetEntries()['fdtmap']
2836 entry = image.GetEntries()['fdtmap']
Brandon Maiera657bc62024-06-04 16:16:05 +00002837 self.assertEqual(orig_entry.offset, entry.offset)
2838 self.assertEqual(orig_entry.size, entry.size)
2839 self.assertEqual(orig_entry.image_pos, entry.image_pos)
Simon Glassb8424fa2019-07-08 14:25:46 -06002840
2841 def testReadImageNoHeader(self):
2842 """Test accessing an image's FDT map without an image header"""
2843 self._CheckLz4()
2844 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002845 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002846 image = Image.FromFile(image_fname)
2847 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002848 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002849
2850 def testReadImageFail(self):
2851 """Test failing to read an image image's FDT map"""
2852 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002853 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002854 with self.assertRaises(ValueError) as e:
2855 image = Image.FromFile(image_fname)
2856 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002857
Simon Glassb2fd11d2019-07-08 14:25:48 -06002858 def testListCmd(self):
2859 """Test listing the files in an image using an Fdtmap"""
2860 self._CheckLz4()
2861 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2862
2863 # lz4 compression size differs depending on the version
2864 image = control.images['image']
2865 entries = image.GetEntries()
2866 section_size = entries['section'].size
2867 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2868 fdtmap_offset = entries['fdtmap'].offset
2869
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002870 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002871 try:
2872 tmpdir, updated_fname = self._SetupImageInTmpdir()
2873 with test_util.capture_sys_output() as (stdout, stderr):
2874 self._DoBinman('ls', '-i', updated_fname)
2875 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002876 if tmpdir:
2877 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002878 lines = stdout.getvalue().splitlines()
2879 expected = [
2880'Name Image-pos Size Entry-type Offset Uncomp-size',
2881'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002882'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002883' u-boot 0 4 u-boot 0',
2884' section 100 %x section 100' % section_size,
2885' cbfs 100 400 cbfs 0',
Simon Glassfa144222023-10-14 14:40:28 -06002886' u-boot 120 4 u-boot 20',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002887' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002888' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002889' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002890 (fdtmap_offset, fdtmap_offset),
2891' image-header bf8 8 image-header bf8',
2892 ]
2893 self.assertEqual(expected, lines)
2894
2895 def testListCmdFail(self):
2896 """Test failing to list an image"""
2897 self._DoReadFile('005_simple.dts')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002898 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002899 try:
2900 tmpdir, updated_fname = self._SetupImageInTmpdir()
2901 with self.assertRaises(ValueError) as e:
2902 self._DoBinman('ls', '-i', updated_fname)
2903 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002904 if tmpdir:
2905 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002906 self.assertIn("Cannot find FDT map in image", str(e.exception))
2907
2908 def _RunListCmd(self, paths, expected):
2909 """List out entries and check the result
2910
2911 Args:
2912 paths: List of paths to pass to the list command
2913 expected: Expected list of filenames to be returned, in order
2914 """
2915 self._CheckLz4()
2916 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002917 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002918 image = Image.FromFile(image_fname)
2919 lines = image.GetListEntries(paths)[1]
2920 files = [line[0].strip() for line in lines[1:]]
2921 self.assertEqual(expected, files)
2922
2923 def testListCmdSection(self):
2924 """Test listing the files in a section"""
2925 self._RunListCmd(['section'],
2926 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2927
2928 def testListCmdFile(self):
2929 """Test listing a particular file"""
2930 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2931
2932 def testListCmdWildcard(self):
2933 """Test listing a wildcarded file"""
2934 self._RunListCmd(['*boot*'],
2935 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2936
2937 def testListCmdWildcardMulti(self):
2938 """Test listing a wildcarded file"""
2939 self._RunListCmd(['*cb*', '*head*'],
2940 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2941
2942 def testListCmdEmpty(self):
2943 """Test listing a wildcarded file"""
2944 self._RunListCmd(['nothing'], [])
2945
2946 def testListCmdPath(self):
2947 """Test listing the files in a sub-entry of a section"""
2948 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2949
Simon Glass4c613bf2019-07-08 14:25:50 -06002950 def _RunExtractCmd(self, entry_name, decomp=True):
2951 """Extract an entry from an image
2952
2953 Args:
2954 entry_name: Entry name to extract
2955 decomp: True to decompress the data if compressed, False to leave
2956 it in its raw uncompressed format
2957
2958 Returns:
2959 data from entry
2960 """
2961 self._CheckLz4()
2962 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002963 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002964 return control.ReadEntry(image_fname, entry_name, decomp)
2965
2966 def testExtractSimple(self):
2967 """Test extracting a single file"""
2968 data = self._RunExtractCmd('u-boot')
2969 self.assertEqual(U_BOOT_DATA, data)
2970
Simon Glass980a2842019-07-08 14:25:52 -06002971 def testExtractSection(self):
2972 """Test extracting the files in a section"""
2973 data = self._RunExtractCmd('section')
2974 cbfs_data = data[:0x400]
2975 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002976 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002977 dtb_data = data[0x400:]
2978 dtb = self._decompress(dtb_data)
2979 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2980
2981 def testExtractCompressed(self):
2982 """Test extracting compressed data"""
2983 data = self._RunExtractCmd('section/u-boot-dtb')
2984 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2985
2986 def testExtractRaw(self):
2987 """Test extracting compressed data without decompressing it"""
2988 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2989 dtb = self._decompress(data)
2990 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2991
2992 def testExtractCbfs(self):
2993 """Test extracting CBFS data"""
2994 data = self._RunExtractCmd('section/cbfs/u-boot')
2995 self.assertEqual(U_BOOT_DATA, data)
2996
2997 def testExtractCbfsCompressed(self):
2998 """Test extracting CBFS compressed data"""
2999 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
3000 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3001
3002 def testExtractCbfsRaw(self):
3003 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003004 bintool = self.comp_bintools['lzma_alone']
3005 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06003006 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003007 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06003008 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3009
Simon Glass4c613bf2019-07-08 14:25:50 -06003010 def testExtractBadEntry(self):
3011 """Test extracting a bad section path"""
3012 with self.assertRaises(ValueError) as e:
3013 self._RunExtractCmd('section/does-not-exist')
3014 self.assertIn("Entry 'does-not-exist' not found in '/section'",
3015 str(e.exception))
3016
3017 def testExtractMissingFile(self):
3018 """Test extracting file that does not exist"""
3019 with self.assertRaises(IOError) as e:
3020 control.ReadEntry('missing-file', 'name')
3021
3022 def testExtractBadFile(self):
3023 """Test extracting an invalid file"""
3024 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07003025 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06003026 with self.assertRaises(ValueError) as e:
3027 control.ReadEntry(fname, 'name')
3028
Simon Glass980a2842019-07-08 14:25:52 -06003029 def testExtractCmd(self):
3030 """Test extracting a file fron an image on the command line"""
3031 self._CheckLz4()
3032 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06003033 fname = os.path.join(self._indir, 'output.extact')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003034 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06003035 try:
3036 tmpdir, updated_fname = self._SetupImageInTmpdir()
3037 with test_util.capture_sys_output() as (stdout, stderr):
3038 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3039 '-f', fname)
3040 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003041 if tmpdir:
3042 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07003043 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003044 self.assertEqual(U_BOOT_DATA, data)
3045
3046 def testExtractOneEntry(self):
3047 """Test extracting a single entry fron an image """
3048 self._CheckLz4()
3049 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003050 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003051 fname = os.path.join(self._indir, 'output.extact')
3052 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003053 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003054 self.assertEqual(U_BOOT_DATA, data)
3055
3056 def _CheckExtractOutput(self, decomp):
3057 """Helper to test file output with and without decompression
3058
3059 Args:
3060 decomp: True to decompress entry data, False to output it raw
3061 """
3062 def _CheckPresent(entry_path, expect_data, expect_size=None):
3063 """Check and remove expected file
3064
3065 This checks the data/size of a file and removes the file both from
3066 the outfiles set and from the output directory. Once all files are
3067 processed, both the set and directory should be empty.
3068
3069 Args:
3070 entry_path: Entry path
3071 expect_data: Data to expect in file, or None to skip check
3072 expect_size: Size of data to expect in file, or None to skip
3073 """
3074 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003075 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003076 os.remove(path)
3077 if expect_data:
3078 self.assertEqual(expect_data, data)
3079 elif expect_size:
3080 self.assertEqual(expect_size, len(data))
3081 outfiles.remove(path)
3082
3083 def _CheckDirPresent(name):
3084 """Remove expected directory
3085
3086 This gives an error if the directory does not exist as expected
3087
3088 Args:
3089 name: Name of directory to remove
3090 """
3091 path = os.path.join(outdir, name)
3092 os.rmdir(path)
3093
3094 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003095 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003096 outdir = os.path.join(self._indir, 'extract')
3097 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3098
3099 # Create a set of all file that were output (should be 9)
3100 outfiles = set()
3101 for root, dirs, files in os.walk(outdir):
3102 outfiles |= set([os.path.join(root, fname) for fname in files])
3103 self.assertEqual(9, len(outfiles))
3104 self.assertEqual(9, len(einfos))
3105
3106 image = control.images['image']
3107 entries = image.GetEntries()
3108
3109 # Check the 9 files in various ways
3110 section = entries['section']
3111 section_entries = section.GetEntries()
3112 cbfs_entries = section_entries['cbfs'].GetEntries()
3113 _CheckPresent('u-boot', U_BOOT_DATA)
3114 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3115 dtb_len = EXTRACT_DTB_SIZE
3116 if not decomp:
3117 dtb_len = cbfs_entries['u-boot-dtb'].size
3118 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3119 if not decomp:
3120 dtb_len = section_entries['u-boot-dtb'].size
3121 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3122
3123 fdtmap = entries['fdtmap']
3124 _CheckPresent('fdtmap', fdtmap.data)
3125 hdr = entries['image-header']
3126 _CheckPresent('image-header', hdr.data)
3127
3128 _CheckPresent('section/root', section.data)
3129 cbfs = section_entries['cbfs']
3130 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003131 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003132 _CheckPresent('root', data)
3133
3134 # There should be no files left. Remove all the directories to check.
3135 # If there are any files/dirs remaining, one of these checks will fail.
3136 self.assertEqual(0, len(outfiles))
3137 _CheckDirPresent('section/cbfs')
3138 _CheckDirPresent('section')
3139 _CheckDirPresent('')
3140 self.assertFalse(os.path.exists(outdir))
3141
3142 def testExtractAllEntries(self):
3143 """Test extracting all entries"""
3144 self._CheckLz4()
3145 self._CheckExtractOutput(decomp=True)
3146
3147 def testExtractAllEntriesRaw(self):
3148 """Test extracting all entries without decompressing them"""
3149 self._CheckLz4()
3150 self._CheckExtractOutput(decomp=False)
3151
3152 def testExtractSelectedEntries(self):
3153 """Test extracting some entries"""
3154 self._CheckLz4()
3155 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003156 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003157 outdir = os.path.join(self._indir, 'extract')
3158 einfos = control.ExtractEntries(image_fname, None, outdir,
3159 ['*cb*', '*head*'])
3160
3161 # File output is tested by testExtractAllEntries(), so just check that
3162 # the expected entries are selected
3163 names = [einfo.name for einfo in einfos]
3164 self.assertEqual(names,
3165 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3166
3167 def testExtractNoEntryPaths(self):
3168 """Test extracting some entries"""
3169 self._CheckLz4()
3170 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003171 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003172 with self.assertRaises(ValueError) as e:
3173 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003174 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003175 str(e.exception))
3176
3177 def testExtractTooManyEntryPaths(self):
3178 """Test extracting some entries"""
3179 self._CheckLz4()
3180 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003181 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003182 with self.assertRaises(ValueError) as e:
3183 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003184 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003185 str(e.exception))
3186
Simon Glass52d06212019-07-08 14:25:53 -06003187 def testPackAlignSection(self):
3188 """Test that sections can have alignment"""
3189 self._DoReadFile('131_pack_align_section.dts')
3190
3191 self.assertIn('image', control.images)
3192 image = control.images['image']
3193 entries = image.GetEntries()
3194 self.assertEqual(3, len(entries))
3195
3196 # First u-boot
3197 self.assertIn('u-boot', entries)
3198 entry = entries['u-boot']
3199 self.assertEqual(0, entry.offset)
3200 self.assertEqual(0, entry.image_pos)
3201 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3202 self.assertEqual(len(U_BOOT_DATA), entry.size)
3203
3204 # Section0
3205 self.assertIn('section0', entries)
3206 section0 = entries['section0']
3207 self.assertEqual(0x10, section0.offset)
3208 self.assertEqual(0x10, section0.image_pos)
3209 self.assertEqual(len(U_BOOT_DATA), section0.size)
3210
3211 # Second u-boot
3212 section_entries = section0.GetEntries()
3213 self.assertIn('u-boot', section_entries)
3214 entry = section_entries['u-boot']
3215 self.assertEqual(0, entry.offset)
3216 self.assertEqual(0x10, entry.image_pos)
3217 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3218 self.assertEqual(len(U_BOOT_DATA), entry.size)
3219
3220 # Section1
3221 self.assertIn('section1', entries)
3222 section1 = entries['section1']
3223 self.assertEqual(0x14, section1.offset)
3224 self.assertEqual(0x14, section1.image_pos)
3225 self.assertEqual(0x20, section1.size)
3226
3227 # Second u-boot
3228 section_entries = section1.GetEntries()
3229 self.assertIn('u-boot', section_entries)
3230 entry = section_entries['u-boot']
3231 self.assertEqual(0, entry.offset)
3232 self.assertEqual(0x14, entry.image_pos)
3233 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3234 self.assertEqual(len(U_BOOT_DATA), entry.size)
3235
3236 # Section2
3237 self.assertIn('section2', section_entries)
3238 section2 = section_entries['section2']
3239 self.assertEqual(0x4, section2.offset)
3240 self.assertEqual(0x18, section2.image_pos)
3241 self.assertEqual(4, section2.size)
3242
3243 # Third u-boot
3244 section_entries = section2.GetEntries()
3245 self.assertIn('u-boot', section_entries)
3246 entry = section_entries['u-boot']
3247 self.assertEqual(0, entry.offset)
3248 self.assertEqual(0x18, entry.image_pos)
3249 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3250 self.assertEqual(len(U_BOOT_DATA), entry.size)
3251
Simon Glassf8a54bc2019-07-20 12:23:56 -06003252 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3253 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003254 """Replace an entry in an image
3255
3256 This writes the entry data to update it, then opens the updated file and
3257 returns the value that it now finds there.
3258
3259 Args:
3260 entry_name: Entry name to replace
3261 data: Data to replace it with
3262 decomp: True to compress the data if needed, False if data is
3263 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003264 allow_resize: True to allow entries to change size, False to raise
3265 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003266
3267 Returns:
3268 Tuple:
3269 data from entry
3270 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003271 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003272 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003273 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003274 update_dtb=True)[1]
3275
3276 self.assertIn('image', control.images)
3277 image = control.images['image']
3278 entries = image.GetEntries()
3279 orig_dtb_data = entries['u-boot-dtb'].data
3280 orig_fdtmap_data = entries['fdtmap'].data
3281
Simon Glass80025522022-01-29 14:14:04 -07003282 image_fname = tools.get_output_filename('image.bin')
3283 updated_fname = tools.get_output_filename('image-updated.bin')
3284 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003285 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3286 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003287 data = control.ReadEntry(updated_fname, entry_name, decomp)
3288
Simon Glassf8a54bc2019-07-20 12:23:56 -06003289 # The DT data should not change unless resized:
3290 if not allow_resize:
3291 new_dtb_data = entries['u-boot-dtb'].data
3292 self.assertEqual(new_dtb_data, orig_dtb_data)
3293 new_fdtmap_data = entries['fdtmap'].data
3294 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003295
Simon Glassf8a54bc2019-07-20 12:23:56 -06003296 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003297
3298 def testReplaceSimple(self):
3299 """Test replacing a single file"""
3300 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003301 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3302 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003303 self.assertEqual(expected, data)
3304
3305 # Test that the state looks right. There should be an FDT for the fdtmap
3306 # that we jsut read back in, and it should match what we find in the
3307 # 'control' tables. Checking for an FDT that does not exist should
3308 # return None.
3309 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003310 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003311 self.assertEqual(expected_fdtmap, fdtmap)
3312
3313 dtb = state.GetFdtForEtype('fdtmap')
3314 self.assertEqual(dtb.GetContents(), fdtmap)
3315
3316 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3317 self.assertIsNone(missing_path)
3318 self.assertIsNone(missing_fdtmap)
3319
3320 missing_dtb = state.GetFdtForEtype('missing')
3321 self.assertIsNone(missing_dtb)
3322
3323 self.assertEqual('/binman', state.fdt_path_prefix)
3324
3325 def testReplaceResizeFail(self):
3326 """Test replacing a file by something larger"""
3327 expected = U_BOOT_DATA + b'x'
3328 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003329 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3330 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003331 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3332 str(e.exception))
3333
3334 def testReplaceMulti(self):
3335 """Test replacing entry data where multiple images are generated"""
3336 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3337 update_dtb=True)[0]
3338 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003339 updated_fname = tools.get_output_filename('image-updated.bin')
3340 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003341 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003342 control.WriteEntry(updated_fname, entry_name, expected,
3343 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003344 data = control.ReadEntry(updated_fname, entry_name)
3345 self.assertEqual(expected, data)
3346
3347 # Check the state looks right.
3348 self.assertEqual('/binman/image', state.fdt_path_prefix)
3349
3350 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003351 image_fname = tools.get_output_filename('first-image.bin')
3352 updated_fname = tools.get_output_filename('first-updated.bin')
3353 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003354 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003355 control.WriteEntry(updated_fname, entry_name, expected,
3356 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003357 data = control.ReadEntry(updated_fname, entry_name)
3358 self.assertEqual(expected, data)
3359
3360 # Check the state looks right.
3361 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003362
Simon Glassfb30e292019-07-20 12:23:51 -06003363 def testUpdateFdtAllRepack(self):
3364 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003365 self._SetupSplElf()
3366 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003367 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3368 SECTION_SIZE = 0x300
3369 DTB_SIZE = 602
3370 FDTMAP_SIZE = 608
3371 base_expected = {
3372 'offset': 0,
3373 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3374 'image-pos': 0,
3375 'section:offset': 0,
3376 'section:size': SECTION_SIZE,
3377 'section:image-pos': 0,
3378 'section/u-boot-dtb:offset': 4,
3379 'section/u-boot-dtb:size': 636,
3380 'section/u-boot-dtb:image-pos': 4,
3381 'u-boot-spl-dtb:offset': SECTION_SIZE,
3382 'u-boot-spl-dtb:size': DTB_SIZE,
3383 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3384 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3385 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3386 'u-boot-tpl-dtb:size': DTB_SIZE,
3387 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3388 'fdtmap:size': FDTMAP_SIZE,
3389 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3390 }
3391 main_expected = {
3392 'section:orig-size': SECTION_SIZE,
3393 'section/u-boot-dtb:orig-offset': 4,
3394 }
3395
3396 # We expect three device-tree files in the output, with the first one
3397 # within a fixed-size section.
3398 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3399 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3400 # main U-Boot tree. All three should have the same positions and offset
3401 # except that the main tree should include the main_expected properties
3402 start = 4
3403 for item in ['', 'spl', 'tpl', None]:
3404 if item is None:
3405 start += 16 # Move past fdtmap header
3406 dtb = fdt.Fdt.FromData(data[start:])
3407 dtb.Scan()
3408 props = self._GetPropTree(dtb,
3409 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3410 prefix='/' if item is None else '/binman/')
3411 expected = dict(base_expected)
3412 if item:
3413 expected[item] = 0
3414 else:
3415 # Main DTB and fdtdec should include the 'orig-' properties
3416 expected.update(main_expected)
3417 # Helpful for debugging:
3418 #for prop in sorted(props):
3419 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3420 self.assertEqual(expected, props)
3421 if item == '':
3422 start = SECTION_SIZE
3423 else:
3424 start += dtb._fdt_obj.totalsize()
3425
Simon Glass11453762019-07-20 12:23:55 -06003426 def testFdtmapHeaderMiddle(self):
3427 """Test an FDT map in the middle of an image when it should be at end"""
3428 with self.assertRaises(ValueError) as e:
3429 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3430 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3431 str(e.exception))
3432
3433 def testFdtmapHeaderStartBad(self):
3434 """Test an FDT map in middle of an image when it should be at start"""
3435 with self.assertRaises(ValueError) as e:
3436 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3437 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3438 str(e.exception))
3439
3440 def testFdtmapHeaderEndBad(self):
3441 """Test an FDT map at the start of an image when it should be at end"""
3442 with self.assertRaises(ValueError) as e:
3443 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3444 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3445 str(e.exception))
3446
3447 def testFdtmapHeaderNoSize(self):
3448 """Test an image header at the end of an image with undefined size"""
3449 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3450
Simon Glassf8a54bc2019-07-20 12:23:56 -06003451 def testReplaceResize(self):
3452 """Test replacing a single file in an entry with a larger file"""
3453 expected = U_BOOT_DATA + b'x'
3454 data, _, image = self._RunReplaceCmd('u-boot', expected,
3455 dts='139_replace_repack.dts')
3456 self.assertEqual(expected, data)
3457
3458 entries = image.GetEntries()
3459 dtb_data = entries['u-boot-dtb'].data
3460 dtb = fdt.Fdt.FromData(dtb_data)
3461 dtb.Scan()
3462
3463 # The u-boot section should now be larger in the dtb
3464 node = dtb.GetNode('/binman/u-boot')
3465 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3466
3467 # Same for the fdtmap
3468 fdata = entries['fdtmap'].data
3469 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3470 fdtb.Scan()
3471 fnode = fdtb.GetNode('/u-boot')
3472 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3473
3474 def testReplaceResizeNoRepack(self):
3475 """Test replacing an entry with a larger file when not allowed"""
3476 expected = U_BOOT_DATA + b'x'
3477 with self.assertRaises(ValueError) as e:
3478 self._RunReplaceCmd('u-boot', expected)
3479 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3480 str(e.exception))
3481
Simon Glass9d8ee322019-07-20 12:23:58 -06003482 def testEntryShrink(self):
3483 """Test contracting an entry after it is packed"""
3484 try:
3485 state.SetAllowEntryContraction(True)
3486 data = self._DoReadFileDtb('140_entry_shrink.dts',
3487 update_dtb=True)[0]
3488 finally:
3489 state.SetAllowEntryContraction(False)
3490 self.assertEqual(b'a', data[:1])
3491 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3492 self.assertEqual(b'a', data[-1:])
3493
3494 def testEntryShrinkFail(self):
3495 """Test not being allowed to contract an entry after it is packed"""
3496 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3497
3498 # In this case there is a spare byte at the end of the data. The size of
3499 # the contents is only 1 byte but we still have the size before it
3500 # shrunk.
3501 self.assertEqual(b'a\0', data[:2])
3502 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3503 self.assertEqual(b'a\0', data[-2:])
3504
Simon Glass70e32982019-07-20 12:24:01 -06003505 def testDescriptorOffset(self):
3506 """Test that the Intel descriptor is always placed at at the start"""
3507 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3508 image = control.images['image']
3509 entries = image.GetEntries()
3510 desc = entries['intel-descriptor']
3511 self.assertEqual(0xff800000, desc.offset);
3512 self.assertEqual(0xff800000, desc.image_pos);
3513
Simon Glass37fdd142019-07-20 12:24:06 -06003514 def testReplaceCbfs(self):
3515 """Test replacing a single file in CBFS without changing the size"""
3516 self._CheckLz4()
3517 expected = b'x' * len(U_BOOT_DATA)
3518 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003519 updated_fname = tools.get_output_filename('image-updated.bin')
3520 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003521 entry_name = 'section/cbfs/u-boot'
3522 control.WriteEntry(updated_fname, entry_name, expected,
3523 allow_resize=True)
3524 data = control.ReadEntry(updated_fname, entry_name)
3525 self.assertEqual(expected, data)
3526
3527 def testReplaceResizeCbfs(self):
3528 """Test replacing a single file in CBFS with one of a different size"""
3529 self._CheckLz4()
3530 expected = U_BOOT_DATA + b'x'
3531 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003532 updated_fname = tools.get_output_filename('image-updated.bin')
3533 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003534 entry_name = 'section/cbfs/u-boot'
3535 control.WriteEntry(updated_fname, entry_name, expected,
3536 allow_resize=True)
3537 data = control.ReadEntry(updated_fname, entry_name)
3538 self.assertEqual(expected, data)
3539
Simon Glass30033c22019-07-20 12:24:15 -06003540 def _SetupForReplace(self):
3541 """Set up some files to use to replace entries
3542
3543 This generates an image, copies it to a new file, extracts all the files
3544 in it and updates some of them
3545
3546 Returns:
3547 List
3548 Image filename
3549 Output directory
3550 Expected values for updated entries, each a string
3551 """
3552 data = self._DoReadFileRealDtb('143_replace_all.dts')
3553
Simon Glass80025522022-01-29 14:14:04 -07003554 updated_fname = tools.get_output_filename('image-updated.bin')
3555 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003556
3557 outdir = os.path.join(self._indir, 'extract')
3558 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3559
3560 expected1 = b'x' + U_BOOT_DATA + b'y'
3561 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003562 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003563
3564 expected2 = b'a' + U_BOOT_DATA + b'b'
3565 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003566 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003567
3568 expected_text = b'not the same text'
3569 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003570 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003571
3572 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3573 dtb = fdt.FdtScan(dtb_fname)
3574 node = dtb.GetNode('/binman/text')
3575 node.AddString('my-property', 'the value')
3576 dtb.Sync(auto_resize=True)
3577 dtb.Flush()
3578
3579 return updated_fname, outdir, expected1, expected2, expected_text
3580
3581 def _CheckReplaceMultiple(self, entry_paths):
3582 """Handle replacing the contents of multiple entries
3583
3584 Args:
3585 entry_paths: List of entry paths to replace
3586
3587 Returns:
3588 List
3589 Dict of entries in the image:
3590 key: Entry name
3591 Value: Entry object
3592 Expected values for updated entries, each a string
3593 """
3594 updated_fname, outdir, expected1, expected2, expected_text = (
3595 self._SetupForReplace())
3596 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3597
3598 image = Image.FromFile(updated_fname)
3599 image.LoadData()
3600 return image.GetEntries(), expected1, expected2, expected_text
3601
3602 def testReplaceAll(self):
3603 """Test replacing the contents of all entries"""
3604 entries, expected1, expected2, expected_text = (
3605 self._CheckReplaceMultiple([]))
3606 data = entries['u-boot'].data
3607 self.assertEqual(expected1, data)
3608
3609 data = entries['u-boot2'].data
3610 self.assertEqual(expected2, data)
3611
3612 data = entries['text'].data
3613 self.assertEqual(expected_text, data)
3614
3615 # Check that the device tree is updated
3616 data = entries['u-boot-dtb'].data
3617 dtb = fdt.Fdt.FromData(data)
3618 dtb.Scan()
3619 node = dtb.GetNode('/binman/text')
3620 self.assertEqual('the value', node.props['my-property'].value)
3621
3622 def testReplaceSome(self):
3623 """Test replacing the contents of a few entries"""
3624 entries, expected1, expected2, expected_text = (
3625 self._CheckReplaceMultiple(['u-boot2', 'text']))
3626
3627 # This one should not change
3628 data = entries['u-boot'].data
3629 self.assertEqual(U_BOOT_DATA, data)
3630
3631 data = entries['u-boot2'].data
3632 self.assertEqual(expected2, data)
3633
3634 data = entries['text'].data
3635 self.assertEqual(expected_text, data)
3636
3637 def testReplaceCmd(self):
3638 """Test replacing a file fron an image on the command line"""
3639 self._DoReadFileRealDtb('143_replace_all.dts')
3640
3641 try:
3642 tmpdir, updated_fname = self._SetupImageInTmpdir()
3643
3644 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3645 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003646 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003647
3648 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003649 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003650 self.assertEqual(expected, data[:len(expected)])
3651 map_fname = os.path.join(tmpdir, 'image-updated.map')
3652 self.assertFalse(os.path.exists(map_fname))
3653 finally:
3654 shutil.rmtree(tmpdir)
3655
3656 def testReplaceCmdSome(self):
3657 """Test replacing some files fron an image on the command line"""
3658 updated_fname, outdir, expected1, expected2, expected_text = (
3659 self._SetupForReplace())
3660
3661 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3662 'u-boot2', 'text')
3663
Simon Glass80025522022-01-29 14:14:04 -07003664 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003665 image = Image.FromFile(updated_fname)
3666 image.LoadData()
3667 entries = image.GetEntries()
3668
3669 # This one should not change
3670 data = entries['u-boot'].data
3671 self.assertEqual(U_BOOT_DATA, data)
3672
3673 data = entries['u-boot2'].data
3674 self.assertEqual(expected2, data)
3675
3676 data = entries['text'].data
3677 self.assertEqual(expected_text, data)
3678
3679 def testReplaceMissing(self):
3680 """Test replacing entries where the file is missing"""
3681 updated_fname, outdir, expected1, expected2, expected_text = (
3682 self._SetupForReplace())
3683
3684 # Remove one of the files, to generate a warning
3685 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3686 os.remove(u_boot_fname1)
3687
3688 with test_util.capture_sys_output() as (stdout, stderr):
3689 control.ReplaceEntries(updated_fname, None, outdir, [])
3690 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003691 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003692
3693 def testReplaceCmdMap(self):
3694 """Test replacing a file fron an image on the command line"""
3695 self._DoReadFileRealDtb('143_replace_all.dts')
3696
3697 try:
3698 tmpdir, updated_fname = self._SetupImageInTmpdir()
3699
3700 fname = os.path.join(self._indir, 'update-u-boot.bin')
3701 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003702 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003703
3704 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3705 '-f', fname, '-m')
3706 map_fname = os.path.join(tmpdir, 'image-updated.map')
3707 self.assertTrue(os.path.exists(map_fname))
3708 finally:
3709 shutil.rmtree(tmpdir)
3710
3711 def testReplaceNoEntryPaths(self):
3712 """Test replacing an entry without an entry path"""
3713 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003714 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003715 with self.assertRaises(ValueError) as e:
3716 control.ReplaceEntries(image_fname, 'fname', None, [])
3717 self.assertIn('Must specify an entry path to read with -f',
3718 str(e.exception))
3719
3720 def testReplaceTooManyEntryPaths(self):
3721 """Test extracting some entries"""
3722 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003723 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003724 with self.assertRaises(ValueError) as e:
3725 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3726 self.assertIn('Must specify exactly one entry path to write with -f',
3727 str(e.exception))
3728
Simon Glass0b074d62019-08-24 07:22:48 -06003729 def testPackReset16(self):
3730 """Test that an image with an x86 reset16 region can be created"""
3731 data = self._DoReadFile('144_x86_reset16.dts')
3732 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3733
3734 def testPackReset16Spl(self):
3735 """Test that an image with an x86 reset16-spl region can be created"""
3736 data = self._DoReadFile('145_x86_reset16_spl.dts')
3737 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3738
3739 def testPackReset16Tpl(self):
3740 """Test that an image with an x86 reset16-tpl region can be created"""
3741 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3742 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3743
Simon Glass232f90c2019-08-24 07:22:50 -06003744 def testPackIntelFit(self):
3745 """Test that an image with an Intel FIT and pointer can be created"""
3746 data = self._DoReadFile('147_intel_fit.dts')
3747 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3748 fit = data[16:32];
3749 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3750 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3751
3752 image = control.images['image']
3753 entries = image.GetEntries()
3754 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3755 self.assertEqual(expected_ptr, ptr)
3756
3757 def testPackIntelFitMissing(self):
3758 """Test detection of a FIT pointer with not FIT region"""
3759 with self.assertRaises(ValueError) as e:
3760 self._DoReadFile('148_intel_fit_missing.dts')
3761 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3762 str(e.exception))
3763
Simon Glass72555fa2019-11-06 17:22:44 -07003764 def _CheckSymbolsTplSection(self, dts, expected_vals):
3765 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003766 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003767 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003768 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003769 self.assertEqual(expected1, data[:upto1])
3770
3771 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003772 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003773 self.assertEqual(expected2, data[upto1:upto2])
3774
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003775 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003776 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003777 self.assertEqual(expected3, data[upto2:upto3])
3778
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003779 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003780 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3781
3782 def testSymbolsTplSection(self):
3783 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3784 self._SetupSplElf('u_boot_binman_syms')
3785 self._SetupTplElf('u_boot_binman_syms')
3786 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003787 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003788
3789 def testSymbolsTplSectionX86(self):
3790 """Test binman can assign symbols in a section with end-at-4gb"""
3791 self._SetupSplElf('u_boot_binman_syms_x86')
3792 self._SetupTplElf('u_boot_binman_syms_x86')
3793 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003794 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003795 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003796
Simon Glass98c59572019-08-24 07:23:03 -06003797 def testPackX86RomIfwiSectiom(self):
3798 """Test that a section can be placed in an IFWI region"""
3799 self._SetupIfwi('fitimage.bin')
3800 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3801 self._CheckIfwi(data)
3802
Simon Glassba7985d2019-08-24 07:23:07 -06003803 def testPackFspM(self):
3804 """Test that an image with a FSP memory-init binary can be created"""
3805 data = self._DoReadFile('152_intel_fsp_m.dts')
3806 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3807
Simon Glass4d9086d2019-10-20 21:31:35 -06003808 def testPackFspS(self):
3809 """Test that an image with a FSP silicon-init binary can be created"""
3810 data = self._DoReadFile('153_intel_fsp_s.dts')
3811 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003812
Simon Glass9ea87b22019-10-20 21:31:36 -06003813 def testPackFspT(self):
3814 """Test that an image with a FSP temp-ram-init binary can be created"""
3815 data = self._DoReadFile('154_intel_fsp_t.dts')
3816 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3817
Simon Glass48f3aad2020-07-09 18:39:31 -06003818 def testMkimage(self):
3819 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003820 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003821 data = self._DoReadFile('156_mkimage.dts')
3822
3823 # Just check that the data appears in the file somewhere
3824 self.assertIn(U_BOOT_SPL_DATA, data)
3825
Simon Glass66152ce2022-01-09 20:14:09 -07003826 def testMkimageMissing(self):
3827 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003828 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003829 with test_util.capture_sys_output() as (_, stderr):
3830 self._DoTestFile('156_mkimage.dts',
3831 force_missing_bintools='mkimage')
3832 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003833 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003834
Simon Glass5e560182020-07-09 18:39:36 -06003835 def testExtblob(self):
3836 """Test an image with an external blob"""
3837 data = self._DoReadFile('157_blob_ext.dts')
3838 self.assertEqual(REFCODE_DATA, data)
3839
3840 def testExtblobMissing(self):
3841 """Test an image with a missing external blob"""
3842 with self.assertRaises(ValueError) as e:
3843 self._DoReadFile('158_blob_ext_missing.dts')
3844 self.assertIn("Filename 'missing-file' not found in input path",
3845 str(e.exception))
3846
Simon Glass5d94cc62020-07-09 18:39:38 -06003847 def testExtblobMissingOk(self):
3848 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003849 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003850 ret = self._DoTestFile('158_blob_ext_missing.dts',
3851 allow_missing=True)
3852 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003853 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003854 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003855 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003856 self.assertIn('Some images are invalid', err)
3857
3858 def testExtblobMissingOkFlag(self):
3859 """Test an image with an missing external blob allowed with -W"""
3860 with test_util.capture_sys_output() as (stdout, stderr):
3861 ret = self._DoTestFile('158_blob_ext_missing.dts',
3862 allow_missing=True, ignore_missing=True)
3863 self.assertEqual(0, ret)
3864 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003865 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003866 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003867 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003868
3869 def testExtblobMissingOkSect(self):
3870 """Test an image with an missing external blob that is allowed"""
3871 with test_util.capture_sys_output() as (stdout, stderr):
3872 self._DoTestFile('159_blob_ext_missing_sect.dts',
3873 allow_missing=True)
3874 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003875 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003876
Simon Glasse88cef92020-07-09 18:39:41 -06003877 def testPackX86RomMeMissingDesc(self):
3878 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003879 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003880 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003881 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003882 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003883
3884 def testPackX86RomMissingIfwi(self):
3885 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3886 self._SetupIfwi('fitimage.bin')
3887 pathname = os.path.join(self._indir, 'fitimage.bin')
3888 os.remove(pathname)
3889 with test_util.capture_sys_output() as (stdout, stderr):
3890 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3891 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003892 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003893
Simon Glass2a0fa982022-02-11 13:23:21 -07003894 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003895 """Test that zero-size overlapping regions are ignored"""
3896 self._DoTestFile('160_pack_overlap_zero.dts')
3897
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003898 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003899 # The data should be inside the FIT
3900 dtb = fdt.Fdt.FromData(fit_data)
3901 dtb.Scan()
3902 fnode = dtb.GetNode('/images/kernel')
3903 self.assertIn('data', fnode.props)
3904
3905 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003906 tools.write_file(fname, fit_data)
3907 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003908
3909 # Check a few features to make sure the plumbing works. We don't need
3910 # to test the operation of mkimage or dumpimage here. First convert the
3911 # output into a dict where the keys are the fields printed by dumpimage
3912 # and the values are a list of values for each field
3913 lines = out.splitlines()
3914
3915 # Converts "Compression: gzip compressed" into two groups:
3916 # 'Compression' and 'gzip compressed'
3917 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3918 vals = collections.defaultdict(list)
3919 for line in lines:
3920 mat = re_line.match(line)
3921 vals[mat.group(1)].append(mat.group(2))
3922
Brandon Maiera657bc62024-06-04 16:16:05 +00003923 self.assertEqual('FIT description: test-desc', lines[0])
Simon Glass45d556d2020-07-09 18:39:45 -06003924 self.assertIn('Created:', lines[1])
3925 self.assertIn('Image 0 (kernel)', vals)
3926 self.assertIn('Hash value', vals)
3927 data_sizes = vals.get('Data Size')
3928 self.assertIsNotNone(data_sizes)
3929 self.assertEqual(2, len(data_sizes))
3930 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003931 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3932 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3933
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003934 # Check if entry listing correctly omits /images/
3935 image = control.images['image']
3936 fit_entry = image.GetEntries()['fit']
3937 subentries = list(fit_entry.GetEntries().keys())
3938 expected = ['kernel', 'fdt-1']
3939 self.assertEqual(expected, subentries)
3940
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003941 def testSimpleFit(self):
3942 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003943 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003944 data = self._DoReadFile('161_fit.dts')
3945 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3946 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3947 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3948
3949 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3950
3951 def testSimpleFitExpandsSubentries(self):
3952 """Test that FIT images expand their subentries"""
3953 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3954 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3955 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3956 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3957
3958 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003959
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003960 def testSimpleFitImagePos(self):
3961 """Test that we have correct image-pos for FIT subentries"""
3962 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3963 update_dtb=True)
3964 dtb = fdt.Fdt(out_dtb_fname)
3965 dtb.Scan()
3966 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3967
Simon Glassb7bad182022-03-05 20:19:01 -07003968 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003969 self.assertEqual({
3970 'image-pos': 0,
3971 'offset': 0,
3972 'size': 1890,
3973
3974 'u-boot:image-pos': 0,
3975 'u-boot:offset': 0,
3976 'u-boot:size': 4,
3977
3978 'fit:image-pos': 4,
3979 'fit:offset': 4,
3980 'fit:size': 1840,
3981
Simon Glassb7bad182022-03-05 20:19:01 -07003982 'fit/images/kernel:image-pos': 304,
3983 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003984 'fit/images/kernel:size': 4,
3985
Simon Glassb7bad182022-03-05 20:19:01 -07003986 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003987 'fit/images/kernel/u-boot:offset': 0,
3988 'fit/images/kernel/u-boot:size': 4,
3989
Simon Glassb7bad182022-03-05 20:19:01 -07003990 'fit/images/fdt-1:image-pos': 552,
3991 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003992 'fit/images/fdt-1:size': 6,
3993
Simon Glassb7bad182022-03-05 20:19:01 -07003994 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003995 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3996 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3997
3998 'u-boot-nodtb:image-pos': 1844,
3999 'u-boot-nodtb:offset': 1844,
4000 'u-boot-nodtb:size': 46,
4001 }, props)
4002
4003 # Actually check the data is where we think it is
4004 for node, expected in [
4005 ("u-boot", U_BOOT_DATA),
4006 ("fit/images/kernel", U_BOOT_DATA),
4007 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4008 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
4009 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
4010 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4011 ]:
4012 image_pos = props[f"{node}:image-pos"]
4013 size = props[f"{node}:size"]
4014 self.assertEqual(len(expected), size)
4015 self.assertEqual(expected, data[image_pos:image_pos+size])
4016
Simon Glass45d556d2020-07-09 18:39:45 -06004017 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06004018 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06004019 data = self._DoReadFile('162_fit_external.dts')
4020 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
4021
Simon Glass7932c882022-01-09 20:13:39 -07004022 # Size of the external-data region as set up by mkimage
4023 external_data_size = len(U_BOOT_DATA) + 2
4024 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07004025 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07004026 len(U_BOOT_NODTB_DATA))
4027
Simon Glass45d556d2020-07-09 18:39:45 -06004028 # The data should be outside the FIT
4029 dtb = fdt.Fdt.FromData(fit_data)
4030 dtb.Scan()
4031 fnode = dtb.GetNode('/images/kernel')
4032 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07004033 self.assertEqual(len(U_BOOT_DATA),
4034 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4035 fit_pos = 0x400;
4036 self.assertEqual(
4037 fit_pos,
4038 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4039
Brandon Maiera657bc62024-06-04 16:16:05 +00004040 self.assertEqual(expected_size, len(data))
Simon Glass7932c882022-01-09 20:13:39 -07004041 actual_pos = len(U_BOOT_DATA) + fit_pos
4042 self.assertEqual(U_BOOT_DATA + b'aa',
4043 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004044
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004045 def testFitExternalImagePos(self):
4046 """Test that we have correct image-pos for external FIT subentries"""
4047 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4048 update_dtb=True)
4049 dtb = fdt.Fdt(out_dtb_fname)
4050 dtb.Scan()
4051 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4052
4053 self.assertEqual({
4054 'image-pos': 0,
4055 'offset': 0,
4056 'size': 1082,
4057
4058 'u-boot:image-pos': 0,
4059 'u-boot:offset': 0,
4060 'u-boot:size': 4,
4061
4062 'fit:size': 1032,
4063 'fit:offset': 4,
4064 'fit:image-pos': 4,
4065
4066 'fit/images/kernel:size': 4,
4067 'fit/images/kernel:offset': 1024,
4068 'fit/images/kernel:image-pos': 1028,
4069
4070 'fit/images/kernel/u-boot:size': 4,
4071 'fit/images/kernel/u-boot:offset': 0,
4072 'fit/images/kernel/u-boot:image-pos': 1028,
4073
4074 'fit/images/fdt-1:size': 2,
4075 'fit/images/fdt-1:offset': 1028,
4076 'fit/images/fdt-1:image-pos': 1032,
4077
4078 'fit/images/fdt-1/_testing:size': 2,
4079 'fit/images/fdt-1/_testing:offset': 0,
4080 'fit/images/fdt-1/_testing:image-pos': 1032,
4081
4082 'u-boot-nodtb:image-pos': 1036,
4083 'u-boot-nodtb:offset': 1036,
4084 'u-boot-nodtb:size': 46,
4085 }, props)
4086
4087 # Actually check the data is where we think it is
4088 for node, expected in [
4089 ("u-boot", U_BOOT_DATA),
4090 ("fit/images/kernel", U_BOOT_DATA),
4091 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4092 ("fit/images/fdt-1", b'aa'),
4093 ("fit/images/fdt-1/_testing", b'aa'),
4094 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4095 ]:
4096 image_pos = props[f"{node}:image-pos"]
4097 size = props[f"{node}:size"]
4098 self.assertEqual(len(expected), size)
4099 self.assertEqual(expected, data[image_pos:image_pos+size])
4100
Simon Glass66152ce2022-01-09 20:14:09 -07004101 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004102 """Test that binman complains if mkimage is missing"""
4103 with self.assertRaises(ValueError) as e:
4104 self._DoTestFile('162_fit_external.dts',
4105 force_missing_bintools='mkimage')
4106 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4107 str(e.exception))
4108
4109 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004110 """Test that binman still produces a FIT image if mkimage is missing"""
4111 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004112 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004113 force_missing_bintools='mkimage')
4114 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004115 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004116
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004117 def testSectionIgnoreHashSignature(self):
4118 """Test that sections ignore hash, signature nodes for its data"""
4119 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4120 expected = (U_BOOT_DATA + U_BOOT_DATA)
4121 self.assertEqual(expected, data)
4122
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004123 def testPadInSections(self):
4124 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004125 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4126 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004127 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4128 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004129 U_BOOT_DATA)
4130 self.assertEqual(expected, data)
4131
Simon Glassd12599d2020-10-26 17:40:09 -06004132 dtb = fdt.Fdt(out_dtb_fname)
4133 dtb.Scan()
4134 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4135 expected = {
4136 'image-pos': 0,
4137 'offset': 0,
4138 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4139
4140 'section:image-pos': 0,
4141 'section:offset': 0,
4142 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4143
4144 'section/before:image-pos': 0,
4145 'section/before:offset': 0,
4146 'section/before:size': len(U_BOOT_DATA),
4147
4148 'section/u-boot:image-pos': 4,
4149 'section/u-boot:offset': 4,
4150 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4151
4152 'section/after:image-pos': 26,
4153 'section/after:offset': 26,
4154 'section/after:size': len(U_BOOT_DATA),
4155 }
4156 self.assertEqual(expected, props)
4157
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004158 def testFitImageSubentryAlignment(self):
4159 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004160 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004161 entry_args = {
4162 'test-id': TEXT_DATA,
4163 }
4164 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4165 entry_args=entry_args)
4166 dtb = fdt.Fdt.FromData(data)
4167 dtb.Scan()
4168
4169 node = dtb.GetNode('/images/kernel')
4170 data = dtb.GetProps(node)["data"].bytes
4171 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004172 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4173 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004174 self.assertEqual(expected, data)
4175
4176 node = dtb.GetNode('/images/fdt-1')
4177 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004178 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4179 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004180 U_BOOT_DTB_DATA)
4181 self.assertEqual(expected, data)
4182
4183 def testFitExtblobMissingOk(self):
4184 """Test a FIT with a missing external blob that is allowed"""
4185 with test_util.capture_sys_output() as (stdout, stderr):
4186 self._DoTestFile('168_fit_missing_blob.dts',
4187 allow_missing=True)
4188 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004189 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004190
Simon Glass21db0ff2020-09-01 05:13:54 -06004191 def testBlobNamedByArgMissing(self):
4192 """Test handling of a missing entry arg"""
4193 with self.assertRaises(ValueError) as e:
4194 self._DoReadFile('068_blob_named_by_arg.dts')
4195 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4196 str(e.exception))
4197
Simon Glass559c4de2020-09-01 05:13:58 -06004198 def testPackBl31(self):
4199 """Test that an image with an ATF BL31 binary can be created"""
4200 data = self._DoReadFile('169_atf_bl31.dts')
4201 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4202
Samuel Holland9d8cc632020-10-21 21:12:15 -05004203 def testPackScp(self):
4204 """Test that an image with an SCP binary can be created"""
4205 data = self._DoReadFile('172_scp.dts')
4206 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4207
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004208 def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True,
4209 default_dt=None):
Simon Glasscd2783e2024-07-20 11:49:46 +01004210 """Check an image with an FIT with multiple FDT images"""
Simon Glassa435cd12020-09-01 05:13:59 -06004211 def _CheckFdt(seq, expected_data):
4212 """Check the FDT nodes
4213
4214 Args:
4215 seq: Sequence number to check (0 or 1)
4216 expected_data: Expected contents of 'data' property
4217 """
4218 name = 'fdt-%d' % seq
4219 fnode = dtb.GetNode('/images/%s' % name)
4220 self.assertIsNotNone(fnode)
4221 self.assertEqual({'description','type', 'compression', 'data'},
4222 set(fnode.props.keys()))
4223 self.assertEqual(expected_data, fnode.props['data'].bytes)
4224 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4225 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004226 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004227
4228 def _CheckConfig(seq, expected_data):
4229 """Check the configuration nodes
4230
4231 Args:
4232 seq: Sequence number to check (0 or 1)
4233 expected_data: Expected contents of 'data' property
4234 """
4235 cnode = dtb.GetNode('/configurations')
4236 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004237 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004238
4239 name = 'config-%d' % seq
4240 fnode = dtb.GetNode('/configurations/%s' % name)
4241 self.assertIsNotNone(fnode)
4242 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4243 set(fnode.props.keys()))
4244 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4245 fnode.props['description'].value)
4246 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4247
4248 entry_args = {
Simon Glass1032acc2020-09-06 10:39:08 -06004249 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004250 }
Simon Glasscd2783e2024-07-20 11:49:46 +01004251 if use_fdt_list:
4252 entry_args['of-list'] = 'test-fdt1 test-fdt2'
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004253 if default_dt:
4254 entry_args['default-dt'] = default_dt
Simon Glassa435cd12020-09-01 05:13:59 -06004255 data = self._DoReadFileDtb(
Simon Glasscd2783e2024-07-20 11:49:46 +01004256 dts,
Simon Glassa435cd12020-09-01 05:13:59 -06004257 entry_args=entry_args,
4258 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4259 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4260 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4261
4262 dtb = fdt.Fdt.FromData(fit_data)
4263 dtb.Scan()
4264 fnode = dtb.GetNode('/images/kernel')
4265 self.assertIn('data', fnode.props)
4266
4267 # Check all the properties in fdt-1 and fdt-2
4268 _CheckFdt(1, TEST_FDT1_DATA)
4269 _CheckFdt(2, TEST_FDT2_DATA)
4270
4271 # Check configurations
4272 _CheckConfig(1, TEST_FDT1_DATA)
4273 _CheckConfig(2, TEST_FDT2_DATA)
4274
Simon Glasscd2783e2024-07-20 11:49:46 +01004275 def testFitFdt(self):
4276 """Test an image with an FIT with multiple FDT images"""
4277 self.CheckFitFdt()
4278
Simon Glassa435cd12020-09-01 05:13:59 -06004279 def testFitFdtMissingList(self):
4280 """Test handling of a missing 'of-list' entry arg"""
4281 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004282 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004283 self.assertIn("Generator node requires 'of-list' entry argument",
4284 str(e.exception))
4285
4286 def testFitFdtEmptyList(self):
4287 """Test handling of an empty 'of-list' entry arg"""
4288 entry_args = {
4289 'of-list': '',
4290 }
4291 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4292
4293 def testFitFdtMissingProp(self):
4294 """Test handling of a missing 'fit,fdt-list' property"""
4295 with self.assertRaises(ValueError) as e:
4296 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4297 self.assertIn("Generator node requires 'fit,fdt-list' property",
4298 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004299
Simon Glass1032acc2020-09-06 10:39:08 -06004300 def testFitFdtMissing(self):
4301 """Test handling of a missing 'default-dt' entry arg"""
4302 entry_args = {
4303 'of-list': 'test-fdt1 test-fdt2',
4304 }
4305 with self.assertRaises(ValueError) as e:
4306 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004307 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004308 entry_args=entry_args,
4309 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4310 self.assertIn("Generated 'default' node requires default-dt entry argument",
4311 str(e.exception))
4312
4313 def testFitFdtNotInList(self):
4314 """Test handling of a default-dt that is not in the of-list"""
4315 entry_args = {
4316 'of-list': 'test-fdt1 test-fdt2',
4317 'default-dt': 'test-fdt3',
4318 }
4319 with self.assertRaises(ValueError) as e:
4320 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004321 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004322 entry_args=entry_args,
4323 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4324 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4325 str(e.exception))
4326
Simon Glassa820af72020-09-06 10:39:09 -06004327 def testFitExtblobMissingHelp(self):
4328 """Test display of help messages when an external blob is missing"""
4329 control.missing_blob_help = control._ReadMissingBlobHelp()
4330 control.missing_blob_help['wibble'] = 'Wibble test'
4331 control.missing_blob_help['another'] = 'Another test'
4332 with test_util.capture_sys_output() as (stdout, stderr):
4333 self._DoTestFile('168_fit_missing_blob.dts',
4334 allow_missing=True)
4335 err = stderr.getvalue()
4336
4337 # We can get the tag from the name, the type or the missing-msg
4338 # property. Check all three.
4339 self.assertIn('You may need to build ARM Trusted', err)
4340 self.assertIn('Wibble test', err)
4341 self.assertIn('Another test', err)
4342
Simon Glass6f1f4d42020-09-06 10:35:32 -06004343 def testMissingBlob(self):
4344 """Test handling of a blob containing a missing file"""
4345 with self.assertRaises(ValueError) as e:
4346 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4347 self.assertIn("Filename 'missing' not found in input path",
4348 str(e.exception))
4349
Simon Glassa0729502020-09-06 10:35:33 -06004350 def testEnvironment(self):
4351 """Test adding a U-Boot environment"""
4352 data = self._DoReadFile('174_env.dts')
4353 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4354 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4355 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4356 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4357 env)
4358
4359 def testEnvironmentNoSize(self):
4360 """Test that a missing 'size' property is detected"""
4361 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004362 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004363 self.assertIn("'u-boot-env' entry must have a size property",
4364 str(e.exception))
4365
4366 def testEnvironmentTooSmall(self):
4367 """Test handling of an environment that does not fit"""
4368 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004369 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004370
4371 # checksum, start byte, environment with \0 terminator, final \0
4372 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4373 short = need - 0x8
4374 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4375 str(e.exception))
4376
Simon Glassd1fdf752020-10-26 17:40:01 -06004377 def testSkipAtStart(self):
4378 """Test handling of skip-at-start section"""
4379 data = self._DoReadFile('177_skip_at_start.dts')
4380 self.assertEqual(U_BOOT_DATA, data)
4381
4382 image = control.images['image']
4383 entries = image.GetEntries()
4384 section = entries['section']
4385 self.assertEqual(0, section.offset)
4386 self.assertEqual(len(U_BOOT_DATA), section.size)
4387 self.assertEqual(U_BOOT_DATA, section.GetData())
4388
4389 entry = section.GetEntries()['u-boot']
4390 self.assertEqual(16, entry.offset)
4391 self.assertEqual(len(U_BOOT_DATA), entry.size)
4392 self.assertEqual(U_BOOT_DATA, entry.data)
4393
4394 def testSkipAtStartPad(self):
4395 """Test handling of skip-at-start section with padded entry"""
4396 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004397 before = tools.get_bytes(0, 8)
4398 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004399 all = before + U_BOOT_DATA + after
4400 self.assertEqual(all, data)
4401
4402 image = control.images['image']
4403 entries = image.GetEntries()
4404 section = entries['section']
4405 self.assertEqual(0, section.offset)
4406 self.assertEqual(len(all), section.size)
4407 self.assertEqual(all, section.GetData())
4408
4409 entry = section.GetEntries()['u-boot']
4410 self.assertEqual(16, entry.offset)
4411 self.assertEqual(len(all), entry.size)
4412 self.assertEqual(U_BOOT_DATA, entry.data)
4413
4414 def testSkipAtStartSectionPad(self):
4415 """Test handling of skip-at-start section with padding"""
4416 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004417 before = tools.get_bytes(0, 8)
4418 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004419 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004420 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004421
4422 image = control.images['image']
4423 entries = image.GetEntries()
4424 section = entries['section']
4425 self.assertEqual(0, section.offset)
4426 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004427 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004428 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004429
4430 entry = section.GetEntries()['u-boot']
4431 self.assertEqual(16, entry.offset)
4432 self.assertEqual(len(U_BOOT_DATA), entry.size)
4433 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004434
Simon Glassbb395742020-10-26 17:40:14 -06004435 def testSectionPad(self):
4436 """Testing padding with sections"""
4437 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004438 expected = (tools.get_bytes(ord('&'), 3) +
4439 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004440 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004441 tools.get_bytes(ord('!'), 1) +
4442 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004443 self.assertEqual(expected, data)
4444
4445 def testSectionAlign(self):
4446 """Testing alignment with sections"""
4447 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4448 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004449 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004450 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004451 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004452 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004453 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4454 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004455 self.assertEqual(expected, data)
4456
Simon Glassd92c8362020-10-26 17:40:25 -06004457 def testCompressImage(self):
4458 """Test compression of the entire image"""
4459 self._CheckLz4()
4460 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4461 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4462 dtb = fdt.Fdt(out_dtb_fname)
4463 dtb.Scan()
4464 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4465 'uncomp-size'])
4466 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004467 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004468
4469 # Do a sanity check on various fields
4470 image = control.images['image']
4471 entries = image.GetEntries()
4472 self.assertEqual(2, len(entries))
4473
4474 entry = entries['blob']
4475 self.assertEqual(COMPRESS_DATA, entry.data)
4476 self.assertEqual(len(COMPRESS_DATA), entry.size)
4477
4478 entry = entries['u-boot']
4479 self.assertEqual(U_BOOT_DATA, entry.data)
4480 self.assertEqual(len(U_BOOT_DATA), entry.size)
4481
4482 self.assertEqual(len(data), image.size)
4483 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4484 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4485 orig = self._decompress(image.data)
4486 self.assertEqual(orig, image.uncomp_data)
4487
4488 expected = {
4489 'blob:offset': 0,
4490 'blob:size': len(COMPRESS_DATA),
4491 'u-boot:offset': len(COMPRESS_DATA),
4492 'u-boot:size': len(U_BOOT_DATA),
4493 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4494 'offset': 0,
4495 'image-pos': 0,
4496 'size': len(data),
4497 }
4498 self.assertEqual(expected, props)
4499
4500 def testCompressImageLess(self):
4501 """Test compression where compression reduces the image size"""
4502 self._CheckLz4()
4503 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4504 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4505 dtb = fdt.Fdt(out_dtb_fname)
4506 dtb.Scan()
4507 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4508 'uncomp-size'])
4509 orig = self._decompress(data)
4510
Brandon Maiera657bc62024-06-04 16:16:05 +00004511 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004512
4513 # Do a sanity check on various fields
4514 image = control.images['image']
4515 entries = image.GetEntries()
4516 self.assertEqual(2, len(entries))
4517
4518 entry = entries['blob']
4519 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4520 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4521
4522 entry = entries['u-boot']
4523 self.assertEqual(U_BOOT_DATA, entry.data)
4524 self.assertEqual(len(U_BOOT_DATA), entry.size)
4525
4526 self.assertEqual(len(data), image.size)
4527 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4528 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4529 image.uncomp_size)
4530 orig = self._decompress(image.data)
4531 self.assertEqual(orig, image.uncomp_data)
4532
4533 expected = {
4534 'blob:offset': 0,
4535 'blob:size': len(COMPRESS_DATA_BIG),
4536 'u-boot:offset': len(COMPRESS_DATA_BIG),
4537 'u-boot:size': len(U_BOOT_DATA),
4538 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4539 'offset': 0,
4540 'image-pos': 0,
4541 'size': len(data),
4542 }
4543 self.assertEqual(expected, props)
4544
4545 def testCompressSectionSize(self):
4546 """Test compression of a section with a fixed size"""
4547 self._CheckLz4()
4548 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4549 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4550 dtb = fdt.Fdt(out_dtb_fname)
4551 dtb.Scan()
4552 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4553 'uncomp-size'])
4554 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004555 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004556 expected = {
4557 'section/blob:offset': 0,
4558 'section/blob:size': len(COMPRESS_DATA),
4559 'section/u-boot:offset': len(COMPRESS_DATA),
4560 'section/u-boot:size': len(U_BOOT_DATA),
4561 'section:offset': 0,
4562 'section:image-pos': 0,
4563 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4564 'section:size': 0x30,
4565 'offset': 0,
4566 'image-pos': 0,
4567 'size': 0x30,
4568 }
4569 self.assertEqual(expected, props)
4570
4571 def testCompressSection(self):
4572 """Test compression of a section with no fixed size"""
4573 self._CheckLz4()
4574 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4575 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4576 dtb = fdt.Fdt(out_dtb_fname)
4577 dtb.Scan()
4578 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4579 'uncomp-size'])
4580 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004581 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004582 expected = {
4583 'section/blob:offset': 0,
4584 'section/blob:size': len(COMPRESS_DATA),
4585 'section/u-boot:offset': len(COMPRESS_DATA),
4586 'section/u-boot:size': len(U_BOOT_DATA),
4587 'section:offset': 0,
4588 'section:image-pos': 0,
4589 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4590 'section:size': len(data),
4591 'offset': 0,
4592 'image-pos': 0,
4593 'size': len(data),
4594 }
4595 self.assertEqual(expected, props)
4596
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004597 def testLz4Missing(self):
4598 """Test that binman still produces an image if lz4 is missing"""
4599 with test_util.capture_sys_output() as (_, stderr):
4600 self._DoTestFile('185_compress_section.dts',
4601 force_missing_bintools='lz4')
4602 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004603 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004604
Simon Glassd92c8362020-10-26 17:40:25 -06004605 def testCompressExtra(self):
4606 """Test compression of a section with no fixed size"""
4607 self._CheckLz4()
4608 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4609 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4610 dtb = fdt.Fdt(out_dtb_fname)
4611 dtb.Scan()
4612 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4613 'uncomp-size'])
4614
4615 base = data[len(U_BOOT_DATA):]
Brandon Maiera657bc62024-06-04 16:16:05 +00004616 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glassd92c8362020-10-26 17:40:25 -06004617 rest = base[len(U_BOOT_DATA):]
4618
4619 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004620 bintool = self.comp_bintools['lz4']
4621 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004622 data1 = rest[:len(expect1)]
4623 section1 = self._decompress(data1)
Brandon Maiera657bc62024-06-04 16:16:05 +00004624 self.assertEqual(expect1, data1)
4625 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glassd92c8362020-10-26 17:40:25 -06004626 rest1 = rest[len(expect1):]
4627
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004628 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004629 data2 = rest1[:len(expect2)]
4630 section2 = self._decompress(data2)
Brandon Maiera657bc62024-06-04 16:16:05 +00004631 self.assertEqual(expect2, data2)
4632 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glassd92c8362020-10-26 17:40:25 -06004633 rest2 = rest1[len(expect2):]
4634
4635 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4636 len(expect2) + len(U_BOOT_DATA))
Brandon Maiera657bc62024-06-04 16:16:05 +00004637 #self.assertEqual(expect_size, len(data))
Simon Glassd92c8362020-10-26 17:40:25 -06004638
Brandon Maiera657bc62024-06-04 16:16:05 +00004639 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glassd92c8362020-10-26 17:40:25 -06004640
4641 self.maxDiff = None
4642 expected = {
4643 'u-boot:offset': 0,
4644 'u-boot:image-pos': 0,
4645 'u-boot:size': len(U_BOOT_DATA),
4646
4647 'base:offset': len(U_BOOT_DATA),
4648 'base:image-pos': len(U_BOOT_DATA),
4649 'base:size': len(data) - len(U_BOOT_DATA),
4650 'base/u-boot:offset': 0,
4651 'base/u-boot:image-pos': len(U_BOOT_DATA),
4652 'base/u-boot:size': len(U_BOOT_DATA),
4653 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4654 len(expect2),
4655 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4656 len(expect2),
4657 'base/u-boot2:size': len(U_BOOT_DATA),
4658
4659 'base/section:offset': len(U_BOOT_DATA),
4660 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4661 'base/section:size': len(expect1),
4662 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4663 'base/section/blob:offset': 0,
4664 'base/section/blob:size': len(COMPRESS_DATA),
4665 'base/section/u-boot:offset': len(COMPRESS_DATA),
4666 'base/section/u-boot:size': len(U_BOOT_DATA),
4667
4668 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4669 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4670 'base/section2:size': len(expect2),
4671 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4672 'base/section2/blob:offset': 0,
4673 'base/section2/blob:size': len(COMPRESS_DATA),
4674 'base/section2/blob2:offset': len(COMPRESS_DATA),
4675 'base/section2/blob2:size': len(COMPRESS_DATA),
4676
4677 'offset': 0,
4678 'image-pos': 0,
4679 'size': len(data),
4680 }
4681 self.assertEqual(expected, props)
4682
Simon Glassecbe4732021-01-06 21:35:15 -07004683 def testSymbolsSubsection(self):
4684 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004685 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004686
Simon Glass3fb25402021-01-06 21:35:16 -07004687 def testReadImageEntryArg(self):
4688 """Test reading an image that would need an entry arg to generate"""
4689 entry_args = {
4690 'cros-ec-rw-path': 'ecrw.bin',
4691 }
4692 data = self.data = self._DoReadFileDtb(
4693 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4694 entry_args=entry_args)
4695
Simon Glass80025522022-01-29 14:14:04 -07004696 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004697 orig_image = control.images['image']
4698
4699 # This should not generate an error about the missing 'cros-ec-rw-path'
4700 # since we are reading the image from a file. Compare with
4701 # testEntryArgsRequired()
4702 image = Image.FromFile(image_fname)
4703 self.assertEqual(orig_image.GetEntries().keys(),
4704 image.GetEntries().keys())
4705
Simon Glassa2af7302021-01-06 21:35:18 -07004706 def testFilesAlign(self):
4707 """Test alignment with files"""
4708 data = self._DoReadFile('190_files_align.dts')
4709
4710 # The first string is 15 bytes so will align to 16
4711 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4712 self.assertEqual(expect, data)
4713
Simon Glassdb84b562021-01-06 21:35:19 -07004714 def testReadImageSkip(self):
4715 """Test reading an image and accessing its FDT map"""
4716 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004717 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004718 orig_image = control.images['image']
4719 image = Image.FromFile(image_fname)
4720 self.assertEqual(orig_image.GetEntries().keys(),
4721 image.GetEntries().keys())
4722
4723 orig_entry = orig_image.GetEntries()['fdtmap']
4724 entry = image.GetEntries()['fdtmap']
4725 self.assertEqual(orig_entry.offset, entry.offset)
4726 self.assertEqual(orig_entry.size, entry.size)
4727 self.assertEqual(16, entry.image_pos)
4728
4729 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4730
Brandon Maiera657bc62024-06-04 16:16:05 +00004731 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glassdb84b562021-01-06 21:35:19 -07004732
Simon Glassc98de972021-03-18 20:24:57 +13004733 def testTplNoDtb(self):
4734 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004735 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004736 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4737 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4738 data[:len(U_BOOT_TPL_NODTB_DATA)])
4739
Simon Glass63f41d42021-03-18 20:24:58 +13004740 def testTplBssPad(self):
4741 """Test that we can pad TPL's BSS with zeros"""
4742 # ELF file with a '__bss_size' symbol
4743 self._SetupTplElf()
4744 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004745 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004746 data)
4747
4748 def testTplBssPadMissing(self):
4749 """Test that a missing symbol is detected"""
4750 self._SetupTplElf('u_boot_ucode_ptr')
4751 with self.assertRaises(ValueError) as e:
4752 self._DoReadFile('193_tpl_bss_pad.dts')
4753 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4754 str(e.exception))
4755
Simon Glass718b5292021-03-18 20:25:07 +13004756 def checkDtbSizes(self, data, pad_len, start):
4757 """Check the size arguments in a dtb embedded in an image
4758
4759 Args:
4760 data: The image data
4761 pad_len: Length of the pad section in the image, in bytes
4762 start: Start offset of the devicetree to examine, within the image
4763
4764 Returns:
4765 Size of the devicetree in bytes
4766 """
4767 dtb_data = data[start:]
4768 dtb = fdt.Fdt.FromData(dtb_data)
4769 fdt_size = dtb.GetFdtObj().totalsize()
4770 dtb.Scan()
4771 props = self._GetPropTree(dtb, 'size')
4772 self.assertEqual({
4773 'size': len(data),
4774 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4775 'u-boot-spl/u-boot-spl-dtb:size': 801,
4776 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4777 'u-boot-spl:size': 860,
4778 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4779 'u-boot/u-boot-dtb:size': 781,
4780 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4781 'u-boot:size': 827,
4782 }, props)
4783 return fdt_size
4784
4785 def testExpanded(self):
4786 """Test that an expanded entry type is selected when needed"""
4787 self._SetupSplElf()
4788 self._SetupTplElf()
4789
4790 # SPL has a devicetree, TPL does not
4791 entry_args = {
4792 'spl-dtb': '1',
4793 'spl-bss-pad': 'y',
4794 'tpl-dtb': '',
4795 }
4796 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4797 entry_args=entry_args)
4798 image = control.images['image']
4799 entries = image.GetEntries()
4800 self.assertEqual(3, len(entries))
4801
4802 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4803 self.assertIn('u-boot', entries)
4804 entry = entries['u-boot']
4805 self.assertEqual('u-boot-expanded', entry.etype)
4806 subent = entry.GetEntries()
4807 self.assertEqual(2, len(subent))
4808 self.assertIn('u-boot-nodtb', subent)
4809 self.assertIn('u-boot-dtb', subent)
4810
4811 # Second, u-boot-spl, which should be expanded into three parts
4812 self.assertIn('u-boot-spl', entries)
4813 entry = entries['u-boot-spl']
4814 self.assertEqual('u-boot-spl-expanded', entry.etype)
4815 subent = entry.GetEntries()
4816 self.assertEqual(3, len(subent))
4817 self.assertIn('u-boot-spl-nodtb', subent)
4818 self.assertIn('u-boot-spl-bss-pad', subent)
4819 self.assertIn('u-boot-spl-dtb', subent)
4820
4821 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4822 # devicetree
4823 self.assertIn('u-boot-tpl', entries)
4824 entry = entries['u-boot-tpl']
4825 self.assertEqual('u-boot-tpl', entry.etype)
4826 self.assertEqual(None, entry.GetEntries())
4827
4828 def testExpandedTpl(self):
4829 """Test that an expanded entry type is selected for TPL when needed"""
4830 self._SetupTplElf()
4831
4832 entry_args = {
4833 'tpl-bss-pad': 'y',
4834 'tpl-dtb': 'y',
4835 }
4836 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4837 entry_args=entry_args)
4838 image = control.images['image']
4839 entries = image.GetEntries()
4840 self.assertEqual(1, len(entries))
4841
4842 # We only have u-boot-tpl, which be expanded
4843 self.assertIn('u-boot-tpl', entries)
4844 entry = entries['u-boot-tpl']
4845 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4846 subent = entry.GetEntries()
4847 self.assertEqual(3, len(subent))
4848 self.assertIn('u-boot-tpl-nodtb', subent)
4849 self.assertIn('u-boot-tpl-bss-pad', subent)
4850 self.assertIn('u-boot-tpl-dtb', subent)
4851
4852 def testExpandedNoPad(self):
4853 """Test an expanded entry without BSS pad enabled"""
4854 self._SetupSplElf()
4855 self._SetupTplElf()
4856
4857 # SPL has a devicetree, TPL does not
4858 entry_args = {
4859 'spl-dtb': 'something',
4860 'spl-bss-pad': 'n',
4861 'tpl-dtb': '',
4862 }
4863 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4864 entry_args=entry_args)
4865 image = control.images['image']
4866 entries = image.GetEntries()
4867
4868 # Just check u-boot-spl, which should be expanded into two parts
4869 self.assertIn('u-boot-spl', entries)
4870 entry = entries['u-boot-spl']
4871 self.assertEqual('u-boot-spl-expanded', entry.etype)
4872 subent = entry.GetEntries()
4873 self.assertEqual(2, len(subent))
4874 self.assertIn('u-boot-spl-nodtb', subent)
4875 self.assertIn('u-boot-spl-dtb', subent)
4876
4877 def testExpandedTplNoPad(self):
4878 """Test that an expanded entry type with padding disabled in TPL"""
4879 self._SetupTplElf()
4880
4881 entry_args = {
4882 'tpl-bss-pad': '',
4883 'tpl-dtb': 'y',
4884 }
4885 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4886 entry_args=entry_args)
4887 image = control.images['image']
4888 entries = image.GetEntries()
4889 self.assertEqual(1, len(entries))
4890
4891 # We only have u-boot-tpl, which be expanded
4892 self.assertIn('u-boot-tpl', entries)
4893 entry = entries['u-boot-tpl']
4894 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4895 subent = entry.GetEntries()
4896 self.assertEqual(2, len(subent))
4897 self.assertIn('u-boot-tpl-nodtb', subent)
4898 self.assertIn('u-boot-tpl-dtb', subent)
4899
4900 def testFdtInclude(self):
4901 """Test that an Fdt is update within all binaries"""
4902 self._SetupSplElf()
4903 self._SetupTplElf()
4904
4905 # SPL has a devicetree, TPL does not
4906 self.maxDiff = None
4907 entry_args = {
4908 'spl-dtb': '1',
4909 'spl-bss-pad': 'y',
4910 'tpl-dtb': '',
4911 }
4912 # Build the image. It includes two separate devicetree binaries, each
4913 # with their own contents, but all contain the binman definition.
4914 data = self._DoReadFileDtb(
4915 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4916 update_dtb=True, entry_args=entry_args)[0]
4917 pad_len = 10
4918
4919 # Check the U-Boot dtb
4920 start = len(U_BOOT_NODTB_DATA)
4921 fdt_size = self.checkDtbSizes(data, pad_len, start)
4922
4923 # Now check SPL
4924 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4925 fdt_size = self.checkDtbSizes(data, pad_len, start)
4926
4927 # TPL has no devicetree
4928 start += fdt_size + len(U_BOOT_TPL_DATA)
4929 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004930
Simon Glass7098b7f2021-03-21 18:24:30 +13004931 def testSymbolsExpanded(self):
4932 """Test binman can assign symbols in expanded entries"""
4933 entry_args = {
4934 'spl-dtb': '1',
4935 }
4936 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4937 U_BOOT_SPL_DTB_DATA, 0x38,
4938 entry_args=entry_args, use_expanded=True)
4939
Simon Glasse1915782021-03-21 18:24:31 +13004940 def testCollection(self):
4941 """Test a collection"""
4942 data = self._DoReadFile('198_collection.dts')
4943 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004944 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4945 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004946 data)
4947
Simon Glass27a7f772021-03-21 18:24:32 +13004948 def testCollectionSection(self):
4949 """Test a collection where a section must be built first"""
4950 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004951 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004952 # building the contents, producing an error is anything is still
4953 # missing.
4954 data = self._DoReadFile('199_collection_section.dts')
4955 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004956 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4957 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004958 data)
4959
Simon Glassf427c5f2021-03-21 18:24:33 +13004960 def testAlignDefault(self):
4961 """Test that default alignment works on sections"""
4962 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004963 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004964 U_BOOT_DATA)
4965 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004966 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004967 # No alignment within the nested section
4968 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4969 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004970 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004971 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004972
Bin Mengc0b15742021-05-10 20:23:33 +08004973 def testPackOpenSBI(self):
4974 """Test that an image with an OpenSBI binary can be created"""
4975 data = self._DoReadFile('201_opensbi.dts')
4976 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4977
Simon Glass76f496d2021-07-06 10:36:37 -06004978 def testSectionsSingleThread(self):
4979 """Test sections without multithreading"""
4980 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004981 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4982 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4983 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004984 self.assertEqual(expected, data)
4985
4986 def testThreadTimeout(self):
4987 """Test handling a thread that takes too long"""
4988 with self.assertRaises(ValueError) as e:
4989 self._DoTestFile('202_section_timeout.dts',
4990 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004991 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004992
Simon Glass748a1d42021-07-06 10:36:41 -06004993 def testTiming(self):
4994 """Test output of timing information"""
4995 data = self._DoReadFile('055_sections.dts')
4996 with test_util.capture_sys_output() as (stdout, stderr):
4997 state.TimingShow()
4998 self.assertIn('read:', stdout.getvalue())
4999 self.assertIn('compress:', stdout.getvalue())
5000
Simon Glassadfb8492021-11-03 21:09:18 -06005001 def testUpdateFdtInElf(self):
5002 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005003 if not elf.ELF_TOOLS:
5004 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005005 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5006 outfile = os.path.join(self._indir, 'u-boot.out')
5007 begin_sym = 'dtb_embed_begin'
5008 end_sym = 'dtb_embed_end'
5009 retcode = self._DoTestFile(
5010 '060_fdt_update.dts', update_dtb=True,
5011 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5012 self.assertEqual(0, retcode)
5013
5014 # Check that the output file does in fact contact a dtb with the binman
5015 # definition in the correct place
5016 syms = elf.GetSymbolFileOffset(infile,
5017 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07005018 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06005019 dtb_data = data[syms['dtb_embed_begin'].offset:
5020 syms['dtb_embed_end'].offset]
5021
5022 dtb = fdt.Fdt.FromData(dtb_data)
5023 dtb.Scan()
5024 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
5025 self.assertEqual({
5026 'image-pos': 0,
5027 'offset': 0,
5028 '_testing:offset': 32,
5029 '_testing:size': 2,
5030 '_testing:image-pos': 32,
5031 'section@0/u-boot:offset': 0,
5032 'section@0/u-boot:size': len(U_BOOT_DATA),
5033 'section@0/u-boot:image-pos': 0,
5034 'section@0:offset': 0,
5035 'section@0:size': 16,
5036 'section@0:image-pos': 0,
5037
5038 'section@1/u-boot:offset': 0,
5039 'section@1/u-boot:size': len(U_BOOT_DATA),
5040 'section@1/u-boot:image-pos': 16,
5041 'section@1:offset': 16,
5042 'section@1:size': 16,
5043 'section@1:image-pos': 16,
5044 'size': 40
5045 }, props)
5046
5047 def testUpdateFdtInElfInvalid(self):
5048 """Test that invalid args are detected with --update-fdt-in-elf"""
5049 with self.assertRaises(ValueError) as e:
5050 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5051 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5052 str(e.exception))
5053
5054 def testUpdateFdtInElfNoSyms(self):
5055 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005056 if not elf.ELF_TOOLS:
5057 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005058 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5059 outfile = ''
5060 begin_sym = 'wrong_begin'
5061 end_sym = 'wrong_end'
5062 with self.assertRaises(ValueError) as e:
5063 self._DoTestFile(
5064 '060_fdt_update.dts',
5065 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5066 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5067 str(e.exception))
5068
5069 def testUpdateFdtInElfTooSmall(self):
5070 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005071 if not elf.ELF_TOOLS:
5072 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005073 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5074 outfile = os.path.join(self._indir, 'u-boot.out')
5075 begin_sym = 'dtb_embed_begin'
5076 end_sym = 'dtb_embed_end'
5077 with self.assertRaises(ValueError) as e:
5078 self._DoTestFile(
5079 '060_fdt_update.dts', update_dtb=True,
5080 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5081 self.assertRegex(
5082 str(e.exception),
5083 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5084
Simon Glass88e04da2021-11-23 11:03:42 -07005085 def testVersion(self):
5086 """Test we can get the binman version"""
5087 version = '(unreleased)'
5088 self.assertEqual(version, state.GetVersion(self._indir))
5089
5090 with self.assertRaises(SystemExit):
5091 with test_util.capture_sys_output() as (_, stderr):
5092 self._DoBinman('-V')
5093 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5094
5095 # Try running the tool too, just to be safe
5096 result = self._RunBinman('-V')
5097 self.assertEqual('Binman %s\n' % version, result.stderr)
5098
5099 # Set up a version file to make sure that works
5100 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005101 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005102 binary=False)
5103 self.assertEqual(version, state.GetVersion(self._indir))
5104
Simon Glass637958f2021-11-23 21:09:50 -07005105 def testAltFormat(self):
5106 """Test that alternative formats can be used to extract"""
5107 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5108
5109 try:
5110 tmpdir, updated_fname = self._SetupImageInTmpdir()
5111 with test_util.capture_sys_output() as (stdout, _):
5112 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5113 self.assertEqual(
5114 '''Flag (-F) Entry type Description
5115fdt fdtmap Extract the devicetree blob from the fdtmap
5116''',
5117 stdout.getvalue())
5118
5119 dtb = os.path.join(tmpdir, 'fdt.dtb')
5120 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5121 dtb, 'fdtmap')
5122
5123 # Check that we can read it and it can be scanning, meaning it does
5124 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005125 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005126 dtb = fdt.Fdt.FromData(data)
5127 dtb.Scan()
5128
5129 # Now check u-boot which has no alt_format
5130 fname = os.path.join(tmpdir, 'fdt.dtb')
5131 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5132 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005133 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005134 self.assertEqual(U_BOOT_DATA, data)
5135
5136 finally:
5137 shutil.rmtree(tmpdir)
5138
Simon Glass0b00ae62021-11-23 21:09:52 -07005139 def testExtblobList(self):
5140 """Test an image with an external blob list"""
5141 data = self._DoReadFile('215_blob_ext_list.dts')
5142 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5143
5144 def testExtblobListMissing(self):
5145 """Test an image with a missing external blob"""
5146 with self.assertRaises(ValueError) as e:
5147 self._DoReadFile('216_blob_ext_list_missing.dts')
5148 self.assertIn("Filename 'missing-file' not found in input path",
5149 str(e.exception))
5150
5151 def testExtblobListMissingOk(self):
5152 """Test an image with an missing external blob that is allowed"""
5153 with test_util.capture_sys_output() as (stdout, stderr):
5154 self._DoTestFile('216_blob_ext_list_missing.dts',
5155 allow_missing=True)
5156 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005157 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005158
Simon Glass3efb2972021-11-23 21:08:59 -07005159 def testFip(self):
5160 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5161 data = self._DoReadFile('203_fip.dts')
5162 hdr, fents = fip_util.decode_fip(data)
5163 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5164 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5165 self.assertEqual(0x123, hdr.flags)
5166
5167 self.assertEqual(2, len(fents))
5168
5169 fent = fents[0]
5170 self.assertEqual(
5171 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5172 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5173 self.assertEqual('soc-fw', fent.fip_type)
5174 self.assertEqual(0x88, fent.offset)
5175 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5176 self.assertEqual(0x123456789abcdef, fent.flags)
5177 self.assertEqual(ATF_BL31_DATA, fent.data)
5178 self.assertEqual(True, fent.valid)
5179
5180 fent = fents[1]
5181 self.assertEqual(
5182 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5183 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5184 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5185 self.assertEqual(0x8c, fent.offset)
5186 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5187 self.assertEqual(0, fent.flags)
5188 self.assertEqual(ATF_BL2U_DATA, fent.data)
5189 self.assertEqual(True, fent.valid)
5190
5191 def testFipOther(self):
5192 """Basic FIP with something that isn't a external blob"""
5193 data = self._DoReadFile('204_fip_other.dts')
5194 hdr, fents = fip_util.decode_fip(data)
5195
5196 self.assertEqual(2, len(fents))
5197 fent = fents[1]
5198 self.assertEqual('rot-cert', fent.fip_type)
5199 self.assertEqual(b'aa', fent.data)
5200
Simon Glass3efb2972021-11-23 21:08:59 -07005201 def testFipNoType(self):
5202 """FIP with an entry of an unknown type"""
5203 with self.assertRaises(ValueError) as e:
5204 self._DoReadFile('205_fip_no_type.dts')
5205 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5206 str(e.exception))
5207
5208 def testFipUuid(self):
5209 """Basic FIP with a manual uuid"""
5210 data = self._DoReadFile('206_fip_uuid.dts')
5211 hdr, fents = fip_util.decode_fip(data)
5212
5213 self.assertEqual(2, len(fents))
5214 fent = fents[1]
5215 self.assertEqual(None, fent.fip_type)
5216 self.assertEqual(
5217 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5218 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5219 fent.uuid)
5220 self.assertEqual(U_BOOT_DATA, fent.data)
5221
5222 def testFipLs(self):
5223 """Test listing a FIP"""
5224 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5225 hdr, fents = fip_util.decode_fip(data)
5226
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005227 tmpdir = None
Simon Glass3efb2972021-11-23 21:08:59 -07005228 try:
5229 tmpdir, updated_fname = self._SetupImageInTmpdir()
5230 with test_util.capture_sys_output() as (stdout, stderr):
5231 self._DoBinman('ls', '-i', updated_fname)
5232 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005233 if tmpdir:
5234 shutil.rmtree(tmpdir)
Simon Glass3efb2972021-11-23 21:08:59 -07005235 lines = stdout.getvalue().splitlines()
5236 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005237'Name Image-pos Size Entry-type Offset Uncomp-size',
5238'--------------------------------------------------------------',
5239'image 0 2d3 section 0',
5240' atf-fip 0 90 atf-fip 0',
5241' soc-fw 88 4 blob-ext 88',
5242' u-boot 8c 4 u-boot 8c',
5243' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005244]
5245 self.assertEqual(expected, lines)
5246
5247 image = control.images['image']
5248 entries = image.GetEntries()
5249 fdtmap = entries['fdtmap']
5250
5251 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5252 magic = fdtmap_data[:8]
5253 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005254 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005255
5256 fdt_data = fdtmap_data[16:]
5257 dtb = fdt.Fdt.FromData(fdt_data)
5258 dtb.Scan()
5259 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5260 self.assertEqual({
5261 'atf-fip/soc-fw:image-pos': 136,
5262 'atf-fip/soc-fw:offset': 136,
5263 'atf-fip/soc-fw:size': 4,
5264 'atf-fip/u-boot:image-pos': 140,
5265 'atf-fip/u-boot:offset': 140,
5266 'atf-fip/u-boot:size': 4,
5267 'atf-fip:image-pos': 0,
5268 'atf-fip:offset': 0,
5269 'atf-fip:size': 144,
5270 'image-pos': 0,
5271 'offset': 0,
5272 'fdtmap:image-pos': fdtmap.image_pos,
5273 'fdtmap:offset': fdtmap.offset,
5274 'fdtmap:size': len(fdtmap_data),
5275 'size': len(data),
5276 }, props)
5277
5278 def testFipExtractOneEntry(self):
5279 """Test extracting a single entry fron an FIP"""
5280 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005281 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005282 fname = os.path.join(self._indir, 'output.extact')
5283 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005284 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005285 self.assertEqual(U_BOOT_DATA, data)
5286
5287 def testFipReplace(self):
5288 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005289 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005290 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005291 updated_fname = tools.get_output_filename('image-updated.bin')
5292 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005293 entry_name = 'atf-fip/u-boot'
5294 control.WriteEntry(updated_fname, entry_name, expected,
5295 allow_resize=True)
5296 actual = control.ReadEntry(updated_fname, entry_name)
5297 self.assertEqual(expected, actual)
5298
Simon Glass80025522022-01-29 14:14:04 -07005299 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005300 hdr, fents = fip_util.decode_fip(new_data)
5301
5302 self.assertEqual(2, len(fents))
5303
5304 # Check that the FIP entry is updated
5305 fent = fents[1]
5306 self.assertEqual(0x8c, fent.offset)
5307 self.assertEqual(len(expected), fent.size)
5308 self.assertEqual(0, fent.flags)
5309 self.assertEqual(expected, fent.data)
5310 self.assertEqual(True, fent.valid)
5311
5312 def testFipMissing(self):
5313 with test_util.capture_sys_output() as (stdout, stderr):
5314 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5315 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005316 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005317
5318 def testFipSize(self):
5319 """Test a FIP with a size property"""
5320 data = self._DoReadFile('210_fip_size.dts')
5321 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5322 hdr, fents = fip_util.decode_fip(data)
5323 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5324 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5325
5326 self.assertEqual(1, len(fents))
5327
5328 fent = fents[0]
5329 self.assertEqual('soc-fw', fent.fip_type)
5330 self.assertEqual(0x60, fent.offset)
5331 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5332 self.assertEqual(ATF_BL31_DATA, fent.data)
5333 self.assertEqual(True, fent.valid)
5334
5335 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005336 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005337
5338 def testFipBadAlign(self):
5339 """Test that an invalid alignment value in a FIP is detected"""
5340 with self.assertRaises(ValueError) as e:
5341 self._DoTestFile('211_fip_bad_align.dts')
5342 self.assertIn(
5343 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5344 str(e.exception))
5345
5346 def testFipCollection(self):
5347 """Test using a FIP in a collection"""
5348 data = self._DoReadFile('212_fip_collection.dts')
5349 entry1 = control.images['image'].GetEntries()['collection']
5350 data1 = data[:entry1.size]
5351 hdr1, fents2 = fip_util.decode_fip(data1)
5352
5353 entry2 = control.images['image'].GetEntries()['atf-fip']
5354 data2 = data[entry2.offset:entry2.offset + entry2.size]
5355 hdr1, fents2 = fip_util.decode_fip(data2)
5356
5357 # The 'collection' entry should have U-Boot included at the end
5358 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5359 self.assertEqual(data1, data2 + U_BOOT_DATA)
5360 self.assertEqual(U_BOOT_DATA, data1[-4:])
5361
5362 # There should be a U-Boot after the final FIP
5363 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005364
Simon Glassccae6862022-01-12 13:10:35 -07005365 def testFakeBlob(self):
5366 """Test handling of faking an external blob"""
5367 with test_util.capture_sys_output() as (stdout, stderr):
5368 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5369 allow_fake_blobs=True)
5370 err = stderr.getvalue()
5371 self.assertRegex(
5372 err,
5373 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005374
Simon Glassceb5f912022-01-09 20:13:46 -07005375 def testExtblobListFaked(self):
5376 """Test an extblob with missing external blob that are faked"""
5377 with test_util.capture_sys_output() as (stdout, stderr):
5378 self._DoTestFile('216_blob_ext_list_missing.dts',
5379 allow_fake_blobs=True)
5380 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005381 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005382
Simon Glass162017b2022-01-09 20:13:57 -07005383 def testListBintools(self):
5384 args = ['tool', '--list']
5385 with test_util.capture_sys_output() as (stdout, _):
5386 self._DoBinman(*args)
5387 out = stdout.getvalue().splitlines()
5388 self.assertTrue(len(out) >= 2)
5389
5390 def testFetchBintools(self):
5391 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005392 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005393 raise urllib.error.URLError('my error')
5394
5395 args = ['tool']
5396 with self.assertRaises(ValueError) as e:
5397 self._DoBinman(*args)
5398 self.assertIn("Invalid arguments to 'tool' subcommand",
5399 str(e.exception))
5400
5401 args = ['tool', '--fetch']
5402 with self.assertRaises(ValueError) as e:
5403 self._DoBinman(*args)
5404 self.assertIn('Please specify bintools to fetch', str(e.exception))
5405
5406 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005407 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005408 side_effect=fail_download):
5409 with test_util.capture_sys_output() as (stdout, _):
5410 self._DoBinman(*args)
5411 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5412
Simon Glass620c4462022-01-09 20:14:11 -07005413 def testBintoolDocs(self):
5414 """Test for creation of bintool documentation"""
5415 with test_util.capture_sys_output() as (stdout, stderr):
5416 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5417 self.assertTrue(len(stdout.getvalue()) > 0)
5418
5419 def testBintoolDocsMissing(self):
5420 """Test handling of missing bintool documentation"""
5421 with self.assertRaises(ValueError) as e:
5422 with test_util.capture_sys_output() as (stdout, stderr):
5423 control.write_bintool_docs(
5424 control.bintool.Bintool.get_tool_list(), 'mkimage')
5425 self.assertIn('Documentation is missing for modules: mkimage',
5426 str(e.exception))
5427
Jan Kiszka58c407f2022-01-28 20:37:53 +01005428 def testListWithGenNode(self):
5429 """Check handling of an FDT map when the section cannot be found"""
5430 entry_args = {
5431 'of-list': 'test-fdt1 test-fdt2',
5432 }
5433 data = self._DoReadFileDtb(
5434 '219_fit_gennode.dts',
5435 entry_args=entry_args,
5436 use_real_dtb=True,
5437 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5438
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005439 tmpdir = None
Jan Kiszka58c407f2022-01-28 20:37:53 +01005440 try:
5441 tmpdir, updated_fname = self._SetupImageInTmpdir()
5442 with test_util.capture_sys_output() as (stdout, stderr):
5443 self._RunBinman('ls', '-i', updated_fname)
5444 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005445 if tmpdir:
5446 shutil.rmtree(tmpdir)
Jan Kiszka58c407f2022-01-28 20:37:53 +01005447
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005448 def testFitSubentryUsesBintool(self):
5449 """Test that binman FIT subentries can use bintools"""
5450 command.test_result = self._HandleGbbCommand
5451 entry_args = {
5452 'keydir': 'devkeys',
5453 'bmpblk': 'bmpblk.bin',
5454 }
5455 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5456 entry_args=entry_args)
5457
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005458 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5459 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005460 self.assertIn(expected, data)
5461
5462 def testFitSubentryMissingBintool(self):
5463 """Test that binman reports missing bintools for FIT subentries"""
5464 entry_args = {
5465 'keydir': 'devkeys',
5466 }
5467 with test_util.capture_sys_output() as (_, stderr):
5468 self._DoTestFile('220_fit_subentry_bintool.dts',
5469 force_missing_bintools='futility', entry_args=entry_args)
5470 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005471 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005472
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005473 def testFitSubentryHashSubnode(self):
5474 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005475 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005476 data, _, _, out_dtb_name = self._DoReadFileDtb(
5477 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5478
5479 mkimage_dtb = fdt.Fdt.FromData(data)
5480 mkimage_dtb.Scan()
5481 binman_dtb = fdt.Fdt(out_dtb_name)
5482 binman_dtb.Scan()
5483
5484 # Check that binman didn't add hash values
5485 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5486 self.assertNotIn('value', fnode.props)
5487
5488 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5489 self.assertNotIn('value', fnode.props)
5490
5491 # Check that mkimage added hash values
5492 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5493 self.assertIn('value', fnode.props)
5494
5495 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5496 self.assertIn('value', fnode.props)
5497
Roger Quadros5cdcea02022-02-19 20:50:04 +02005498 def testPackTeeOs(self):
5499 """Test that an image with an TEE binary can be created"""
5500 data = self._DoReadFile('222_tee_os.dts')
5501 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5502
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305503 def testPackTiDm(self):
5504 """Test that an image with a TI DM binary can be created"""
5505 data = self._DoReadFile('225_ti_dm.dts')
5506 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5507
Simon Glass912339f2022-02-08 11:50:03 -07005508 def testFitFdtOper(self):
5509 """Check handling of a specified FIT operation"""
5510 entry_args = {
5511 'of-list': 'test-fdt1 test-fdt2',
5512 'default-dt': 'test-fdt2',
5513 }
5514 self._DoReadFileDtb(
5515 '223_fit_fdt_oper.dts',
5516 entry_args=entry_args,
5517 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5518
5519 def testFitFdtBadOper(self):
5520 """Check handling of an FDT map when the section cannot be found"""
5521 with self.assertRaises(ValueError) as exc:
5522 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005523 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005524 str(exc.exception))
5525
Simon Glassdd156a42022-03-05 20:18:59 -07005526 def test_uses_expand_size(self):
5527 """Test that the 'expand-size' property cannot be used anymore"""
5528 with self.assertRaises(ValueError) as e:
5529 data = self._DoReadFile('225_expand_size_bad.dts')
5530 self.assertIn(
5531 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5532 str(e.exception))
5533
Simon Glass5f423422022-03-05 20:19:12 -07005534 def testFitSplitElf(self):
5535 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005536 if not elf.ELF_TOOLS:
5537 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005538 entry_args = {
5539 'of-list': 'test-fdt1 test-fdt2',
5540 'default-dt': 'test-fdt2',
5541 'atf-bl31-path': 'bl31.elf',
5542 'tee-os-path': 'tee.elf',
5543 }
5544 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5545 data = self._DoReadFileDtb(
5546 '226_fit_split_elf.dts',
5547 entry_args=entry_args,
5548 extra_indirs=[test_subdir])[0]
5549
5550 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5551 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5552
5553 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5554 'data', 'load'}
5555 dtb = fdt.Fdt.FromData(fit_data)
5556 dtb.Scan()
5557
5558 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5559 segments, entry = elf.read_loadable_segments(elf_data)
5560
5561 # We assume there are two segments
Brandon Maiera657bc62024-06-04 16:16:05 +00005562 self.assertEqual(2, len(segments))
Simon Glass5f423422022-03-05 20:19:12 -07005563
5564 atf1 = dtb.GetNode('/images/atf-1')
5565 _, start, data = segments[0]
5566 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5567 self.assertEqual(entry,
5568 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5569 self.assertEqual(start,
5570 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5571 self.assertEqual(data, atf1.props['data'].bytes)
5572
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005573 hash_node = atf1.FindNode('hash')
5574 self.assertIsNotNone(hash_node)
5575 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5576
Simon Glass5f423422022-03-05 20:19:12 -07005577 atf2 = dtb.GetNode('/images/atf-2')
5578 self.assertEqual(base_keys, atf2.props.keys())
5579 _, start, data = segments[1]
5580 self.assertEqual(start,
5581 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5582 self.assertEqual(data, atf2.props['data'].bytes)
5583
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005584 hash_node = atf2.FindNode('hash')
5585 self.assertIsNotNone(hash_node)
5586 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5587
5588 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5589 self.assertIsNotNone(hash_node)
5590 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5591
Simon Glass5f423422022-03-05 20:19:12 -07005592 conf = dtb.GetNode('/configurations')
5593 self.assertEqual({'default'}, conf.props.keys())
5594
5595 for subnode in conf.subnodes:
5596 self.assertEqual({'description', 'fdt', 'loadables'},
5597 subnode.props.keys())
5598 self.assertEqual(
5599 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5600 fdt_util.GetStringList(subnode, 'loadables'))
5601
5602 def _check_bad_fit(self, dts):
5603 """Check a bad FIT
5604
5605 This runs with the given dts and returns the assertion raised
5606
5607 Args:
5608 dts (str): dts filename to use
5609
5610 Returns:
5611 str: Assertion string raised
5612 """
5613 entry_args = {
5614 'of-list': 'test-fdt1 test-fdt2',
5615 'default-dt': 'test-fdt2',
5616 'atf-bl31-path': 'bl31.elf',
5617 'tee-os-path': 'tee.elf',
5618 }
5619 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5620 with self.assertRaises(ValueError) as exc:
5621 self._DoReadFileDtb(dts, entry_args=entry_args,
5622 extra_indirs=[test_subdir])[0]
5623 return str(exc.exception)
5624
5625 def testFitSplitElfBadElf(self):
5626 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005627 if not elf.ELF_TOOLS:
5628 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005629 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5630 entry_args = {
5631 'of-list': 'test-fdt1 test-fdt2',
5632 'default-dt': 'test-fdt2',
5633 'atf-bl31-path': 'bad.elf',
5634 'tee-os-path': 'tee.elf',
5635 }
5636 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5637 with self.assertRaises(ValueError) as exc:
5638 self._DoReadFileDtb(
5639 '226_fit_split_elf.dts',
5640 entry_args=entry_args,
5641 extra_indirs=[test_subdir])[0]
5642 self.assertIn(
5643 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5644 str(exc.exception))
5645
Simon Glass5f423422022-03-05 20:19:12 -07005646 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005647 """Test an split-elf FIT with a missing ELF file
5648
5649 Args:
5650 kwargs (dict of str): Arguments to pass to _DoTestFile()
5651
5652 Returns:
5653 tuple:
5654 str: stdout result
5655 str: stderr result
5656 """
Simon Glass5f423422022-03-05 20:19:12 -07005657 entry_args = {
5658 'of-list': 'test-fdt1 test-fdt2',
5659 'default-dt': 'test-fdt2',
5660 'atf-bl31-path': 'bl31.elf',
5661 'tee-os-path': 'missing.elf',
5662 }
5663 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5664 with test_util.capture_sys_output() as (stdout, stderr):
5665 self._DoTestFile(
5666 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005667 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5668 out = stdout.getvalue()
5669 err = stderr.getvalue()
5670 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005671
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005672 def testFitSplitElfBadDirective(self):
5673 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5674 if not elf.ELF_TOOLS:
5675 self.skipTest('Python elftools not available')
5676 err = self._check_bad_fit('227_fit_bad_dir.dts')
5677 self.assertIn(
5678 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5679 err)
5680
5681 def testFitSplitElfBadDirectiveConfig(self):
5682 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5683 if not elf.ELF_TOOLS:
5684 self.skipTest('Python elftools not available')
5685 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5686 self.assertEqual(
5687 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5688 err)
5689
5690
Simon Glass5f423422022-03-05 20:19:12 -07005691 def testFitSplitElfMissing(self):
5692 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005693 if not elf.ELF_TOOLS:
5694 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005695 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005696 self.assertRegex(
5697 err,
5698 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005699 self.assertNotRegex(out, '.*Faked blob.*')
5700 fname = tools.get_output_filename('binman-fake/missing.elf')
5701 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005702
5703 def testFitSplitElfFaked(self):
5704 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005705 if not elf.ELF_TOOLS:
5706 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005707 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005708 self.assertRegex(
5709 err,
5710 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005711 self.assertRegex(
5712 out,
5713 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5714 fname = tools.get_output_filename('binman-fake/missing.elf')
5715 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005716
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005717 def testMkimageMissingBlob(self):
5718 """Test using mkimage to build an image"""
5719 with test_util.capture_sys_output() as (stdout, stderr):
5720 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5721 allow_fake_blobs=True)
5722 err = stderr.getvalue()
5723 self.assertRegex(
5724 err,
5725 "Image '.*' has faked external blobs and is non-functional: .*")
5726
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005727 def testPreLoad(self):
5728 """Test an image with a pre-load header"""
5729 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005730 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005731 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005732 data = self._DoReadFileDtb(
5733 '230_pre_load.dts', entry_args=entry_args,
5734 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005735 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5736 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5737 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Simon Glasse2dfb962023-07-24 09:19:57 -06005738
5739 def testPreLoadNoKey(self):
5740 """Test an image with a pre-load heade0r with missing key"""
5741 with self.assertRaises(FileNotFoundError) as exc:
5742 self._DoReadFile('230_pre_load.dts')
5743 self.assertIn("No such file or directory: 'dev.key'",
5744 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005745
5746 def testPreLoadPkcs(self):
5747 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005748 entry_args = {
5749 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5750 }
5751 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5752 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005753 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5754 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5755 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5756
5757 def testPreLoadPss(self):
5758 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005759 entry_args = {
5760 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5761 }
5762 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5763 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005764 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5765 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5766 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5767
5768 def testPreLoadInvalidPadding(self):
5769 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005770 entry_args = {
5771 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5772 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005773 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005774 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5775 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005776
5777 def testPreLoadInvalidSha(self):
5778 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005779 entry_args = {
5780 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5781 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005782 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005783 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5784 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005785
5786 def testPreLoadInvalidAlgo(self):
5787 """Test an image with a pre-load header with an invalid algo"""
5788 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005789 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005790
5791 def testPreLoadInvalidKey(self):
5792 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005793 entry_args = {
5794 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5795 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005796 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005797 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5798 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005799
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005800 def _CheckSafeUniqueNames(self, *images):
5801 """Check all entries of given images for unsafe unique names"""
5802 for image in images:
5803 entries = {}
5804 image._CollectEntries(entries, {}, image)
5805 for entry in entries.values():
5806 uniq = entry.GetUniqueName()
5807
5808 # Used as part of a filename, so must not be absolute paths.
5809 self.assertFalse(os.path.isabs(uniq))
5810
5811 def testSafeUniqueNames(self):
5812 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005813 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005814
5815 orig_image = control.images['image']
5816 image_fname = tools.get_output_filename('image.bin')
5817 image = Image.FromFile(image_fname)
5818
5819 self._CheckSafeUniqueNames(orig_image, image)
5820
5821 def testSafeUniqueNamesMulti(self):
5822 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005823 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005824
5825 orig_image = control.images['image']
5826 image_fname = tools.get_output_filename('image.bin')
5827 image = Image.FromFile(image_fname)
5828
5829 self._CheckSafeUniqueNames(orig_image, image)
5830
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005831 def testReplaceCmdWithBintool(self):
5832 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005833 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005834 expected = U_BOOT_DATA + b'aa'
5835 self.assertEqual(expected, data[:len(expected)])
5836
5837 try:
5838 tmpdir, updated_fname = self._SetupImageInTmpdir()
5839 fname = os.path.join(tmpdir, 'update-testing.bin')
5840 tools.write_file(fname, b'zz')
5841 self._DoBinman('replace', '-i', updated_fname,
5842 '_testing', '-f', fname)
5843
5844 data = tools.read_file(updated_fname)
5845 expected = U_BOOT_DATA + b'zz'
5846 self.assertEqual(expected, data[:len(expected)])
5847 finally:
5848 shutil.rmtree(tmpdir)
5849
5850 def testReplaceCmdOtherWithBintool(self):
5851 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005852 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005853 expected = U_BOOT_DATA + b'aa'
5854 self.assertEqual(expected, data[:len(expected)])
5855
5856 try:
5857 tmpdir, updated_fname = self._SetupImageInTmpdir()
5858 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5859 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5860 self._DoBinman('replace', '-i', updated_fname,
5861 'u-boot', '-f', fname)
5862
5863 data = tools.read_file(updated_fname)
5864 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5865 self.assertEqual(expected, data[:len(expected)])
5866 finally:
5867 shutil.rmtree(tmpdir)
5868
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005869 def testReplaceResizeNoRepackSameSize(self):
5870 """Test replacing entries with same-size data without repacking"""
5871 expected = b'x' * len(U_BOOT_DATA)
5872 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5873 self.assertEqual(expected, data)
5874
5875 path, fdtmap = state.GetFdtContents('fdtmap')
5876 self.assertIsNotNone(path)
5877 self.assertEqual(expected_fdtmap, fdtmap)
5878
5879 def testReplaceResizeNoRepackSmallerSize(self):
5880 """Test replacing entries with smaller-size data without repacking"""
5881 new_data = b'x'
5882 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5883 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5884 self.assertEqual(expected, data)
5885
5886 path, fdtmap = state.GetFdtContents('fdtmap')
5887 self.assertIsNotNone(path)
5888 self.assertEqual(expected_fdtmap, fdtmap)
5889
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005890 def testExtractFit(self):
5891 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005892 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005893 image_fname = tools.get_output_filename('image.bin')
5894
5895 fit_data = control.ReadEntry(image_fname, 'fit')
5896 fit = fdt.Fdt.FromData(fit_data)
5897 fit.Scan()
5898
5899 # Check subentry data inside the extracted fit
5900 for node_path, expected in [
5901 ('/images/kernel', U_BOOT_DATA),
5902 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5903 ('/images/scr-1', COMPRESS_DATA),
5904 ]:
5905 node = fit.GetNode(node_path)
5906 data = fit.GetProps(node)['data'].bytes
5907 self.assertEqual(expected, data)
5908
5909 def testExtractFitSubentries(self):
5910 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005911 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005912 image_fname = tools.get_output_filename('image.bin')
5913
5914 for entry_path, expected in [
5915 ('fit/kernel', U_BOOT_DATA),
5916 ('fit/kernel/u-boot', U_BOOT_DATA),
5917 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5918 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5919 ('fit/scr-1', COMPRESS_DATA),
5920 ('fit/scr-1/blob', COMPRESS_DATA),
5921 ]:
5922 data = control.ReadEntry(image_fname, entry_path)
5923 self.assertEqual(expected, data)
5924
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005925 def testReplaceFitSubentryLeafSameSize(self):
5926 """Test replacing a FIT leaf subentry with same-size data"""
5927 new_data = b'x' * len(U_BOOT_DATA)
5928 data, expected_fdtmap, _ = self._RunReplaceCmd(
5929 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005930 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005931 self.assertEqual(new_data, data)
5932
5933 path, fdtmap = state.GetFdtContents('fdtmap')
5934 self.assertIsNotNone(path)
5935 self.assertEqual(expected_fdtmap, fdtmap)
5936
5937 def testReplaceFitSubentryLeafBiggerSize(self):
5938 """Test replacing a FIT leaf subentry with bigger-size data"""
5939 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5940 data, expected_fdtmap, _ = self._RunReplaceCmd(
5941 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005942 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005943 self.assertEqual(new_data, data)
5944
5945 # Will be repacked, so fdtmap must change
5946 path, fdtmap = state.GetFdtContents('fdtmap')
5947 self.assertIsNotNone(path)
5948 self.assertNotEqual(expected_fdtmap, fdtmap)
5949
5950 def testReplaceFitSubentryLeafSmallerSize(self):
5951 """Test replacing a FIT leaf subentry with smaller-size data"""
5952 new_data = b'x'
5953 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5954 data, expected_fdtmap, _ = self._RunReplaceCmd(
5955 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005956 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005957 self.assertEqual(expected, data)
5958
5959 path, fdtmap = state.GetFdtContents('fdtmap')
5960 self.assertIsNotNone(path)
5961 self.assertEqual(expected_fdtmap, fdtmap)
5962
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005963 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005964 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005965 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005966 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5967 new_data, dts='241_replace_section_simple.dts')
5968 self.assertEqual(new_data, data)
5969
5970 entries = image.GetEntries()
5971 self.assertIn('section', entries)
5972 entry = entries['section']
5973 self.assertEqual(len(new_data), entry.size)
5974
5975 def testReplaceSectionLarger(self):
5976 """Test replacing a simple section with larger data"""
5977 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5978 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5979 new_data, dts='241_replace_section_simple.dts')
5980 self.assertEqual(new_data, data)
5981
5982 entries = image.GetEntries()
5983 self.assertIn('section', entries)
5984 entry = entries['section']
5985 self.assertEqual(len(new_data), entry.size)
5986 fentry = entries['fdtmap']
5987 self.assertEqual(entry.offset + entry.size, fentry.offset)
5988
5989 def testReplaceSectionSmaller(self):
5990 """Test replacing a simple section with smaller data"""
5991 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5992 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5993 new_data, dts='241_replace_section_simple.dts')
5994 self.assertEqual(new_data, data)
5995
5996 # The new size is the same as the old, just with a pad byte at the end
5997 entries = image.GetEntries()
5998 self.assertIn('section', entries)
5999 entry = entries['section']
6000 self.assertEqual(len(new_data), entry.size)
6001
6002 def testReplaceSectionSmallerAllow(self):
6003 """Test failing to replace a simple section with smaller data"""
6004 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
6005 try:
6006 state.SetAllowEntryContraction(True)
6007 with self.assertRaises(ValueError) as exc:
6008 self._RunReplaceCmd('section', new_data,
6009 dts='241_replace_section_simple.dts')
6010 finally:
6011 state.SetAllowEntryContraction(False)
6012
6013 # Since we have no information about the position of things within the
6014 # section, we cannot adjust the position of /section-u-boot so it ends
6015 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06006016 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07006017 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
6018 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06006019 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006020
Simon Glass8fbca772022-08-13 11:40:48 -06006021 def testMkimageImagename(self):
6022 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006023 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006024 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06006025
6026 # Check that the data appears in the file somewhere
6027 self.assertIn(U_BOOT_SPL_DATA, data)
6028
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006029 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06006030 name = data[0x20:0x40]
6031
6032 # Build the filename that we expect to be placed in there, by virtue of
6033 # the -n paraameter
6034 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6035
6036 # Check that the image name is set to the temporary filename used
6037 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6038
Simon Glassb1669752022-08-13 11:40:49 -06006039 def testMkimageImage(self):
6040 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006041 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006042 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006043
6044 # Check that the data appears in the file somewhere
6045 self.assertIn(U_BOOT_SPL_DATA, data)
6046
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006047 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006048 name = data[0x20:0x40]
6049
6050 # Build the filename that we expect to be placed in there, by virtue of
6051 # the -n paraameter
6052 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6053
6054 # Check that the image name is set to the temporary filename used
6055 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6056
6057 # Check the corect data is in the imagename file
6058 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6059
6060 def testMkimageImageNoContent(self):
6061 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006062 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006063 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006064 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006065 self.assertIn('Could not complete processing of contents',
6066 str(exc.exception))
6067
6068 def testMkimageImageBad(self):
6069 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006070 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006071 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006072 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006073 self.assertIn('Cannot use both imagename node and data-to-imagename',
6074 str(exc.exception))
6075
Simon Glassbd5cd882022-08-13 11:40:50 -06006076 def testCollectionOther(self):
6077 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006078 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006079 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6080 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6081 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6082 data)
6083
6084 def testMkimageCollection(self):
6085 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006086 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006087 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006088 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6089 self.assertEqual(expect, data[:len(expect)])
6090
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006091 def testCompressDtbPrependInvalid(self):
6092 """Test that invalid header is detected"""
6093 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006094 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006095 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6096 "'u-boot-dtb': 'invalid'", str(e.exception))
6097
6098 def testCompressDtbPrependLength(self):
6099 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006100 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006101 image = control.images['image']
6102 entries = image.GetEntries()
6103 self.assertIn('u-boot-dtb', entries)
6104 u_boot_dtb = entries['u-boot-dtb']
6105 self.assertIn('fdtmap', entries)
6106 fdtmap = entries['fdtmap']
6107
6108 image_fname = tools.get_output_filename('image.bin')
6109 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6110 dtb = fdt.Fdt.FromData(orig)
6111 dtb.Scan()
6112 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6113 expected = {
6114 'u-boot:size': len(U_BOOT_DATA),
6115 'u-boot-dtb:uncomp-size': len(orig),
6116 'u-boot-dtb:size': u_boot_dtb.size,
6117 'fdtmap:size': fdtmap.size,
6118 'size': len(data),
6119 }
6120 self.assertEqual(expected, props)
6121
6122 # Check implementation
6123 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6124 rest = data[len(U_BOOT_DATA):]
6125 comp_data_len = struct.unpack('<I', rest[:4])[0]
6126 comp_data = rest[4:4 + comp_data_len]
6127 orig2 = self._decompress(comp_data)
6128 self.assertEqual(orig, orig2)
6129
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006130 def testInvalidCompress(self):
6131 """Test that invalid compress algorithm is detected"""
6132 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006133 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006134 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6135
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006136 def testCompUtilCompressions(self):
6137 """Test compression algorithms"""
6138 for bintool in self.comp_bintools.values():
6139 self._CheckBintool(bintool)
6140 data = bintool.compress(COMPRESS_DATA)
6141 self.assertNotEqual(COMPRESS_DATA, data)
6142 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006143 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006144
6145 def testCompUtilVersions(self):
6146 """Test tool version of compression algorithms"""
6147 for bintool in self.comp_bintools.values():
6148 self._CheckBintool(bintool)
6149 version = bintool.version()
6150 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6151
6152 def testCompUtilPadding(self):
6153 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006154 # Skip zstd because it doesn't support padding
6155 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006156 self._CheckBintool(bintool)
6157 data = bintool.compress(COMPRESS_DATA)
6158 self.assertNotEqual(COMPRESS_DATA, data)
6159 data += tools.get_bytes(0, 64)
6160 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006161 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006162
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006163 def testCompressDtbZstd(self):
6164 """Test that zstd compress of device-tree files failed"""
6165 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006166 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006167 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6168 "requires a length header", str(e.exception))
6169
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006170 def testMkimageMultipleDataFiles(self):
6171 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006172 self._SetupSplElf()
6173 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006174 data = self._DoReadFile('252_mkimage_mult_data.dts')
6175 # Size of files are packed in their 4B big-endian format
6176 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6177 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6178 # Size info is always followed by a 4B zero value.
6179 expect += tools.get_bytes(0, 4)
6180 expect += U_BOOT_TPL_DATA
6181 # All but last files are 4B-aligned
6182 align_pad = len(U_BOOT_TPL_DATA) % 4
6183 if align_pad:
6184 expect += tools.get_bytes(0, align_pad)
6185 expect += U_BOOT_SPL_DATA
6186 self.assertEqual(expect, data[-len(expect):])
6187
Marek Vasutf7413f02023-07-18 07:23:58 -06006188 def testMkimageMultipleExpanded(self):
6189 """Test passing multiple files to mkimage in a mkimage entry"""
6190 self._SetupSplElf()
6191 self._SetupTplElf()
6192 entry_args = {
6193 'spl-bss-pad': 'y',
6194 'spl-dtb': 'y',
6195 }
6196 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6197 use_expanded=True, entry_args=entry_args)[0]
6198 pad_len = 10
6199 tpl_expect = U_BOOT_TPL_DATA
6200 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6201 spl_expect += U_BOOT_SPL_DTB_DATA
6202
6203 content = data[0x40:]
6204 lens = struct.unpack('>III', content[:12])
6205
6206 # Size of files are packed in their 4B big-endian format
6207 # Size info is always followed by a 4B zero value.
6208 self.assertEqual(len(tpl_expect), lens[0])
6209 self.assertEqual(len(spl_expect), lens[1])
6210 self.assertEqual(0, lens[2])
6211
6212 rest = content[12:]
6213 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6214
6215 rest = rest[len(tpl_expect):]
6216 align_pad = len(tpl_expect) % 4
6217 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6218 rest = rest[align_pad:]
6219 self.assertEqual(spl_expect, rest)
6220
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006221 def testMkimageMultipleNoContent(self):
6222 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006223 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006224 with self.assertRaises(ValueError) as exc:
6225 self._DoReadFile('253_mkimage_mult_no_content.dts')
6226 self.assertIn('Could not complete processing of contents',
6227 str(exc.exception))
6228
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006229 def testMkimageFilename(self):
6230 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006231 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006232 retcode = self._DoTestFile('254_mkimage_filename.dts')
6233 self.assertEqual(0, retcode)
6234 fname = tools.get_output_filename('mkimage-test.bin')
6235 self.assertTrue(os.path.exists(fname))
6236
Simon Glass56d05412022-02-28 07:16:54 -07006237 def testVpl(self):
6238 """Test that an image with VPL and its device tree can be created"""
6239 # ELF file with a '__bss_size' symbol
6240 self._SetupVplElf()
6241 data = self._DoReadFile('255_u_boot_vpl.dts')
6242 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6243
6244 def testVplNoDtb(self):
6245 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6246 self._SetupVplElf()
6247 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6248 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6249 data[:len(U_BOOT_VPL_NODTB_DATA)])
6250
6251 def testExpandedVpl(self):
6252 """Test that an expanded entry type is selected for TPL when needed"""
6253 self._SetupVplElf()
6254
6255 entry_args = {
6256 'vpl-bss-pad': 'y',
6257 'vpl-dtb': 'y',
6258 }
6259 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6260 entry_args=entry_args)
6261 image = control.images['image']
6262 entries = image.GetEntries()
6263 self.assertEqual(1, len(entries))
6264
6265 # We only have u-boot-vpl, which be expanded
6266 self.assertIn('u-boot-vpl', entries)
6267 entry = entries['u-boot-vpl']
6268 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6269 subent = entry.GetEntries()
6270 self.assertEqual(3, len(subent))
6271 self.assertIn('u-boot-vpl-nodtb', subent)
6272 self.assertIn('u-boot-vpl-bss-pad', subent)
6273 self.assertIn('u-boot-vpl-dtb', subent)
6274
6275 def testVplBssPadMissing(self):
6276 """Test that a missing symbol is detected"""
6277 self._SetupVplElf('u_boot_ucode_ptr')
6278 with self.assertRaises(ValueError) as e:
6279 self._DoReadFile('258_vpl_bss_pad.dts')
6280 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6281 str(e.exception))
6282
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306283 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306284 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306285 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6286 self.assertEqual(0, retcode)
6287 image = control.images['test_image']
6288 fname = tools.get_output_filename('test_image.bin')
6289 sname = tools.get_output_filename('symlink_to_test.bin')
6290 self.assertTrue(os.path.islink(sname))
6291 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006292
Andrew Davis6b463da2023-07-22 00:14:44 +05306293 def testSymlinkOverwrite(self):
6294 """Test that symlinked images can be overwritten"""
6295 testdir = TestFunctional._MakeInputDir('symlinktest')
6296 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6297 # build the same image again in the same directory so that existing symlink is present
6298 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6299 fname = tools.get_output_filename('test_image.bin')
6300 sname = tools.get_output_filename('symlink_to_test.bin')
6301 self.assertTrue(os.path.islink(sname))
6302 self.assertEqual(os.readlink(sname), fname)
6303
Simon Glass37f85de2022-10-20 18:22:47 -06006304 def testSymbolsElf(self):
6305 """Test binman can assign symbols embedded in an ELF file"""
6306 if not elf.ELF_TOOLS:
6307 self.skipTest('Python elftools not available')
6308 self._SetupTplElf('u_boot_binman_syms')
6309 self._SetupVplElf('u_boot_binman_syms')
6310 self._SetupSplElf('u_boot_binman_syms')
6311 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6312 image_fname = tools.get_output_filename('image.bin')
6313
6314 image = control.images['image']
6315 entries = image.GetEntries()
6316
6317 for entry in entries.values():
6318 # No symbols in u-boot and it has faked contents anyway
6319 if entry.name == 'u-boot':
6320 continue
6321 edata = data[entry.image_pos:entry.image_pos + entry.size]
6322 efname = tools.get_output_filename(f'edata-{entry.name}')
6323 tools.write_file(efname, edata)
6324
6325 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6326 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6327 for name, sym in syms.items():
6328 msg = 'test'
6329 val = elf.GetSymbolValue(sym, edata, msg)
6330 entry_m = re_name.match(name)
6331 if entry_m:
6332 ename, prop = entry_m.group(1), entry_m.group(3)
6333 entry, entry_name, prop_name = image.LookupEntry(entries,
6334 name, msg)
6335 if prop_name == 'offset':
6336 expect_val = entry.offset
6337 elif prop_name == 'image_pos':
6338 expect_val = entry.image_pos
6339 elif prop_name == 'size':
6340 expect_val = entry.size
6341 self.assertEqual(expect_val, val)
6342
6343 def testSymbolsElfBad(self):
6344 """Check error when trying to write symbols without the elftools lib"""
6345 if not elf.ELF_TOOLS:
6346 self.skipTest('Python elftools not available')
6347 self._SetupTplElf('u_boot_binman_syms')
6348 self._SetupVplElf('u_boot_binman_syms')
6349 self._SetupSplElf('u_boot_binman_syms')
6350 try:
6351 elf.ELF_TOOLS = False
6352 with self.assertRaises(ValueError) as exc:
6353 self._DoReadFileDtb('260_symbols_elf.dts')
6354 finally:
6355 elf.ELF_TOOLS = True
6356 self.assertIn(
6357 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6358 'Cannot write symbols to an ELF file without Python elftools',
6359 str(exc.exception))
6360
Simon Glassde244162023-01-07 14:07:08 -07006361 def testSectionFilename(self):
6362 """Check writing of section contents to a file"""
6363 data = self._DoReadFile('261_section_fname.dts')
6364 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6365 tools.get_bytes(ord('!'), 7) +
6366 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6367 self.assertEqual(expected, data)
6368
6369 sect_fname = tools.get_output_filename('outfile.bin')
6370 self.assertTrue(os.path.exists(sect_fname))
6371 sect_data = tools.read_file(sect_fname)
6372 self.assertEqual(U_BOOT_DATA, sect_data)
6373
Simon Glass1e9e61c2023-01-07 14:07:12 -07006374 def testAbsent(self):
6375 """Check handling of absent entries"""
6376 data = self._DoReadFile('262_absent.dts')
6377 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6378
Simon Glassad5cfe12023-01-07 14:07:14 -07006379 def testPackTeeOsOptional(self):
6380 """Test that an image with an optional TEE binary can be created"""
6381 entry_args = {
6382 'tee-os-path': 'tee.elf',
6383 }
6384 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6385 entry_args=entry_args)[0]
6386 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6387
6388 def checkFitTee(self, dts, tee_fname):
6389 """Check that a tee-os entry works and returns data
6390
6391 Args:
6392 dts (str): Device tree filename to use
6393 tee_fname (str): filename containing tee-os
6394
6395 Returns:
6396 bytes: Image contents
6397 """
6398 if not elf.ELF_TOOLS:
6399 self.skipTest('Python elftools not available')
6400 entry_args = {
6401 'of-list': 'test-fdt1 test-fdt2',
6402 'default-dt': 'test-fdt2',
6403 'tee-os-path': tee_fname,
6404 }
6405 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6406 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6407 extra_indirs=[test_subdir])[0]
6408 return data
6409
6410 def testFitTeeOsOptionalFit(self):
6411 """Test an image with a FIT with an optional OP-TEE binary"""
6412 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6413
6414 # There should be only one node, holding the data set up in SetUpClass()
6415 # for tee.bin
6416 dtb = fdt.Fdt.FromData(data)
6417 dtb.Scan()
6418 node = dtb.GetNode('/images/tee-1')
6419 self.assertEqual(TEE_ADDR,
6420 fdt_util.fdt32_to_cpu(node.props['load'].value))
6421 self.assertEqual(TEE_ADDR,
6422 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6423 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6424
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006425 with test_util.capture_sys_output() as (stdout, stderr):
6426 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6427 err = stderr.getvalue()
6428 self.assertRegex(
6429 err,
6430 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6431
Simon Glassad5cfe12023-01-07 14:07:14 -07006432 def testFitTeeOsOptionalFitBad(self):
6433 """Test an image with a FIT with an optional OP-TEE binary"""
6434 with self.assertRaises(ValueError) as exc:
6435 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6436 self.assertIn(
6437 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6438 str(exc.exception))
6439
6440 def testFitTeeOsBad(self):
6441 """Test an OP-TEE binary with wrong formats"""
6442 self.make_tee_bin('tee.bad1', 123)
6443 with self.assertRaises(ValueError) as exc:
6444 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6445 self.assertIn(
6446 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6447 str(exc.exception))
6448
6449 self.make_tee_bin('tee.bad2', 0, b'extra data')
6450 with self.assertRaises(ValueError) as exc:
6451 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6452 self.assertIn(
6453 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6454 str(exc.exception))
6455
Simon Glass63328f12023-01-07 14:07:15 -07006456 def testExtblobOptional(self):
6457 """Test an image with an external blob that is optional"""
6458 with test_util.capture_sys_output() as (stdout, stderr):
6459 data = self._DoReadFile('266_blob_ext_opt.dts')
6460 self.assertEqual(REFCODE_DATA, data)
6461 err = stderr.getvalue()
6462 self.assertRegex(
6463 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006464 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006465
Simon Glass7447a9d2023-01-11 16:10:12 -07006466 def testSectionInner(self):
6467 """Test an inner section with a size"""
6468 data = self._DoReadFile('267_section_inner.dts')
6469 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6470 self.assertEqual(expected, data)
6471
Simon Glassa4948b22023-01-11 16:10:14 -07006472 def testNull(self):
6473 """Test an image with a null entry"""
6474 data = self._DoReadFile('268_null.dts')
6475 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6476
Simon Glassf1ee03b2023-01-11 16:10:16 -07006477 def testOverlap(self):
6478 """Test an image with a overlapping entry"""
6479 data = self._DoReadFile('269_overlap.dts')
6480 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6481
6482 image = control.images['image']
6483 entries = image.GetEntries()
6484
6485 self.assertIn('inset', entries)
6486 inset = entries['inset']
6487 self.assertEqual(1, inset.offset);
6488 self.assertEqual(1, inset.image_pos);
6489 self.assertEqual(2, inset.size);
6490
6491 def testOverlapNull(self):
6492 """Test an image with a null overlap"""
6493 data = self._DoReadFile('270_overlap_null.dts')
6494 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6495
6496 # Check the FMAP
6497 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6498 self.assertEqual(4, fhdr.nareas)
6499 fiter = iter(fentries)
6500
6501 fentry = next(fiter)
6502 self.assertEqual(b'SECTION', fentry.name)
6503 self.assertEqual(0, fentry.offset)
6504 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6505 self.assertEqual(0, fentry.flags)
6506
6507 fentry = next(fiter)
6508 self.assertEqual(b'U_BOOT', fentry.name)
6509 self.assertEqual(0, fentry.offset)
6510 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6511 self.assertEqual(0, fentry.flags)
6512
6513 # Make sure that the NULL entry appears in the FMAP
6514 fentry = next(fiter)
6515 self.assertEqual(b'NULL', fentry.name)
6516 self.assertEqual(1, fentry.offset)
6517 self.assertEqual(2, fentry.size)
6518 self.assertEqual(0, fentry.flags)
6519
6520 fentry = next(fiter)
6521 self.assertEqual(b'FMAP', fentry.name)
6522 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6523
6524 def testOverlapBad(self):
6525 """Test an image with a bad overlapping entry"""
6526 with self.assertRaises(ValueError) as exc:
6527 self._DoReadFile('271_overlap_bad.dts')
6528 self.assertIn(
6529 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6530 str(exc.exception))
6531
6532 def testOverlapNoOffset(self):
6533 """Test an image with a bad overlapping entry"""
6534 with self.assertRaises(ValueError) as exc:
6535 self._DoReadFile('272_overlap_no_size.dts')
6536 self.assertIn(
6537 "Node '/binman/inset': 'fill' entry is missing properties: size",
6538 str(exc.exception))
6539
Simon Glasse0035c92023-01-11 16:10:17 -07006540 def testBlobSymbol(self):
6541 """Test a blob with symbols read from an ELF file"""
6542 elf_fname = self.ElfTestFile('blob_syms')
6543 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6544 TestFunctional._MakeInputFile('blob_syms.bin',
6545 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6546
6547 data = self._DoReadFile('273_blob_symbol.dts')
6548
6549 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6550 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6551 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6552 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6553 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6554
6555 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6556 expected = sym_values
6557 self.assertEqual(expected, data[:len(expected)])
6558
Simon Glass49e9c002023-01-11 16:10:19 -07006559 def testOffsetFromElf(self):
6560 """Test a blob with symbols read from an ELF file"""
6561 elf_fname = self.ElfTestFile('blob_syms')
6562 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6563 TestFunctional._MakeInputFile('blob_syms.bin',
6564 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6565
6566 data = self._DoReadFile('274_offset_from_elf.dts')
6567
6568 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6569 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6570
6571 image = control.images['image']
6572 entries = image.GetEntries()
6573
6574 self.assertIn('inset', entries)
6575 inset = entries['inset']
6576
6577 self.assertEqual(base + 4, inset.offset);
6578 self.assertEqual(base + 4, inset.image_pos);
6579 self.assertEqual(4, inset.size);
6580
6581 self.assertIn('inset2', entries)
6582 inset = entries['inset2']
6583 self.assertEqual(base + 8, inset.offset);
6584 self.assertEqual(base + 8, inset.image_pos);
6585 self.assertEqual(4, inset.size);
6586
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006587 def testFitAlign(self):
6588 """Test an image with an FIT with aligned external data"""
6589 data = self._DoReadFile('275_fit_align.dts')
6590 self.assertEqual(4096, len(data))
6591
6592 dtb = fdt.Fdt.FromData(data)
6593 dtb.Scan()
6594
6595 props = self._GetPropTree(dtb, ['data-position'])
6596 expected = {
6597 'u-boot:data-position': 1024,
6598 'fdt-1:data-position': 2048,
6599 'fdt-2:data-position': 3072,
6600 }
6601 self.assertEqual(expected, props)
6602
Jonas Karlman490f73c2023-01-21 19:02:12 +00006603 def testFitFirmwareLoadables(self):
6604 """Test an image with an FIT that use fit,firmware"""
6605 if not elf.ELF_TOOLS:
6606 self.skipTest('Python elftools not available')
6607 entry_args = {
6608 'of-list': 'test-fdt1',
6609 'default-dt': 'test-fdt1',
6610 'atf-bl31-path': 'bl31.elf',
6611 'tee-os-path': 'missing.bin',
6612 }
6613 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006614 with test_util.capture_sys_output() as (stdout, stderr):
6615 data = self._DoReadFileDtb(
6616 '276_fit_firmware_loadables.dts',
6617 entry_args=entry_args,
6618 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006619
6620 dtb = fdt.Fdt.FromData(data)
6621 dtb.Scan()
6622
6623 node = dtb.GetNode('/configurations/conf-uboot-1')
6624 self.assertEqual('u-boot', node.props['firmware'].value)
6625 self.assertEqual(['atf-1', 'atf-2'],
6626 fdt_util.GetStringList(node, 'loadables'))
6627
6628 node = dtb.GetNode('/configurations/conf-atf-1')
6629 self.assertEqual('atf-1', node.props['firmware'].value)
6630 self.assertEqual(['u-boot', 'atf-2'],
6631 fdt_util.GetStringList(node, 'loadables'))
6632
6633 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6634 self.assertEqual('u-boot', node.props['firmware'].value)
6635 self.assertEqual(['atf-1', 'atf-2'],
6636 fdt_util.GetStringList(node, 'loadables'))
6637
6638 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6639 self.assertEqual('atf-1', node.props['firmware'].value)
6640 self.assertEqual(['u-boot', 'atf-2'],
6641 fdt_util.GetStringList(node, 'loadables'))
6642
6643 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6644 self.assertEqual('atf-1', node.props['firmware'].value)
6645 self.assertEqual(['u-boot', 'atf-2'],
6646 fdt_util.GetStringList(node, 'loadables'))
6647
Simon Glass9a1c7262023-02-22 12:14:49 -07006648 def testTooldir(self):
6649 """Test that we can specify the tooldir"""
6650 with test_util.capture_sys_output() as (stdout, stderr):
6651 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6652 'tool', '-l'))
6653 self.assertEqual('fred', bintool.Bintool.tooldir)
6654
6655 # Check that the toolpath is updated correctly
6656 self.assertEqual(['fred'], tools.tool_search_paths)
6657
6658 # Try with a few toolpaths; the tooldir should be at the end
6659 with test_util.capture_sys_output() as (stdout, stderr):
6660 self.assertEqual(0, self._DoBinman(
6661 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6662 'tool', '-l'))
6663 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6664
Simon Glass49b77e82023-03-02 17:02:44 -07006665 def testReplaceSectionEntry(self):
6666 """Test replacing an entry in a section"""
6667 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6668 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6669 expect_data, dts='241_replace_section_simple.dts')
6670 self.assertEqual(expect_data, entry_data)
6671
6672 entries = image.GetEntries()
6673 self.assertIn('section', entries)
6674 section = entries['section']
6675
6676 sect_entries = section.GetEntries()
6677 self.assertIn('blob', sect_entries)
6678 entry = sect_entries['blob']
6679 self.assertEqual(len(expect_data), entry.size)
6680
6681 fname = tools.get_output_filename('image-updated.bin')
6682 data = tools.read_file(fname)
6683
6684 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6685 self.assertEqual(expect_data, new_blob_data)
6686
6687 self.assertEqual(U_BOOT_DATA,
6688 data[entry.image_pos + len(expect_data):]
6689 [:len(U_BOOT_DATA)])
6690
6691 def testReplaceSectionDeep(self):
6692 """Test replacing an entry in two levels of sections"""
6693 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6694 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6695 'section/section/blob', expect_data,
6696 dts='278_replace_section_deep.dts')
6697 self.assertEqual(expect_data, entry_data)
6698
6699 entries = image.GetEntries()
6700 self.assertIn('section', entries)
6701 section = entries['section']
6702
6703 subentries = section.GetEntries()
6704 self.assertIn('section', subentries)
6705 section = subentries['section']
6706
6707 sect_entries = section.GetEntries()
6708 self.assertIn('blob', sect_entries)
6709 entry = sect_entries['blob']
6710 self.assertEqual(len(expect_data), entry.size)
6711
6712 fname = tools.get_output_filename('image-updated.bin')
6713 data = tools.read_file(fname)
6714
6715 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6716 self.assertEqual(expect_data, new_blob_data)
6717
6718 self.assertEqual(U_BOOT_DATA,
6719 data[entry.image_pos + len(expect_data):]
6720 [:len(U_BOOT_DATA)])
6721
6722 def testReplaceFitSibling(self):
6723 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006724 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006725 fname = TestFunctional._MakeInputFile('once', b'available once')
6726 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6727 os.remove(fname)
6728
6729 try:
6730 tmpdir, updated_fname = self._SetupImageInTmpdir()
6731
6732 fname = os.path.join(tmpdir, 'update-blob')
6733 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6734 tools.write_file(fname, expected)
6735
6736 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6737 data = tools.read_file(updated_fname)
6738 start = len(U_BOOT_DTB_DATA)
6739 self.assertEqual(expected, data[start:start + len(expected)])
6740 map_fname = os.path.join(tmpdir, 'image-updated.map')
6741 self.assertFalse(os.path.exists(map_fname))
6742 finally:
6743 shutil.rmtree(tmpdir)
6744
Simon Glassc3fe97f2023-03-02 17:02:45 -07006745 def testX509Cert(self):
6746 """Test creating an X509 certificate"""
6747 keyfile = self.TestFile('key.key')
6748 entry_args = {
6749 'keyfile': keyfile,
6750 }
6751 data = self._DoReadFileDtb('279_x509_cert.dts',
6752 entry_args=entry_args)[0]
6753 cert = data[:-4]
6754 self.assertEqual(U_BOOT_DATA, data[-4:])
6755
6756 # TODO: verify the signature
6757
6758 def testX509CertMissing(self):
6759 """Test that binman still produces an image if openssl is missing"""
6760 keyfile = self.TestFile('key.key')
6761 entry_args = {
6762 'keyfile': 'keyfile',
6763 }
6764 with test_util.capture_sys_output() as (_, stderr):
6765 self._DoTestFile('279_x509_cert.dts',
6766 force_missing_bintools='openssl',
6767 entry_args=entry_args)
6768 err = stderr.getvalue()
6769 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6770
Jonas Karlman35305492023-02-25 19:01:33 +00006771 def testPackRockchipTpl(self):
6772 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006773 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006774 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6775
Jonas Karlman1016ec72023-02-25 19:01:35 +00006776 def testMkimageMissingBlobMultiple(self):
6777 """Test missing blob with mkimage entry and multiple-data-files"""
6778 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006779 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006780 err = stderr.getvalue()
6781 self.assertIn("is missing external blobs and is non-functional", err)
6782
6783 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006784 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006785 self.assertIn("not found in input path", str(e.exception))
6786
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006787 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6788 """Prepare sign environment
6789
6790 Create private and public keys, add pubkey into dtb.
6791
6792 Returns:
6793 Tuple:
6794 FIT container
6795 Image name
6796 Private key
6797 DTB
6798 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006799 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006800 data = self._DoReadFileRealDtb(dts)
6801 updated_fname = tools.get_output_filename('image-updated.bin')
6802 tools.write_file(updated_fname, data)
6803 dtb = tools.get_output_filename('source.dtb')
6804 private_key = tools.get_output_filename('test_key.key')
6805 public_key = tools.get_output_filename('test_key.crt')
6806 fit = tools.get_output_filename('fit.fit')
6807 key_dir = tools.get_output_dir()
6808
6809 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6810 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6811 private_key, '-out', public_key)
6812 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6813 '-n', 'test_key', '-r', 'conf', dtb)
6814
6815 return fit, updated_fname, private_key, dtb
6816
6817 def testSignSimple(self):
6818 """Test that a FIT container can be signed in image"""
6819 is_signed = False
6820 fit, fname, private_key, dtb = self._PrepareSignEnv()
6821
6822 # do sign with private key
6823 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6824 ['fit'])
6825 is_signed = self._CheckSign(fit, dtb)
6826
6827 self.assertEqual(is_signed, True)
6828
6829 def testSignExactFIT(self):
6830 """Test that a FIT container can be signed and replaced in image"""
6831 is_signed = False
6832 fit, fname, private_key, dtb = self._PrepareSignEnv()
6833
6834 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6835 args = []
6836 if self.toolpath:
6837 for path in self.toolpath:
6838 args += ['--toolpath', path]
6839
6840 # do sign with private key
6841 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6842 'sha256,rsa4096', '-f', fit, 'fit')
6843 is_signed = self._CheckSign(fit, dtb)
6844
6845 self.assertEqual(is_signed, True)
6846
6847 def testSignNonFit(self):
6848 """Test a non-FIT entry cannot be signed"""
6849 is_signed = False
6850 fit, fname, private_key, _ = self._PrepareSignEnv(
6851 '281_sign_non_fit.dts')
6852
6853 # do sign with private key
6854 with self.assertRaises(ValueError) as e:
6855 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6856 'sha256,rsa4096', '-f', fit, 'u-boot')
6857 self.assertIn(
6858 "Node '/u-boot': Updating signatures is not supported with this entry type",
6859 str(e.exception))
6860
6861 def testSignMissingMkimage(self):
6862 """Test that FIT signing handles a missing mkimage tool"""
6863 fit, fname, private_key, _ = self._PrepareSignEnv()
6864
6865 # try to sign with a missing mkimage tool
6866 bintool.Bintool.set_missing_list(['mkimage'])
6867 with self.assertRaises(ValueError) as e:
6868 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6869 ['fit'])
6870 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6871
Simon Glass4abf7842023-07-18 07:23:54 -06006872 def testSymbolNoWrite(self):
6873 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006874 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006875 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6876 no_write_symbols=True)
6877
6878 def testSymbolNoWriteExpanded(self):
6879 """Test disabling of symbol writing in expanded entries"""
6880 entry_args = {
6881 'spl-dtb': '1',
6882 }
6883 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6884 U_BOOT_SPL_DTB_DATA, 0x38,
6885 entry_args=entry_args, use_expanded=True,
6886 no_write_symbols=True)
6887
Marek Vasutf7413f02023-07-18 07:23:58 -06006888 def testMkimageSpecial(self):
6889 """Test mkimage ignores special hash-1 node"""
6890 data = self._DoReadFile('283_mkimage_special.dts')
6891
6892 # Just check that the data appears in the file somewhere
6893 self.assertIn(U_BOOT_DATA, data)
6894
Simon Glass2d94c422023-07-18 07:23:59 -06006895 def testFitFdtList(self):
6896 """Test an image with an FIT with the fit,fdt-list-val option"""
6897 entry_args = {
6898 'default-dt': 'test-fdt2',
6899 }
6900 data = self._DoReadFileDtb(
6901 '284_fit_fdt_list.dts',
6902 entry_args=entry_args,
6903 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6904 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6905 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6906
Simon Glass83b8bfe2023-07-18 07:24:01 -06006907 def testSplEmptyBss(self):
6908 """Test an expanded SPL with a zero-size BSS"""
6909 # ELF file with a '__bss_size' symbol
6910 self._SetupSplElf(src_fname='bss_data_zero')
6911
6912 entry_args = {
6913 'spl-bss-pad': 'y',
6914 'spl-dtb': 'y',
6915 }
6916 data = self._DoReadFileDtb('285_spl_expand.dts',
6917 use_expanded=True, entry_args=entry_args)[0]
6918
Simon Glassfc792842023-07-18 07:24:04 -06006919 def testTemplate(self):
6920 """Test using a template"""
6921 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6922 data = self._DoReadFile('286_template.dts')
6923 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6924 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6925 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6926
Simon Glass09490b02023-07-22 21:43:52 -06006927 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6928 self.assertTrue(os.path.exists(dtb_fname1))
6929 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6930 dtb.Scan()
6931 node1 = dtb.GetNode('/binman/template')
6932 self.assertTrue(node1)
6933 vga = dtb.GetNode('/binman/first/intel-vga')
6934 self.assertTrue(vga)
6935
Simon Glass54825e12023-07-22 21:43:56 -06006936 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6937 self.assertTrue(os.path.exists(dtb_fname2))
6938 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6939 dtb2.Scan()
6940 node2 = dtb2.GetNode('/binman/template')
6941 self.assertFalse(node2)
6942
Simon Glass9909c112023-07-18 07:24:05 -06006943 def testTemplateBlobMulti(self):
6944 """Test using a template with 'multiple-images' enabled"""
6945 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6946 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6947 retcode = self._DoTestFile('287_template_multi.dts')
6948
6949 self.assertEqual(0, retcode)
6950 image = control.images['image']
6951 image_fname = tools.get_output_filename('my-image.bin')
6952 data = tools.read_file(image_fname)
6953 self.assertEqual(b'blob@@@@other', data)
6954
Simon Glass5dc511b2023-07-18 07:24:06 -06006955 def testTemplateFit(self):
6956 """Test using a template in a FIT"""
6957 fit_data = self._DoReadFile('288_template_fit.dts')
6958 fname = os.path.join(self._indir, 'fit_data.fit')
6959 tools.write_file(fname, fit_data)
6960 out = tools.run('dumpimage', '-l', fname)
6961
Simon Glassaa6e0552023-07-18 07:24:07 -06006962 def testTemplateSection(self):
6963 """Test using a template in a section (not at top level)"""
6964 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6965 data = self._DoReadFile('289_template_section.dts')
6966 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6967 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6968 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6969
Simon Glassf53a7bc2023-07-18 07:24:08 -06006970 def testMkimageSymbols(self):
6971 """Test using mkimage to build an image with symbols in it"""
6972 self._SetupSplElf('u_boot_binman_syms')
6973 data = self._DoReadFile('290_mkimage_sym.dts')
6974
6975 image = control.images['image']
6976 entries = image.GetEntries()
6977 self.assertIn('u-boot', entries)
6978 u_boot = entries['u-boot']
6979
6980 mkim = entries['mkimage']
6981 mkim_entries = mkim.GetEntries()
6982 self.assertIn('u-boot-spl', mkim_entries)
6983 spl = mkim_entries['u-boot-spl']
6984 self.assertIn('u-boot-spl2', mkim_entries)
6985 spl2 = mkim_entries['u-boot-spl2']
6986
6987 # skip the mkimage header and the area sizes
6988 mk_data = data[mkim.offset + 0x40:]
6989 size, term = struct.unpack('>LL', mk_data[:8])
6990
6991 # There should be only one image, so check that the zero terminator is
6992 # present
6993 self.assertEqual(0, term)
6994
6995 content = mk_data[8:8 + size]
6996
6997 # The image should contain the symbols from u_boot_binman_syms.c
6998 # Note that image_pos is adjusted by the base address of the image,
6999 # which is 0x10 in our test image
7000 spl_data = content[:0x18]
7001 content = content[0x1b:]
7002
7003 # After the header is a table of offsets for each image. There should
7004 # only be one image, then a 0 terminator, so figure out the real start
7005 # of the image data
7006 base = 0x40 + 8
7007
7008 # Check symbols in both u-boot-spl and u-boot-spl2
7009 for i in range(2):
7010 vals = struct.unpack('<LLQLL', spl_data)
7011
7012 # The image should contain the symbols from u_boot_binman_syms.c
7013 # Note that image_pos is adjusted by the base address of the image,
7014 # which is 0x10 in our 'u_boot_binman_syms' test image
7015 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
7016 self.assertEqual(base, vals[1])
7017 self.assertEqual(spl2.offset, vals[2])
7018 # figure out the internal positions of its components
7019 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
7020
7021 # Check that spl and spl2 are actually at the indicated positions
7022 self.assertEqual(
7023 elf.BINMAN_SYM_MAGIC_VALUE,
7024 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
7025 self.assertEqual(
7026 elf.BINMAN_SYM_MAGIC_VALUE,
7027 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
7028
7029 self.assertEqual(len(U_BOOT_DATA), vals[4])
7030
7031 # Move to next
7032 spl_data = content[:0x18]
7033
Simon Glass86b3e472023-07-22 21:43:57 -06007034 def testTemplatePhandle(self):
7035 """Test using a template in a node containing a phandle"""
7036 entry_args = {
7037 'atf-bl31-path': 'bl31.elf',
7038 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06007039 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007040 entry_args=entry_args)
7041 fname = tools.get_output_filename('image.bin')
7042 out = tools.run('dumpimage', '-l', fname)
7043
7044 # We should see the FIT description and one for each of the two images
7045 lines = out.splitlines()
7046 descs = [line.split()[-1] for line in lines if 'escription' in line]
7047 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7048
7049 def testTemplatePhandleDup(self):
7050 """Test using a template in a node containing a phandle"""
7051 entry_args = {
7052 'atf-bl31-path': 'bl31.elf',
7053 }
7054 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007055 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007056 entry_args=entry_args)
7057 self.assertIn(
7058 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7059 str(e.exception))
7060
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307061 def testTIBoardConfig(self):
7062 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007063 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307064 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7065
Neha Malcom Francis8cd04512024-01-05 17:09:17 +05307066 def testTIBoardConfigLint(self):
7067 """Test that an incorrectly linted config file would generate error"""
7068 with self.assertRaises(ValueError) as e:
7069 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7070 self.assertIn("Yamllint error", str(e.exception))
7071
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307072 def testTIBoardConfigCombined(self):
7073 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007074 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307075 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7076 self.assertGreater(data, configlen_noheader)
7077
7078 def testTIBoardConfigNoDataType(self):
7079 """Test that error is thrown when data type is not supported"""
7080 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007081 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307082 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007083
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307084 def testPackTiSecure(self):
7085 """Test that an image with a TI secured binary can be created"""
7086 keyfile = self.TestFile('key.key')
7087 entry_args = {
7088 'keyfile': keyfile,
7089 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007090 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307091 entry_args=entry_args)[0]
7092 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7093
Manorit Chawdhry2e523b02023-12-29 16:16:27 +05307094 def testPackTiSecureFirewall(self):
7095 """Test that an image with a TI secured binary can be created"""
7096 keyfile = self.TestFile('key.key')
7097 entry_args = {
7098 'keyfile': keyfile,
7099 }
7100 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7101 entry_args=entry_args)[0]
7102 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7103 entry_args=entry_args)[0]
7104 self.assertGreater(len(data_firewall),len(data_no_firewall))
7105
7106 def testPackTiSecureFirewallMissingProperty(self):
7107 """Test that an image with a TI secured binary can be created"""
7108 keyfile = self.TestFile('key.key')
7109 entry_args = {
7110 'keyfile': keyfile,
7111 }
7112 with self.assertRaises(ValueError) as e:
7113 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7114 entry_args=entry_args)[0]
7115 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7116
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307117 def testPackTiSecureMissingTool(self):
7118 """Test that an image with a TI secured binary (non-functional) can be created
7119 when openssl is missing"""
7120 keyfile = self.TestFile('key.key')
7121 entry_args = {
7122 'keyfile': keyfile,
7123 }
7124 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007125 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307126 force_missing_bintools='openssl',
7127 entry_args=entry_args)
7128 err = stderr.getvalue()
7129 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7130
7131 def testPackTiSecureROM(self):
7132 """Test that a ROM image with a TI secured binary can be created"""
7133 keyfile = self.TestFile('key.key')
7134 entry_args = {
7135 'keyfile': keyfile,
7136 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007137 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307138 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007139 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307140 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007141 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307142 entry_args=entry_args)[0]
7143 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7144 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7145 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7146
7147 def testPackTiSecureROMCombined(self):
7148 """Test that a ROM image with a TI secured binary can be created"""
7149 keyfile = self.TestFile('key.key')
7150 entry_args = {
7151 'keyfile': keyfile,
7152 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007153 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307154 entry_args=entry_args)[0]
7155 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7156
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007157 def testEncryptedNoAlgo(self):
7158 """Test encrypted node with missing required properties"""
7159 with self.assertRaises(ValueError) as e:
7160 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7161 self.assertIn(
7162 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7163 str(e.exception))
7164
7165 def testEncryptedInvalidIvfile(self):
7166 """Test encrypted node with invalid iv file"""
7167 with self.assertRaises(ValueError) as e:
7168 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7169 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7170 str(e.exception))
7171
7172 def testEncryptedMissingKey(self):
7173 """Test encrypted node with missing key properties"""
7174 with self.assertRaises(ValueError) as e:
7175 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7176 self.assertIn(
7177 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7178 str(e.exception))
7179
7180 def testEncryptedKeySource(self):
7181 """Test encrypted node with key-source property"""
7182 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7183
7184 dtb = fdt.Fdt.FromData(data)
7185 dtb.Scan()
7186
7187 node = dtb.GetNode('/images/u-boot/cipher')
7188 self.assertEqual('algo-name', node.props['algo'].value)
7189 self.assertEqual('key-source-value', node.props['key-source'].value)
7190 self.assertEqual(ENCRYPTED_IV_DATA,
7191 tools.to_bytes(''.join(node.props['iv'].value)))
7192 self.assertNotIn('key', node.props)
7193
7194 def testEncryptedKeyFile(self):
7195 """Test encrypted node with key-filename property"""
7196 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7197
7198 dtb = fdt.Fdt.FromData(data)
7199 dtb.Scan()
7200
7201 node = dtb.GetNode('/images/u-boot/cipher')
7202 self.assertEqual('algo-name', node.props['algo'].value)
7203 self.assertEqual(ENCRYPTED_IV_DATA,
7204 tools.to_bytes(''.join(node.props['iv'].value)))
7205 self.assertEqual(ENCRYPTED_KEY_DATA,
7206 tools.to_bytes(''.join(node.props['key'].value)))
7207 self.assertNotIn('key-source', node.props)
7208
Lukas Funkee901faf2023-07-18 13:53:13 +02007209
7210 def testSplPubkeyDtb(self):
Simon Glass4b861272024-07-20 11:49:41 +01007211 """Test u_boot_spl_pubkey_dtb etype"""
7212 data = tools.read_file(self.TestFile("key.pem"))
7213 self._MakeInputFile("key.crt", data)
7214 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7215 image = control.images['image']
7216 entries = image.GetEntries()
7217 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7218 dtb_data = dtb_entry.GetData()
7219 dtb = fdt.Fdt.FromData(dtb_data)
7220 dtb.Scan()
Lukas Funkee901faf2023-07-18 13:53:13 +02007221
Simon Glass4b861272024-07-20 11:49:41 +01007222 signature_node = dtb.GetNode('/signature')
7223 self.assertIsNotNone(signature_node)
7224 key_node = signature_node.FindNode("key-key")
7225 self.assertIsNotNone(key_node)
7226 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7227 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7228 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007229
Lukas Funke712e1062023-08-03 17:22:14 +02007230 def testXilinxBootgenSigning(self):
7231 """Test xilinx-bootgen etype"""
7232 bootgen = bintool.Bintool.create('bootgen')
7233 self._CheckBintool(bootgen)
7234 data = tools.read_file(self.TestFile("key.key"))
7235 self._MakeInputFile("psk.pem", data)
7236 self._MakeInputFile("ssk.pem", data)
7237 self._SetupPmuFwlElf()
7238 self._SetupSplElf()
7239 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7240 image_fname = tools.get_output_filename('image.bin')
7241
7242 # Read partition header table and check if authentication is enabled
7243 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7244 "-read", image_fname, "pht").splitlines()
7245 attributes = {"authentication": None,
7246 "core": None,
7247 "encryption": None}
7248
7249 for l in bootgen_out:
7250 for a in attributes.keys():
7251 if a in l:
7252 m = re.match(fr".*{a} \[([^]]+)\]", l)
7253 attributes[a] = m.group(1)
7254
7255 self.assertTrue(attributes['authentication'] == "rsa")
7256 self.assertTrue(attributes['core'] == "a53-0")
7257 self.assertTrue(attributes['encryption'] == "no")
7258
7259 def testXilinxBootgenSigningEncryption(self):
7260 """Test xilinx-bootgen etype"""
7261 bootgen = bintool.Bintool.create('bootgen')
7262 self._CheckBintool(bootgen)
7263 data = tools.read_file(self.TestFile("key.key"))
7264 self._MakeInputFile("psk.pem", data)
7265 self._MakeInputFile("ssk.pem", data)
7266 self._SetupPmuFwlElf()
7267 self._SetupSplElf()
7268 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7269 image_fname = tools.get_output_filename('image.bin')
7270
7271 # Read boot header in order to verify encryption source and
7272 # encryption parameter
7273 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7274 "-read", image_fname, "bh").splitlines()
7275 attributes = {"auth_only":
7276 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7277 "encryption_keystore":
7278 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7279 "value": None},
7280 }
7281
7282 for l in bootgen_out:
7283 for a in attributes.keys():
7284 if a in l:
7285 m = re.match(attributes[a]['re'], l)
7286 attributes[a] = m.group(1)
7287
7288 # Check if fsbl-attribute is set correctly
7289 self.assertTrue(attributes['auth_only'] == "true")
7290 # Check if key is stored in efuse
7291 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7292
7293 def testXilinxBootgenMissing(self):
7294 """Test that binman still produces an image if bootgen is missing"""
7295 data = tools.read_file(self.TestFile("key.key"))
7296 self._MakeInputFile("psk.pem", data)
7297 self._MakeInputFile("ssk.pem", data)
7298 self._SetupPmuFwlElf()
7299 self._SetupSplElf()
7300 with test_util.capture_sys_output() as (_, stderr):
7301 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7302 force_missing_bintools='bootgen')
7303 err = stderr.getvalue()
7304 self.assertRegex(err,
7305 "Image 'image'.*missing bintools.*: bootgen")
7306
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307307 def _GetCapsuleHeaders(self, data):
7308 """Get the capsule header contents
7309
7310 Args:
7311 data: Capsule file contents
7312
7313 Returns:
7314 Dict:
7315 key: Capsule Header name (str)
7316 value: Header field value (str)
7317 """
7318 capsule_file = os.path.join(self._indir, 'test.capsule')
7319 tools.write_file(capsule_file, data)
7320
7321 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7322 lines = out.splitlines()
7323
7324 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7325 vals = {}
7326 for line in lines:
7327 mat = re_line.match(line)
7328 if mat:
7329 vals[mat.group(1)] = mat.group(2)
7330
7331 return vals
7332
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307333 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7334 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307335 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7336 fmp_size = "00000010"
7337 fmp_fw_version = "00000002"
7338 capsule_image_index = "00000001"
7339 oemflag = "00018000"
7340 auth_hdr_revision = "00000200"
7341 auth_hdr_cert_type = "00000EF1"
7342
7343 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307344
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307345 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307346
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307347 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307348
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307349 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7350 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7351 self.assertEqual(capsule_image_index,
7352 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307353
7354 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307355 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7356
7357 if signed_capsule:
7358 self.assertEqual(auth_hdr_revision,
7359 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7360 self.assertEqual(auth_hdr_cert_type,
7361 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7362 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7363 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7364
7365 if version_check:
7366 self.assertEqual(fmp_signature,
7367 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7368 self.assertEqual(fmp_size,
7369 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7370 self.assertEqual(fmp_fw_version,
7371 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7372
7373 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307374
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307375 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7376 if accept_capsule:
7377 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7378 else:
7379 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7380
7381 hdr = self._GetCapsuleHeaders(data)
7382
7383 self.assertEqual(capsule_hdr_guid.upper(),
7384 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7385
7386 if accept_capsule:
7387 capsule_size = "0000002C"
7388 else:
7389 capsule_size = "0000001C"
7390 self.assertEqual(capsule_size,
7391 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7392
7393 if accept_capsule:
7394 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7395
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307396 def testCapsuleGen(self):
7397 """Test generation of EFI capsule"""
7398 data = self._DoReadFile('311_capsule.dts')
7399
7400 self._CheckCapsule(data)
7401
7402 def testSignedCapsuleGen(self):
7403 """Test generation of EFI capsule"""
7404 data = tools.read_file(self.TestFile("key.key"))
7405 self._MakeInputFile("key.key", data)
7406 data = tools.read_file(self.TestFile("key.pem"))
7407 self._MakeInputFile("key.crt", data)
7408
7409 data = self._DoReadFile('312_capsule_signed.dts')
7410
7411 self._CheckCapsule(data, signed_capsule=True)
7412
7413 def testCapsuleGenVersionSupport(self):
7414 """Test generation of EFI capsule with version support"""
7415 data = self._DoReadFile('313_capsule_version.dts')
7416
7417 self._CheckCapsule(data, version_check=True)
7418
7419 def testCapsuleGenSignedVer(self):
7420 """Test generation of signed EFI capsule with version information"""
7421 data = tools.read_file(self.TestFile("key.key"))
7422 self._MakeInputFile("key.key", data)
7423 data = tools.read_file(self.TestFile("key.pem"))
7424 self._MakeInputFile("key.crt", data)
7425
7426 data = self._DoReadFile('314_capsule_signed_ver.dts')
7427
7428 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7429
7430 def testCapsuleGenCapOemFlags(self):
7431 """Test generation of EFI capsule with OEM Flags set"""
7432 data = self._DoReadFile('315_capsule_oemflags.dts')
7433
7434 self._CheckCapsule(data, capoemflags=True)
7435
7436 def testCapsuleGenKeyMissing(self):
7437 """Test that binman errors out on missing key"""
7438 with self.assertRaises(ValueError) as e:
7439 self._DoReadFile('316_capsule_missing_key.dts')
7440
7441 self.assertIn("Both private key and public key certificate need to be provided",
7442 str(e.exception))
7443
7444 def testCapsuleGenIndexMissing(self):
7445 """Test that binman errors out on missing image index"""
7446 with self.assertRaises(ValueError) as e:
7447 self._DoReadFile('317_capsule_missing_index.dts')
7448
7449 self.assertIn("entry is missing properties: image-index",
7450 str(e.exception))
7451
7452 def testCapsuleGenGuidMissing(self):
7453 """Test that binman errors out on missing image GUID"""
7454 with self.assertRaises(ValueError) as e:
7455 self._DoReadFile('318_capsule_missing_guid.dts')
7456
7457 self.assertIn("entry is missing properties: image-guid",
7458 str(e.exception))
7459
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307460 def testCapsuleGenAcceptCapsule(self):
7461 """Test generationg of accept EFI capsule"""
7462 data = self._DoReadFile('319_capsule_accept.dts')
7463
7464 self._CheckEmptyCapsule(data, accept_capsule=True)
7465
7466 def testCapsuleGenRevertCapsule(self):
7467 """Test generationg of revert EFI capsule"""
7468 data = self._DoReadFile('320_capsule_revert.dts')
7469
7470 self._CheckEmptyCapsule(data)
7471
7472 def testCapsuleGenAcceptGuidMissing(self):
7473 """Test that binman errors out on missing image GUID for accept capsule"""
7474 with self.assertRaises(ValueError) as e:
7475 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7476
7477 self.assertIn("Image GUID needed for generating accept capsule",
7478 str(e.exception))
7479
7480 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7481 """Test that capsule-type is specified"""
7482 with self.assertRaises(ValueError) as e:
7483 self._DoReadFile('322_empty_capsule_type_missing.dts')
7484
7485 self.assertIn("entry is missing properties: capsule-type",
7486 str(e.exception))
7487
7488 def testCapsuleGenAcceptOrRevertMissing(self):
7489 """Test that both accept and revert capsule are not specified"""
7490 with self.assertRaises(ValueError) as e:
7491 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7492
Simon Glassa360b8f2024-06-23 11:55:06 -06007493 def test_assume_size(self):
7494 """Test handling of the assume-size property for external blob"""
7495 with self.assertRaises(ValueError) as e:
7496 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7497 allow_fake_blobs=True)
7498 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7499 str(e.exception))
7500
7501 def test_assume_size_ok(self):
7502 """Test handling of the assume-size where it fits OK"""
7503 with test_util.capture_sys_output() as (stdout, stderr):
7504 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7505 allow_fake_blobs=True)
7506 err = stderr.getvalue()
7507 self.assertRegex(
7508 err,
7509 "Image '.*' has faked external blobs and is non-functional: .*")
7510
7511 def test_assume_size_no_fake(self):
7512 """Test handling of the assume-size where it fits OK"""
7513 with test_util.capture_sys_output() as (stdout, stderr):
7514 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7515 err = stderr.getvalue()
7516 self.assertRegex(
7517 err,
7518 "Image '.*' is missing external blobs and is non-functional: .*")
7519
Simon Glass5f7aadf2024-07-20 11:49:47 +01007520 def SetupAlternateDts(self):
7521 """Compile the .dts test files for alternative-fdt
7522
7523 Returns:
7524 tuple:
7525 str: Test directory created
7526 list of str: '.bin' files which we expect Binman to create
7527 """
7528 testdir = TestFunctional._MakeInputDir('dtb')
7529 dtb_list = []
7530 for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
7531 tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
7532 base = os.path.splitext(os.path.basename(fname))[0]
7533 dtb_list.append(base + '.bin')
7534 shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
7535
7536 return testdir, dtb_list
7537
Simon Glassf3598922024-07-20 11:49:45 +01007538 def CheckAlternates(self, dts, phase, xpl_data):
7539 """Run the test for the alterative-fdt etype
7540
7541 Args:
7542 dts (str): Devicetree file to process
7543 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7544 xpl_data (bytes): Expected data for the phase's binary
7545
7546 Returns:
7547 dict of .dtb files produced
7548 key: str filename
7549 value: Fdt object
7550 """
Simon Glass5f7aadf2024-07-20 11:49:47 +01007551 dtb_list = self.SetupAlternateDts()[1]
Simon Glassf3598922024-07-20 11:49:45 +01007552
7553 entry_args = {
7554 f'{phase}-dtb': '1',
7555 f'{phase}-bss-pad': 'y',
7556 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7557 }
7558 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7559 use_expanded=True, entry_args=entry_args)[0]
7560 self.assertEqual(xpl_data, data[:len(xpl_data)])
7561 rest = data[len(xpl_data):]
7562 pad_len = 10
7563 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7564
7565 # Check the dtb is using the test file
7566 dtb_data = rest[pad_len:]
7567 dtb = fdt.Fdt.FromData(dtb_data)
7568 dtb.Scan()
7569 fdt_size = dtb.GetFdtObj().totalsize()
7570 self.assertEqual('model-not-set',
7571 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7572
7573 pad_len = 10
7574
7575 # Check the other output files
7576 dtbs = {}
7577 for fname in dtb_list:
7578 pathname = tools.get_output_filename(fname)
7579 self.assertTrue(os.path.exists(pathname))
7580
7581 data = tools.read_file(pathname)
7582 self.assertEqual(xpl_data, data[:len(xpl_data)])
7583 rest = data[len(xpl_data):]
7584
7585 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7586 rest = rest[pad_len:]
7587
7588 dtb = fdt.Fdt.FromData(rest)
7589 dtb.Scan()
7590 dtbs[fname] = dtb
7591
7592 expected = 'one' if '1' in fname else 'two'
7593 self.assertEqual(f'u-boot,model-{expected}',
7594 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7595
7596 # Make sure the FDT is the same size as the 'main' one
7597 rest = rest[fdt_size:]
7598
7599 self.assertEqual(b'', rest)
7600 return dtbs
7601
7602 def testAlternatesFdt(self):
7603 """Test handling of alternates-fdt etype"""
7604 self._SetupTplElf()
7605 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7606 U_BOOT_TPL_NODTB_DATA)
7607 for dtb in dtbs.values():
7608 # Check for the node with the tag
7609 node = dtb.GetNode('/node')
7610 self.assertIsNotNone(node)
7611 self.assertEqual(5, len(node.props.keys()))
7612
7613 # Make sure the other node is still there
7614 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7615
7616 def testAlternatesFdtgrep(self):
7617 """Test handling of alternates-fdt etype using fdtgrep"""
7618 self._SetupTplElf()
7619 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7620 U_BOOT_TPL_NODTB_DATA)
7621 for dtb in dtbs.values():
7622 # Check for the node with the tag
7623 node = dtb.GetNode('/node')
7624 self.assertIsNotNone(node)
7625 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7626 node.props.keys())
7627
7628 # Make sure the other node is gone
7629 self.assertIsNone(dtb.GetNode('/node/other-node'))
7630
7631 def testAlternatesFdtgrepVpl(self):
7632 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7633 self._SetupVplElf()
7634 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7635 U_BOOT_VPL_NODTB_DATA)
7636
7637 def testAlternatesFdtgrepSpl(self):
7638 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7639 self._SetupSplElf()
7640 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7641 U_BOOT_SPL_NODTB_DATA)
7642
7643 def testAlternatesFdtgrepInval(self):
7644 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7645 self._SetupSplElf()
7646 with self.assertRaises(ValueError) as e:
7647 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7648 U_BOOT_SPL_NODTB_DATA)
7649 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7650 str(e.exception))
7651
Simon Glasscd2783e2024-07-20 11:49:46 +01007652 def testFitFdtListDir(self):
7653 """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
Simon Glass1bba8942024-08-26 13:11:34 -06007654 old_dir = os.getcwd()
7655 try:
7656 os.chdir(self._indir)
7657 self.CheckFitFdt('333_fit_fdt_dir.dts', False)
7658 finally:
7659 os.chdir(old_dir)
Simon Glasscd2783e2024-07-20 11:49:46 +01007660
Simon Glassd2a9d6e2024-08-26 13:11:37 -06007661 def testFitFdtListDirDefault(self):
7662 """Test an FIT fit,fdt-list-dir where the default DT in is a subdir"""
7663 old_dir = os.getcwd()
7664 try:
7665 os.chdir(self._indir)
7666 self.CheckFitFdt('333_fit_fdt_dir.dts', False,
7667 default_dt='rockchip/test-fdt2')
7668 finally:
7669 os.chdir(old_dir)
7670
Simon Glass5f7aadf2024-07-20 11:49:47 +01007671 def testFitFdtCompat(self):
7672 """Test an image with an FIT with compatible in the config nodes"""
7673 entry_args = {
7674 'of-list': 'model1 model2',
7675 'default-dt': 'model2',
7676 }
7677 testdir, dtb_list = self.SetupAlternateDts()
7678 data = self._DoReadFileDtb(
7679 '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
7680 entry_args=entry_args, extra_indirs=[testdir])[0]
7681
7682 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7683
7684 fit = fdt.Fdt.FromData(fit_data)
7685 fit.Scan()
7686
7687 cnode = fit.GetNode('/configurations')
7688 self.assertIn('default', cnode.props)
7689 self.assertEqual('config-2', cnode.props['default'].value)
7690
7691 for seq in range(1, 2):
7692 name = f'config-{seq}'
7693 fnode = fit.GetNode('/configurations/%s' % name)
7694 self.assertIsNotNone(fnode)
7695 self.assertIn('compatible', fnode.props.keys())
7696 expected = 'one' if seq == 1 else 'two'
7697 self.assertEqual(f'u-boot,model-{expected}',
7698 fnode.props['compatible'].value)
7699
Simon Glassa04b9942024-07-20 11:49:48 +01007700 def testFitFdtPhase(self):
7701 """Test an image with an FIT with fdt-phase in the fdt nodes"""
7702 phase = 'tpl'
7703 entry_args = {
7704 f'{phase}-dtb': '1',
7705 f'{phase}-bss-pad': 'y',
7706 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7707 'of-list': 'model1 model2',
7708 'default-dt': 'model2',
7709 }
7710 testdir, dtb_list = self.SetupAlternateDts()
7711 data = self._DoReadFileDtb(
7712 '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
7713 entry_args=entry_args, extra_indirs=[testdir])[0]
7714 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7715 fit = fdt.Fdt.FromData(fit_data)
7716 fit.Scan()
7717
7718 # Check that each FDT has only the expected properties for the phase
7719 for seq in range(1, 2):
7720 fnode = fit.GetNode(f'/images/fdt-{seq}')
7721 self.assertIsNotNone(fnode)
7722 dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
7723 dtb.Scan()
7724
7725 # Make sure that the 'bootph-pre-sram' tag in /node protects it from
7726 # removal
7727 node = dtb.GetNode('/node')
7728 self.assertIsNotNone(node)
7729 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7730 node.props.keys())
7731
7732 # Make sure the other node is gone
7733 self.assertIsNone(dtb.GetNode('/node/other-node'))
7734
Simon Glassb553e8a2024-08-26 13:11:29 -06007735 def testMkeficapsuleMissing(self):
7736 """Test that binman complains if mkeficapsule is missing"""
7737 with self.assertRaises(ValueError) as e:
7738 self._DoTestFile('311_capsule.dts',
7739 force_missing_bintools='mkeficapsule')
7740 self.assertIn("Node '/binman/efi-capsule': Missing tool: 'mkeficapsule'",
7741 str(e.exception))
7742
7743 def testMkeficapsuleMissingOk(self):
7744 """Test that binman deals with mkeficapsule being missing"""
7745 with test_util.capture_sys_output() as (stdout, stderr):
7746 ret = self._DoTestFile('311_capsule.dts',
7747 force_missing_bintools='mkeficapsule',
7748 allow_missing=True)
7749 self.assertEqual(103, ret)
7750 err = stderr.getvalue()
7751 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkeficapsule")
7752
Simon Glassa360b8f2024-06-23 11:55:06 -06007753
Simon Glassac599912017-11-12 21:52:22 -07007754if __name__ == "__main__":
7755 unittest.main()