blob: 3f05559501dd4fdbf8d83a974d0175297452c7a5 [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
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001529 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1530 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glass31e04cb2021-03-18 20:24:56 +13001531 0x10 + u_boot_offset, 0x04)
Simon Glass4abf7842023-07-18 07:23:54 -06001532 if no_write_symbols:
1533 expected = (base_data +
1534 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1535 U_BOOT_DATA + base_data)
1536 else:
1537 expected = (sym_values + base_data[24:] +
1538 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1539 base_data[24:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001540 self.assertEqual(expected, data)
1541
Simon Glass31e04cb2021-03-18 20:24:56 +13001542 def testSymbols(self):
1543 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001544 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001545
1546 def testSymbolsNoDtb(self):
1547 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001548 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001549 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1550 0x38)
1551
Simon Glasse76a3e62018-06-01 09:38:11 -06001552 def testPackUnitAddress(self):
1553 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001554 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001555 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1556
Simon Glassa91e1152018-06-01 09:38:16 -06001557 def testSections(self):
1558 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001559 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001560 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1561 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1562 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001563 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001564
Simon Glass30732662018-06-01 09:38:20 -06001565 def testMap(self):
1566 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001567 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001568 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700156900000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600157000000000 00000000 00000010 section@0
157100000000 00000000 00000004 u-boot
157200000010 00000010 00000010 section@1
157300000010 00000000 00000004 u-boot
157400000020 00000020 00000004 section@2
157500000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001576''', map_data)
1577
Simon Glass3b78d532018-06-01 09:38:21 -06001578 def testNamePrefix(self):
1579 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001580 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001581 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700158200000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600158300000000 00000000 00000010 section@0
158400000000 00000000 00000004 ro-u-boot
158500000010 00000010 00000010 section@1
158600000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001587''', map_data)
1588
Simon Glass6ba679c2018-07-06 10:27:17 -06001589 def testUnknownContents(self):
1590 """Test that obtaining the contents works as expected"""
1591 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001592 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001593 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001594 "processing of contents: remaining ["
1595 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001596
Simon Glass2e1169f2018-07-06 10:27:19 -06001597 def testBadChangeSize(self):
1598 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001599 try:
1600 state.SetAllowEntryExpansion(False)
1601 with self.assertRaises(ValueError) as e:
1602 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001603 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001604 str(e.exception))
1605 finally:
1606 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001607
Simon Glassa87014e2018-07-06 10:27:42 -06001608 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001609 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001610 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001611 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001612 dtb = fdt.Fdt(out_dtb_fname)
1613 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001614 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001615 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001616 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001617 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001618 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001619 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001620 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001621 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001622 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001623 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001624 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001625 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001626 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001627
Simon Glasse8561af2018-08-01 15:22:37 -06001628 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001629 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001630 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001631 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001632 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001633 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001634 'size': 40
1635 }, props)
1636
1637 def testUpdateFdtBad(self):
1638 """Test that we detect when ProcessFdt never completes"""
1639 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001640 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001641 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001642 '[<binman.etype._testing.Entry__testing',
1643 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001644
Simon Glass91710b32018-07-17 13:25:32 -06001645 def testEntryArgs(self):
1646 """Test passing arguments to entries from the command line"""
1647 entry_args = {
1648 'test-str-arg': 'test1',
1649 'test-int-arg': '456',
1650 }
Simon Glass511f6582018-10-01 12:22:30 -06001651 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001652 self.assertIn('image', control.images)
1653 entry = control.images['image'].GetEntries()['_testing']
1654 self.assertEqual('test0', entry.test_str_fdt)
1655 self.assertEqual('test1', entry.test_str_arg)
1656 self.assertEqual(123, entry.test_int_fdt)
1657 self.assertEqual(456, entry.test_int_arg)
1658
1659 def testEntryArgsMissing(self):
1660 """Test missing arguments and properties"""
1661 entry_args = {
1662 'test-int-arg': '456',
1663 }
Simon Glass511f6582018-10-01 12:22:30 -06001664 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001665 entry = control.images['image'].GetEntries()['_testing']
1666 self.assertEqual('test0', entry.test_str_fdt)
1667 self.assertEqual(None, entry.test_str_arg)
1668 self.assertEqual(None, entry.test_int_fdt)
1669 self.assertEqual(456, entry.test_int_arg)
1670
1671 def testEntryArgsRequired(self):
1672 """Test missing arguments and properties"""
1673 entry_args = {
1674 'test-int-arg': '456',
1675 }
1676 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001677 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001678 self.assertIn("Node '/binman/_testing': "
1679 'Missing required properties/entry args: test-str-arg, '
1680 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001681 str(e.exception))
1682
1683 def testEntryArgsInvalidFormat(self):
1684 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001685 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1686 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001687 with self.assertRaises(ValueError) as e:
1688 self._DoBinman(*args)
1689 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1690
1691 def testEntryArgsInvalidInteger(self):
1692 """Test that an invalid entry-argument integer is detected"""
1693 entry_args = {
1694 'test-int-arg': 'abc',
1695 }
1696 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001697 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001698 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1699 "'test-int-arg' (value 'abc') to integer",
1700 str(e.exception))
1701
1702 def testEntryArgsInvalidDatatype(self):
1703 """Test that an invalid entry-argument datatype is detected
1704
1705 This test could be written in entry_test.py except that it needs
1706 access to control.entry_args, which seems more than that module should
1707 be able to see.
1708 """
1709 entry_args = {
1710 'test-bad-datatype-arg': '12',
1711 }
1712 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001713 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001714 entry_args=entry_args)
1715 self.assertIn('GetArg() internal error: Unknown data type ',
1716 str(e.exception))
1717
Simon Glass2ca52032018-07-17 13:25:33 -06001718 def testText(self):
1719 """Test for a text entry type"""
1720 entry_args = {
1721 'test-id': TEXT_DATA,
1722 'test-id2': TEXT_DATA2,
1723 'test-id3': TEXT_DATA3,
1724 }
Simon Glass511f6582018-10-01 12:22:30 -06001725 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001726 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001727 expected = (tools.to_bytes(TEXT_DATA) +
1728 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1729 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001730 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001731 self.assertEqual(expected, data)
1732
Simon Glass969616c2018-07-17 13:25:36 -06001733 def testEntryDocs(self):
1734 """Test for creation of entry documentation"""
1735 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001736 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001737 self.assertTrue(len(stdout.getvalue()) > 0)
1738
1739 def testEntryDocsMissing(self):
1740 """Test handling of missing entry documentation"""
1741 with self.assertRaises(ValueError) as e:
1742 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001743 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001744 self.assertIn('Documentation is missing for modules: u_boot',
1745 str(e.exception))
1746
Simon Glass704784b2018-07-17 13:25:38 -06001747 def testFmap(self):
1748 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001749 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001750 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001751 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1752 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001753 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001754 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001755 self.assertEqual(1, fhdr.ver_major)
1756 self.assertEqual(0, fhdr.ver_minor)
1757 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001758 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001759 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001760 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001761 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001762 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001763
Simon Glass82059c22021-04-03 11:05:09 +13001764 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001765 self.assertEqual(b'SECTION0', fentry.name)
1766 self.assertEqual(0, fentry.offset)
1767 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001768 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001769
1770 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001771 self.assertEqual(b'RO_U_BOOT', fentry.name)
1772 self.assertEqual(0, fentry.offset)
1773 self.assertEqual(4, fentry.size)
1774 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001775
Simon Glass82059c22021-04-03 11:05:09 +13001776 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001777 self.assertEqual(b'SECTION1', fentry.name)
1778 self.assertEqual(16, fentry.offset)
1779 self.assertEqual(16, fentry.size)
1780 self.assertEqual(0, fentry.flags)
1781
1782 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001783 self.assertEqual(b'RW_U_BOOT', fentry.name)
1784 self.assertEqual(16, fentry.offset)
1785 self.assertEqual(4, fentry.size)
1786 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001787
Simon Glass82059c22021-04-03 11:05:09 +13001788 fentry = next(fiter)
1789 self.assertEqual(b'FMAP', fentry.name)
1790 self.assertEqual(32, fentry.offset)
1791 self.assertEqual(expect_size, fentry.size)
1792 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001793
Simon Glassdb168d42018-07-17 13:25:39 -06001794 def testBlobNamedByArg(self):
1795 """Test we can add a blob with the filename coming from an entry arg"""
1796 entry_args = {
1797 'cros-ec-rw-path': 'ecrw.bin',
1798 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001799 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001800
Simon Glass53f53992018-07-17 13:25:40 -06001801 def testFill(self):
1802 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001803 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001804 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001805 self.assertEqual(expected, data)
1806
1807 def testFillNoSize(self):
1808 """Test for an fill entry type with no size"""
1809 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001810 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001811 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001812 str(e.exception))
1813
Simon Glassc1ae83c2018-07-17 13:25:44 -06001814 def _HandleGbbCommand(self, pipe_list):
1815 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001816 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001817 fname = pipe_list[0][-1]
1818 # Append our GBB data to the file, which will happen every time the
1819 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001820 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001821 fd.write(GBB_DATA)
1822 return command.CommandResult()
1823
1824 def testGbb(self):
1825 """Test for the Chromium OS Google Binary Block"""
1826 command.test_result = self._HandleGbbCommand
1827 entry_args = {
1828 'keydir': 'devkeys',
1829 'bmpblk': 'bmpblk.bin',
1830 }
Simon Glass511f6582018-10-01 12:22:30 -06001831 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001832
1833 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001834 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1835 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001836 self.assertEqual(expected, data)
1837
1838 def testGbbTooSmall(self):
1839 """Test for the Chromium OS Google Binary Block being large enough"""
1840 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001841 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001842 self.assertIn("Node '/binman/gbb': GBB is too small",
1843 str(e.exception))
1844
1845 def testGbbNoSize(self):
1846 """Test for the Chromium OS Google Binary Block having a size"""
1847 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001848 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001849 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1850 str(e.exception))
1851
Simon Glass66152ce2022-01-09 20:14:09 -07001852 def testGbbMissing(self):
1853 """Test that binman still produces an image if futility is missing"""
1854 entry_args = {
1855 'keydir': 'devkeys',
1856 }
1857 with test_util.capture_sys_output() as (_, stderr):
1858 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1859 entry_args=entry_args)
1860 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001861 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001862
Simon Glass5c350162018-07-17 13:25:47 -06001863 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001864 """Fake calls to the futility utility
1865
1866 The expected pipe is:
1867
1868 [('futility', 'vbutil_firmware', '--vblock',
1869 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1870 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1871 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1872 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1873
1874 This writes to the output file (here, 'vblock.vblock'). If
1875 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1876 of the input data (here, 'input.vblock').
1877 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001878 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001879 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001880 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001881 if self._hash_data:
1882 infile = pipe_list[0][11]
1883 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001884 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001885 m.update(data)
1886 fd.write(m.digest())
1887 else:
1888 fd.write(VBLOCK_DATA)
1889
Simon Glass5c350162018-07-17 13:25:47 -06001890 return command.CommandResult()
1891
1892 def testVblock(self):
1893 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001894 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001895 command.test_result = self._HandleVblockCommand
1896 entry_args = {
1897 'keydir': 'devkeys',
1898 }
Simon Glass511f6582018-10-01 12:22:30 -06001899 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001900 entry_args=entry_args)
1901 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1902 self.assertEqual(expected, data)
1903
1904 def testVblockNoContent(self):
1905 """Test we detect a vblock which has no content to sign"""
1906 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001907 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001908 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001909 'property', str(e.exception))
1910
1911 def testVblockBadPhandle(self):
1912 """Test that we detect a vblock with an invalid phandle in contents"""
1913 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001914 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001915 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1916 '1000', str(e.exception))
1917
1918 def testVblockBadEntry(self):
1919 """Test that we detect an entry that points to a non-entry"""
1920 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001921 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001922 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1923 "'other'", str(e.exception))
1924
Simon Glass220c6222021-01-06 21:35:17 -07001925 def testVblockContent(self):
1926 """Test that the vblock signs the right data"""
1927 self._hash_data = True
1928 command.test_result = self._HandleVblockCommand
1929 entry_args = {
1930 'keydir': 'devkeys',
1931 }
1932 data = self._DoReadFileDtb(
1933 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1934 entry_args=entry_args)[0]
1935 hashlen = 32 # SHA256 hash is 32 bytes
1936 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1937 hashval = data[-hashlen:]
1938 dtb = data[len(U_BOOT_DATA):-hashlen]
1939
1940 expected_data = U_BOOT_DATA + dtb
1941
1942 # The hashval should be a hash of the dtb
1943 m = hashlib.sha256()
1944 m.update(expected_data)
1945 expected_hashval = m.digest()
1946 self.assertEqual(expected_hashval, hashval)
1947
Simon Glass66152ce2022-01-09 20:14:09 -07001948 def testVblockMissing(self):
1949 """Test that binman still produces an image if futility is missing"""
1950 entry_args = {
1951 'keydir': 'devkeys',
1952 }
1953 with test_util.capture_sys_output() as (_, stderr):
1954 self._DoTestFile('074_vblock.dts',
1955 force_missing_bintools='futility',
1956 entry_args=entry_args)
1957 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001958 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001959
Simon Glass8425a1f2018-07-17 13:25:48 -06001960 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001961 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001962 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001963 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001964 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001965 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1966
Simon Glass24b97442018-07-17 13:25:51 -06001967 def testUsesPos(self):
1968 """Test that the 'pos' property cannot be used anymore"""
1969 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001970 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001971 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1972 "'pos'", str(e.exception))
1973
Simon Glass274bf092018-09-14 04:57:08 -06001974 def testFillZero(self):
1975 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001976 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001977 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001978
Simon Glass267de432018-09-14 04:57:09 -06001979 def testTextMissing(self):
1980 """Test for a text entry type where there is no text"""
1981 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001982 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001983 self.assertIn("Node '/binman/text': No value provided for text label "
1984 "'test-id'", str(e.exception))
1985
Simon Glassed40e962018-09-14 04:57:10 -06001986 def testPackStart16Tpl(self):
1987 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001988 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001989 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1990
Simon Glass3b376c32018-09-14 04:57:12 -06001991 def testSelectImage(self):
1992 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001993 expected = 'Skipping images: image1'
1994
1995 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001996 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001997 with test_util.capture_sys_output() as (stdout, stderr):
1998 retcode = self._DoTestFile('006_dual_image.dts',
1999 verbosity=verbosity,
2000 images=['image2'])
2001 self.assertEqual(0, retcode)
2002 if verbosity:
2003 self.assertIn(expected, stdout.getvalue())
2004 else:
2005 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06002006
Simon Glass80025522022-01-29 14:14:04 -07002007 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2008 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06002009 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06002010
Simon Glasse219aa42018-09-14 04:57:24 -06002011 def testUpdateFdtAll(self):
2012 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06002013 self._SetupSplElf()
2014 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06002015 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06002016
2017 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06002018 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002019 'image-pos': 0,
2020 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06002021 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002022 'section:image-pos': 0,
2023 'section:size': 565,
2024 'section/u-boot-dtb:offset': 0,
2025 'section/u-boot-dtb:image-pos': 0,
2026 'section/u-boot-dtb:size': 565,
2027 'u-boot-spl-dtb:offset': 565,
2028 'u-boot-spl-dtb:image-pos': 565,
2029 'u-boot-spl-dtb:size': 585,
2030 'u-boot-tpl-dtb:offset': 1150,
2031 'u-boot-tpl-dtb:image-pos': 1150,
2032 'u-boot-tpl-dtb:size': 585,
2033 'u-boot-vpl-dtb:image-pos': 1735,
2034 'u-boot-vpl-dtb:offset': 1735,
2035 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002036 }
2037
2038 # We expect three device-tree files in the output, one after the other.
2039 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2040 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2041 # main U-Boot tree. All three should have the same postions and offset.
2042 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002043 self.maxDiff = None
2044 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002045 dtb = fdt.Fdt.FromData(data[start:])
2046 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002047 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002048 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002049 expected = dict(base_expected)
2050 if item:
2051 expected[item] = 0
2052 self.assertEqual(expected, props)
2053 start += dtb._fdt_obj.totalsize()
2054
2055 def testUpdateFdtOutput(self):
2056 """Test that output DTB files are updated"""
2057 try:
Simon Glass511f6582018-10-01 12:22:30 -06002058 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002059 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2060
2061 # Unfortunately, compiling a source file always results in a file
2062 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002063 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002064 # binman as a file called u-boot.dtb. To fix this, copy the file
2065 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002066 start = 0
2067 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002068 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002069 dtb = fdt.Fdt.FromData(data[start:])
2070 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002071 pathname = tools.get_output_filename(os.path.split(fname)[1])
2072 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002073 name = os.path.split(fname)[0]
2074
2075 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002076 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002077 else:
2078 orig_indata = dtb_data
2079 self.assertNotEqual(outdata, orig_indata,
2080 "Expected output file '%s' be updated" % pathname)
2081 self.assertEqual(outdata, data[start:start + size],
2082 "Expected output file '%s' to match output image" %
2083 pathname)
2084 start += size
2085 finally:
2086 self._ResetDtbs()
2087
Simon Glass7ba33592018-09-14 04:57:26 -06002088 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002089 bintool = self.comp_bintools['lz4']
2090 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002091
2092 def testCompress(self):
2093 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002094 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002095 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002096 use_real_dtb=True, update_dtb=True)
2097 dtb = fdt.Fdt(out_dtb_fname)
2098 dtb.Scan()
2099 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2100 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00002101 self.assertEqual(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002102
2103 # Do a sanity check on various fields
2104 image = control.images['image']
2105 entries = image.GetEntries()
2106 self.assertEqual(1, len(entries))
2107
2108 entry = entries['blob']
2109 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2110 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2111 orig = self._decompress(entry.data)
2112 self.assertEqual(orig, entry.uncomp_data)
2113
Simon Glass72eeff12020-10-26 17:40:16 -06002114 self.assertEqual(image.data, entry.data)
2115
Simon Glass7ba33592018-09-14 04:57:26 -06002116 expected = {
2117 'blob:uncomp-size': len(COMPRESS_DATA),
2118 'blob:size': len(data),
2119 'size': len(data),
2120 }
2121 self.assertEqual(expected, props)
2122
Simon Glassac6328c2018-09-14 04:57:28 -06002123 def testFiles(self):
2124 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002125 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002126 self.assertEqual(FILES_DATA, data)
2127
2128 def testFilesCompress(self):
2129 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002130 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002131 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002132
2133 image = control.images['image']
2134 entries = image.GetEntries()
2135 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002136 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002137
Simon Glass303f62f2019-05-17 22:00:46 -06002138 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002139 for i in range(1, 3):
2140 key = '%d.dat' % i
2141 start = entries[key].image_pos
2142 len = entries[key].size
2143 chunk = data[start:start + len]
2144 orig += self._decompress(chunk)
2145
2146 self.assertEqual(FILES_DATA, orig)
2147
2148 def testFilesMissing(self):
2149 """Test missing files"""
2150 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002151 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002152 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2153 'no files', str(e.exception))
2154
2155 def testFilesNoPattern(self):
2156 """Test missing files"""
2157 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002158 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002159 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2160 str(e.exception))
2161
Simon Glassdd156a42022-03-05 20:18:59 -07002162 def testExtendSize(self):
2163 """Test an extending entry"""
2164 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002165 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002166 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2167 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2168 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2169 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002170 self.assertEqual(expect, data)
2171 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700217200000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600217300000000 00000000 00000008 fill
217400000008 00000008 00000004 u-boot
21750000000c 0000000c 00000004 section
21760000000c 00000000 00000003 intel-mrc
217700000010 00000010 00000004 u-boot2
217800000014 00000014 0000000c section2
217900000014 00000000 00000008 fill
21800000001c 00000008 00000004 u-boot
218100000020 00000020 00000008 fill2
2182''', map_data)
2183
Simon Glassdd156a42022-03-05 20:18:59 -07002184 def testExtendSizeBad(self):
2185 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002186 with test_util.capture_sys_output() as (stdout, stderr):
2187 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002188 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002189 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2190 'expanding entry', str(e.exception))
2191
Simon Glassae7cf032018-09-14 04:57:31 -06002192 def testHash(self):
2193 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002194 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002195 use_real_dtb=True, update_dtb=True)
2196 dtb = fdt.Fdt(out_dtb_fname)
2197 dtb.Scan()
2198 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2199 m = hashlib.sha256()
2200 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002201 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002202
2203 def testHashNoAlgo(self):
2204 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002205 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002206 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2207 'hash node', str(e.exception))
2208
2209 def testHashBadAlgo(self):
2210 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002211 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002212 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002213 str(e.exception))
2214
2215 def testHashSection(self):
2216 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002217 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002218 use_real_dtb=True, update_dtb=True)
2219 dtb = fdt.Fdt(out_dtb_fname)
2220 dtb.Scan()
2221 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2222 m = hashlib.sha256()
2223 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002224 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002225 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002226
Simon Glass3fb4f422018-09-14 04:57:32 -06002227 def testPackUBootTplMicrocode(self):
2228 """Test that x86 microcode can be handled correctly in TPL
2229
2230 We expect to see the following in the image, in order:
2231 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2232 place
2233 u-boot-tpl.dtb with the microcode removed
2234 the microcode
2235 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002236 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002237 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002238 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002239 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2240 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002241
Simon Glassc64aea52018-09-14 04:57:34 -06002242 def testFmapX86(self):
2243 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002244 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002245 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002246 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002247 self.assertEqual(expected, data[:32])
2248 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2249
2250 self.assertEqual(0x100, fhdr.image_size)
2251
2252 self.assertEqual(0, fentries[0].offset)
2253 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002254 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002255
2256 self.assertEqual(4, fentries[1].offset)
2257 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002258 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002259
2260 self.assertEqual(32, fentries[2].offset)
2261 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2262 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002263 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002264
2265 def testFmapX86Section(self):
2266 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002267 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002268 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002269 self.assertEqual(expected, data[:32])
2270 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2271
Simon Glassb1d414c2021-04-03 11:05:10 +13002272 self.assertEqual(0x180, fhdr.image_size)
2273 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002274 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002275
Simon Glass82059c22021-04-03 11:05:09 +13002276 fentry = next(fiter)
2277 self.assertEqual(b'U_BOOT', fentry.name)
2278 self.assertEqual(0, fentry.offset)
2279 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002280
Simon Glass82059c22021-04-03 11:05:09 +13002281 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002282 self.assertEqual(b'SECTION', fentry.name)
2283 self.assertEqual(4, fentry.offset)
2284 self.assertEqual(0x20 + expect_size, fentry.size)
2285
2286 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002287 self.assertEqual(b'INTEL_MRC', fentry.name)
2288 self.assertEqual(4, fentry.offset)
2289 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002290
Simon Glass82059c22021-04-03 11:05:09 +13002291 fentry = next(fiter)
2292 self.assertEqual(b'FMAP', fentry.name)
2293 self.assertEqual(36, fentry.offset)
2294 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002295
Simon Glassb1714232018-09-14 04:57:35 -06002296 def testElf(self):
2297 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002298 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002299 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002300 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002301 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002302 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002303
Simon Glass0d673792019-07-08 13:18:25 -06002304 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002305 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002306 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002307 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002308 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002309 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002310
Simon Glasscd817d52018-09-14 04:57:36 -06002311 def testPackOverlapMap(self):
2312 """Test that overlapping regions are detected"""
2313 with test_util.capture_sys_output() as (stdout, stderr):
2314 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002315 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002316 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002317 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2318 stdout.getvalue())
2319
2320 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002321 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002322 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002323 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002324 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002325<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002326<none> 00000000 00000004 u-boot
2327<none> 00000003 00000004 u-boot-align
2328''', map_data)
2329
Simon Glass0d673792019-07-08 13:18:25 -06002330 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002331 """Test that an image with an Intel Reference code binary works"""
2332 data = self._DoReadFile('100_intel_refcode.dts')
2333 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2334
Simon Glasseb023b32019-04-25 21:58:39 -06002335 def testSectionOffset(self):
2336 """Tests use of a section with an offset"""
2337 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2338 map=True)
2339 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700234000000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600234100000004 00000004 00000010 section@0
234200000004 00000000 00000004 u-boot
234300000018 00000018 00000010 section@1
234400000018 00000000 00000004 u-boot
23450000002c 0000002c 00000004 section@2
23460000002c 00000000 00000004 u-boot
2347''', map_data)
2348 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002349 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2350 tools.get_bytes(0x21, 12) +
2351 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2352 tools.get_bytes(0x61, 12) +
2353 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2354 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002355
Simon Glass1de34482019-07-08 13:18:53 -06002356 def testCbfsRaw(self):
2357 """Test base handling of a Coreboot Filesystem (CBFS)
2358
2359 The exact contents of the CBFS is verified by similar tests in
2360 cbfs_util_test.py. The tests here merely check that the files added to
2361 the CBFS can be found in the final image.
2362 """
2363 data = self._DoReadFile('102_cbfs_raw.dts')
2364 size = 0xb0
2365
2366 cbfs = cbfs_util.CbfsReader(data)
2367 self.assertEqual(size, cbfs.rom_size)
2368
2369 self.assertIn('u-boot-dtb', cbfs.files)
2370 cfile = cbfs.files['u-boot-dtb']
2371 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2372
2373 def testCbfsArch(self):
2374 """Test on non-x86 architecture"""
2375 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2376 size = 0x100
2377
2378 cbfs = cbfs_util.CbfsReader(data)
2379 self.assertEqual(size, cbfs.rom_size)
2380
2381 self.assertIn('u-boot-dtb', cbfs.files)
2382 cfile = cbfs.files['u-boot-dtb']
2383 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2384
2385 def testCbfsStage(self):
2386 """Tests handling of a Coreboot Filesystem (CBFS)"""
2387 if not elf.ELF_TOOLS:
2388 self.skipTest('Python elftools not available')
2389 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2390 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2391 size = 0xb0
2392
2393 data = self._DoReadFile('104_cbfs_stage.dts')
2394 cbfs = cbfs_util.CbfsReader(data)
2395 self.assertEqual(size, cbfs.rom_size)
2396
2397 self.assertIn('u-boot', cbfs.files)
2398 cfile = cbfs.files['u-boot']
2399 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2400
2401 def testCbfsRawCompress(self):
2402 """Test handling of compressing raw files"""
2403 self._CheckLz4()
2404 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2405 size = 0x140
2406
2407 cbfs = cbfs_util.CbfsReader(data)
2408 self.assertIn('u-boot', cbfs.files)
2409 cfile = cbfs.files['u-boot']
2410 self.assertEqual(COMPRESS_DATA, cfile.data)
2411
2412 def testCbfsBadArch(self):
2413 """Test handling of a bad architecture"""
2414 with self.assertRaises(ValueError) as e:
2415 self._DoReadFile('106_cbfs_bad_arch.dts')
2416 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2417
2418 def testCbfsNoSize(self):
2419 """Test handling of a missing size property"""
2420 with self.assertRaises(ValueError) as e:
2421 self._DoReadFile('107_cbfs_no_size.dts')
2422 self.assertIn('entry must have a size property', str(e.exception))
2423
Simon Glass3e28f4f2021-11-23 11:03:54 -07002424 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002425 """Test handling of a CBFS entry which does not provide contentsy"""
2426 with self.assertRaises(ValueError) as e:
2427 self._DoReadFile('108_cbfs_no_contents.dts')
2428 self.assertIn('Could not complete processing of contents',
2429 str(e.exception))
2430
2431 def testCbfsBadCompress(self):
2432 """Test handling of a bad architecture"""
2433 with self.assertRaises(ValueError) as e:
2434 self._DoReadFile('109_cbfs_bad_compress.dts')
2435 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2436 str(e.exception))
2437
2438 def testCbfsNamedEntries(self):
2439 """Test handling of named entries"""
2440 data = self._DoReadFile('110_cbfs_name.dts')
2441
2442 cbfs = cbfs_util.CbfsReader(data)
2443 self.assertIn('FRED', cbfs.files)
2444 cfile1 = cbfs.files['FRED']
2445 self.assertEqual(U_BOOT_DATA, cfile1.data)
2446
2447 self.assertIn('hello', cbfs.files)
2448 cfile2 = cbfs.files['hello']
2449 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2450
Simon Glass759af872019-07-08 13:18:54 -06002451 def _SetupIfwi(self, fname):
2452 """Set up to run an IFWI test
2453
2454 Args:
2455 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2456 """
2457 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002458 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002459
2460 # Intel Integrated Firmware Image (IFWI) file
2461 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2462 data = fd.read()
2463 TestFunctional._MakeInputFile(fname,data)
2464
2465 def _CheckIfwi(self, data):
2466 """Check that an image with an IFWI contains the correct output
2467
2468 Args:
2469 data: Conents of output file
2470 """
Simon Glass80025522022-01-29 14:14:04 -07002471 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002472 if data[:0x1000] != expected_desc:
2473 self.fail('Expected descriptor binary at start of image')
2474
2475 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002476 image_fname = tools.get_output_filename('image.bin')
2477 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002478 ifwitool = bintool.Bintool.create('ifwitool')
2479 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002480
Simon Glass80025522022-01-29 14:14:04 -07002481 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002482 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002483
2484 def testPackX86RomIfwi(self):
2485 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2486 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002487 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002488 self._CheckIfwi(data)
2489
2490 def testPackX86RomIfwiNoDesc(self):
2491 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2492 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002493 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002494 self._CheckIfwi(data)
2495
2496 def testPackX86RomIfwiNoData(self):
2497 """Test that an x86 ROM with IFWI handles missing data"""
2498 self._SetupIfwi('ifwi.bin')
2499 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002500 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002501 self.assertIn('Could not complete processing of contents',
2502 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002503
Simon Glass66152ce2022-01-09 20:14:09 -07002504 def testIfwiMissing(self):
2505 """Test that binman still produces an image if ifwitool is missing"""
2506 self._SetupIfwi('fitimage.bin')
2507 with test_util.capture_sys_output() as (_, stderr):
2508 self._DoTestFile('111_x86_rom_ifwi.dts',
2509 force_missing_bintools='ifwitool')
2510 err = stderr.getvalue()
2511 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002512 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002513
Simon Glassc2f1aed2019-07-08 13:18:56 -06002514 def testCbfsOffset(self):
2515 """Test a CBFS with files at particular offsets
2516
2517 Like all CFBS tests, this is just checking the logic that calls
2518 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2519 """
2520 data = self._DoReadFile('114_cbfs_offset.dts')
2521 size = 0x200
2522
2523 cbfs = cbfs_util.CbfsReader(data)
2524 self.assertEqual(size, cbfs.rom_size)
2525
2526 self.assertIn('u-boot', cbfs.files)
2527 cfile = cbfs.files['u-boot']
2528 self.assertEqual(U_BOOT_DATA, cfile.data)
2529 self.assertEqual(0x40, cfile.cbfs_offset)
2530
2531 self.assertIn('u-boot-dtb', cbfs.files)
2532 cfile2 = cbfs.files['u-boot-dtb']
2533 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2534 self.assertEqual(0x140, cfile2.cbfs_offset)
2535
Simon Glass0f621332019-07-08 14:25:27 -06002536 def testFdtmap(self):
2537 """Test an FDT map can be inserted in the image"""
2538 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2539 fdtmap_data = data[len(U_BOOT_DATA):]
2540 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002541 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002542 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002543
2544 fdt_data = fdtmap_data[16:]
2545 dtb = fdt.Fdt.FromData(fdt_data)
2546 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002547 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002548 self.assertEqual({
2549 'image-pos': 0,
2550 'offset': 0,
2551 'u-boot:offset': 0,
2552 'u-boot:size': len(U_BOOT_DATA),
2553 'u-boot:image-pos': 0,
2554 'fdtmap:image-pos': 4,
2555 'fdtmap:offset': 4,
2556 'fdtmap:size': len(fdtmap_data),
2557 'size': len(data),
2558 }, props)
2559
2560 def testFdtmapNoMatch(self):
2561 """Check handling of an FDT map when the section cannot be found"""
2562 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2563
2564 # Mangle the section name, which should cause a mismatch between the
2565 # correct FDT path and the one expected by the section
2566 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002567 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002568 entries = image.GetEntries()
2569 fdtmap = entries['fdtmap']
2570 with self.assertRaises(ValueError) as e:
2571 fdtmap._GetFdtmap()
2572 self.assertIn("Cannot locate node for path '/binman-suffix'",
2573 str(e.exception))
2574
Simon Glasscec34ba2019-07-08 14:25:28 -06002575 def testFdtmapHeader(self):
2576 """Test an FDT map and image header can be inserted in the image"""
2577 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2578 fdtmap_pos = len(U_BOOT_DATA)
2579 fdtmap_data = data[fdtmap_pos:]
2580 fdt_data = fdtmap_data[16:]
2581 dtb = fdt.Fdt.FromData(fdt_data)
2582 fdt_size = dtb.GetFdtObj().totalsize()
2583 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002584 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002585 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2586 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2587
2588 def testFdtmapHeaderStart(self):
2589 """Test an image header can be inserted at the image start"""
2590 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2591 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2592 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002593 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002594 offset = struct.unpack('<I', hdr_data[4:])[0]
2595 self.assertEqual(fdtmap_pos, offset)
2596
2597 def testFdtmapHeaderPos(self):
2598 """Test an image header can be inserted at a chosen position"""
2599 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2600 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2601 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002602 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002603 offset = struct.unpack('<I', hdr_data[4:])[0]
2604 self.assertEqual(fdtmap_pos, offset)
2605
2606 def testHeaderMissingFdtmap(self):
2607 """Test an image header requires an fdtmap"""
2608 with self.assertRaises(ValueError) as e:
2609 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2610 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2611 str(e.exception))
2612
2613 def testHeaderNoLocation(self):
2614 """Test an image header with a no specified location is detected"""
2615 with self.assertRaises(ValueError) as e:
2616 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2617 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2618 str(e.exception))
2619
Simon Glasse61b6f62019-07-08 14:25:37 -06002620 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002621 """Test extending an entry after it is packed"""
2622 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002623 self.assertEqual(b'aaa', data[:3])
2624 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2625 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002626
Simon Glassdd156a42022-03-05 20:18:59 -07002627 def testEntryExtendBad(self):
2628 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002629 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002630 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002631 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002632 str(e.exception))
2633
Simon Glassdd156a42022-03-05 20:18:59 -07002634 def testEntryExtendSection(self):
2635 """Test extending an entry within a section after it is packed"""
2636 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002637 self.assertEqual(b'aaa', data[:3])
2638 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2639 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002640
Simon Glass90d29682019-07-08 14:25:38 -06002641 def testCompressDtb(self):
2642 """Test that compress of device-tree files is supported"""
2643 self._CheckLz4()
2644 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2645 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2646 comp_data = data[len(U_BOOT_DATA):]
2647 orig = self._decompress(comp_data)
2648 dtb = fdt.Fdt.FromData(orig)
2649 dtb.Scan()
2650 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2651 expected = {
2652 'u-boot:size': len(U_BOOT_DATA),
2653 'u-boot-dtb:uncomp-size': len(orig),
2654 'u-boot-dtb:size': len(comp_data),
2655 'size': len(data),
2656 }
2657 self.assertEqual(expected, props)
2658
Simon Glass151bbbf2019-07-08 14:25:41 -06002659 def testCbfsUpdateFdt(self):
2660 """Test that we can update the device tree with CBFS offset/size info"""
2661 self._CheckLz4()
2662 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2663 update_dtb=True)
2664 dtb = fdt.Fdt(out_dtb_fname)
2665 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002666 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002667 del props['cbfs/u-boot:size']
2668 self.assertEqual({
2669 'offset': 0,
2670 'size': len(data),
2671 'image-pos': 0,
2672 'cbfs:offset': 0,
2673 'cbfs:size': len(data),
2674 'cbfs:image-pos': 0,
Simon Glassfa144222023-10-14 14:40:28 -06002675 'cbfs/u-boot:offset': 0x30,
Simon Glass151bbbf2019-07-08 14:25:41 -06002676 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002677 'cbfs/u-boot:image-pos': 0x30,
2678 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002679 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002680 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002681 }, props)
2682
Simon Glass3c9b4f22019-07-08 14:25:42 -06002683 def testCbfsBadType(self):
2684 """Test an image header with a no specified location is detected"""
2685 with self.assertRaises(ValueError) as e:
2686 self._DoReadFile('126_cbfs_bad_type.dts')
2687 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2688
Simon Glass6b156f82019-07-08 14:25:43 -06002689 def testList(self):
2690 """Test listing the files in an image"""
2691 self._CheckLz4()
2692 data = self._DoReadFile('127_list.dts')
2693 image = control.images['image']
2694 entries = image.BuildEntryList()
2695 self.assertEqual(7, len(entries))
2696
2697 ent = entries[0]
2698 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002699 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002700 self.assertEqual('section', ent.etype)
2701 self.assertEqual(len(data), ent.size)
2702 self.assertEqual(0, ent.image_pos)
2703 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002704 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002705
2706 ent = entries[1]
2707 self.assertEqual(1, ent.indent)
2708 self.assertEqual('u-boot', ent.name)
2709 self.assertEqual('u-boot', ent.etype)
2710 self.assertEqual(len(U_BOOT_DATA), ent.size)
2711 self.assertEqual(0, ent.image_pos)
2712 self.assertEqual(None, ent.uncomp_size)
2713 self.assertEqual(0, ent.offset)
2714
2715 ent = entries[2]
2716 self.assertEqual(1, ent.indent)
2717 self.assertEqual('section', ent.name)
2718 self.assertEqual('section', ent.etype)
2719 section_size = ent.size
2720 self.assertEqual(0x100, ent.image_pos)
2721 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002722 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002723
2724 ent = entries[3]
2725 self.assertEqual(2, ent.indent)
2726 self.assertEqual('cbfs', ent.name)
2727 self.assertEqual('cbfs', ent.etype)
2728 self.assertEqual(0x400, ent.size)
2729 self.assertEqual(0x100, ent.image_pos)
2730 self.assertEqual(None, ent.uncomp_size)
2731 self.assertEqual(0, ent.offset)
2732
2733 ent = entries[4]
2734 self.assertEqual(3, ent.indent)
2735 self.assertEqual('u-boot', ent.name)
2736 self.assertEqual('u-boot', ent.etype)
2737 self.assertEqual(len(U_BOOT_DATA), ent.size)
2738 self.assertEqual(0x138, ent.image_pos)
2739 self.assertEqual(None, ent.uncomp_size)
2740 self.assertEqual(0x38, ent.offset)
2741
2742 ent = entries[5]
2743 self.assertEqual(3, ent.indent)
2744 self.assertEqual('u-boot-dtb', ent.name)
2745 self.assertEqual('text', ent.etype)
2746 self.assertGreater(len(COMPRESS_DATA), ent.size)
2747 self.assertEqual(0x178, ent.image_pos)
2748 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2749 self.assertEqual(0x78, ent.offset)
2750
2751 ent = entries[6]
2752 self.assertEqual(2, ent.indent)
2753 self.assertEqual('u-boot-dtb', ent.name)
2754 self.assertEqual('u-boot-dtb', ent.etype)
2755 self.assertEqual(0x500, ent.image_pos)
2756 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2757 dtb_size = ent.size
2758 # Compressing this data expands it since headers are added
2759 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2760 self.assertEqual(0x400, ent.offset)
2761
2762 self.assertEqual(len(data), 0x100 + section_size)
2763 self.assertEqual(section_size, 0x400 + dtb_size)
2764
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002765 def testFindFdtmap(self):
2766 """Test locating an FDT map in an image"""
2767 self._CheckLz4()
2768 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2769 image = control.images['image']
2770 entries = image.GetEntries()
2771 entry = entries['fdtmap']
2772 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2773
2774 def testFindFdtmapMissing(self):
2775 """Test failing to locate an FDP map"""
2776 data = self._DoReadFile('005_simple.dts')
2777 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2778
Simon Glassed39a3c2019-07-08 14:25:45 -06002779 def testFindImageHeader(self):
2780 """Test locating a image header"""
2781 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002782 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002783 image = control.images['image']
2784 entries = image.GetEntries()
2785 entry = entries['fdtmap']
2786 # The header should point to the FDT map
2787 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2788
2789 def testFindImageHeaderStart(self):
2790 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002791 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002792 image = control.images['image']
2793 entries = image.GetEntries()
2794 entry = entries['fdtmap']
2795 # The header should point to the FDT map
2796 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2797
2798 def testFindImageHeaderMissing(self):
2799 """Test failing to locate an image header"""
2800 data = self._DoReadFile('005_simple.dts')
2801 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2802
Simon Glassb8424fa2019-07-08 14:25:46 -06002803 def testReadImage(self):
2804 """Test reading an image and accessing its FDT map"""
2805 self._CheckLz4()
2806 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002807 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002808 orig_image = control.images['image']
2809 image = Image.FromFile(image_fname)
2810 self.assertEqual(orig_image.GetEntries().keys(),
2811 image.GetEntries().keys())
2812
2813 orig_entry = orig_image.GetEntries()['fdtmap']
2814 entry = image.GetEntries()['fdtmap']
Brandon Maiera657bc62024-06-04 16:16:05 +00002815 self.assertEqual(orig_entry.offset, entry.offset)
2816 self.assertEqual(orig_entry.size, entry.size)
2817 self.assertEqual(orig_entry.image_pos, entry.image_pos)
Simon Glassb8424fa2019-07-08 14:25:46 -06002818
2819 def testReadImageNoHeader(self):
2820 """Test accessing an image's FDT map without an image header"""
2821 self._CheckLz4()
2822 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002823 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002824 image = Image.FromFile(image_fname)
2825 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002826 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002827
2828 def testReadImageFail(self):
2829 """Test failing to read an image image's FDT map"""
2830 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002831 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002832 with self.assertRaises(ValueError) as e:
2833 image = Image.FromFile(image_fname)
2834 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002835
Simon Glassb2fd11d2019-07-08 14:25:48 -06002836 def testListCmd(self):
2837 """Test listing the files in an image using an Fdtmap"""
2838 self._CheckLz4()
2839 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2840
2841 # lz4 compression size differs depending on the version
2842 image = control.images['image']
2843 entries = image.GetEntries()
2844 section_size = entries['section'].size
2845 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2846 fdtmap_offset = entries['fdtmap'].offset
2847
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002848 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002849 try:
2850 tmpdir, updated_fname = self._SetupImageInTmpdir()
2851 with test_util.capture_sys_output() as (stdout, stderr):
2852 self._DoBinman('ls', '-i', updated_fname)
2853 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002854 if tmpdir:
2855 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002856 lines = stdout.getvalue().splitlines()
2857 expected = [
2858'Name Image-pos Size Entry-type Offset Uncomp-size',
2859'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002860'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002861' u-boot 0 4 u-boot 0',
2862' section 100 %x section 100' % section_size,
2863' cbfs 100 400 cbfs 0',
Simon Glassfa144222023-10-14 14:40:28 -06002864' u-boot 120 4 u-boot 20',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002865' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002866' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002867' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002868 (fdtmap_offset, fdtmap_offset),
2869' image-header bf8 8 image-header bf8',
2870 ]
2871 self.assertEqual(expected, lines)
2872
2873 def testListCmdFail(self):
2874 """Test failing to list an image"""
2875 self._DoReadFile('005_simple.dts')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002876 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002877 try:
2878 tmpdir, updated_fname = self._SetupImageInTmpdir()
2879 with self.assertRaises(ValueError) as e:
2880 self._DoBinman('ls', '-i', updated_fname)
2881 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002882 if tmpdir:
2883 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002884 self.assertIn("Cannot find FDT map in image", str(e.exception))
2885
2886 def _RunListCmd(self, paths, expected):
2887 """List out entries and check the result
2888
2889 Args:
2890 paths: List of paths to pass to the list command
2891 expected: Expected list of filenames to be returned, in order
2892 """
2893 self._CheckLz4()
2894 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002895 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002896 image = Image.FromFile(image_fname)
2897 lines = image.GetListEntries(paths)[1]
2898 files = [line[0].strip() for line in lines[1:]]
2899 self.assertEqual(expected, files)
2900
2901 def testListCmdSection(self):
2902 """Test listing the files in a section"""
2903 self._RunListCmd(['section'],
2904 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2905
2906 def testListCmdFile(self):
2907 """Test listing a particular file"""
2908 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2909
2910 def testListCmdWildcard(self):
2911 """Test listing a wildcarded file"""
2912 self._RunListCmd(['*boot*'],
2913 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2914
2915 def testListCmdWildcardMulti(self):
2916 """Test listing a wildcarded file"""
2917 self._RunListCmd(['*cb*', '*head*'],
2918 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2919
2920 def testListCmdEmpty(self):
2921 """Test listing a wildcarded file"""
2922 self._RunListCmd(['nothing'], [])
2923
2924 def testListCmdPath(self):
2925 """Test listing the files in a sub-entry of a section"""
2926 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2927
Simon Glass4c613bf2019-07-08 14:25:50 -06002928 def _RunExtractCmd(self, entry_name, decomp=True):
2929 """Extract an entry from an image
2930
2931 Args:
2932 entry_name: Entry name to extract
2933 decomp: True to decompress the data if compressed, False to leave
2934 it in its raw uncompressed format
2935
2936 Returns:
2937 data from entry
2938 """
2939 self._CheckLz4()
2940 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002941 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002942 return control.ReadEntry(image_fname, entry_name, decomp)
2943
2944 def testExtractSimple(self):
2945 """Test extracting a single file"""
2946 data = self._RunExtractCmd('u-boot')
2947 self.assertEqual(U_BOOT_DATA, data)
2948
Simon Glass980a2842019-07-08 14:25:52 -06002949 def testExtractSection(self):
2950 """Test extracting the files in a section"""
2951 data = self._RunExtractCmd('section')
2952 cbfs_data = data[:0x400]
2953 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002954 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002955 dtb_data = data[0x400:]
2956 dtb = self._decompress(dtb_data)
2957 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2958
2959 def testExtractCompressed(self):
2960 """Test extracting compressed data"""
2961 data = self._RunExtractCmd('section/u-boot-dtb')
2962 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2963
2964 def testExtractRaw(self):
2965 """Test extracting compressed data without decompressing it"""
2966 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2967 dtb = self._decompress(data)
2968 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2969
2970 def testExtractCbfs(self):
2971 """Test extracting CBFS data"""
2972 data = self._RunExtractCmd('section/cbfs/u-boot')
2973 self.assertEqual(U_BOOT_DATA, data)
2974
2975 def testExtractCbfsCompressed(self):
2976 """Test extracting CBFS compressed data"""
2977 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2978 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2979
2980 def testExtractCbfsRaw(self):
2981 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002982 bintool = self.comp_bintools['lzma_alone']
2983 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06002984 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002985 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06002986 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2987
Simon Glass4c613bf2019-07-08 14:25:50 -06002988 def testExtractBadEntry(self):
2989 """Test extracting a bad section path"""
2990 with self.assertRaises(ValueError) as e:
2991 self._RunExtractCmd('section/does-not-exist')
2992 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2993 str(e.exception))
2994
2995 def testExtractMissingFile(self):
2996 """Test extracting file that does not exist"""
2997 with self.assertRaises(IOError) as e:
2998 control.ReadEntry('missing-file', 'name')
2999
3000 def testExtractBadFile(self):
3001 """Test extracting an invalid file"""
3002 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07003003 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06003004 with self.assertRaises(ValueError) as e:
3005 control.ReadEntry(fname, 'name')
3006
Simon Glass980a2842019-07-08 14:25:52 -06003007 def testExtractCmd(self):
3008 """Test extracting a file fron an image on the command line"""
3009 self._CheckLz4()
3010 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06003011 fname = os.path.join(self._indir, 'output.extact')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003012 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06003013 try:
3014 tmpdir, updated_fname = self._SetupImageInTmpdir()
3015 with test_util.capture_sys_output() as (stdout, stderr):
3016 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3017 '-f', fname)
3018 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003019 if tmpdir:
3020 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07003021 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003022 self.assertEqual(U_BOOT_DATA, data)
3023
3024 def testExtractOneEntry(self):
3025 """Test extracting a single entry fron an image """
3026 self._CheckLz4()
3027 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003028 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003029 fname = os.path.join(self._indir, 'output.extact')
3030 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003031 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003032 self.assertEqual(U_BOOT_DATA, data)
3033
3034 def _CheckExtractOutput(self, decomp):
3035 """Helper to test file output with and without decompression
3036
3037 Args:
3038 decomp: True to decompress entry data, False to output it raw
3039 """
3040 def _CheckPresent(entry_path, expect_data, expect_size=None):
3041 """Check and remove expected file
3042
3043 This checks the data/size of a file and removes the file both from
3044 the outfiles set and from the output directory. Once all files are
3045 processed, both the set and directory should be empty.
3046
3047 Args:
3048 entry_path: Entry path
3049 expect_data: Data to expect in file, or None to skip check
3050 expect_size: Size of data to expect in file, or None to skip
3051 """
3052 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003053 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003054 os.remove(path)
3055 if expect_data:
3056 self.assertEqual(expect_data, data)
3057 elif expect_size:
3058 self.assertEqual(expect_size, len(data))
3059 outfiles.remove(path)
3060
3061 def _CheckDirPresent(name):
3062 """Remove expected directory
3063
3064 This gives an error if the directory does not exist as expected
3065
3066 Args:
3067 name: Name of directory to remove
3068 """
3069 path = os.path.join(outdir, name)
3070 os.rmdir(path)
3071
3072 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003073 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003074 outdir = os.path.join(self._indir, 'extract')
3075 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3076
3077 # Create a set of all file that were output (should be 9)
3078 outfiles = set()
3079 for root, dirs, files in os.walk(outdir):
3080 outfiles |= set([os.path.join(root, fname) for fname in files])
3081 self.assertEqual(9, len(outfiles))
3082 self.assertEqual(9, len(einfos))
3083
3084 image = control.images['image']
3085 entries = image.GetEntries()
3086
3087 # Check the 9 files in various ways
3088 section = entries['section']
3089 section_entries = section.GetEntries()
3090 cbfs_entries = section_entries['cbfs'].GetEntries()
3091 _CheckPresent('u-boot', U_BOOT_DATA)
3092 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3093 dtb_len = EXTRACT_DTB_SIZE
3094 if not decomp:
3095 dtb_len = cbfs_entries['u-boot-dtb'].size
3096 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3097 if not decomp:
3098 dtb_len = section_entries['u-boot-dtb'].size
3099 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3100
3101 fdtmap = entries['fdtmap']
3102 _CheckPresent('fdtmap', fdtmap.data)
3103 hdr = entries['image-header']
3104 _CheckPresent('image-header', hdr.data)
3105
3106 _CheckPresent('section/root', section.data)
3107 cbfs = section_entries['cbfs']
3108 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003109 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003110 _CheckPresent('root', data)
3111
3112 # There should be no files left. Remove all the directories to check.
3113 # If there are any files/dirs remaining, one of these checks will fail.
3114 self.assertEqual(0, len(outfiles))
3115 _CheckDirPresent('section/cbfs')
3116 _CheckDirPresent('section')
3117 _CheckDirPresent('')
3118 self.assertFalse(os.path.exists(outdir))
3119
3120 def testExtractAllEntries(self):
3121 """Test extracting all entries"""
3122 self._CheckLz4()
3123 self._CheckExtractOutput(decomp=True)
3124
3125 def testExtractAllEntriesRaw(self):
3126 """Test extracting all entries without decompressing them"""
3127 self._CheckLz4()
3128 self._CheckExtractOutput(decomp=False)
3129
3130 def testExtractSelectedEntries(self):
3131 """Test extracting some entries"""
3132 self._CheckLz4()
3133 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003134 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003135 outdir = os.path.join(self._indir, 'extract')
3136 einfos = control.ExtractEntries(image_fname, None, outdir,
3137 ['*cb*', '*head*'])
3138
3139 # File output is tested by testExtractAllEntries(), so just check that
3140 # the expected entries are selected
3141 names = [einfo.name for einfo in einfos]
3142 self.assertEqual(names,
3143 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3144
3145 def testExtractNoEntryPaths(self):
3146 """Test extracting some entries"""
3147 self._CheckLz4()
3148 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003149 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003150 with self.assertRaises(ValueError) as e:
3151 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003152 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003153 str(e.exception))
3154
3155 def testExtractTooManyEntryPaths(self):
3156 """Test extracting some entries"""
3157 self._CheckLz4()
3158 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003159 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003160 with self.assertRaises(ValueError) as e:
3161 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003162 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003163 str(e.exception))
3164
Simon Glass52d06212019-07-08 14:25:53 -06003165 def testPackAlignSection(self):
3166 """Test that sections can have alignment"""
3167 self._DoReadFile('131_pack_align_section.dts')
3168
3169 self.assertIn('image', control.images)
3170 image = control.images['image']
3171 entries = image.GetEntries()
3172 self.assertEqual(3, len(entries))
3173
3174 # First u-boot
3175 self.assertIn('u-boot', entries)
3176 entry = entries['u-boot']
3177 self.assertEqual(0, entry.offset)
3178 self.assertEqual(0, entry.image_pos)
3179 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3180 self.assertEqual(len(U_BOOT_DATA), entry.size)
3181
3182 # Section0
3183 self.assertIn('section0', entries)
3184 section0 = entries['section0']
3185 self.assertEqual(0x10, section0.offset)
3186 self.assertEqual(0x10, section0.image_pos)
3187 self.assertEqual(len(U_BOOT_DATA), section0.size)
3188
3189 # Second u-boot
3190 section_entries = section0.GetEntries()
3191 self.assertIn('u-boot', section_entries)
3192 entry = section_entries['u-boot']
3193 self.assertEqual(0, entry.offset)
3194 self.assertEqual(0x10, entry.image_pos)
3195 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3196 self.assertEqual(len(U_BOOT_DATA), entry.size)
3197
3198 # Section1
3199 self.assertIn('section1', entries)
3200 section1 = entries['section1']
3201 self.assertEqual(0x14, section1.offset)
3202 self.assertEqual(0x14, section1.image_pos)
3203 self.assertEqual(0x20, section1.size)
3204
3205 # Second u-boot
3206 section_entries = section1.GetEntries()
3207 self.assertIn('u-boot', section_entries)
3208 entry = section_entries['u-boot']
3209 self.assertEqual(0, entry.offset)
3210 self.assertEqual(0x14, entry.image_pos)
3211 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3212 self.assertEqual(len(U_BOOT_DATA), entry.size)
3213
3214 # Section2
3215 self.assertIn('section2', section_entries)
3216 section2 = section_entries['section2']
3217 self.assertEqual(0x4, section2.offset)
3218 self.assertEqual(0x18, section2.image_pos)
3219 self.assertEqual(4, section2.size)
3220
3221 # Third u-boot
3222 section_entries = section2.GetEntries()
3223 self.assertIn('u-boot', section_entries)
3224 entry = section_entries['u-boot']
3225 self.assertEqual(0, entry.offset)
3226 self.assertEqual(0x18, entry.image_pos)
3227 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3228 self.assertEqual(len(U_BOOT_DATA), entry.size)
3229
Simon Glassf8a54bc2019-07-20 12:23:56 -06003230 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3231 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003232 """Replace an entry in an image
3233
3234 This writes the entry data to update it, then opens the updated file and
3235 returns the value that it now finds there.
3236
3237 Args:
3238 entry_name: Entry name to replace
3239 data: Data to replace it with
3240 decomp: True to compress the data if needed, False if data is
3241 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003242 allow_resize: True to allow entries to change size, False to raise
3243 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003244
3245 Returns:
3246 Tuple:
3247 data from entry
3248 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003249 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003250 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003251 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003252 update_dtb=True)[1]
3253
3254 self.assertIn('image', control.images)
3255 image = control.images['image']
3256 entries = image.GetEntries()
3257 orig_dtb_data = entries['u-boot-dtb'].data
3258 orig_fdtmap_data = entries['fdtmap'].data
3259
Simon Glass80025522022-01-29 14:14:04 -07003260 image_fname = tools.get_output_filename('image.bin')
3261 updated_fname = tools.get_output_filename('image-updated.bin')
3262 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003263 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3264 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003265 data = control.ReadEntry(updated_fname, entry_name, decomp)
3266
Simon Glassf8a54bc2019-07-20 12:23:56 -06003267 # The DT data should not change unless resized:
3268 if not allow_resize:
3269 new_dtb_data = entries['u-boot-dtb'].data
3270 self.assertEqual(new_dtb_data, orig_dtb_data)
3271 new_fdtmap_data = entries['fdtmap'].data
3272 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003273
Simon Glassf8a54bc2019-07-20 12:23:56 -06003274 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003275
3276 def testReplaceSimple(self):
3277 """Test replacing a single file"""
3278 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003279 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3280 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003281 self.assertEqual(expected, data)
3282
3283 # Test that the state looks right. There should be an FDT for the fdtmap
3284 # that we jsut read back in, and it should match what we find in the
3285 # 'control' tables. Checking for an FDT that does not exist should
3286 # return None.
3287 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003288 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003289 self.assertEqual(expected_fdtmap, fdtmap)
3290
3291 dtb = state.GetFdtForEtype('fdtmap')
3292 self.assertEqual(dtb.GetContents(), fdtmap)
3293
3294 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3295 self.assertIsNone(missing_path)
3296 self.assertIsNone(missing_fdtmap)
3297
3298 missing_dtb = state.GetFdtForEtype('missing')
3299 self.assertIsNone(missing_dtb)
3300
3301 self.assertEqual('/binman', state.fdt_path_prefix)
3302
3303 def testReplaceResizeFail(self):
3304 """Test replacing a file by something larger"""
3305 expected = U_BOOT_DATA + b'x'
3306 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003307 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3308 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003309 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3310 str(e.exception))
3311
3312 def testReplaceMulti(self):
3313 """Test replacing entry data where multiple images are generated"""
3314 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3315 update_dtb=True)[0]
3316 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003317 updated_fname = tools.get_output_filename('image-updated.bin')
3318 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003319 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003320 control.WriteEntry(updated_fname, entry_name, expected,
3321 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003322 data = control.ReadEntry(updated_fname, entry_name)
3323 self.assertEqual(expected, data)
3324
3325 # Check the state looks right.
3326 self.assertEqual('/binman/image', state.fdt_path_prefix)
3327
3328 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003329 image_fname = tools.get_output_filename('first-image.bin')
3330 updated_fname = tools.get_output_filename('first-updated.bin')
3331 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003332 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003333 control.WriteEntry(updated_fname, entry_name, expected,
3334 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003335 data = control.ReadEntry(updated_fname, entry_name)
3336 self.assertEqual(expected, data)
3337
3338 # Check the state looks right.
3339 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003340
Simon Glassfb30e292019-07-20 12:23:51 -06003341 def testUpdateFdtAllRepack(self):
3342 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003343 self._SetupSplElf()
3344 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003345 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3346 SECTION_SIZE = 0x300
3347 DTB_SIZE = 602
3348 FDTMAP_SIZE = 608
3349 base_expected = {
3350 'offset': 0,
3351 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3352 'image-pos': 0,
3353 'section:offset': 0,
3354 'section:size': SECTION_SIZE,
3355 'section:image-pos': 0,
3356 'section/u-boot-dtb:offset': 4,
3357 'section/u-boot-dtb:size': 636,
3358 'section/u-boot-dtb:image-pos': 4,
3359 'u-boot-spl-dtb:offset': SECTION_SIZE,
3360 'u-boot-spl-dtb:size': DTB_SIZE,
3361 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3362 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3363 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3364 'u-boot-tpl-dtb:size': DTB_SIZE,
3365 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3366 'fdtmap:size': FDTMAP_SIZE,
3367 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3368 }
3369 main_expected = {
3370 'section:orig-size': SECTION_SIZE,
3371 'section/u-boot-dtb:orig-offset': 4,
3372 }
3373
3374 # We expect three device-tree files in the output, with the first one
3375 # within a fixed-size section.
3376 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3377 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3378 # main U-Boot tree. All three should have the same positions and offset
3379 # except that the main tree should include the main_expected properties
3380 start = 4
3381 for item in ['', 'spl', 'tpl', None]:
3382 if item is None:
3383 start += 16 # Move past fdtmap header
3384 dtb = fdt.Fdt.FromData(data[start:])
3385 dtb.Scan()
3386 props = self._GetPropTree(dtb,
3387 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3388 prefix='/' if item is None else '/binman/')
3389 expected = dict(base_expected)
3390 if item:
3391 expected[item] = 0
3392 else:
3393 # Main DTB and fdtdec should include the 'orig-' properties
3394 expected.update(main_expected)
3395 # Helpful for debugging:
3396 #for prop in sorted(props):
3397 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3398 self.assertEqual(expected, props)
3399 if item == '':
3400 start = SECTION_SIZE
3401 else:
3402 start += dtb._fdt_obj.totalsize()
3403
Simon Glass11453762019-07-20 12:23:55 -06003404 def testFdtmapHeaderMiddle(self):
3405 """Test an FDT map in the middle of an image when it should be at end"""
3406 with self.assertRaises(ValueError) as e:
3407 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3408 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3409 str(e.exception))
3410
3411 def testFdtmapHeaderStartBad(self):
3412 """Test an FDT map in middle of an image when it should be at start"""
3413 with self.assertRaises(ValueError) as e:
3414 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3415 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3416 str(e.exception))
3417
3418 def testFdtmapHeaderEndBad(self):
3419 """Test an FDT map at the start of an image when it should be at end"""
3420 with self.assertRaises(ValueError) as e:
3421 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3422 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3423 str(e.exception))
3424
3425 def testFdtmapHeaderNoSize(self):
3426 """Test an image header at the end of an image with undefined size"""
3427 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3428
Simon Glassf8a54bc2019-07-20 12:23:56 -06003429 def testReplaceResize(self):
3430 """Test replacing a single file in an entry with a larger file"""
3431 expected = U_BOOT_DATA + b'x'
3432 data, _, image = self._RunReplaceCmd('u-boot', expected,
3433 dts='139_replace_repack.dts')
3434 self.assertEqual(expected, data)
3435
3436 entries = image.GetEntries()
3437 dtb_data = entries['u-boot-dtb'].data
3438 dtb = fdt.Fdt.FromData(dtb_data)
3439 dtb.Scan()
3440
3441 # The u-boot section should now be larger in the dtb
3442 node = dtb.GetNode('/binman/u-boot')
3443 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3444
3445 # Same for the fdtmap
3446 fdata = entries['fdtmap'].data
3447 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3448 fdtb.Scan()
3449 fnode = fdtb.GetNode('/u-boot')
3450 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3451
3452 def testReplaceResizeNoRepack(self):
3453 """Test replacing an entry with a larger file when not allowed"""
3454 expected = U_BOOT_DATA + b'x'
3455 with self.assertRaises(ValueError) as e:
3456 self._RunReplaceCmd('u-boot', expected)
3457 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3458 str(e.exception))
3459
Simon Glass9d8ee322019-07-20 12:23:58 -06003460 def testEntryShrink(self):
3461 """Test contracting an entry after it is packed"""
3462 try:
3463 state.SetAllowEntryContraction(True)
3464 data = self._DoReadFileDtb('140_entry_shrink.dts',
3465 update_dtb=True)[0]
3466 finally:
3467 state.SetAllowEntryContraction(False)
3468 self.assertEqual(b'a', data[:1])
3469 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3470 self.assertEqual(b'a', data[-1:])
3471
3472 def testEntryShrinkFail(self):
3473 """Test not being allowed to contract an entry after it is packed"""
3474 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3475
3476 # In this case there is a spare byte at the end of the data. The size of
3477 # the contents is only 1 byte but we still have the size before it
3478 # shrunk.
3479 self.assertEqual(b'a\0', data[:2])
3480 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3481 self.assertEqual(b'a\0', data[-2:])
3482
Simon Glass70e32982019-07-20 12:24:01 -06003483 def testDescriptorOffset(self):
3484 """Test that the Intel descriptor is always placed at at the start"""
3485 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3486 image = control.images['image']
3487 entries = image.GetEntries()
3488 desc = entries['intel-descriptor']
3489 self.assertEqual(0xff800000, desc.offset);
3490 self.assertEqual(0xff800000, desc.image_pos);
3491
Simon Glass37fdd142019-07-20 12:24:06 -06003492 def testReplaceCbfs(self):
3493 """Test replacing a single file in CBFS without changing the size"""
3494 self._CheckLz4()
3495 expected = b'x' * len(U_BOOT_DATA)
3496 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003497 updated_fname = tools.get_output_filename('image-updated.bin')
3498 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003499 entry_name = 'section/cbfs/u-boot'
3500 control.WriteEntry(updated_fname, entry_name, expected,
3501 allow_resize=True)
3502 data = control.ReadEntry(updated_fname, entry_name)
3503 self.assertEqual(expected, data)
3504
3505 def testReplaceResizeCbfs(self):
3506 """Test replacing a single file in CBFS with one of a different size"""
3507 self._CheckLz4()
3508 expected = U_BOOT_DATA + b'x'
3509 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003510 updated_fname = tools.get_output_filename('image-updated.bin')
3511 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003512 entry_name = 'section/cbfs/u-boot'
3513 control.WriteEntry(updated_fname, entry_name, expected,
3514 allow_resize=True)
3515 data = control.ReadEntry(updated_fname, entry_name)
3516 self.assertEqual(expected, data)
3517
Simon Glass30033c22019-07-20 12:24:15 -06003518 def _SetupForReplace(self):
3519 """Set up some files to use to replace entries
3520
3521 This generates an image, copies it to a new file, extracts all the files
3522 in it and updates some of them
3523
3524 Returns:
3525 List
3526 Image filename
3527 Output directory
3528 Expected values for updated entries, each a string
3529 """
3530 data = self._DoReadFileRealDtb('143_replace_all.dts')
3531
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 Glass30033c22019-07-20 12:24:15 -06003534
3535 outdir = os.path.join(self._indir, 'extract')
3536 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3537
3538 expected1 = b'x' + U_BOOT_DATA + b'y'
3539 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003540 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003541
3542 expected2 = b'a' + U_BOOT_DATA + b'b'
3543 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003544 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003545
3546 expected_text = b'not the same text'
3547 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003548 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003549
3550 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3551 dtb = fdt.FdtScan(dtb_fname)
3552 node = dtb.GetNode('/binman/text')
3553 node.AddString('my-property', 'the value')
3554 dtb.Sync(auto_resize=True)
3555 dtb.Flush()
3556
3557 return updated_fname, outdir, expected1, expected2, expected_text
3558
3559 def _CheckReplaceMultiple(self, entry_paths):
3560 """Handle replacing the contents of multiple entries
3561
3562 Args:
3563 entry_paths: List of entry paths to replace
3564
3565 Returns:
3566 List
3567 Dict of entries in the image:
3568 key: Entry name
3569 Value: Entry object
3570 Expected values for updated entries, each a string
3571 """
3572 updated_fname, outdir, expected1, expected2, expected_text = (
3573 self._SetupForReplace())
3574 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3575
3576 image = Image.FromFile(updated_fname)
3577 image.LoadData()
3578 return image.GetEntries(), expected1, expected2, expected_text
3579
3580 def testReplaceAll(self):
3581 """Test replacing the contents of all entries"""
3582 entries, expected1, expected2, expected_text = (
3583 self._CheckReplaceMultiple([]))
3584 data = entries['u-boot'].data
3585 self.assertEqual(expected1, data)
3586
3587 data = entries['u-boot2'].data
3588 self.assertEqual(expected2, data)
3589
3590 data = entries['text'].data
3591 self.assertEqual(expected_text, data)
3592
3593 # Check that the device tree is updated
3594 data = entries['u-boot-dtb'].data
3595 dtb = fdt.Fdt.FromData(data)
3596 dtb.Scan()
3597 node = dtb.GetNode('/binman/text')
3598 self.assertEqual('the value', node.props['my-property'].value)
3599
3600 def testReplaceSome(self):
3601 """Test replacing the contents of a few entries"""
3602 entries, expected1, expected2, expected_text = (
3603 self._CheckReplaceMultiple(['u-boot2', 'text']))
3604
3605 # This one should not change
3606 data = entries['u-boot'].data
3607 self.assertEqual(U_BOOT_DATA, 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 def testReplaceCmd(self):
3616 """Test replacing a file fron an image on the command line"""
3617 self._DoReadFileRealDtb('143_replace_all.dts')
3618
3619 try:
3620 tmpdir, updated_fname = self._SetupImageInTmpdir()
3621
3622 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3623 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003624 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003625
3626 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003627 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003628 self.assertEqual(expected, data[:len(expected)])
3629 map_fname = os.path.join(tmpdir, 'image-updated.map')
3630 self.assertFalse(os.path.exists(map_fname))
3631 finally:
3632 shutil.rmtree(tmpdir)
3633
3634 def testReplaceCmdSome(self):
3635 """Test replacing some files fron an image on the command line"""
3636 updated_fname, outdir, expected1, expected2, expected_text = (
3637 self._SetupForReplace())
3638
3639 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3640 'u-boot2', 'text')
3641
Simon Glass80025522022-01-29 14:14:04 -07003642 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003643 image = Image.FromFile(updated_fname)
3644 image.LoadData()
3645 entries = image.GetEntries()
3646
3647 # This one should not change
3648 data = entries['u-boot'].data
3649 self.assertEqual(U_BOOT_DATA, data)
3650
3651 data = entries['u-boot2'].data
3652 self.assertEqual(expected2, data)
3653
3654 data = entries['text'].data
3655 self.assertEqual(expected_text, data)
3656
3657 def testReplaceMissing(self):
3658 """Test replacing entries where the file is missing"""
3659 updated_fname, outdir, expected1, expected2, expected_text = (
3660 self._SetupForReplace())
3661
3662 # Remove one of the files, to generate a warning
3663 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3664 os.remove(u_boot_fname1)
3665
3666 with test_util.capture_sys_output() as (stdout, stderr):
3667 control.ReplaceEntries(updated_fname, None, outdir, [])
3668 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003669 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003670
3671 def testReplaceCmdMap(self):
3672 """Test replacing a file fron an image on the command line"""
3673 self._DoReadFileRealDtb('143_replace_all.dts')
3674
3675 try:
3676 tmpdir, updated_fname = self._SetupImageInTmpdir()
3677
3678 fname = os.path.join(self._indir, 'update-u-boot.bin')
3679 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003680 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003681
3682 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3683 '-f', fname, '-m')
3684 map_fname = os.path.join(tmpdir, 'image-updated.map')
3685 self.assertTrue(os.path.exists(map_fname))
3686 finally:
3687 shutil.rmtree(tmpdir)
3688
3689 def testReplaceNoEntryPaths(self):
3690 """Test replacing an entry without an entry path"""
3691 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003692 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003693 with self.assertRaises(ValueError) as e:
3694 control.ReplaceEntries(image_fname, 'fname', None, [])
3695 self.assertIn('Must specify an entry path to read with -f',
3696 str(e.exception))
3697
3698 def testReplaceTooManyEntryPaths(self):
3699 """Test extracting some entries"""
3700 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003701 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003702 with self.assertRaises(ValueError) as e:
3703 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3704 self.assertIn('Must specify exactly one entry path to write with -f',
3705 str(e.exception))
3706
Simon Glass0b074d62019-08-24 07:22:48 -06003707 def testPackReset16(self):
3708 """Test that an image with an x86 reset16 region can be created"""
3709 data = self._DoReadFile('144_x86_reset16.dts')
3710 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3711
3712 def testPackReset16Spl(self):
3713 """Test that an image with an x86 reset16-spl region can be created"""
3714 data = self._DoReadFile('145_x86_reset16_spl.dts')
3715 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3716
3717 def testPackReset16Tpl(self):
3718 """Test that an image with an x86 reset16-tpl region can be created"""
3719 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3720 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3721
Simon Glass232f90c2019-08-24 07:22:50 -06003722 def testPackIntelFit(self):
3723 """Test that an image with an Intel FIT and pointer can be created"""
3724 data = self._DoReadFile('147_intel_fit.dts')
3725 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3726 fit = data[16:32];
3727 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3728 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3729
3730 image = control.images['image']
3731 entries = image.GetEntries()
3732 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3733 self.assertEqual(expected_ptr, ptr)
3734
3735 def testPackIntelFitMissing(self):
3736 """Test detection of a FIT pointer with not FIT region"""
3737 with self.assertRaises(ValueError) as e:
3738 self._DoReadFile('148_intel_fit_missing.dts')
3739 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3740 str(e.exception))
3741
Simon Glass72555fa2019-11-06 17:22:44 -07003742 def _CheckSymbolsTplSection(self, dts, expected_vals):
3743 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003744 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003745 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003746 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003747 self.assertEqual(expected1, data[:upto1])
3748
3749 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003750 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003751 self.assertEqual(expected2, data[upto1:upto2])
3752
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003753 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003754 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003755 self.assertEqual(expected3, data[upto2:upto3])
3756
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003757 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003758 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3759
3760 def testSymbolsTplSection(self):
3761 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3762 self._SetupSplElf('u_boot_binman_syms')
3763 self._SetupTplElf('u_boot_binman_syms')
3764 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003765 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003766
3767 def testSymbolsTplSectionX86(self):
3768 """Test binman can assign symbols in a section with end-at-4gb"""
3769 self._SetupSplElf('u_boot_binman_syms_x86')
3770 self._SetupTplElf('u_boot_binman_syms_x86')
3771 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003772 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003773 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003774
Simon Glass98c59572019-08-24 07:23:03 -06003775 def testPackX86RomIfwiSectiom(self):
3776 """Test that a section can be placed in an IFWI region"""
3777 self._SetupIfwi('fitimage.bin')
3778 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3779 self._CheckIfwi(data)
3780
Simon Glassba7985d2019-08-24 07:23:07 -06003781 def testPackFspM(self):
3782 """Test that an image with a FSP memory-init binary can be created"""
3783 data = self._DoReadFile('152_intel_fsp_m.dts')
3784 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3785
Simon Glass4d9086d2019-10-20 21:31:35 -06003786 def testPackFspS(self):
3787 """Test that an image with a FSP silicon-init binary can be created"""
3788 data = self._DoReadFile('153_intel_fsp_s.dts')
3789 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003790
Simon Glass9ea87b22019-10-20 21:31:36 -06003791 def testPackFspT(self):
3792 """Test that an image with a FSP temp-ram-init binary can be created"""
3793 data = self._DoReadFile('154_intel_fsp_t.dts')
3794 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3795
Simon Glass48f3aad2020-07-09 18:39:31 -06003796 def testMkimage(self):
3797 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003798 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003799 data = self._DoReadFile('156_mkimage.dts')
3800
3801 # Just check that the data appears in the file somewhere
3802 self.assertIn(U_BOOT_SPL_DATA, data)
3803
Simon Glass66152ce2022-01-09 20:14:09 -07003804 def testMkimageMissing(self):
3805 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003806 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003807 with test_util.capture_sys_output() as (_, stderr):
3808 self._DoTestFile('156_mkimage.dts',
3809 force_missing_bintools='mkimage')
3810 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003811 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003812
Simon Glass5e560182020-07-09 18:39:36 -06003813 def testExtblob(self):
3814 """Test an image with an external blob"""
3815 data = self._DoReadFile('157_blob_ext.dts')
3816 self.assertEqual(REFCODE_DATA, data)
3817
3818 def testExtblobMissing(self):
3819 """Test an image with a missing external blob"""
3820 with self.assertRaises(ValueError) as e:
3821 self._DoReadFile('158_blob_ext_missing.dts')
3822 self.assertIn("Filename 'missing-file' not found in input path",
3823 str(e.exception))
3824
Simon Glass5d94cc62020-07-09 18:39:38 -06003825 def testExtblobMissingOk(self):
3826 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003827 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003828 ret = self._DoTestFile('158_blob_ext_missing.dts',
3829 allow_missing=True)
3830 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003831 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003832 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003833 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003834 self.assertIn('Some images are invalid', err)
3835
3836 def testExtblobMissingOkFlag(self):
3837 """Test an image with an missing external blob allowed with -W"""
3838 with test_util.capture_sys_output() as (stdout, stderr):
3839 ret = self._DoTestFile('158_blob_ext_missing.dts',
3840 allow_missing=True, ignore_missing=True)
3841 self.assertEqual(0, ret)
3842 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003843 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003844 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003845 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003846
3847 def testExtblobMissingOkSect(self):
3848 """Test an image with an missing external blob that is allowed"""
3849 with test_util.capture_sys_output() as (stdout, stderr):
3850 self._DoTestFile('159_blob_ext_missing_sect.dts',
3851 allow_missing=True)
3852 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003853 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003854
Simon Glasse88cef92020-07-09 18:39:41 -06003855 def testPackX86RomMeMissingDesc(self):
3856 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003857 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003858 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003859 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003860 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003861
3862 def testPackX86RomMissingIfwi(self):
3863 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3864 self._SetupIfwi('fitimage.bin')
3865 pathname = os.path.join(self._indir, 'fitimage.bin')
3866 os.remove(pathname)
3867 with test_util.capture_sys_output() as (stdout, stderr):
3868 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3869 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003870 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003871
Simon Glass2a0fa982022-02-11 13:23:21 -07003872 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003873 """Test that zero-size overlapping regions are ignored"""
3874 self._DoTestFile('160_pack_overlap_zero.dts')
3875
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003876 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003877 # The data should be inside the FIT
3878 dtb = fdt.Fdt.FromData(fit_data)
3879 dtb.Scan()
3880 fnode = dtb.GetNode('/images/kernel')
3881 self.assertIn('data', fnode.props)
3882
3883 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003884 tools.write_file(fname, fit_data)
3885 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003886
3887 # Check a few features to make sure the plumbing works. We don't need
3888 # to test the operation of mkimage or dumpimage here. First convert the
3889 # output into a dict where the keys are the fields printed by dumpimage
3890 # and the values are a list of values for each field
3891 lines = out.splitlines()
3892
3893 # Converts "Compression: gzip compressed" into two groups:
3894 # 'Compression' and 'gzip compressed'
3895 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3896 vals = collections.defaultdict(list)
3897 for line in lines:
3898 mat = re_line.match(line)
3899 vals[mat.group(1)].append(mat.group(2))
3900
Brandon Maiera657bc62024-06-04 16:16:05 +00003901 self.assertEqual('FIT description: test-desc', lines[0])
Simon Glass45d556d2020-07-09 18:39:45 -06003902 self.assertIn('Created:', lines[1])
3903 self.assertIn('Image 0 (kernel)', vals)
3904 self.assertIn('Hash value', vals)
3905 data_sizes = vals.get('Data Size')
3906 self.assertIsNotNone(data_sizes)
3907 self.assertEqual(2, len(data_sizes))
3908 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003909 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3910 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3911
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003912 # Check if entry listing correctly omits /images/
3913 image = control.images['image']
3914 fit_entry = image.GetEntries()['fit']
3915 subentries = list(fit_entry.GetEntries().keys())
3916 expected = ['kernel', 'fdt-1']
3917 self.assertEqual(expected, subentries)
3918
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003919 def testSimpleFit(self):
3920 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003921 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003922 data = self._DoReadFile('161_fit.dts')
3923 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3924 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3925 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3926
3927 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3928
3929 def testSimpleFitExpandsSubentries(self):
3930 """Test that FIT images expand their subentries"""
3931 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3932 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3933 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3934 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3935
3936 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003937
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003938 def testSimpleFitImagePos(self):
3939 """Test that we have correct image-pos for FIT subentries"""
3940 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3941 update_dtb=True)
3942 dtb = fdt.Fdt(out_dtb_fname)
3943 dtb.Scan()
3944 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3945
Simon Glassb7bad182022-03-05 20:19:01 -07003946 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003947 self.assertEqual({
3948 'image-pos': 0,
3949 'offset': 0,
3950 'size': 1890,
3951
3952 'u-boot:image-pos': 0,
3953 'u-boot:offset': 0,
3954 'u-boot:size': 4,
3955
3956 'fit:image-pos': 4,
3957 'fit:offset': 4,
3958 'fit:size': 1840,
3959
Simon Glassb7bad182022-03-05 20:19:01 -07003960 'fit/images/kernel:image-pos': 304,
3961 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003962 'fit/images/kernel:size': 4,
3963
Simon Glassb7bad182022-03-05 20:19:01 -07003964 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003965 'fit/images/kernel/u-boot:offset': 0,
3966 'fit/images/kernel/u-boot:size': 4,
3967
Simon Glassb7bad182022-03-05 20:19:01 -07003968 'fit/images/fdt-1:image-pos': 552,
3969 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003970 'fit/images/fdt-1:size': 6,
3971
Simon Glassb7bad182022-03-05 20:19:01 -07003972 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003973 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3974 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3975
3976 'u-boot-nodtb:image-pos': 1844,
3977 'u-boot-nodtb:offset': 1844,
3978 'u-boot-nodtb:size': 46,
3979 }, props)
3980
3981 # Actually check the data is where we think it is
3982 for node, expected in [
3983 ("u-boot", U_BOOT_DATA),
3984 ("fit/images/kernel", U_BOOT_DATA),
3985 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3986 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3987 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3988 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3989 ]:
3990 image_pos = props[f"{node}:image-pos"]
3991 size = props[f"{node}:size"]
3992 self.assertEqual(len(expected), size)
3993 self.assertEqual(expected, data[image_pos:image_pos+size])
3994
Simon Glass45d556d2020-07-09 18:39:45 -06003995 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003996 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003997 data = self._DoReadFile('162_fit_external.dts')
3998 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3999
Simon Glass7932c882022-01-09 20:13:39 -07004000 # Size of the external-data region as set up by mkimage
4001 external_data_size = len(U_BOOT_DATA) + 2
4002 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07004003 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07004004 len(U_BOOT_NODTB_DATA))
4005
Simon Glass45d556d2020-07-09 18:39:45 -06004006 # The data should be outside the FIT
4007 dtb = fdt.Fdt.FromData(fit_data)
4008 dtb.Scan()
4009 fnode = dtb.GetNode('/images/kernel')
4010 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07004011 self.assertEqual(len(U_BOOT_DATA),
4012 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4013 fit_pos = 0x400;
4014 self.assertEqual(
4015 fit_pos,
4016 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4017
Brandon Maiera657bc62024-06-04 16:16:05 +00004018 self.assertEqual(expected_size, len(data))
Simon Glass7932c882022-01-09 20:13:39 -07004019 actual_pos = len(U_BOOT_DATA) + fit_pos
4020 self.assertEqual(U_BOOT_DATA + b'aa',
4021 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004022
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004023 def testFitExternalImagePos(self):
4024 """Test that we have correct image-pos for external FIT subentries"""
4025 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4026 update_dtb=True)
4027 dtb = fdt.Fdt(out_dtb_fname)
4028 dtb.Scan()
4029 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4030
4031 self.assertEqual({
4032 'image-pos': 0,
4033 'offset': 0,
4034 'size': 1082,
4035
4036 'u-boot:image-pos': 0,
4037 'u-boot:offset': 0,
4038 'u-boot:size': 4,
4039
4040 'fit:size': 1032,
4041 'fit:offset': 4,
4042 'fit:image-pos': 4,
4043
4044 'fit/images/kernel:size': 4,
4045 'fit/images/kernel:offset': 1024,
4046 'fit/images/kernel:image-pos': 1028,
4047
4048 'fit/images/kernel/u-boot:size': 4,
4049 'fit/images/kernel/u-boot:offset': 0,
4050 'fit/images/kernel/u-boot:image-pos': 1028,
4051
4052 'fit/images/fdt-1:size': 2,
4053 'fit/images/fdt-1:offset': 1028,
4054 'fit/images/fdt-1:image-pos': 1032,
4055
4056 'fit/images/fdt-1/_testing:size': 2,
4057 'fit/images/fdt-1/_testing:offset': 0,
4058 'fit/images/fdt-1/_testing:image-pos': 1032,
4059
4060 'u-boot-nodtb:image-pos': 1036,
4061 'u-boot-nodtb:offset': 1036,
4062 'u-boot-nodtb:size': 46,
4063 }, props)
4064
4065 # Actually check the data is where we think it is
4066 for node, expected in [
4067 ("u-boot", U_BOOT_DATA),
4068 ("fit/images/kernel", U_BOOT_DATA),
4069 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4070 ("fit/images/fdt-1", b'aa'),
4071 ("fit/images/fdt-1/_testing", b'aa'),
4072 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4073 ]:
4074 image_pos = props[f"{node}:image-pos"]
4075 size = props[f"{node}:size"]
4076 self.assertEqual(len(expected), size)
4077 self.assertEqual(expected, data[image_pos:image_pos+size])
4078
Simon Glass66152ce2022-01-09 20:14:09 -07004079 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004080 """Test that binman complains if mkimage is missing"""
4081 with self.assertRaises(ValueError) as e:
4082 self._DoTestFile('162_fit_external.dts',
4083 force_missing_bintools='mkimage')
4084 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4085 str(e.exception))
4086
4087 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004088 """Test that binman still produces a FIT image if mkimage is missing"""
4089 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004090 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004091 force_missing_bintools='mkimage')
4092 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004093 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004094
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004095 def testSectionIgnoreHashSignature(self):
4096 """Test that sections ignore hash, signature nodes for its data"""
4097 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4098 expected = (U_BOOT_DATA + U_BOOT_DATA)
4099 self.assertEqual(expected, data)
4100
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004101 def testPadInSections(self):
4102 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004103 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4104 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004105 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4106 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004107 U_BOOT_DATA)
4108 self.assertEqual(expected, data)
4109
Simon Glassd12599d2020-10-26 17:40:09 -06004110 dtb = fdt.Fdt(out_dtb_fname)
4111 dtb.Scan()
4112 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4113 expected = {
4114 'image-pos': 0,
4115 'offset': 0,
4116 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4117
4118 'section:image-pos': 0,
4119 'section:offset': 0,
4120 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4121
4122 'section/before:image-pos': 0,
4123 'section/before:offset': 0,
4124 'section/before:size': len(U_BOOT_DATA),
4125
4126 'section/u-boot:image-pos': 4,
4127 'section/u-boot:offset': 4,
4128 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4129
4130 'section/after:image-pos': 26,
4131 'section/after:offset': 26,
4132 'section/after:size': len(U_BOOT_DATA),
4133 }
4134 self.assertEqual(expected, props)
4135
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004136 def testFitImageSubentryAlignment(self):
4137 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004138 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004139 entry_args = {
4140 'test-id': TEXT_DATA,
4141 }
4142 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4143 entry_args=entry_args)
4144 dtb = fdt.Fdt.FromData(data)
4145 dtb.Scan()
4146
4147 node = dtb.GetNode('/images/kernel')
4148 data = dtb.GetProps(node)["data"].bytes
4149 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004150 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4151 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004152 self.assertEqual(expected, data)
4153
4154 node = dtb.GetNode('/images/fdt-1')
4155 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004156 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4157 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004158 U_BOOT_DTB_DATA)
4159 self.assertEqual(expected, data)
4160
4161 def testFitExtblobMissingOk(self):
4162 """Test a FIT with a missing external blob that is allowed"""
4163 with test_util.capture_sys_output() as (stdout, stderr):
4164 self._DoTestFile('168_fit_missing_blob.dts',
4165 allow_missing=True)
4166 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004167 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004168
Simon Glass21db0ff2020-09-01 05:13:54 -06004169 def testBlobNamedByArgMissing(self):
4170 """Test handling of a missing entry arg"""
4171 with self.assertRaises(ValueError) as e:
4172 self._DoReadFile('068_blob_named_by_arg.dts')
4173 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4174 str(e.exception))
4175
Simon Glass559c4de2020-09-01 05:13:58 -06004176 def testPackBl31(self):
4177 """Test that an image with an ATF BL31 binary can be created"""
4178 data = self._DoReadFile('169_atf_bl31.dts')
4179 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4180
Samuel Holland9d8cc632020-10-21 21:12:15 -05004181 def testPackScp(self):
4182 """Test that an image with an SCP binary can be created"""
4183 data = self._DoReadFile('172_scp.dts')
4184 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4185
Simon Glasscd2783e2024-07-20 11:49:46 +01004186 def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True):
4187 """Check an image with an FIT with multiple FDT images"""
Simon Glassa435cd12020-09-01 05:13:59 -06004188 def _CheckFdt(seq, expected_data):
4189 """Check the FDT nodes
4190
4191 Args:
4192 seq: Sequence number to check (0 or 1)
4193 expected_data: Expected contents of 'data' property
4194 """
4195 name = 'fdt-%d' % seq
4196 fnode = dtb.GetNode('/images/%s' % name)
4197 self.assertIsNotNone(fnode)
4198 self.assertEqual({'description','type', 'compression', 'data'},
4199 set(fnode.props.keys()))
4200 self.assertEqual(expected_data, fnode.props['data'].bytes)
4201 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4202 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004203 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004204
4205 def _CheckConfig(seq, expected_data):
4206 """Check the configuration nodes
4207
4208 Args:
4209 seq: Sequence number to check (0 or 1)
4210 expected_data: Expected contents of 'data' property
4211 """
4212 cnode = dtb.GetNode('/configurations')
4213 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004214 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004215
4216 name = 'config-%d' % seq
4217 fnode = dtb.GetNode('/configurations/%s' % name)
4218 self.assertIsNotNone(fnode)
4219 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4220 set(fnode.props.keys()))
4221 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4222 fnode.props['description'].value)
4223 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4224
4225 entry_args = {
Simon Glass1032acc2020-09-06 10:39:08 -06004226 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004227 }
Simon Glasscd2783e2024-07-20 11:49:46 +01004228 if use_fdt_list:
4229 entry_args['of-list'] = 'test-fdt1 test-fdt2'
Simon Glassa435cd12020-09-01 05:13:59 -06004230 data = self._DoReadFileDtb(
Simon Glasscd2783e2024-07-20 11:49:46 +01004231 dts,
Simon Glassa435cd12020-09-01 05:13:59 -06004232 entry_args=entry_args,
4233 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4234 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4235 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4236
4237 dtb = fdt.Fdt.FromData(fit_data)
4238 dtb.Scan()
4239 fnode = dtb.GetNode('/images/kernel')
4240 self.assertIn('data', fnode.props)
4241
4242 # Check all the properties in fdt-1 and fdt-2
4243 _CheckFdt(1, TEST_FDT1_DATA)
4244 _CheckFdt(2, TEST_FDT2_DATA)
4245
4246 # Check configurations
4247 _CheckConfig(1, TEST_FDT1_DATA)
4248 _CheckConfig(2, TEST_FDT2_DATA)
4249
Simon Glasscd2783e2024-07-20 11:49:46 +01004250 def testFitFdt(self):
4251 """Test an image with an FIT with multiple FDT images"""
4252 self.CheckFitFdt()
4253
Simon Glassa435cd12020-09-01 05:13:59 -06004254 def testFitFdtMissingList(self):
4255 """Test handling of a missing 'of-list' entry arg"""
4256 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004257 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004258 self.assertIn("Generator node requires 'of-list' entry argument",
4259 str(e.exception))
4260
4261 def testFitFdtEmptyList(self):
4262 """Test handling of an empty 'of-list' entry arg"""
4263 entry_args = {
4264 'of-list': '',
4265 }
4266 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4267
4268 def testFitFdtMissingProp(self):
4269 """Test handling of a missing 'fit,fdt-list' property"""
4270 with self.assertRaises(ValueError) as e:
4271 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4272 self.assertIn("Generator node requires 'fit,fdt-list' property",
4273 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004274
Simon Glass1032acc2020-09-06 10:39:08 -06004275 def testFitFdtMissing(self):
4276 """Test handling of a missing 'default-dt' entry arg"""
4277 entry_args = {
4278 'of-list': 'test-fdt1 test-fdt2',
4279 }
4280 with self.assertRaises(ValueError) as e:
4281 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004282 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004283 entry_args=entry_args,
4284 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4285 self.assertIn("Generated 'default' node requires default-dt entry argument",
4286 str(e.exception))
4287
4288 def testFitFdtNotInList(self):
4289 """Test handling of a default-dt that is not in the of-list"""
4290 entry_args = {
4291 'of-list': 'test-fdt1 test-fdt2',
4292 'default-dt': 'test-fdt3',
4293 }
4294 with self.assertRaises(ValueError) as e:
4295 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004296 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004297 entry_args=entry_args,
4298 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4299 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4300 str(e.exception))
4301
Simon Glassa820af72020-09-06 10:39:09 -06004302 def testFitExtblobMissingHelp(self):
4303 """Test display of help messages when an external blob is missing"""
4304 control.missing_blob_help = control._ReadMissingBlobHelp()
4305 control.missing_blob_help['wibble'] = 'Wibble test'
4306 control.missing_blob_help['another'] = 'Another test'
4307 with test_util.capture_sys_output() as (stdout, stderr):
4308 self._DoTestFile('168_fit_missing_blob.dts',
4309 allow_missing=True)
4310 err = stderr.getvalue()
4311
4312 # We can get the tag from the name, the type or the missing-msg
4313 # property. Check all three.
4314 self.assertIn('You may need to build ARM Trusted', err)
4315 self.assertIn('Wibble test', err)
4316 self.assertIn('Another test', err)
4317
Simon Glass6f1f4d42020-09-06 10:35:32 -06004318 def testMissingBlob(self):
4319 """Test handling of a blob containing a missing file"""
4320 with self.assertRaises(ValueError) as e:
4321 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4322 self.assertIn("Filename 'missing' not found in input path",
4323 str(e.exception))
4324
Simon Glassa0729502020-09-06 10:35:33 -06004325 def testEnvironment(self):
4326 """Test adding a U-Boot environment"""
4327 data = self._DoReadFile('174_env.dts')
4328 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4329 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4330 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4331 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4332 env)
4333
4334 def testEnvironmentNoSize(self):
4335 """Test that a missing 'size' property is detected"""
4336 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004337 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004338 self.assertIn("'u-boot-env' entry must have a size property",
4339 str(e.exception))
4340
4341 def testEnvironmentTooSmall(self):
4342 """Test handling of an environment that does not fit"""
4343 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004344 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004345
4346 # checksum, start byte, environment with \0 terminator, final \0
4347 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4348 short = need - 0x8
4349 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4350 str(e.exception))
4351
Simon Glassd1fdf752020-10-26 17:40:01 -06004352 def testSkipAtStart(self):
4353 """Test handling of skip-at-start section"""
4354 data = self._DoReadFile('177_skip_at_start.dts')
4355 self.assertEqual(U_BOOT_DATA, data)
4356
4357 image = control.images['image']
4358 entries = image.GetEntries()
4359 section = entries['section']
4360 self.assertEqual(0, section.offset)
4361 self.assertEqual(len(U_BOOT_DATA), section.size)
4362 self.assertEqual(U_BOOT_DATA, section.GetData())
4363
4364 entry = section.GetEntries()['u-boot']
4365 self.assertEqual(16, entry.offset)
4366 self.assertEqual(len(U_BOOT_DATA), entry.size)
4367 self.assertEqual(U_BOOT_DATA, entry.data)
4368
4369 def testSkipAtStartPad(self):
4370 """Test handling of skip-at-start section with padded entry"""
4371 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004372 before = tools.get_bytes(0, 8)
4373 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004374 all = before + U_BOOT_DATA + after
4375 self.assertEqual(all, data)
4376
4377 image = control.images['image']
4378 entries = image.GetEntries()
4379 section = entries['section']
4380 self.assertEqual(0, section.offset)
4381 self.assertEqual(len(all), section.size)
4382 self.assertEqual(all, section.GetData())
4383
4384 entry = section.GetEntries()['u-boot']
4385 self.assertEqual(16, entry.offset)
4386 self.assertEqual(len(all), entry.size)
4387 self.assertEqual(U_BOOT_DATA, entry.data)
4388
4389 def testSkipAtStartSectionPad(self):
4390 """Test handling of skip-at-start section with padding"""
4391 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004392 before = tools.get_bytes(0, 8)
4393 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004394 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004395 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004396
4397 image = control.images['image']
4398 entries = image.GetEntries()
4399 section = entries['section']
4400 self.assertEqual(0, section.offset)
4401 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004402 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004403 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004404
4405 entry = section.GetEntries()['u-boot']
4406 self.assertEqual(16, entry.offset)
4407 self.assertEqual(len(U_BOOT_DATA), entry.size)
4408 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004409
Simon Glassbb395742020-10-26 17:40:14 -06004410 def testSectionPad(self):
4411 """Testing padding with sections"""
4412 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004413 expected = (tools.get_bytes(ord('&'), 3) +
4414 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004415 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004416 tools.get_bytes(ord('!'), 1) +
4417 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004418 self.assertEqual(expected, data)
4419
4420 def testSectionAlign(self):
4421 """Testing alignment with sections"""
4422 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4423 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004424 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004425 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004426 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004427 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004428 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4429 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004430 self.assertEqual(expected, data)
4431
Simon Glassd92c8362020-10-26 17:40:25 -06004432 def testCompressImage(self):
4433 """Test compression of the entire image"""
4434 self._CheckLz4()
4435 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4436 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4437 dtb = fdt.Fdt(out_dtb_fname)
4438 dtb.Scan()
4439 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4440 'uncomp-size'])
4441 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004442 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004443
4444 # Do a sanity check on various fields
4445 image = control.images['image']
4446 entries = image.GetEntries()
4447 self.assertEqual(2, len(entries))
4448
4449 entry = entries['blob']
4450 self.assertEqual(COMPRESS_DATA, entry.data)
4451 self.assertEqual(len(COMPRESS_DATA), entry.size)
4452
4453 entry = entries['u-boot']
4454 self.assertEqual(U_BOOT_DATA, entry.data)
4455 self.assertEqual(len(U_BOOT_DATA), entry.size)
4456
4457 self.assertEqual(len(data), image.size)
4458 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4459 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4460 orig = self._decompress(image.data)
4461 self.assertEqual(orig, image.uncomp_data)
4462
4463 expected = {
4464 'blob:offset': 0,
4465 'blob:size': len(COMPRESS_DATA),
4466 'u-boot:offset': len(COMPRESS_DATA),
4467 'u-boot:size': len(U_BOOT_DATA),
4468 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4469 'offset': 0,
4470 'image-pos': 0,
4471 'size': len(data),
4472 }
4473 self.assertEqual(expected, props)
4474
4475 def testCompressImageLess(self):
4476 """Test compression where compression reduces the image size"""
4477 self._CheckLz4()
4478 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4479 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4480 dtb = fdt.Fdt(out_dtb_fname)
4481 dtb.Scan()
4482 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4483 'uncomp-size'])
4484 orig = self._decompress(data)
4485
Brandon Maiera657bc62024-06-04 16:16:05 +00004486 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004487
4488 # Do a sanity check on various fields
4489 image = control.images['image']
4490 entries = image.GetEntries()
4491 self.assertEqual(2, len(entries))
4492
4493 entry = entries['blob']
4494 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4495 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4496
4497 entry = entries['u-boot']
4498 self.assertEqual(U_BOOT_DATA, entry.data)
4499 self.assertEqual(len(U_BOOT_DATA), entry.size)
4500
4501 self.assertEqual(len(data), image.size)
4502 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4503 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4504 image.uncomp_size)
4505 orig = self._decompress(image.data)
4506 self.assertEqual(orig, image.uncomp_data)
4507
4508 expected = {
4509 'blob:offset': 0,
4510 'blob:size': len(COMPRESS_DATA_BIG),
4511 'u-boot:offset': len(COMPRESS_DATA_BIG),
4512 'u-boot:size': len(U_BOOT_DATA),
4513 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4514 'offset': 0,
4515 'image-pos': 0,
4516 'size': len(data),
4517 }
4518 self.assertEqual(expected, props)
4519
4520 def testCompressSectionSize(self):
4521 """Test compression of a section with a fixed size"""
4522 self._CheckLz4()
4523 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4524 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4525 dtb = fdt.Fdt(out_dtb_fname)
4526 dtb.Scan()
4527 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4528 'uncomp-size'])
4529 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004530 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004531 expected = {
4532 'section/blob:offset': 0,
4533 'section/blob:size': len(COMPRESS_DATA),
4534 'section/u-boot:offset': len(COMPRESS_DATA),
4535 'section/u-boot:size': len(U_BOOT_DATA),
4536 'section:offset': 0,
4537 'section:image-pos': 0,
4538 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4539 'section:size': 0x30,
4540 'offset': 0,
4541 'image-pos': 0,
4542 'size': 0x30,
4543 }
4544 self.assertEqual(expected, props)
4545
4546 def testCompressSection(self):
4547 """Test compression of a section with no fixed size"""
4548 self._CheckLz4()
4549 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4550 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4551 dtb = fdt.Fdt(out_dtb_fname)
4552 dtb.Scan()
4553 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4554 'uncomp-size'])
4555 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004556 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004557 expected = {
4558 'section/blob:offset': 0,
4559 'section/blob:size': len(COMPRESS_DATA),
4560 'section/u-boot:offset': len(COMPRESS_DATA),
4561 'section/u-boot:size': len(U_BOOT_DATA),
4562 'section:offset': 0,
4563 'section:image-pos': 0,
4564 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4565 'section:size': len(data),
4566 'offset': 0,
4567 'image-pos': 0,
4568 'size': len(data),
4569 }
4570 self.assertEqual(expected, props)
4571
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004572 def testLz4Missing(self):
4573 """Test that binman still produces an image if lz4 is missing"""
4574 with test_util.capture_sys_output() as (_, stderr):
4575 self._DoTestFile('185_compress_section.dts',
4576 force_missing_bintools='lz4')
4577 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004578 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004579
Simon Glassd92c8362020-10-26 17:40:25 -06004580 def testCompressExtra(self):
4581 """Test compression of a section with no fixed size"""
4582 self._CheckLz4()
4583 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4584 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4585 dtb = fdt.Fdt(out_dtb_fname)
4586 dtb.Scan()
4587 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4588 'uncomp-size'])
4589
4590 base = data[len(U_BOOT_DATA):]
Brandon Maiera657bc62024-06-04 16:16:05 +00004591 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glassd92c8362020-10-26 17:40:25 -06004592 rest = base[len(U_BOOT_DATA):]
4593
4594 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004595 bintool = self.comp_bintools['lz4']
4596 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004597 data1 = rest[:len(expect1)]
4598 section1 = self._decompress(data1)
Brandon Maiera657bc62024-06-04 16:16:05 +00004599 self.assertEqual(expect1, data1)
4600 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glassd92c8362020-10-26 17:40:25 -06004601 rest1 = rest[len(expect1):]
4602
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004603 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004604 data2 = rest1[:len(expect2)]
4605 section2 = self._decompress(data2)
Brandon Maiera657bc62024-06-04 16:16:05 +00004606 self.assertEqual(expect2, data2)
4607 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glassd92c8362020-10-26 17:40:25 -06004608 rest2 = rest1[len(expect2):]
4609
4610 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4611 len(expect2) + len(U_BOOT_DATA))
Brandon Maiera657bc62024-06-04 16:16:05 +00004612 #self.assertEqual(expect_size, len(data))
Simon Glassd92c8362020-10-26 17:40:25 -06004613
Brandon Maiera657bc62024-06-04 16:16:05 +00004614 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glassd92c8362020-10-26 17:40:25 -06004615
4616 self.maxDiff = None
4617 expected = {
4618 'u-boot:offset': 0,
4619 'u-boot:image-pos': 0,
4620 'u-boot:size': len(U_BOOT_DATA),
4621
4622 'base:offset': len(U_BOOT_DATA),
4623 'base:image-pos': len(U_BOOT_DATA),
4624 'base:size': len(data) - len(U_BOOT_DATA),
4625 'base/u-boot:offset': 0,
4626 'base/u-boot:image-pos': len(U_BOOT_DATA),
4627 'base/u-boot:size': len(U_BOOT_DATA),
4628 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4629 len(expect2),
4630 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4631 len(expect2),
4632 'base/u-boot2:size': len(U_BOOT_DATA),
4633
4634 'base/section:offset': len(U_BOOT_DATA),
4635 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4636 'base/section:size': len(expect1),
4637 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4638 'base/section/blob:offset': 0,
4639 'base/section/blob:size': len(COMPRESS_DATA),
4640 'base/section/u-boot:offset': len(COMPRESS_DATA),
4641 'base/section/u-boot:size': len(U_BOOT_DATA),
4642
4643 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4644 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4645 'base/section2:size': len(expect2),
4646 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4647 'base/section2/blob:offset': 0,
4648 'base/section2/blob:size': len(COMPRESS_DATA),
4649 'base/section2/blob2:offset': len(COMPRESS_DATA),
4650 'base/section2/blob2:size': len(COMPRESS_DATA),
4651
4652 'offset': 0,
4653 'image-pos': 0,
4654 'size': len(data),
4655 }
4656 self.assertEqual(expected, props)
4657
Simon Glassecbe4732021-01-06 21:35:15 -07004658 def testSymbolsSubsection(self):
4659 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004660 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004661
Simon Glass3fb25402021-01-06 21:35:16 -07004662 def testReadImageEntryArg(self):
4663 """Test reading an image that would need an entry arg to generate"""
4664 entry_args = {
4665 'cros-ec-rw-path': 'ecrw.bin',
4666 }
4667 data = self.data = self._DoReadFileDtb(
4668 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4669 entry_args=entry_args)
4670
Simon Glass80025522022-01-29 14:14:04 -07004671 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004672 orig_image = control.images['image']
4673
4674 # This should not generate an error about the missing 'cros-ec-rw-path'
4675 # since we are reading the image from a file. Compare with
4676 # testEntryArgsRequired()
4677 image = Image.FromFile(image_fname)
4678 self.assertEqual(orig_image.GetEntries().keys(),
4679 image.GetEntries().keys())
4680
Simon Glassa2af7302021-01-06 21:35:18 -07004681 def testFilesAlign(self):
4682 """Test alignment with files"""
4683 data = self._DoReadFile('190_files_align.dts')
4684
4685 # The first string is 15 bytes so will align to 16
4686 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4687 self.assertEqual(expect, data)
4688
Simon Glassdb84b562021-01-06 21:35:19 -07004689 def testReadImageSkip(self):
4690 """Test reading an image and accessing its FDT map"""
4691 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004692 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004693 orig_image = control.images['image']
4694 image = Image.FromFile(image_fname)
4695 self.assertEqual(orig_image.GetEntries().keys(),
4696 image.GetEntries().keys())
4697
4698 orig_entry = orig_image.GetEntries()['fdtmap']
4699 entry = image.GetEntries()['fdtmap']
4700 self.assertEqual(orig_entry.offset, entry.offset)
4701 self.assertEqual(orig_entry.size, entry.size)
4702 self.assertEqual(16, entry.image_pos)
4703
4704 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4705
Brandon Maiera657bc62024-06-04 16:16:05 +00004706 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glassdb84b562021-01-06 21:35:19 -07004707
Simon Glassc98de972021-03-18 20:24:57 +13004708 def testTplNoDtb(self):
4709 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004710 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004711 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4712 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4713 data[:len(U_BOOT_TPL_NODTB_DATA)])
4714
Simon Glass63f41d42021-03-18 20:24:58 +13004715 def testTplBssPad(self):
4716 """Test that we can pad TPL's BSS with zeros"""
4717 # ELF file with a '__bss_size' symbol
4718 self._SetupTplElf()
4719 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004720 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004721 data)
4722
4723 def testTplBssPadMissing(self):
4724 """Test that a missing symbol is detected"""
4725 self._SetupTplElf('u_boot_ucode_ptr')
4726 with self.assertRaises(ValueError) as e:
4727 self._DoReadFile('193_tpl_bss_pad.dts')
4728 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4729 str(e.exception))
4730
Simon Glass718b5292021-03-18 20:25:07 +13004731 def checkDtbSizes(self, data, pad_len, start):
4732 """Check the size arguments in a dtb embedded in an image
4733
4734 Args:
4735 data: The image data
4736 pad_len: Length of the pad section in the image, in bytes
4737 start: Start offset of the devicetree to examine, within the image
4738
4739 Returns:
4740 Size of the devicetree in bytes
4741 """
4742 dtb_data = data[start:]
4743 dtb = fdt.Fdt.FromData(dtb_data)
4744 fdt_size = dtb.GetFdtObj().totalsize()
4745 dtb.Scan()
4746 props = self._GetPropTree(dtb, 'size')
4747 self.assertEqual({
4748 'size': len(data),
4749 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4750 'u-boot-spl/u-boot-spl-dtb:size': 801,
4751 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4752 'u-boot-spl:size': 860,
4753 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4754 'u-boot/u-boot-dtb:size': 781,
4755 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4756 'u-boot:size': 827,
4757 }, props)
4758 return fdt_size
4759
4760 def testExpanded(self):
4761 """Test that an expanded entry type is selected when needed"""
4762 self._SetupSplElf()
4763 self._SetupTplElf()
4764
4765 # SPL has a devicetree, TPL does not
4766 entry_args = {
4767 'spl-dtb': '1',
4768 'spl-bss-pad': 'y',
4769 'tpl-dtb': '',
4770 }
4771 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4772 entry_args=entry_args)
4773 image = control.images['image']
4774 entries = image.GetEntries()
4775 self.assertEqual(3, len(entries))
4776
4777 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4778 self.assertIn('u-boot', entries)
4779 entry = entries['u-boot']
4780 self.assertEqual('u-boot-expanded', entry.etype)
4781 subent = entry.GetEntries()
4782 self.assertEqual(2, len(subent))
4783 self.assertIn('u-boot-nodtb', subent)
4784 self.assertIn('u-boot-dtb', subent)
4785
4786 # Second, u-boot-spl, which should be expanded into three parts
4787 self.assertIn('u-boot-spl', entries)
4788 entry = entries['u-boot-spl']
4789 self.assertEqual('u-boot-spl-expanded', entry.etype)
4790 subent = entry.GetEntries()
4791 self.assertEqual(3, len(subent))
4792 self.assertIn('u-boot-spl-nodtb', subent)
4793 self.assertIn('u-boot-spl-bss-pad', subent)
4794 self.assertIn('u-boot-spl-dtb', subent)
4795
4796 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4797 # devicetree
4798 self.assertIn('u-boot-tpl', entries)
4799 entry = entries['u-boot-tpl']
4800 self.assertEqual('u-boot-tpl', entry.etype)
4801 self.assertEqual(None, entry.GetEntries())
4802
4803 def testExpandedTpl(self):
4804 """Test that an expanded entry type is selected for TPL when needed"""
4805 self._SetupTplElf()
4806
4807 entry_args = {
4808 'tpl-bss-pad': 'y',
4809 'tpl-dtb': 'y',
4810 }
4811 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4812 entry_args=entry_args)
4813 image = control.images['image']
4814 entries = image.GetEntries()
4815 self.assertEqual(1, len(entries))
4816
4817 # We only have u-boot-tpl, which be expanded
4818 self.assertIn('u-boot-tpl', entries)
4819 entry = entries['u-boot-tpl']
4820 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4821 subent = entry.GetEntries()
4822 self.assertEqual(3, len(subent))
4823 self.assertIn('u-boot-tpl-nodtb', subent)
4824 self.assertIn('u-boot-tpl-bss-pad', subent)
4825 self.assertIn('u-boot-tpl-dtb', subent)
4826
4827 def testExpandedNoPad(self):
4828 """Test an expanded entry without BSS pad enabled"""
4829 self._SetupSplElf()
4830 self._SetupTplElf()
4831
4832 # SPL has a devicetree, TPL does not
4833 entry_args = {
4834 'spl-dtb': 'something',
4835 'spl-bss-pad': 'n',
4836 'tpl-dtb': '',
4837 }
4838 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4839 entry_args=entry_args)
4840 image = control.images['image']
4841 entries = image.GetEntries()
4842
4843 # Just check u-boot-spl, which should be expanded into two parts
4844 self.assertIn('u-boot-spl', entries)
4845 entry = entries['u-boot-spl']
4846 self.assertEqual('u-boot-spl-expanded', entry.etype)
4847 subent = entry.GetEntries()
4848 self.assertEqual(2, len(subent))
4849 self.assertIn('u-boot-spl-nodtb', subent)
4850 self.assertIn('u-boot-spl-dtb', subent)
4851
4852 def testExpandedTplNoPad(self):
4853 """Test that an expanded entry type with padding disabled in TPL"""
4854 self._SetupTplElf()
4855
4856 entry_args = {
4857 'tpl-bss-pad': '',
4858 'tpl-dtb': 'y',
4859 }
4860 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4861 entry_args=entry_args)
4862 image = control.images['image']
4863 entries = image.GetEntries()
4864 self.assertEqual(1, len(entries))
4865
4866 # We only have u-boot-tpl, which be expanded
4867 self.assertIn('u-boot-tpl', entries)
4868 entry = entries['u-boot-tpl']
4869 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4870 subent = entry.GetEntries()
4871 self.assertEqual(2, len(subent))
4872 self.assertIn('u-boot-tpl-nodtb', subent)
4873 self.assertIn('u-boot-tpl-dtb', subent)
4874
4875 def testFdtInclude(self):
4876 """Test that an Fdt is update within all binaries"""
4877 self._SetupSplElf()
4878 self._SetupTplElf()
4879
4880 # SPL has a devicetree, TPL does not
4881 self.maxDiff = None
4882 entry_args = {
4883 'spl-dtb': '1',
4884 'spl-bss-pad': 'y',
4885 'tpl-dtb': '',
4886 }
4887 # Build the image. It includes two separate devicetree binaries, each
4888 # with their own contents, but all contain the binman definition.
4889 data = self._DoReadFileDtb(
4890 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4891 update_dtb=True, entry_args=entry_args)[0]
4892 pad_len = 10
4893
4894 # Check the U-Boot dtb
4895 start = len(U_BOOT_NODTB_DATA)
4896 fdt_size = self.checkDtbSizes(data, pad_len, start)
4897
4898 # Now check SPL
4899 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4900 fdt_size = self.checkDtbSizes(data, pad_len, start)
4901
4902 # TPL has no devicetree
4903 start += fdt_size + len(U_BOOT_TPL_DATA)
4904 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004905
Simon Glass7098b7f2021-03-21 18:24:30 +13004906 def testSymbolsExpanded(self):
4907 """Test binman can assign symbols in expanded entries"""
4908 entry_args = {
4909 'spl-dtb': '1',
4910 }
4911 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4912 U_BOOT_SPL_DTB_DATA, 0x38,
4913 entry_args=entry_args, use_expanded=True)
4914
Simon Glasse1915782021-03-21 18:24:31 +13004915 def testCollection(self):
4916 """Test a collection"""
4917 data = self._DoReadFile('198_collection.dts')
4918 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004919 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4920 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004921 data)
4922
Simon Glass27a7f772021-03-21 18:24:32 +13004923 def testCollectionSection(self):
4924 """Test a collection where a section must be built first"""
4925 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004926 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004927 # building the contents, producing an error is anything is still
4928 # missing.
4929 data = self._DoReadFile('199_collection_section.dts')
4930 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004931 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4932 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004933 data)
4934
Simon Glassf427c5f2021-03-21 18:24:33 +13004935 def testAlignDefault(self):
4936 """Test that default alignment works on sections"""
4937 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004938 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004939 U_BOOT_DATA)
4940 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004941 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004942 # No alignment within the nested section
4943 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4944 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004945 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004946 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004947
Bin Mengc0b15742021-05-10 20:23:33 +08004948 def testPackOpenSBI(self):
4949 """Test that an image with an OpenSBI binary can be created"""
4950 data = self._DoReadFile('201_opensbi.dts')
4951 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4952
Simon Glass76f496d2021-07-06 10:36:37 -06004953 def testSectionsSingleThread(self):
4954 """Test sections without multithreading"""
4955 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004956 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4957 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4958 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004959 self.assertEqual(expected, data)
4960
4961 def testThreadTimeout(self):
4962 """Test handling a thread that takes too long"""
4963 with self.assertRaises(ValueError) as e:
4964 self._DoTestFile('202_section_timeout.dts',
4965 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004966 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004967
Simon Glass748a1d42021-07-06 10:36:41 -06004968 def testTiming(self):
4969 """Test output of timing information"""
4970 data = self._DoReadFile('055_sections.dts')
4971 with test_util.capture_sys_output() as (stdout, stderr):
4972 state.TimingShow()
4973 self.assertIn('read:', stdout.getvalue())
4974 self.assertIn('compress:', stdout.getvalue())
4975
Simon Glassadfb8492021-11-03 21:09:18 -06004976 def testUpdateFdtInElf(self):
4977 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004978 if not elf.ELF_TOOLS:
4979 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004980 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4981 outfile = os.path.join(self._indir, 'u-boot.out')
4982 begin_sym = 'dtb_embed_begin'
4983 end_sym = 'dtb_embed_end'
4984 retcode = self._DoTestFile(
4985 '060_fdt_update.dts', update_dtb=True,
4986 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4987 self.assertEqual(0, retcode)
4988
4989 # Check that the output file does in fact contact a dtb with the binman
4990 # definition in the correct place
4991 syms = elf.GetSymbolFileOffset(infile,
4992 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004993 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004994 dtb_data = data[syms['dtb_embed_begin'].offset:
4995 syms['dtb_embed_end'].offset]
4996
4997 dtb = fdt.Fdt.FromData(dtb_data)
4998 dtb.Scan()
4999 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
5000 self.assertEqual({
5001 'image-pos': 0,
5002 'offset': 0,
5003 '_testing:offset': 32,
5004 '_testing:size': 2,
5005 '_testing:image-pos': 32,
5006 'section@0/u-boot:offset': 0,
5007 'section@0/u-boot:size': len(U_BOOT_DATA),
5008 'section@0/u-boot:image-pos': 0,
5009 'section@0:offset': 0,
5010 'section@0:size': 16,
5011 'section@0:image-pos': 0,
5012
5013 'section@1/u-boot:offset': 0,
5014 'section@1/u-boot:size': len(U_BOOT_DATA),
5015 'section@1/u-boot:image-pos': 16,
5016 'section@1:offset': 16,
5017 'section@1:size': 16,
5018 'section@1:image-pos': 16,
5019 'size': 40
5020 }, props)
5021
5022 def testUpdateFdtInElfInvalid(self):
5023 """Test that invalid args are detected with --update-fdt-in-elf"""
5024 with self.assertRaises(ValueError) as e:
5025 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5026 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5027 str(e.exception))
5028
5029 def testUpdateFdtInElfNoSyms(self):
5030 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005031 if not elf.ELF_TOOLS:
5032 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005033 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5034 outfile = ''
5035 begin_sym = 'wrong_begin'
5036 end_sym = 'wrong_end'
5037 with self.assertRaises(ValueError) as e:
5038 self._DoTestFile(
5039 '060_fdt_update.dts',
5040 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5041 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5042 str(e.exception))
5043
5044 def testUpdateFdtInElfTooSmall(self):
5045 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005046 if not elf.ELF_TOOLS:
5047 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005048 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5049 outfile = os.path.join(self._indir, 'u-boot.out')
5050 begin_sym = 'dtb_embed_begin'
5051 end_sym = 'dtb_embed_end'
5052 with self.assertRaises(ValueError) as e:
5053 self._DoTestFile(
5054 '060_fdt_update.dts', update_dtb=True,
5055 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5056 self.assertRegex(
5057 str(e.exception),
5058 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5059
Simon Glass88e04da2021-11-23 11:03:42 -07005060 def testVersion(self):
5061 """Test we can get the binman version"""
5062 version = '(unreleased)'
5063 self.assertEqual(version, state.GetVersion(self._indir))
5064
5065 with self.assertRaises(SystemExit):
5066 with test_util.capture_sys_output() as (_, stderr):
5067 self._DoBinman('-V')
5068 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5069
5070 # Try running the tool too, just to be safe
5071 result = self._RunBinman('-V')
5072 self.assertEqual('Binman %s\n' % version, result.stderr)
5073
5074 # Set up a version file to make sure that works
5075 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005076 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005077 binary=False)
5078 self.assertEqual(version, state.GetVersion(self._indir))
5079
Simon Glass637958f2021-11-23 21:09:50 -07005080 def testAltFormat(self):
5081 """Test that alternative formats can be used to extract"""
5082 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5083
5084 try:
5085 tmpdir, updated_fname = self._SetupImageInTmpdir()
5086 with test_util.capture_sys_output() as (stdout, _):
5087 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5088 self.assertEqual(
5089 '''Flag (-F) Entry type Description
5090fdt fdtmap Extract the devicetree blob from the fdtmap
5091''',
5092 stdout.getvalue())
5093
5094 dtb = os.path.join(tmpdir, 'fdt.dtb')
5095 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5096 dtb, 'fdtmap')
5097
5098 # Check that we can read it and it can be scanning, meaning it does
5099 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005100 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005101 dtb = fdt.Fdt.FromData(data)
5102 dtb.Scan()
5103
5104 # Now check u-boot which has no alt_format
5105 fname = os.path.join(tmpdir, 'fdt.dtb')
5106 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5107 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005108 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005109 self.assertEqual(U_BOOT_DATA, data)
5110
5111 finally:
5112 shutil.rmtree(tmpdir)
5113
Simon Glass0b00ae62021-11-23 21:09:52 -07005114 def testExtblobList(self):
5115 """Test an image with an external blob list"""
5116 data = self._DoReadFile('215_blob_ext_list.dts')
5117 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5118
5119 def testExtblobListMissing(self):
5120 """Test an image with a missing external blob"""
5121 with self.assertRaises(ValueError) as e:
5122 self._DoReadFile('216_blob_ext_list_missing.dts')
5123 self.assertIn("Filename 'missing-file' not found in input path",
5124 str(e.exception))
5125
5126 def testExtblobListMissingOk(self):
5127 """Test an image with an missing external blob that is allowed"""
5128 with test_util.capture_sys_output() as (stdout, stderr):
5129 self._DoTestFile('216_blob_ext_list_missing.dts',
5130 allow_missing=True)
5131 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005132 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005133
Simon Glass3efb2972021-11-23 21:08:59 -07005134 def testFip(self):
5135 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5136 data = self._DoReadFile('203_fip.dts')
5137 hdr, fents = fip_util.decode_fip(data)
5138 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5139 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5140 self.assertEqual(0x123, hdr.flags)
5141
5142 self.assertEqual(2, len(fents))
5143
5144 fent = fents[0]
5145 self.assertEqual(
5146 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5147 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5148 self.assertEqual('soc-fw', fent.fip_type)
5149 self.assertEqual(0x88, fent.offset)
5150 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5151 self.assertEqual(0x123456789abcdef, fent.flags)
5152 self.assertEqual(ATF_BL31_DATA, fent.data)
5153 self.assertEqual(True, fent.valid)
5154
5155 fent = fents[1]
5156 self.assertEqual(
5157 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5158 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5159 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5160 self.assertEqual(0x8c, fent.offset)
5161 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5162 self.assertEqual(0, fent.flags)
5163 self.assertEqual(ATF_BL2U_DATA, fent.data)
5164 self.assertEqual(True, fent.valid)
5165
5166 def testFipOther(self):
5167 """Basic FIP with something that isn't a external blob"""
5168 data = self._DoReadFile('204_fip_other.dts')
5169 hdr, fents = fip_util.decode_fip(data)
5170
5171 self.assertEqual(2, len(fents))
5172 fent = fents[1]
5173 self.assertEqual('rot-cert', fent.fip_type)
5174 self.assertEqual(b'aa', fent.data)
5175
Simon Glass3efb2972021-11-23 21:08:59 -07005176 def testFipNoType(self):
5177 """FIP with an entry of an unknown type"""
5178 with self.assertRaises(ValueError) as e:
5179 self._DoReadFile('205_fip_no_type.dts')
5180 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5181 str(e.exception))
5182
5183 def testFipUuid(self):
5184 """Basic FIP with a manual uuid"""
5185 data = self._DoReadFile('206_fip_uuid.dts')
5186 hdr, fents = fip_util.decode_fip(data)
5187
5188 self.assertEqual(2, len(fents))
5189 fent = fents[1]
5190 self.assertEqual(None, fent.fip_type)
5191 self.assertEqual(
5192 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5193 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5194 fent.uuid)
5195 self.assertEqual(U_BOOT_DATA, fent.data)
5196
5197 def testFipLs(self):
5198 """Test listing a FIP"""
5199 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5200 hdr, fents = fip_util.decode_fip(data)
5201
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005202 tmpdir = None
Simon Glass3efb2972021-11-23 21:08:59 -07005203 try:
5204 tmpdir, updated_fname = self._SetupImageInTmpdir()
5205 with test_util.capture_sys_output() as (stdout, stderr):
5206 self._DoBinman('ls', '-i', updated_fname)
5207 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005208 if tmpdir:
5209 shutil.rmtree(tmpdir)
Simon Glass3efb2972021-11-23 21:08:59 -07005210 lines = stdout.getvalue().splitlines()
5211 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005212'Name Image-pos Size Entry-type Offset Uncomp-size',
5213'--------------------------------------------------------------',
5214'image 0 2d3 section 0',
5215' atf-fip 0 90 atf-fip 0',
5216' soc-fw 88 4 blob-ext 88',
5217' u-boot 8c 4 u-boot 8c',
5218' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005219]
5220 self.assertEqual(expected, lines)
5221
5222 image = control.images['image']
5223 entries = image.GetEntries()
5224 fdtmap = entries['fdtmap']
5225
5226 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5227 magic = fdtmap_data[:8]
5228 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005229 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005230
5231 fdt_data = fdtmap_data[16:]
5232 dtb = fdt.Fdt.FromData(fdt_data)
5233 dtb.Scan()
5234 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5235 self.assertEqual({
5236 'atf-fip/soc-fw:image-pos': 136,
5237 'atf-fip/soc-fw:offset': 136,
5238 'atf-fip/soc-fw:size': 4,
5239 'atf-fip/u-boot:image-pos': 140,
5240 'atf-fip/u-boot:offset': 140,
5241 'atf-fip/u-boot:size': 4,
5242 'atf-fip:image-pos': 0,
5243 'atf-fip:offset': 0,
5244 'atf-fip:size': 144,
5245 'image-pos': 0,
5246 'offset': 0,
5247 'fdtmap:image-pos': fdtmap.image_pos,
5248 'fdtmap:offset': fdtmap.offset,
5249 'fdtmap:size': len(fdtmap_data),
5250 'size': len(data),
5251 }, props)
5252
5253 def testFipExtractOneEntry(self):
5254 """Test extracting a single entry fron an FIP"""
5255 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005256 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005257 fname = os.path.join(self._indir, 'output.extact')
5258 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005259 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005260 self.assertEqual(U_BOOT_DATA, data)
5261
5262 def testFipReplace(self):
5263 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005264 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005265 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005266 updated_fname = tools.get_output_filename('image-updated.bin')
5267 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005268 entry_name = 'atf-fip/u-boot'
5269 control.WriteEntry(updated_fname, entry_name, expected,
5270 allow_resize=True)
5271 actual = control.ReadEntry(updated_fname, entry_name)
5272 self.assertEqual(expected, actual)
5273
Simon Glass80025522022-01-29 14:14:04 -07005274 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005275 hdr, fents = fip_util.decode_fip(new_data)
5276
5277 self.assertEqual(2, len(fents))
5278
5279 # Check that the FIP entry is updated
5280 fent = fents[1]
5281 self.assertEqual(0x8c, fent.offset)
5282 self.assertEqual(len(expected), fent.size)
5283 self.assertEqual(0, fent.flags)
5284 self.assertEqual(expected, fent.data)
5285 self.assertEqual(True, fent.valid)
5286
5287 def testFipMissing(self):
5288 with test_util.capture_sys_output() as (stdout, stderr):
5289 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5290 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005291 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005292
5293 def testFipSize(self):
5294 """Test a FIP with a size property"""
5295 data = self._DoReadFile('210_fip_size.dts')
5296 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5297 hdr, fents = fip_util.decode_fip(data)
5298 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5299 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5300
5301 self.assertEqual(1, len(fents))
5302
5303 fent = fents[0]
5304 self.assertEqual('soc-fw', fent.fip_type)
5305 self.assertEqual(0x60, fent.offset)
5306 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5307 self.assertEqual(ATF_BL31_DATA, fent.data)
5308 self.assertEqual(True, fent.valid)
5309
5310 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005311 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005312
5313 def testFipBadAlign(self):
5314 """Test that an invalid alignment value in a FIP is detected"""
5315 with self.assertRaises(ValueError) as e:
5316 self._DoTestFile('211_fip_bad_align.dts')
5317 self.assertIn(
5318 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5319 str(e.exception))
5320
5321 def testFipCollection(self):
5322 """Test using a FIP in a collection"""
5323 data = self._DoReadFile('212_fip_collection.dts')
5324 entry1 = control.images['image'].GetEntries()['collection']
5325 data1 = data[:entry1.size]
5326 hdr1, fents2 = fip_util.decode_fip(data1)
5327
5328 entry2 = control.images['image'].GetEntries()['atf-fip']
5329 data2 = data[entry2.offset:entry2.offset + entry2.size]
5330 hdr1, fents2 = fip_util.decode_fip(data2)
5331
5332 # The 'collection' entry should have U-Boot included at the end
5333 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5334 self.assertEqual(data1, data2 + U_BOOT_DATA)
5335 self.assertEqual(U_BOOT_DATA, data1[-4:])
5336
5337 # There should be a U-Boot after the final FIP
5338 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005339
Simon Glassccae6862022-01-12 13:10:35 -07005340 def testFakeBlob(self):
5341 """Test handling of faking an external blob"""
5342 with test_util.capture_sys_output() as (stdout, stderr):
5343 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5344 allow_fake_blobs=True)
5345 err = stderr.getvalue()
5346 self.assertRegex(
5347 err,
5348 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005349
Simon Glassceb5f912022-01-09 20:13:46 -07005350 def testExtblobListFaked(self):
5351 """Test an extblob with missing external blob that are faked"""
5352 with test_util.capture_sys_output() as (stdout, stderr):
5353 self._DoTestFile('216_blob_ext_list_missing.dts',
5354 allow_fake_blobs=True)
5355 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005356 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005357
Simon Glass162017b2022-01-09 20:13:57 -07005358 def testListBintools(self):
5359 args = ['tool', '--list']
5360 with test_util.capture_sys_output() as (stdout, _):
5361 self._DoBinman(*args)
5362 out = stdout.getvalue().splitlines()
5363 self.assertTrue(len(out) >= 2)
5364
5365 def testFetchBintools(self):
5366 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005367 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005368 raise urllib.error.URLError('my error')
5369
5370 args = ['tool']
5371 with self.assertRaises(ValueError) as e:
5372 self._DoBinman(*args)
5373 self.assertIn("Invalid arguments to 'tool' subcommand",
5374 str(e.exception))
5375
5376 args = ['tool', '--fetch']
5377 with self.assertRaises(ValueError) as e:
5378 self._DoBinman(*args)
5379 self.assertIn('Please specify bintools to fetch', str(e.exception))
5380
5381 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005382 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005383 side_effect=fail_download):
5384 with test_util.capture_sys_output() as (stdout, _):
5385 self._DoBinman(*args)
5386 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5387
Simon Glass620c4462022-01-09 20:14:11 -07005388 def testBintoolDocs(self):
5389 """Test for creation of bintool documentation"""
5390 with test_util.capture_sys_output() as (stdout, stderr):
5391 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5392 self.assertTrue(len(stdout.getvalue()) > 0)
5393
5394 def testBintoolDocsMissing(self):
5395 """Test handling of missing bintool documentation"""
5396 with self.assertRaises(ValueError) as e:
5397 with test_util.capture_sys_output() as (stdout, stderr):
5398 control.write_bintool_docs(
5399 control.bintool.Bintool.get_tool_list(), 'mkimage')
5400 self.assertIn('Documentation is missing for modules: mkimage',
5401 str(e.exception))
5402
Jan Kiszka58c407f2022-01-28 20:37:53 +01005403 def testListWithGenNode(self):
5404 """Check handling of an FDT map when the section cannot be found"""
5405 entry_args = {
5406 'of-list': 'test-fdt1 test-fdt2',
5407 }
5408 data = self._DoReadFileDtb(
5409 '219_fit_gennode.dts',
5410 entry_args=entry_args,
5411 use_real_dtb=True,
5412 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5413
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005414 tmpdir = None
Jan Kiszka58c407f2022-01-28 20:37:53 +01005415 try:
5416 tmpdir, updated_fname = self._SetupImageInTmpdir()
5417 with test_util.capture_sys_output() as (stdout, stderr):
5418 self._RunBinman('ls', '-i', updated_fname)
5419 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005420 if tmpdir:
5421 shutil.rmtree(tmpdir)
Jan Kiszka58c407f2022-01-28 20:37:53 +01005422
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005423 def testFitSubentryUsesBintool(self):
5424 """Test that binman FIT subentries can use bintools"""
5425 command.test_result = self._HandleGbbCommand
5426 entry_args = {
5427 'keydir': 'devkeys',
5428 'bmpblk': 'bmpblk.bin',
5429 }
5430 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5431 entry_args=entry_args)
5432
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005433 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5434 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005435 self.assertIn(expected, data)
5436
5437 def testFitSubentryMissingBintool(self):
5438 """Test that binman reports missing bintools for FIT subentries"""
5439 entry_args = {
5440 'keydir': 'devkeys',
5441 }
5442 with test_util.capture_sys_output() as (_, stderr):
5443 self._DoTestFile('220_fit_subentry_bintool.dts',
5444 force_missing_bintools='futility', entry_args=entry_args)
5445 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005446 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005447
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005448 def testFitSubentryHashSubnode(self):
5449 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005450 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005451 data, _, _, out_dtb_name = self._DoReadFileDtb(
5452 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5453
5454 mkimage_dtb = fdt.Fdt.FromData(data)
5455 mkimage_dtb.Scan()
5456 binman_dtb = fdt.Fdt(out_dtb_name)
5457 binman_dtb.Scan()
5458
5459 # Check that binman didn't add hash values
5460 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5461 self.assertNotIn('value', fnode.props)
5462
5463 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5464 self.assertNotIn('value', fnode.props)
5465
5466 # Check that mkimage added hash values
5467 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5468 self.assertIn('value', fnode.props)
5469
5470 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5471 self.assertIn('value', fnode.props)
5472
Roger Quadros5cdcea02022-02-19 20:50:04 +02005473 def testPackTeeOs(self):
5474 """Test that an image with an TEE binary can be created"""
5475 data = self._DoReadFile('222_tee_os.dts')
5476 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5477
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305478 def testPackTiDm(self):
5479 """Test that an image with a TI DM binary can be created"""
5480 data = self._DoReadFile('225_ti_dm.dts')
5481 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5482
Simon Glass912339f2022-02-08 11:50:03 -07005483 def testFitFdtOper(self):
5484 """Check handling of a specified FIT operation"""
5485 entry_args = {
5486 'of-list': 'test-fdt1 test-fdt2',
5487 'default-dt': 'test-fdt2',
5488 }
5489 self._DoReadFileDtb(
5490 '223_fit_fdt_oper.dts',
5491 entry_args=entry_args,
5492 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5493
5494 def testFitFdtBadOper(self):
5495 """Check handling of an FDT map when the section cannot be found"""
5496 with self.assertRaises(ValueError) as exc:
5497 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005498 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005499 str(exc.exception))
5500
Simon Glassdd156a42022-03-05 20:18:59 -07005501 def test_uses_expand_size(self):
5502 """Test that the 'expand-size' property cannot be used anymore"""
5503 with self.assertRaises(ValueError) as e:
5504 data = self._DoReadFile('225_expand_size_bad.dts')
5505 self.assertIn(
5506 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5507 str(e.exception))
5508
Simon Glass5f423422022-03-05 20:19:12 -07005509 def testFitSplitElf(self):
5510 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005511 if not elf.ELF_TOOLS:
5512 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005513 entry_args = {
5514 'of-list': 'test-fdt1 test-fdt2',
5515 'default-dt': 'test-fdt2',
5516 'atf-bl31-path': 'bl31.elf',
5517 'tee-os-path': 'tee.elf',
5518 }
5519 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5520 data = self._DoReadFileDtb(
5521 '226_fit_split_elf.dts',
5522 entry_args=entry_args,
5523 extra_indirs=[test_subdir])[0]
5524
5525 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5526 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5527
5528 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5529 'data', 'load'}
5530 dtb = fdt.Fdt.FromData(fit_data)
5531 dtb.Scan()
5532
5533 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5534 segments, entry = elf.read_loadable_segments(elf_data)
5535
5536 # We assume there are two segments
Brandon Maiera657bc62024-06-04 16:16:05 +00005537 self.assertEqual(2, len(segments))
Simon Glass5f423422022-03-05 20:19:12 -07005538
5539 atf1 = dtb.GetNode('/images/atf-1')
5540 _, start, data = segments[0]
5541 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5542 self.assertEqual(entry,
5543 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5544 self.assertEqual(start,
5545 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5546 self.assertEqual(data, atf1.props['data'].bytes)
5547
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005548 hash_node = atf1.FindNode('hash')
5549 self.assertIsNotNone(hash_node)
5550 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5551
Simon Glass5f423422022-03-05 20:19:12 -07005552 atf2 = dtb.GetNode('/images/atf-2')
5553 self.assertEqual(base_keys, atf2.props.keys())
5554 _, start, data = segments[1]
5555 self.assertEqual(start,
5556 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5557 self.assertEqual(data, atf2.props['data'].bytes)
5558
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005559 hash_node = atf2.FindNode('hash')
5560 self.assertIsNotNone(hash_node)
5561 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5562
5563 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5564 self.assertIsNotNone(hash_node)
5565 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5566
Simon Glass5f423422022-03-05 20:19:12 -07005567 conf = dtb.GetNode('/configurations')
5568 self.assertEqual({'default'}, conf.props.keys())
5569
5570 for subnode in conf.subnodes:
5571 self.assertEqual({'description', 'fdt', 'loadables'},
5572 subnode.props.keys())
5573 self.assertEqual(
5574 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5575 fdt_util.GetStringList(subnode, 'loadables'))
5576
5577 def _check_bad_fit(self, dts):
5578 """Check a bad FIT
5579
5580 This runs with the given dts and returns the assertion raised
5581
5582 Args:
5583 dts (str): dts filename to use
5584
5585 Returns:
5586 str: Assertion string raised
5587 """
5588 entry_args = {
5589 'of-list': 'test-fdt1 test-fdt2',
5590 'default-dt': 'test-fdt2',
5591 'atf-bl31-path': 'bl31.elf',
5592 'tee-os-path': 'tee.elf',
5593 }
5594 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5595 with self.assertRaises(ValueError) as exc:
5596 self._DoReadFileDtb(dts, entry_args=entry_args,
5597 extra_indirs=[test_subdir])[0]
5598 return str(exc.exception)
5599
5600 def testFitSplitElfBadElf(self):
5601 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005602 if not elf.ELF_TOOLS:
5603 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005604 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5605 entry_args = {
5606 'of-list': 'test-fdt1 test-fdt2',
5607 'default-dt': 'test-fdt2',
5608 'atf-bl31-path': 'bad.elf',
5609 'tee-os-path': 'tee.elf',
5610 }
5611 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5612 with self.assertRaises(ValueError) as exc:
5613 self._DoReadFileDtb(
5614 '226_fit_split_elf.dts',
5615 entry_args=entry_args,
5616 extra_indirs=[test_subdir])[0]
5617 self.assertIn(
5618 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5619 str(exc.exception))
5620
Simon Glass5f423422022-03-05 20:19:12 -07005621 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005622 """Test an split-elf FIT with a missing ELF file
5623
5624 Args:
5625 kwargs (dict of str): Arguments to pass to _DoTestFile()
5626
5627 Returns:
5628 tuple:
5629 str: stdout result
5630 str: stderr result
5631 """
Simon Glass5f423422022-03-05 20:19:12 -07005632 entry_args = {
5633 'of-list': 'test-fdt1 test-fdt2',
5634 'default-dt': 'test-fdt2',
5635 'atf-bl31-path': 'bl31.elf',
5636 'tee-os-path': 'missing.elf',
5637 }
5638 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5639 with test_util.capture_sys_output() as (stdout, stderr):
5640 self._DoTestFile(
5641 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005642 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5643 out = stdout.getvalue()
5644 err = stderr.getvalue()
5645 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005646
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005647 def testFitSplitElfBadDirective(self):
5648 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5649 if not elf.ELF_TOOLS:
5650 self.skipTest('Python elftools not available')
5651 err = self._check_bad_fit('227_fit_bad_dir.dts')
5652 self.assertIn(
5653 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5654 err)
5655
5656 def testFitSplitElfBadDirectiveConfig(self):
5657 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5658 if not elf.ELF_TOOLS:
5659 self.skipTest('Python elftools not available')
5660 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5661 self.assertEqual(
5662 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5663 err)
5664
5665
Simon Glass5f423422022-03-05 20:19:12 -07005666 def testFitSplitElfMissing(self):
5667 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005668 if not elf.ELF_TOOLS:
5669 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005670 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005671 self.assertRegex(
5672 err,
5673 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005674 self.assertNotRegex(out, '.*Faked blob.*')
5675 fname = tools.get_output_filename('binman-fake/missing.elf')
5676 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005677
5678 def testFitSplitElfFaked(self):
5679 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005680 if not elf.ELF_TOOLS:
5681 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005682 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005683 self.assertRegex(
5684 err,
5685 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005686 self.assertRegex(
5687 out,
5688 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5689 fname = tools.get_output_filename('binman-fake/missing.elf')
5690 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005691
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005692 def testMkimageMissingBlob(self):
5693 """Test using mkimage to build an image"""
5694 with test_util.capture_sys_output() as (stdout, stderr):
5695 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5696 allow_fake_blobs=True)
5697 err = stderr.getvalue()
5698 self.assertRegex(
5699 err,
5700 "Image '.*' has faked external blobs and is non-functional: .*")
5701
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005702 def testPreLoad(self):
5703 """Test an image with a pre-load header"""
5704 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005705 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005706 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005707 data = self._DoReadFileDtb(
5708 '230_pre_load.dts', entry_args=entry_args,
5709 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005710 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5711 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5712 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Simon Glasse2dfb962023-07-24 09:19:57 -06005713
5714 def testPreLoadNoKey(self):
5715 """Test an image with a pre-load heade0r with missing key"""
5716 with self.assertRaises(FileNotFoundError) as exc:
5717 self._DoReadFile('230_pre_load.dts')
5718 self.assertIn("No such file or directory: 'dev.key'",
5719 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005720
5721 def testPreLoadPkcs(self):
5722 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005723 entry_args = {
5724 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5725 }
5726 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5727 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005728 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5729 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5730 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5731
5732 def testPreLoadPss(self):
5733 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005734 entry_args = {
5735 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5736 }
5737 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5738 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005739 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5740 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5741 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5742
5743 def testPreLoadInvalidPadding(self):
5744 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005745 entry_args = {
5746 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5747 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005748 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005749 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5750 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005751
5752 def testPreLoadInvalidSha(self):
5753 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005754 entry_args = {
5755 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5756 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005757 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005758 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5759 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005760
5761 def testPreLoadInvalidAlgo(self):
5762 """Test an image with a pre-load header with an invalid algo"""
5763 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005764 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005765
5766 def testPreLoadInvalidKey(self):
5767 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005768 entry_args = {
5769 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5770 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005771 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005772 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5773 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005774
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005775 def _CheckSafeUniqueNames(self, *images):
5776 """Check all entries of given images for unsafe unique names"""
5777 for image in images:
5778 entries = {}
5779 image._CollectEntries(entries, {}, image)
5780 for entry in entries.values():
5781 uniq = entry.GetUniqueName()
5782
5783 # Used as part of a filename, so must not be absolute paths.
5784 self.assertFalse(os.path.isabs(uniq))
5785
5786 def testSafeUniqueNames(self):
5787 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005788 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005789
5790 orig_image = control.images['image']
5791 image_fname = tools.get_output_filename('image.bin')
5792 image = Image.FromFile(image_fname)
5793
5794 self._CheckSafeUniqueNames(orig_image, image)
5795
5796 def testSafeUniqueNamesMulti(self):
5797 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005798 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005799
5800 orig_image = control.images['image']
5801 image_fname = tools.get_output_filename('image.bin')
5802 image = Image.FromFile(image_fname)
5803
5804 self._CheckSafeUniqueNames(orig_image, image)
5805
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005806 def testReplaceCmdWithBintool(self):
5807 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005808 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005809 expected = U_BOOT_DATA + b'aa'
5810 self.assertEqual(expected, data[:len(expected)])
5811
5812 try:
5813 tmpdir, updated_fname = self._SetupImageInTmpdir()
5814 fname = os.path.join(tmpdir, 'update-testing.bin')
5815 tools.write_file(fname, b'zz')
5816 self._DoBinman('replace', '-i', updated_fname,
5817 '_testing', '-f', fname)
5818
5819 data = tools.read_file(updated_fname)
5820 expected = U_BOOT_DATA + b'zz'
5821 self.assertEqual(expected, data[:len(expected)])
5822 finally:
5823 shutil.rmtree(tmpdir)
5824
5825 def testReplaceCmdOtherWithBintool(self):
5826 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005827 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005828 expected = U_BOOT_DATA + b'aa'
5829 self.assertEqual(expected, data[:len(expected)])
5830
5831 try:
5832 tmpdir, updated_fname = self._SetupImageInTmpdir()
5833 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5834 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5835 self._DoBinman('replace', '-i', updated_fname,
5836 'u-boot', '-f', fname)
5837
5838 data = tools.read_file(updated_fname)
5839 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5840 self.assertEqual(expected, data[:len(expected)])
5841 finally:
5842 shutil.rmtree(tmpdir)
5843
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005844 def testReplaceResizeNoRepackSameSize(self):
5845 """Test replacing entries with same-size data without repacking"""
5846 expected = b'x' * len(U_BOOT_DATA)
5847 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5848 self.assertEqual(expected, data)
5849
5850 path, fdtmap = state.GetFdtContents('fdtmap')
5851 self.assertIsNotNone(path)
5852 self.assertEqual(expected_fdtmap, fdtmap)
5853
5854 def testReplaceResizeNoRepackSmallerSize(self):
5855 """Test replacing entries with smaller-size data without repacking"""
5856 new_data = b'x'
5857 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5858 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5859 self.assertEqual(expected, data)
5860
5861 path, fdtmap = state.GetFdtContents('fdtmap')
5862 self.assertIsNotNone(path)
5863 self.assertEqual(expected_fdtmap, fdtmap)
5864
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005865 def testExtractFit(self):
5866 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005867 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005868 image_fname = tools.get_output_filename('image.bin')
5869
5870 fit_data = control.ReadEntry(image_fname, 'fit')
5871 fit = fdt.Fdt.FromData(fit_data)
5872 fit.Scan()
5873
5874 # Check subentry data inside the extracted fit
5875 for node_path, expected in [
5876 ('/images/kernel', U_BOOT_DATA),
5877 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5878 ('/images/scr-1', COMPRESS_DATA),
5879 ]:
5880 node = fit.GetNode(node_path)
5881 data = fit.GetProps(node)['data'].bytes
5882 self.assertEqual(expected, data)
5883
5884 def testExtractFitSubentries(self):
5885 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005886 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005887 image_fname = tools.get_output_filename('image.bin')
5888
5889 for entry_path, expected in [
5890 ('fit/kernel', U_BOOT_DATA),
5891 ('fit/kernel/u-boot', U_BOOT_DATA),
5892 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5893 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5894 ('fit/scr-1', COMPRESS_DATA),
5895 ('fit/scr-1/blob', COMPRESS_DATA),
5896 ]:
5897 data = control.ReadEntry(image_fname, entry_path)
5898 self.assertEqual(expected, data)
5899
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005900 def testReplaceFitSubentryLeafSameSize(self):
5901 """Test replacing a FIT leaf subentry with same-size data"""
5902 new_data = b'x' * len(U_BOOT_DATA)
5903 data, expected_fdtmap, _ = self._RunReplaceCmd(
5904 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005905 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005906 self.assertEqual(new_data, data)
5907
5908 path, fdtmap = state.GetFdtContents('fdtmap')
5909 self.assertIsNotNone(path)
5910 self.assertEqual(expected_fdtmap, fdtmap)
5911
5912 def testReplaceFitSubentryLeafBiggerSize(self):
5913 """Test replacing a FIT leaf subentry with bigger-size data"""
5914 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5915 data, expected_fdtmap, _ = self._RunReplaceCmd(
5916 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005917 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005918 self.assertEqual(new_data, data)
5919
5920 # Will be repacked, so fdtmap must change
5921 path, fdtmap = state.GetFdtContents('fdtmap')
5922 self.assertIsNotNone(path)
5923 self.assertNotEqual(expected_fdtmap, fdtmap)
5924
5925 def testReplaceFitSubentryLeafSmallerSize(self):
5926 """Test replacing a FIT leaf subentry with smaller-size data"""
5927 new_data = b'x'
5928 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5929 data, expected_fdtmap, _ = self._RunReplaceCmd(
5930 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005931 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005932 self.assertEqual(expected, data)
5933
5934 path, fdtmap = state.GetFdtContents('fdtmap')
5935 self.assertIsNotNone(path)
5936 self.assertEqual(expected_fdtmap, fdtmap)
5937
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005938 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005939 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005940 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005941 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5942 new_data, dts='241_replace_section_simple.dts')
5943 self.assertEqual(new_data, data)
5944
5945 entries = image.GetEntries()
5946 self.assertIn('section', entries)
5947 entry = entries['section']
5948 self.assertEqual(len(new_data), entry.size)
5949
5950 def testReplaceSectionLarger(self):
5951 """Test replacing a simple section with larger data"""
5952 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5953 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5954 new_data, dts='241_replace_section_simple.dts')
5955 self.assertEqual(new_data, data)
5956
5957 entries = image.GetEntries()
5958 self.assertIn('section', entries)
5959 entry = entries['section']
5960 self.assertEqual(len(new_data), entry.size)
5961 fentry = entries['fdtmap']
5962 self.assertEqual(entry.offset + entry.size, fentry.offset)
5963
5964 def testReplaceSectionSmaller(self):
5965 """Test replacing a simple section with smaller data"""
5966 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5967 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5968 new_data, dts='241_replace_section_simple.dts')
5969 self.assertEqual(new_data, data)
5970
5971 # The new size is the same as the old, just with a pad byte at the end
5972 entries = image.GetEntries()
5973 self.assertIn('section', entries)
5974 entry = entries['section']
5975 self.assertEqual(len(new_data), entry.size)
5976
5977 def testReplaceSectionSmallerAllow(self):
5978 """Test failing to replace a simple section with smaller data"""
5979 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5980 try:
5981 state.SetAllowEntryContraction(True)
5982 with self.assertRaises(ValueError) as exc:
5983 self._RunReplaceCmd('section', new_data,
5984 dts='241_replace_section_simple.dts')
5985 finally:
5986 state.SetAllowEntryContraction(False)
5987
5988 # Since we have no information about the position of things within the
5989 # section, we cannot adjust the position of /section-u-boot so it ends
5990 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06005991 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07005992 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5993 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06005994 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005995
Simon Glass8fbca772022-08-13 11:40:48 -06005996 def testMkimageImagename(self):
5997 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005998 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005999 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06006000
6001 # Check that the data appears in the file somewhere
6002 self.assertIn(U_BOOT_SPL_DATA, data)
6003
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006004 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06006005 name = data[0x20:0x40]
6006
6007 # Build the filename that we expect to be placed in there, by virtue of
6008 # the -n paraameter
6009 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6010
6011 # Check that the image name is set to the temporary filename used
6012 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6013
Simon Glassb1669752022-08-13 11:40:49 -06006014 def testMkimageImage(self):
6015 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006016 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006017 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006018
6019 # Check that the data appears in the file somewhere
6020 self.assertIn(U_BOOT_SPL_DATA, data)
6021
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006022 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006023 name = data[0x20:0x40]
6024
6025 # Build the filename that we expect to be placed in there, by virtue of
6026 # the -n paraameter
6027 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6028
6029 # Check that the image name is set to the temporary filename used
6030 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6031
6032 # Check the corect data is in the imagename file
6033 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6034
6035 def testMkimageImageNoContent(self):
6036 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006037 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006038 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006039 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006040 self.assertIn('Could not complete processing of contents',
6041 str(exc.exception))
6042
6043 def testMkimageImageBad(self):
6044 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006045 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006046 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006047 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006048 self.assertIn('Cannot use both imagename node and data-to-imagename',
6049 str(exc.exception))
6050
Simon Glassbd5cd882022-08-13 11:40:50 -06006051 def testCollectionOther(self):
6052 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006053 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006054 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6055 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6056 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6057 data)
6058
6059 def testMkimageCollection(self):
6060 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006061 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006062 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006063 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6064 self.assertEqual(expect, data[:len(expect)])
6065
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006066 def testCompressDtbPrependInvalid(self):
6067 """Test that invalid header is detected"""
6068 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006069 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006070 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6071 "'u-boot-dtb': 'invalid'", str(e.exception))
6072
6073 def testCompressDtbPrependLength(self):
6074 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006075 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006076 image = control.images['image']
6077 entries = image.GetEntries()
6078 self.assertIn('u-boot-dtb', entries)
6079 u_boot_dtb = entries['u-boot-dtb']
6080 self.assertIn('fdtmap', entries)
6081 fdtmap = entries['fdtmap']
6082
6083 image_fname = tools.get_output_filename('image.bin')
6084 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6085 dtb = fdt.Fdt.FromData(orig)
6086 dtb.Scan()
6087 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6088 expected = {
6089 'u-boot:size': len(U_BOOT_DATA),
6090 'u-boot-dtb:uncomp-size': len(orig),
6091 'u-boot-dtb:size': u_boot_dtb.size,
6092 'fdtmap:size': fdtmap.size,
6093 'size': len(data),
6094 }
6095 self.assertEqual(expected, props)
6096
6097 # Check implementation
6098 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6099 rest = data[len(U_BOOT_DATA):]
6100 comp_data_len = struct.unpack('<I', rest[:4])[0]
6101 comp_data = rest[4:4 + comp_data_len]
6102 orig2 = self._decompress(comp_data)
6103 self.assertEqual(orig, orig2)
6104
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006105 def testInvalidCompress(self):
6106 """Test that invalid compress algorithm is detected"""
6107 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006108 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006109 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6110
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006111 def testCompUtilCompressions(self):
6112 """Test compression algorithms"""
6113 for bintool in self.comp_bintools.values():
6114 self._CheckBintool(bintool)
6115 data = bintool.compress(COMPRESS_DATA)
6116 self.assertNotEqual(COMPRESS_DATA, data)
6117 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006118 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006119
6120 def testCompUtilVersions(self):
6121 """Test tool version of compression algorithms"""
6122 for bintool in self.comp_bintools.values():
6123 self._CheckBintool(bintool)
6124 version = bintool.version()
6125 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6126
6127 def testCompUtilPadding(self):
6128 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006129 # Skip zstd because it doesn't support padding
6130 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006131 self._CheckBintool(bintool)
6132 data = bintool.compress(COMPRESS_DATA)
6133 self.assertNotEqual(COMPRESS_DATA, data)
6134 data += tools.get_bytes(0, 64)
6135 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006136 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006137
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006138 def testCompressDtbZstd(self):
6139 """Test that zstd compress of device-tree files failed"""
6140 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006141 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006142 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6143 "requires a length header", str(e.exception))
6144
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006145 def testMkimageMultipleDataFiles(self):
6146 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006147 self._SetupSplElf()
6148 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006149 data = self._DoReadFile('252_mkimage_mult_data.dts')
6150 # Size of files are packed in their 4B big-endian format
6151 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6152 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6153 # Size info is always followed by a 4B zero value.
6154 expect += tools.get_bytes(0, 4)
6155 expect += U_BOOT_TPL_DATA
6156 # All but last files are 4B-aligned
6157 align_pad = len(U_BOOT_TPL_DATA) % 4
6158 if align_pad:
6159 expect += tools.get_bytes(0, align_pad)
6160 expect += U_BOOT_SPL_DATA
6161 self.assertEqual(expect, data[-len(expect):])
6162
Marek Vasutf7413f02023-07-18 07:23:58 -06006163 def testMkimageMultipleExpanded(self):
6164 """Test passing multiple files to mkimage in a mkimage entry"""
6165 self._SetupSplElf()
6166 self._SetupTplElf()
6167 entry_args = {
6168 'spl-bss-pad': 'y',
6169 'spl-dtb': 'y',
6170 }
6171 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6172 use_expanded=True, entry_args=entry_args)[0]
6173 pad_len = 10
6174 tpl_expect = U_BOOT_TPL_DATA
6175 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6176 spl_expect += U_BOOT_SPL_DTB_DATA
6177
6178 content = data[0x40:]
6179 lens = struct.unpack('>III', content[:12])
6180
6181 # Size of files are packed in their 4B big-endian format
6182 # Size info is always followed by a 4B zero value.
6183 self.assertEqual(len(tpl_expect), lens[0])
6184 self.assertEqual(len(spl_expect), lens[1])
6185 self.assertEqual(0, lens[2])
6186
6187 rest = content[12:]
6188 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6189
6190 rest = rest[len(tpl_expect):]
6191 align_pad = len(tpl_expect) % 4
6192 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6193 rest = rest[align_pad:]
6194 self.assertEqual(spl_expect, rest)
6195
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006196 def testMkimageMultipleNoContent(self):
6197 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006198 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006199 with self.assertRaises(ValueError) as exc:
6200 self._DoReadFile('253_mkimage_mult_no_content.dts')
6201 self.assertIn('Could not complete processing of contents',
6202 str(exc.exception))
6203
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006204 def testMkimageFilename(self):
6205 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006206 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006207 retcode = self._DoTestFile('254_mkimage_filename.dts')
6208 self.assertEqual(0, retcode)
6209 fname = tools.get_output_filename('mkimage-test.bin')
6210 self.assertTrue(os.path.exists(fname))
6211
Simon Glass56d05412022-02-28 07:16:54 -07006212 def testVpl(self):
6213 """Test that an image with VPL and its device tree can be created"""
6214 # ELF file with a '__bss_size' symbol
6215 self._SetupVplElf()
6216 data = self._DoReadFile('255_u_boot_vpl.dts')
6217 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6218
6219 def testVplNoDtb(self):
6220 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6221 self._SetupVplElf()
6222 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6223 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6224 data[:len(U_BOOT_VPL_NODTB_DATA)])
6225
6226 def testExpandedVpl(self):
6227 """Test that an expanded entry type is selected for TPL when needed"""
6228 self._SetupVplElf()
6229
6230 entry_args = {
6231 'vpl-bss-pad': 'y',
6232 'vpl-dtb': 'y',
6233 }
6234 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6235 entry_args=entry_args)
6236 image = control.images['image']
6237 entries = image.GetEntries()
6238 self.assertEqual(1, len(entries))
6239
6240 # We only have u-boot-vpl, which be expanded
6241 self.assertIn('u-boot-vpl', entries)
6242 entry = entries['u-boot-vpl']
6243 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6244 subent = entry.GetEntries()
6245 self.assertEqual(3, len(subent))
6246 self.assertIn('u-boot-vpl-nodtb', subent)
6247 self.assertIn('u-boot-vpl-bss-pad', subent)
6248 self.assertIn('u-boot-vpl-dtb', subent)
6249
6250 def testVplBssPadMissing(self):
6251 """Test that a missing symbol is detected"""
6252 self._SetupVplElf('u_boot_ucode_ptr')
6253 with self.assertRaises(ValueError) as e:
6254 self._DoReadFile('258_vpl_bss_pad.dts')
6255 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6256 str(e.exception))
6257
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306258 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306259 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306260 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6261 self.assertEqual(0, retcode)
6262 image = control.images['test_image']
6263 fname = tools.get_output_filename('test_image.bin')
6264 sname = tools.get_output_filename('symlink_to_test.bin')
6265 self.assertTrue(os.path.islink(sname))
6266 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006267
Andrew Davis6b463da2023-07-22 00:14:44 +05306268 def testSymlinkOverwrite(self):
6269 """Test that symlinked images can be overwritten"""
6270 testdir = TestFunctional._MakeInputDir('symlinktest')
6271 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6272 # build the same image again in the same directory so that existing symlink is present
6273 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6274 fname = tools.get_output_filename('test_image.bin')
6275 sname = tools.get_output_filename('symlink_to_test.bin')
6276 self.assertTrue(os.path.islink(sname))
6277 self.assertEqual(os.readlink(sname), fname)
6278
Simon Glass37f85de2022-10-20 18:22:47 -06006279 def testSymbolsElf(self):
6280 """Test binman can assign symbols embedded in an ELF file"""
6281 if not elf.ELF_TOOLS:
6282 self.skipTest('Python elftools not available')
6283 self._SetupTplElf('u_boot_binman_syms')
6284 self._SetupVplElf('u_boot_binman_syms')
6285 self._SetupSplElf('u_boot_binman_syms')
6286 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6287 image_fname = tools.get_output_filename('image.bin')
6288
6289 image = control.images['image']
6290 entries = image.GetEntries()
6291
6292 for entry in entries.values():
6293 # No symbols in u-boot and it has faked contents anyway
6294 if entry.name == 'u-boot':
6295 continue
6296 edata = data[entry.image_pos:entry.image_pos + entry.size]
6297 efname = tools.get_output_filename(f'edata-{entry.name}')
6298 tools.write_file(efname, edata)
6299
6300 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6301 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6302 for name, sym in syms.items():
6303 msg = 'test'
6304 val = elf.GetSymbolValue(sym, edata, msg)
6305 entry_m = re_name.match(name)
6306 if entry_m:
6307 ename, prop = entry_m.group(1), entry_m.group(3)
6308 entry, entry_name, prop_name = image.LookupEntry(entries,
6309 name, msg)
6310 if prop_name == 'offset':
6311 expect_val = entry.offset
6312 elif prop_name == 'image_pos':
6313 expect_val = entry.image_pos
6314 elif prop_name == 'size':
6315 expect_val = entry.size
6316 self.assertEqual(expect_val, val)
6317
6318 def testSymbolsElfBad(self):
6319 """Check error when trying to write symbols without the elftools lib"""
6320 if not elf.ELF_TOOLS:
6321 self.skipTest('Python elftools not available')
6322 self._SetupTplElf('u_boot_binman_syms')
6323 self._SetupVplElf('u_boot_binman_syms')
6324 self._SetupSplElf('u_boot_binman_syms')
6325 try:
6326 elf.ELF_TOOLS = False
6327 with self.assertRaises(ValueError) as exc:
6328 self._DoReadFileDtb('260_symbols_elf.dts')
6329 finally:
6330 elf.ELF_TOOLS = True
6331 self.assertIn(
6332 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6333 'Cannot write symbols to an ELF file without Python elftools',
6334 str(exc.exception))
6335
Simon Glassde244162023-01-07 14:07:08 -07006336 def testSectionFilename(self):
6337 """Check writing of section contents to a file"""
6338 data = self._DoReadFile('261_section_fname.dts')
6339 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6340 tools.get_bytes(ord('!'), 7) +
6341 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6342 self.assertEqual(expected, data)
6343
6344 sect_fname = tools.get_output_filename('outfile.bin')
6345 self.assertTrue(os.path.exists(sect_fname))
6346 sect_data = tools.read_file(sect_fname)
6347 self.assertEqual(U_BOOT_DATA, sect_data)
6348
Simon Glass1e9e61c2023-01-07 14:07:12 -07006349 def testAbsent(self):
6350 """Check handling of absent entries"""
6351 data = self._DoReadFile('262_absent.dts')
6352 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6353
Simon Glassad5cfe12023-01-07 14:07:14 -07006354 def testPackTeeOsOptional(self):
6355 """Test that an image with an optional TEE binary can be created"""
6356 entry_args = {
6357 'tee-os-path': 'tee.elf',
6358 }
6359 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6360 entry_args=entry_args)[0]
6361 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6362
6363 def checkFitTee(self, dts, tee_fname):
6364 """Check that a tee-os entry works and returns data
6365
6366 Args:
6367 dts (str): Device tree filename to use
6368 tee_fname (str): filename containing tee-os
6369
6370 Returns:
6371 bytes: Image contents
6372 """
6373 if not elf.ELF_TOOLS:
6374 self.skipTest('Python elftools not available')
6375 entry_args = {
6376 'of-list': 'test-fdt1 test-fdt2',
6377 'default-dt': 'test-fdt2',
6378 'tee-os-path': tee_fname,
6379 }
6380 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6381 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6382 extra_indirs=[test_subdir])[0]
6383 return data
6384
6385 def testFitTeeOsOptionalFit(self):
6386 """Test an image with a FIT with an optional OP-TEE binary"""
6387 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6388
6389 # There should be only one node, holding the data set up in SetUpClass()
6390 # for tee.bin
6391 dtb = fdt.Fdt.FromData(data)
6392 dtb.Scan()
6393 node = dtb.GetNode('/images/tee-1')
6394 self.assertEqual(TEE_ADDR,
6395 fdt_util.fdt32_to_cpu(node.props['load'].value))
6396 self.assertEqual(TEE_ADDR,
6397 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6398 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6399
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006400 with test_util.capture_sys_output() as (stdout, stderr):
6401 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6402 err = stderr.getvalue()
6403 self.assertRegex(
6404 err,
6405 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6406
Simon Glassad5cfe12023-01-07 14:07:14 -07006407 def testFitTeeOsOptionalFitBad(self):
6408 """Test an image with a FIT with an optional OP-TEE binary"""
6409 with self.assertRaises(ValueError) as exc:
6410 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6411 self.assertIn(
6412 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6413 str(exc.exception))
6414
6415 def testFitTeeOsBad(self):
6416 """Test an OP-TEE binary with wrong formats"""
6417 self.make_tee_bin('tee.bad1', 123)
6418 with self.assertRaises(ValueError) as exc:
6419 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6420 self.assertIn(
6421 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6422 str(exc.exception))
6423
6424 self.make_tee_bin('tee.bad2', 0, b'extra data')
6425 with self.assertRaises(ValueError) as exc:
6426 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6427 self.assertIn(
6428 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6429 str(exc.exception))
6430
Simon Glass63328f12023-01-07 14:07:15 -07006431 def testExtblobOptional(self):
6432 """Test an image with an external blob that is optional"""
6433 with test_util.capture_sys_output() as (stdout, stderr):
6434 data = self._DoReadFile('266_blob_ext_opt.dts')
6435 self.assertEqual(REFCODE_DATA, data)
6436 err = stderr.getvalue()
6437 self.assertRegex(
6438 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006439 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006440
Simon Glass7447a9d2023-01-11 16:10:12 -07006441 def testSectionInner(self):
6442 """Test an inner section with a size"""
6443 data = self._DoReadFile('267_section_inner.dts')
6444 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6445 self.assertEqual(expected, data)
6446
Simon Glassa4948b22023-01-11 16:10:14 -07006447 def testNull(self):
6448 """Test an image with a null entry"""
6449 data = self._DoReadFile('268_null.dts')
6450 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6451
Simon Glassf1ee03b2023-01-11 16:10:16 -07006452 def testOverlap(self):
6453 """Test an image with a overlapping entry"""
6454 data = self._DoReadFile('269_overlap.dts')
6455 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6456
6457 image = control.images['image']
6458 entries = image.GetEntries()
6459
6460 self.assertIn('inset', entries)
6461 inset = entries['inset']
6462 self.assertEqual(1, inset.offset);
6463 self.assertEqual(1, inset.image_pos);
6464 self.assertEqual(2, inset.size);
6465
6466 def testOverlapNull(self):
6467 """Test an image with a null overlap"""
6468 data = self._DoReadFile('270_overlap_null.dts')
6469 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6470
6471 # Check the FMAP
6472 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6473 self.assertEqual(4, fhdr.nareas)
6474 fiter = iter(fentries)
6475
6476 fentry = next(fiter)
6477 self.assertEqual(b'SECTION', fentry.name)
6478 self.assertEqual(0, fentry.offset)
6479 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6480 self.assertEqual(0, fentry.flags)
6481
6482 fentry = next(fiter)
6483 self.assertEqual(b'U_BOOT', fentry.name)
6484 self.assertEqual(0, fentry.offset)
6485 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6486 self.assertEqual(0, fentry.flags)
6487
6488 # Make sure that the NULL entry appears in the FMAP
6489 fentry = next(fiter)
6490 self.assertEqual(b'NULL', fentry.name)
6491 self.assertEqual(1, fentry.offset)
6492 self.assertEqual(2, fentry.size)
6493 self.assertEqual(0, fentry.flags)
6494
6495 fentry = next(fiter)
6496 self.assertEqual(b'FMAP', fentry.name)
6497 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6498
6499 def testOverlapBad(self):
6500 """Test an image with a bad overlapping entry"""
6501 with self.assertRaises(ValueError) as exc:
6502 self._DoReadFile('271_overlap_bad.dts')
6503 self.assertIn(
6504 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6505 str(exc.exception))
6506
6507 def testOverlapNoOffset(self):
6508 """Test an image with a bad overlapping entry"""
6509 with self.assertRaises(ValueError) as exc:
6510 self._DoReadFile('272_overlap_no_size.dts')
6511 self.assertIn(
6512 "Node '/binman/inset': 'fill' entry is missing properties: size",
6513 str(exc.exception))
6514
Simon Glasse0035c92023-01-11 16:10:17 -07006515 def testBlobSymbol(self):
6516 """Test a blob with symbols read from an ELF file"""
6517 elf_fname = self.ElfTestFile('blob_syms')
6518 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6519 TestFunctional._MakeInputFile('blob_syms.bin',
6520 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6521
6522 data = self._DoReadFile('273_blob_symbol.dts')
6523
6524 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6525 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6526 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6527 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6528 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6529
6530 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6531 expected = sym_values
6532 self.assertEqual(expected, data[:len(expected)])
6533
Simon Glass49e9c002023-01-11 16:10:19 -07006534 def testOffsetFromElf(self):
6535 """Test a blob with symbols read from an ELF file"""
6536 elf_fname = self.ElfTestFile('blob_syms')
6537 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6538 TestFunctional._MakeInputFile('blob_syms.bin',
6539 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6540
6541 data = self._DoReadFile('274_offset_from_elf.dts')
6542
6543 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6544 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6545
6546 image = control.images['image']
6547 entries = image.GetEntries()
6548
6549 self.assertIn('inset', entries)
6550 inset = entries['inset']
6551
6552 self.assertEqual(base + 4, inset.offset);
6553 self.assertEqual(base + 4, inset.image_pos);
6554 self.assertEqual(4, inset.size);
6555
6556 self.assertIn('inset2', entries)
6557 inset = entries['inset2']
6558 self.assertEqual(base + 8, inset.offset);
6559 self.assertEqual(base + 8, inset.image_pos);
6560 self.assertEqual(4, inset.size);
6561
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006562 def testFitAlign(self):
6563 """Test an image with an FIT with aligned external data"""
6564 data = self._DoReadFile('275_fit_align.dts')
6565 self.assertEqual(4096, len(data))
6566
6567 dtb = fdt.Fdt.FromData(data)
6568 dtb.Scan()
6569
6570 props = self._GetPropTree(dtb, ['data-position'])
6571 expected = {
6572 'u-boot:data-position': 1024,
6573 'fdt-1:data-position': 2048,
6574 'fdt-2:data-position': 3072,
6575 }
6576 self.assertEqual(expected, props)
6577
Jonas Karlman490f73c2023-01-21 19:02:12 +00006578 def testFitFirmwareLoadables(self):
6579 """Test an image with an FIT that use fit,firmware"""
6580 if not elf.ELF_TOOLS:
6581 self.skipTest('Python elftools not available')
6582 entry_args = {
6583 'of-list': 'test-fdt1',
6584 'default-dt': 'test-fdt1',
6585 'atf-bl31-path': 'bl31.elf',
6586 'tee-os-path': 'missing.bin',
6587 }
6588 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006589 with test_util.capture_sys_output() as (stdout, stderr):
6590 data = self._DoReadFileDtb(
6591 '276_fit_firmware_loadables.dts',
6592 entry_args=entry_args,
6593 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006594
6595 dtb = fdt.Fdt.FromData(data)
6596 dtb.Scan()
6597
6598 node = dtb.GetNode('/configurations/conf-uboot-1')
6599 self.assertEqual('u-boot', node.props['firmware'].value)
6600 self.assertEqual(['atf-1', 'atf-2'],
6601 fdt_util.GetStringList(node, 'loadables'))
6602
6603 node = dtb.GetNode('/configurations/conf-atf-1')
6604 self.assertEqual('atf-1', node.props['firmware'].value)
6605 self.assertEqual(['u-boot', 'atf-2'],
6606 fdt_util.GetStringList(node, 'loadables'))
6607
6608 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6609 self.assertEqual('u-boot', node.props['firmware'].value)
6610 self.assertEqual(['atf-1', 'atf-2'],
6611 fdt_util.GetStringList(node, 'loadables'))
6612
6613 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6614 self.assertEqual('atf-1', node.props['firmware'].value)
6615 self.assertEqual(['u-boot', 'atf-2'],
6616 fdt_util.GetStringList(node, 'loadables'))
6617
6618 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6619 self.assertEqual('atf-1', node.props['firmware'].value)
6620 self.assertEqual(['u-boot', 'atf-2'],
6621 fdt_util.GetStringList(node, 'loadables'))
6622
Simon Glass9a1c7262023-02-22 12:14:49 -07006623 def testTooldir(self):
6624 """Test that we can specify the tooldir"""
6625 with test_util.capture_sys_output() as (stdout, stderr):
6626 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6627 'tool', '-l'))
6628 self.assertEqual('fred', bintool.Bintool.tooldir)
6629
6630 # Check that the toolpath is updated correctly
6631 self.assertEqual(['fred'], tools.tool_search_paths)
6632
6633 # Try with a few toolpaths; the tooldir should be at the end
6634 with test_util.capture_sys_output() as (stdout, stderr):
6635 self.assertEqual(0, self._DoBinman(
6636 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6637 'tool', '-l'))
6638 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6639
Simon Glass49b77e82023-03-02 17:02:44 -07006640 def testReplaceSectionEntry(self):
6641 """Test replacing an entry in a section"""
6642 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6643 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6644 expect_data, dts='241_replace_section_simple.dts')
6645 self.assertEqual(expect_data, entry_data)
6646
6647 entries = image.GetEntries()
6648 self.assertIn('section', entries)
6649 section = entries['section']
6650
6651 sect_entries = section.GetEntries()
6652 self.assertIn('blob', sect_entries)
6653 entry = sect_entries['blob']
6654 self.assertEqual(len(expect_data), entry.size)
6655
6656 fname = tools.get_output_filename('image-updated.bin')
6657 data = tools.read_file(fname)
6658
6659 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6660 self.assertEqual(expect_data, new_blob_data)
6661
6662 self.assertEqual(U_BOOT_DATA,
6663 data[entry.image_pos + len(expect_data):]
6664 [:len(U_BOOT_DATA)])
6665
6666 def testReplaceSectionDeep(self):
6667 """Test replacing an entry in two levels of sections"""
6668 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6669 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6670 'section/section/blob', expect_data,
6671 dts='278_replace_section_deep.dts')
6672 self.assertEqual(expect_data, entry_data)
6673
6674 entries = image.GetEntries()
6675 self.assertIn('section', entries)
6676 section = entries['section']
6677
6678 subentries = section.GetEntries()
6679 self.assertIn('section', subentries)
6680 section = subentries['section']
6681
6682 sect_entries = section.GetEntries()
6683 self.assertIn('blob', sect_entries)
6684 entry = sect_entries['blob']
6685 self.assertEqual(len(expect_data), entry.size)
6686
6687 fname = tools.get_output_filename('image-updated.bin')
6688 data = tools.read_file(fname)
6689
6690 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6691 self.assertEqual(expect_data, new_blob_data)
6692
6693 self.assertEqual(U_BOOT_DATA,
6694 data[entry.image_pos + len(expect_data):]
6695 [:len(U_BOOT_DATA)])
6696
6697 def testReplaceFitSibling(self):
6698 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006699 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006700 fname = TestFunctional._MakeInputFile('once', b'available once')
6701 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6702 os.remove(fname)
6703
6704 try:
6705 tmpdir, updated_fname = self._SetupImageInTmpdir()
6706
6707 fname = os.path.join(tmpdir, 'update-blob')
6708 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6709 tools.write_file(fname, expected)
6710
6711 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6712 data = tools.read_file(updated_fname)
6713 start = len(U_BOOT_DTB_DATA)
6714 self.assertEqual(expected, data[start:start + len(expected)])
6715 map_fname = os.path.join(tmpdir, 'image-updated.map')
6716 self.assertFalse(os.path.exists(map_fname))
6717 finally:
6718 shutil.rmtree(tmpdir)
6719
Simon Glassc3fe97f2023-03-02 17:02:45 -07006720 def testX509Cert(self):
6721 """Test creating an X509 certificate"""
6722 keyfile = self.TestFile('key.key')
6723 entry_args = {
6724 'keyfile': keyfile,
6725 }
6726 data = self._DoReadFileDtb('279_x509_cert.dts',
6727 entry_args=entry_args)[0]
6728 cert = data[:-4]
6729 self.assertEqual(U_BOOT_DATA, data[-4:])
6730
6731 # TODO: verify the signature
6732
6733 def testX509CertMissing(self):
6734 """Test that binman still produces an image if openssl is missing"""
6735 keyfile = self.TestFile('key.key')
6736 entry_args = {
6737 'keyfile': 'keyfile',
6738 }
6739 with test_util.capture_sys_output() as (_, stderr):
6740 self._DoTestFile('279_x509_cert.dts',
6741 force_missing_bintools='openssl',
6742 entry_args=entry_args)
6743 err = stderr.getvalue()
6744 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6745
Jonas Karlman35305492023-02-25 19:01:33 +00006746 def testPackRockchipTpl(self):
6747 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006748 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006749 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6750
Jonas Karlman1016ec72023-02-25 19:01:35 +00006751 def testMkimageMissingBlobMultiple(self):
6752 """Test missing blob with mkimage entry and multiple-data-files"""
6753 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006754 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006755 err = stderr.getvalue()
6756 self.assertIn("is missing external blobs and is non-functional", err)
6757
6758 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006759 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006760 self.assertIn("not found in input path", str(e.exception))
6761
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006762 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6763 """Prepare sign environment
6764
6765 Create private and public keys, add pubkey into dtb.
6766
6767 Returns:
6768 Tuple:
6769 FIT container
6770 Image name
6771 Private key
6772 DTB
6773 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006774 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006775 data = self._DoReadFileRealDtb(dts)
6776 updated_fname = tools.get_output_filename('image-updated.bin')
6777 tools.write_file(updated_fname, data)
6778 dtb = tools.get_output_filename('source.dtb')
6779 private_key = tools.get_output_filename('test_key.key')
6780 public_key = tools.get_output_filename('test_key.crt')
6781 fit = tools.get_output_filename('fit.fit')
6782 key_dir = tools.get_output_dir()
6783
6784 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6785 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6786 private_key, '-out', public_key)
6787 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6788 '-n', 'test_key', '-r', 'conf', dtb)
6789
6790 return fit, updated_fname, private_key, dtb
6791
6792 def testSignSimple(self):
6793 """Test that a FIT container can be signed in image"""
6794 is_signed = False
6795 fit, fname, private_key, dtb = self._PrepareSignEnv()
6796
6797 # do sign with private key
6798 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6799 ['fit'])
6800 is_signed = self._CheckSign(fit, dtb)
6801
6802 self.assertEqual(is_signed, True)
6803
6804 def testSignExactFIT(self):
6805 """Test that a FIT container can be signed and replaced in image"""
6806 is_signed = False
6807 fit, fname, private_key, dtb = self._PrepareSignEnv()
6808
6809 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6810 args = []
6811 if self.toolpath:
6812 for path in self.toolpath:
6813 args += ['--toolpath', path]
6814
6815 # do sign with private key
6816 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6817 'sha256,rsa4096', '-f', fit, 'fit')
6818 is_signed = self._CheckSign(fit, dtb)
6819
6820 self.assertEqual(is_signed, True)
6821
6822 def testSignNonFit(self):
6823 """Test a non-FIT entry cannot be signed"""
6824 is_signed = False
6825 fit, fname, private_key, _ = self._PrepareSignEnv(
6826 '281_sign_non_fit.dts')
6827
6828 # do sign with private key
6829 with self.assertRaises(ValueError) as e:
6830 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6831 'sha256,rsa4096', '-f', fit, 'u-boot')
6832 self.assertIn(
6833 "Node '/u-boot': Updating signatures is not supported with this entry type",
6834 str(e.exception))
6835
6836 def testSignMissingMkimage(self):
6837 """Test that FIT signing handles a missing mkimage tool"""
6838 fit, fname, private_key, _ = self._PrepareSignEnv()
6839
6840 # try to sign with a missing mkimage tool
6841 bintool.Bintool.set_missing_list(['mkimage'])
6842 with self.assertRaises(ValueError) as e:
6843 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6844 ['fit'])
6845 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6846
Simon Glass4abf7842023-07-18 07:23:54 -06006847 def testSymbolNoWrite(self):
6848 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006849 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006850 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6851 no_write_symbols=True)
6852
6853 def testSymbolNoWriteExpanded(self):
6854 """Test disabling of symbol writing in expanded entries"""
6855 entry_args = {
6856 'spl-dtb': '1',
6857 }
6858 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6859 U_BOOT_SPL_DTB_DATA, 0x38,
6860 entry_args=entry_args, use_expanded=True,
6861 no_write_symbols=True)
6862
Marek Vasutf7413f02023-07-18 07:23:58 -06006863 def testMkimageSpecial(self):
6864 """Test mkimage ignores special hash-1 node"""
6865 data = self._DoReadFile('283_mkimage_special.dts')
6866
6867 # Just check that the data appears in the file somewhere
6868 self.assertIn(U_BOOT_DATA, data)
6869
Simon Glass2d94c422023-07-18 07:23:59 -06006870 def testFitFdtList(self):
6871 """Test an image with an FIT with the fit,fdt-list-val option"""
6872 entry_args = {
6873 'default-dt': 'test-fdt2',
6874 }
6875 data = self._DoReadFileDtb(
6876 '284_fit_fdt_list.dts',
6877 entry_args=entry_args,
6878 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6879 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6880 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6881
Simon Glass83b8bfe2023-07-18 07:24:01 -06006882 def testSplEmptyBss(self):
6883 """Test an expanded SPL with a zero-size BSS"""
6884 # ELF file with a '__bss_size' symbol
6885 self._SetupSplElf(src_fname='bss_data_zero')
6886
6887 entry_args = {
6888 'spl-bss-pad': 'y',
6889 'spl-dtb': 'y',
6890 }
6891 data = self._DoReadFileDtb('285_spl_expand.dts',
6892 use_expanded=True, entry_args=entry_args)[0]
6893
Simon Glassfc792842023-07-18 07:24:04 -06006894 def testTemplate(self):
6895 """Test using a template"""
6896 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6897 data = self._DoReadFile('286_template.dts')
6898 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6899 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6900 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6901
Simon Glass09490b02023-07-22 21:43:52 -06006902 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6903 self.assertTrue(os.path.exists(dtb_fname1))
6904 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6905 dtb.Scan()
6906 node1 = dtb.GetNode('/binman/template')
6907 self.assertTrue(node1)
6908 vga = dtb.GetNode('/binman/first/intel-vga')
6909 self.assertTrue(vga)
6910
Simon Glass54825e12023-07-22 21:43:56 -06006911 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6912 self.assertTrue(os.path.exists(dtb_fname2))
6913 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6914 dtb2.Scan()
6915 node2 = dtb2.GetNode('/binman/template')
6916 self.assertFalse(node2)
6917
Simon Glass9909c112023-07-18 07:24:05 -06006918 def testTemplateBlobMulti(self):
6919 """Test using a template with 'multiple-images' enabled"""
6920 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6921 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6922 retcode = self._DoTestFile('287_template_multi.dts')
6923
6924 self.assertEqual(0, retcode)
6925 image = control.images['image']
6926 image_fname = tools.get_output_filename('my-image.bin')
6927 data = tools.read_file(image_fname)
6928 self.assertEqual(b'blob@@@@other', data)
6929
Simon Glass5dc511b2023-07-18 07:24:06 -06006930 def testTemplateFit(self):
6931 """Test using a template in a FIT"""
6932 fit_data = self._DoReadFile('288_template_fit.dts')
6933 fname = os.path.join(self._indir, 'fit_data.fit')
6934 tools.write_file(fname, fit_data)
6935 out = tools.run('dumpimage', '-l', fname)
6936
Simon Glassaa6e0552023-07-18 07:24:07 -06006937 def testTemplateSection(self):
6938 """Test using a template in a section (not at top level)"""
6939 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6940 data = self._DoReadFile('289_template_section.dts')
6941 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6942 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6943 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6944
Simon Glassf53a7bc2023-07-18 07:24:08 -06006945 def testMkimageSymbols(self):
6946 """Test using mkimage to build an image with symbols in it"""
6947 self._SetupSplElf('u_boot_binman_syms')
6948 data = self._DoReadFile('290_mkimage_sym.dts')
6949
6950 image = control.images['image']
6951 entries = image.GetEntries()
6952 self.assertIn('u-boot', entries)
6953 u_boot = entries['u-boot']
6954
6955 mkim = entries['mkimage']
6956 mkim_entries = mkim.GetEntries()
6957 self.assertIn('u-boot-spl', mkim_entries)
6958 spl = mkim_entries['u-boot-spl']
6959 self.assertIn('u-boot-spl2', mkim_entries)
6960 spl2 = mkim_entries['u-boot-spl2']
6961
6962 # skip the mkimage header and the area sizes
6963 mk_data = data[mkim.offset + 0x40:]
6964 size, term = struct.unpack('>LL', mk_data[:8])
6965
6966 # There should be only one image, so check that the zero terminator is
6967 # present
6968 self.assertEqual(0, term)
6969
6970 content = mk_data[8:8 + size]
6971
6972 # The image should contain the symbols from u_boot_binman_syms.c
6973 # Note that image_pos is adjusted by the base address of the image,
6974 # which is 0x10 in our test image
6975 spl_data = content[:0x18]
6976 content = content[0x1b:]
6977
6978 # After the header is a table of offsets for each image. There should
6979 # only be one image, then a 0 terminator, so figure out the real start
6980 # of the image data
6981 base = 0x40 + 8
6982
6983 # Check symbols in both u-boot-spl and u-boot-spl2
6984 for i in range(2):
6985 vals = struct.unpack('<LLQLL', spl_data)
6986
6987 # The image should contain the symbols from u_boot_binman_syms.c
6988 # Note that image_pos is adjusted by the base address of the image,
6989 # which is 0x10 in our 'u_boot_binman_syms' test image
6990 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6991 self.assertEqual(base, vals[1])
6992 self.assertEqual(spl2.offset, vals[2])
6993 # figure out the internal positions of its components
6994 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6995
6996 # Check that spl and spl2 are actually at the indicated positions
6997 self.assertEqual(
6998 elf.BINMAN_SYM_MAGIC_VALUE,
6999 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
7000 self.assertEqual(
7001 elf.BINMAN_SYM_MAGIC_VALUE,
7002 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
7003
7004 self.assertEqual(len(U_BOOT_DATA), vals[4])
7005
7006 # Move to next
7007 spl_data = content[:0x18]
7008
Simon Glass86b3e472023-07-22 21:43:57 -06007009 def testTemplatePhandle(self):
7010 """Test using a template in a node containing a phandle"""
7011 entry_args = {
7012 'atf-bl31-path': 'bl31.elf',
7013 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06007014 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007015 entry_args=entry_args)
7016 fname = tools.get_output_filename('image.bin')
7017 out = tools.run('dumpimage', '-l', fname)
7018
7019 # We should see the FIT description and one for each of the two images
7020 lines = out.splitlines()
7021 descs = [line.split()[-1] for line in lines if 'escription' in line]
7022 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7023
7024 def testTemplatePhandleDup(self):
7025 """Test using a template in a node containing a phandle"""
7026 entry_args = {
7027 'atf-bl31-path': 'bl31.elf',
7028 }
7029 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007030 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007031 entry_args=entry_args)
7032 self.assertIn(
7033 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7034 str(e.exception))
7035
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307036 def testTIBoardConfig(self):
7037 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007038 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307039 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7040
Neha Malcom Francis8cd04512024-01-05 17:09:17 +05307041 def testTIBoardConfigLint(self):
7042 """Test that an incorrectly linted config file would generate error"""
7043 with self.assertRaises(ValueError) as e:
7044 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7045 self.assertIn("Yamllint error", str(e.exception))
7046
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307047 def testTIBoardConfigCombined(self):
7048 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007049 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307050 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7051 self.assertGreater(data, configlen_noheader)
7052
7053 def testTIBoardConfigNoDataType(self):
7054 """Test that error is thrown when data type is not supported"""
7055 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007056 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307057 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007058
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307059 def testPackTiSecure(self):
7060 """Test that an image with a TI secured binary can be created"""
7061 keyfile = self.TestFile('key.key')
7062 entry_args = {
7063 'keyfile': keyfile,
7064 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007065 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307066 entry_args=entry_args)[0]
7067 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7068
Manorit Chawdhry2e523b02023-12-29 16:16:27 +05307069 def testPackTiSecureFirewall(self):
7070 """Test that an image with a TI secured binary can be created"""
7071 keyfile = self.TestFile('key.key')
7072 entry_args = {
7073 'keyfile': keyfile,
7074 }
7075 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7076 entry_args=entry_args)[0]
7077 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7078 entry_args=entry_args)[0]
7079 self.assertGreater(len(data_firewall),len(data_no_firewall))
7080
7081 def testPackTiSecureFirewallMissingProperty(self):
7082 """Test that an image with a TI secured binary can be created"""
7083 keyfile = self.TestFile('key.key')
7084 entry_args = {
7085 'keyfile': keyfile,
7086 }
7087 with self.assertRaises(ValueError) as e:
7088 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7089 entry_args=entry_args)[0]
7090 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7091
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307092 def testPackTiSecureMissingTool(self):
7093 """Test that an image with a TI secured binary (non-functional) can be created
7094 when openssl is missing"""
7095 keyfile = self.TestFile('key.key')
7096 entry_args = {
7097 'keyfile': keyfile,
7098 }
7099 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007100 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307101 force_missing_bintools='openssl',
7102 entry_args=entry_args)
7103 err = stderr.getvalue()
7104 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7105
7106 def testPackTiSecureROM(self):
7107 """Test that a ROM image with a TI secured binary can be created"""
7108 keyfile = self.TestFile('key.key')
7109 entry_args = {
7110 'keyfile': keyfile,
7111 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007112 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307113 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007114 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307115 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007116 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307117 entry_args=entry_args)[0]
7118 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7119 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7120 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7121
7122 def testPackTiSecureROMCombined(self):
7123 """Test that a ROM image with a TI secured binary can be created"""
7124 keyfile = self.TestFile('key.key')
7125 entry_args = {
7126 'keyfile': keyfile,
7127 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007128 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307129 entry_args=entry_args)[0]
7130 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7131
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007132 def testEncryptedNoAlgo(self):
7133 """Test encrypted node with missing required properties"""
7134 with self.assertRaises(ValueError) as e:
7135 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7136 self.assertIn(
7137 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7138 str(e.exception))
7139
7140 def testEncryptedInvalidIvfile(self):
7141 """Test encrypted node with invalid iv file"""
7142 with self.assertRaises(ValueError) as e:
7143 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7144 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7145 str(e.exception))
7146
7147 def testEncryptedMissingKey(self):
7148 """Test encrypted node with missing key properties"""
7149 with self.assertRaises(ValueError) as e:
7150 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7151 self.assertIn(
7152 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7153 str(e.exception))
7154
7155 def testEncryptedKeySource(self):
7156 """Test encrypted node with key-source property"""
7157 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7158
7159 dtb = fdt.Fdt.FromData(data)
7160 dtb.Scan()
7161
7162 node = dtb.GetNode('/images/u-boot/cipher')
7163 self.assertEqual('algo-name', node.props['algo'].value)
7164 self.assertEqual('key-source-value', node.props['key-source'].value)
7165 self.assertEqual(ENCRYPTED_IV_DATA,
7166 tools.to_bytes(''.join(node.props['iv'].value)))
7167 self.assertNotIn('key', node.props)
7168
7169 def testEncryptedKeyFile(self):
7170 """Test encrypted node with key-filename property"""
7171 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7172
7173 dtb = fdt.Fdt.FromData(data)
7174 dtb.Scan()
7175
7176 node = dtb.GetNode('/images/u-boot/cipher')
7177 self.assertEqual('algo-name', node.props['algo'].value)
7178 self.assertEqual(ENCRYPTED_IV_DATA,
7179 tools.to_bytes(''.join(node.props['iv'].value)))
7180 self.assertEqual(ENCRYPTED_KEY_DATA,
7181 tools.to_bytes(''.join(node.props['key'].value)))
7182 self.assertNotIn('key-source', node.props)
7183
Lukas Funkee901faf2023-07-18 13:53:13 +02007184
7185 def testSplPubkeyDtb(self):
Simon Glass4b861272024-07-20 11:49:41 +01007186 """Test u_boot_spl_pubkey_dtb etype"""
7187 data = tools.read_file(self.TestFile("key.pem"))
7188 self._MakeInputFile("key.crt", data)
7189 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7190 image = control.images['image']
7191 entries = image.GetEntries()
7192 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7193 dtb_data = dtb_entry.GetData()
7194 dtb = fdt.Fdt.FromData(dtb_data)
7195 dtb.Scan()
Lukas Funkee901faf2023-07-18 13:53:13 +02007196
Simon Glass4b861272024-07-20 11:49:41 +01007197 signature_node = dtb.GetNode('/signature')
7198 self.assertIsNotNone(signature_node)
7199 key_node = signature_node.FindNode("key-key")
7200 self.assertIsNotNone(key_node)
7201 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7202 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7203 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007204
Lukas Funke712e1062023-08-03 17:22:14 +02007205 def testXilinxBootgenSigning(self):
7206 """Test xilinx-bootgen etype"""
7207 bootgen = bintool.Bintool.create('bootgen')
7208 self._CheckBintool(bootgen)
7209 data = tools.read_file(self.TestFile("key.key"))
7210 self._MakeInputFile("psk.pem", data)
7211 self._MakeInputFile("ssk.pem", data)
7212 self._SetupPmuFwlElf()
7213 self._SetupSplElf()
7214 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7215 image_fname = tools.get_output_filename('image.bin')
7216
7217 # Read partition header table and check if authentication is enabled
7218 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7219 "-read", image_fname, "pht").splitlines()
7220 attributes = {"authentication": None,
7221 "core": None,
7222 "encryption": None}
7223
7224 for l in bootgen_out:
7225 for a in attributes.keys():
7226 if a in l:
7227 m = re.match(fr".*{a} \[([^]]+)\]", l)
7228 attributes[a] = m.group(1)
7229
7230 self.assertTrue(attributes['authentication'] == "rsa")
7231 self.assertTrue(attributes['core'] == "a53-0")
7232 self.assertTrue(attributes['encryption'] == "no")
7233
7234 def testXilinxBootgenSigningEncryption(self):
7235 """Test xilinx-bootgen etype"""
7236 bootgen = bintool.Bintool.create('bootgen')
7237 self._CheckBintool(bootgen)
7238 data = tools.read_file(self.TestFile("key.key"))
7239 self._MakeInputFile("psk.pem", data)
7240 self._MakeInputFile("ssk.pem", data)
7241 self._SetupPmuFwlElf()
7242 self._SetupSplElf()
7243 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7244 image_fname = tools.get_output_filename('image.bin')
7245
7246 # Read boot header in order to verify encryption source and
7247 # encryption parameter
7248 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7249 "-read", image_fname, "bh").splitlines()
7250 attributes = {"auth_only":
7251 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7252 "encryption_keystore":
7253 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7254 "value": None},
7255 }
7256
7257 for l in bootgen_out:
7258 for a in attributes.keys():
7259 if a in l:
7260 m = re.match(attributes[a]['re'], l)
7261 attributes[a] = m.group(1)
7262
7263 # Check if fsbl-attribute is set correctly
7264 self.assertTrue(attributes['auth_only'] == "true")
7265 # Check if key is stored in efuse
7266 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7267
7268 def testXilinxBootgenMissing(self):
7269 """Test that binman still produces an image if bootgen is missing"""
7270 data = tools.read_file(self.TestFile("key.key"))
7271 self._MakeInputFile("psk.pem", data)
7272 self._MakeInputFile("ssk.pem", data)
7273 self._SetupPmuFwlElf()
7274 self._SetupSplElf()
7275 with test_util.capture_sys_output() as (_, stderr):
7276 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7277 force_missing_bintools='bootgen')
7278 err = stderr.getvalue()
7279 self.assertRegex(err,
7280 "Image 'image'.*missing bintools.*: bootgen")
7281
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307282 def _GetCapsuleHeaders(self, data):
7283 """Get the capsule header contents
7284
7285 Args:
7286 data: Capsule file contents
7287
7288 Returns:
7289 Dict:
7290 key: Capsule Header name (str)
7291 value: Header field value (str)
7292 """
7293 capsule_file = os.path.join(self._indir, 'test.capsule')
7294 tools.write_file(capsule_file, data)
7295
7296 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7297 lines = out.splitlines()
7298
7299 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7300 vals = {}
7301 for line in lines:
7302 mat = re_line.match(line)
7303 if mat:
7304 vals[mat.group(1)] = mat.group(2)
7305
7306 return vals
7307
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307308 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7309 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307310 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7311 fmp_size = "00000010"
7312 fmp_fw_version = "00000002"
7313 capsule_image_index = "00000001"
7314 oemflag = "00018000"
7315 auth_hdr_revision = "00000200"
7316 auth_hdr_cert_type = "00000EF1"
7317
7318 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307319
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307320 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307321
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307322 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307323
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307324 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7325 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7326 self.assertEqual(capsule_image_index,
7327 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307328
7329 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307330 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7331
7332 if signed_capsule:
7333 self.assertEqual(auth_hdr_revision,
7334 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7335 self.assertEqual(auth_hdr_cert_type,
7336 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7337 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7338 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7339
7340 if version_check:
7341 self.assertEqual(fmp_signature,
7342 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7343 self.assertEqual(fmp_size,
7344 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7345 self.assertEqual(fmp_fw_version,
7346 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7347
7348 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307349
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307350 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7351 if accept_capsule:
7352 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7353 else:
7354 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7355
7356 hdr = self._GetCapsuleHeaders(data)
7357
7358 self.assertEqual(capsule_hdr_guid.upper(),
7359 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7360
7361 if accept_capsule:
7362 capsule_size = "0000002C"
7363 else:
7364 capsule_size = "0000001C"
7365 self.assertEqual(capsule_size,
7366 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7367
7368 if accept_capsule:
7369 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7370
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307371 def testCapsuleGen(self):
7372 """Test generation of EFI capsule"""
7373 data = self._DoReadFile('311_capsule.dts')
7374
7375 self._CheckCapsule(data)
7376
7377 def testSignedCapsuleGen(self):
7378 """Test generation of EFI capsule"""
7379 data = tools.read_file(self.TestFile("key.key"))
7380 self._MakeInputFile("key.key", data)
7381 data = tools.read_file(self.TestFile("key.pem"))
7382 self._MakeInputFile("key.crt", data)
7383
7384 data = self._DoReadFile('312_capsule_signed.dts')
7385
7386 self._CheckCapsule(data, signed_capsule=True)
7387
7388 def testCapsuleGenVersionSupport(self):
7389 """Test generation of EFI capsule with version support"""
7390 data = self._DoReadFile('313_capsule_version.dts')
7391
7392 self._CheckCapsule(data, version_check=True)
7393
7394 def testCapsuleGenSignedVer(self):
7395 """Test generation of signed EFI capsule with version information"""
7396 data = tools.read_file(self.TestFile("key.key"))
7397 self._MakeInputFile("key.key", data)
7398 data = tools.read_file(self.TestFile("key.pem"))
7399 self._MakeInputFile("key.crt", data)
7400
7401 data = self._DoReadFile('314_capsule_signed_ver.dts')
7402
7403 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7404
7405 def testCapsuleGenCapOemFlags(self):
7406 """Test generation of EFI capsule with OEM Flags set"""
7407 data = self._DoReadFile('315_capsule_oemflags.dts')
7408
7409 self._CheckCapsule(data, capoemflags=True)
7410
7411 def testCapsuleGenKeyMissing(self):
7412 """Test that binman errors out on missing key"""
7413 with self.assertRaises(ValueError) as e:
7414 self._DoReadFile('316_capsule_missing_key.dts')
7415
7416 self.assertIn("Both private key and public key certificate need to be provided",
7417 str(e.exception))
7418
7419 def testCapsuleGenIndexMissing(self):
7420 """Test that binman errors out on missing image index"""
7421 with self.assertRaises(ValueError) as e:
7422 self._DoReadFile('317_capsule_missing_index.dts')
7423
7424 self.assertIn("entry is missing properties: image-index",
7425 str(e.exception))
7426
7427 def testCapsuleGenGuidMissing(self):
7428 """Test that binman errors out on missing image GUID"""
7429 with self.assertRaises(ValueError) as e:
7430 self._DoReadFile('318_capsule_missing_guid.dts')
7431
7432 self.assertIn("entry is missing properties: image-guid",
7433 str(e.exception))
7434
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307435 def testCapsuleGenAcceptCapsule(self):
7436 """Test generationg of accept EFI capsule"""
7437 data = self._DoReadFile('319_capsule_accept.dts')
7438
7439 self._CheckEmptyCapsule(data, accept_capsule=True)
7440
7441 def testCapsuleGenRevertCapsule(self):
7442 """Test generationg of revert EFI capsule"""
7443 data = self._DoReadFile('320_capsule_revert.dts')
7444
7445 self._CheckEmptyCapsule(data)
7446
7447 def testCapsuleGenAcceptGuidMissing(self):
7448 """Test that binman errors out on missing image GUID for accept capsule"""
7449 with self.assertRaises(ValueError) as e:
7450 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7451
7452 self.assertIn("Image GUID needed for generating accept capsule",
7453 str(e.exception))
7454
7455 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7456 """Test that capsule-type is specified"""
7457 with self.assertRaises(ValueError) as e:
7458 self._DoReadFile('322_empty_capsule_type_missing.dts')
7459
7460 self.assertIn("entry is missing properties: capsule-type",
7461 str(e.exception))
7462
7463 def testCapsuleGenAcceptOrRevertMissing(self):
7464 """Test that both accept and revert capsule are not specified"""
7465 with self.assertRaises(ValueError) as e:
7466 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7467
Simon Glassa360b8f2024-06-23 11:55:06 -06007468 def test_assume_size(self):
7469 """Test handling of the assume-size property for external blob"""
7470 with self.assertRaises(ValueError) as e:
7471 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7472 allow_fake_blobs=True)
7473 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7474 str(e.exception))
7475
7476 def test_assume_size_ok(self):
7477 """Test handling of the assume-size where it fits OK"""
7478 with test_util.capture_sys_output() as (stdout, stderr):
7479 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7480 allow_fake_blobs=True)
7481 err = stderr.getvalue()
7482 self.assertRegex(
7483 err,
7484 "Image '.*' has faked external blobs and is non-functional: .*")
7485
7486 def test_assume_size_no_fake(self):
7487 """Test handling of the assume-size where it fits OK"""
7488 with test_util.capture_sys_output() as (stdout, stderr):
7489 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7490 err = stderr.getvalue()
7491 self.assertRegex(
7492 err,
7493 "Image '.*' is missing external blobs and is non-functional: .*")
7494
Simon Glass5f7aadf2024-07-20 11:49:47 +01007495 def SetupAlternateDts(self):
7496 """Compile the .dts test files for alternative-fdt
7497
7498 Returns:
7499 tuple:
7500 str: Test directory created
7501 list of str: '.bin' files which we expect Binman to create
7502 """
7503 testdir = TestFunctional._MakeInputDir('dtb')
7504 dtb_list = []
7505 for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
7506 tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
7507 base = os.path.splitext(os.path.basename(fname))[0]
7508 dtb_list.append(base + '.bin')
7509 shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
7510
7511 return testdir, dtb_list
7512
Simon Glassf3598922024-07-20 11:49:45 +01007513 def CheckAlternates(self, dts, phase, xpl_data):
7514 """Run the test for the alterative-fdt etype
7515
7516 Args:
7517 dts (str): Devicetree file to process
7518 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7519 xpl_data (bytes): Expected data for the phase's binary
7520
7521 Returns:
7522 dict of .dtb files produced
7523 key: str filename
7524 value: Fdt object
7525 """
Simon Glass5f7aadf2024-07-20 11:49:47 +01007526 dtb_list = self.SetupAlternateDts()[1]
Simon Glassf3598922024-07-20 11:49:45 +01007527
7528 entry_args = {
7529 f'{phase}-dtb': '1',
7530 f'{phase}-bss-pad': 'y',
7531 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7532 }
7533 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7534 use_expanded=True, entry_args=entry_args)[0]
7535 self.assertEqual(xpl_data, data[:len(xpl_data)])
7536 rest = data[len(xpl_data):]
7537 pad_len = 10
7538 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7539
7540 # Check the dtb is using the test file
7541 dtb_data = rest[pad_len:]
7542 dtb = fdt.Fdt.FromData(dtb_data)
7543 dtb.Scan()
7544 fdt_size = dtb.GetFdtObj().totalsize()
7545 self.assertEqual('model-not-set',
7546 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7547
7548 pad_len = 10
7549
7550 # Check the other output files
7551 dtbs = {}
7552 for fname in dtb_list:
7553 pathname = tools.get_output_filename(fname)
7554 self.assertTrue(os.path.exists(pathname))
7555
7556 data = tools.read_file(pathname)
7557 self.assertEqual(xpl_data, data[:len(xpl_data)])
7558 rest = data[len(xpl_data):]
7559
7560 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7561 rest = rest[pad_len:]
7562
7563 dtb = fdt.Fdt.FromData(rest)
7564 dtb.Scan()
7565 dtbs[fname] = dtb
7566
7567 expected = 'one' if '1' in fname else 'two'
7568 self.assertEqual(f'u-boot,model-{expected}',
7569 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7570
7571 # Make sure the FDT is the same size as the 'main' one
7572 rest = rest[fdt_size:]
7573
7574 self.assertEqual(b'', rest)
7575 return dtbs
7576
7577 def testAlternatesFdt(self):
7578 """Test handling of alternates-fdt etype"""
7579 self._SetupTplElf()
7580 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7581 U_BOOT_TPL_NODTB_DATA)
7582 for dtb in dtbs.values():
7583 # Check for the node with the tag
7584 node = dtb.GetNode('/node')
7585 self.assertIsNotNone(node)
7586 self.assertEqual(5, len(node.props.keys()))
7587
7588 # Make sure the other node is still there
7589 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7590
7591 def testAlternatesFdtgrep(self):
7592 """Test handling of alternates-fdt etype using fdtgrep"""
7593 self._SetupTplElf()
7594 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7595 U_BOOT_TPL_NODTB_DATA)
7596 for dtb in dtbs.values():
7597 # Check for the node with the tag
7598 node = dtb.GetNode('/node')
7599 self.assertIsNotNone(node)
7600 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7601 node.props.keys())
7602
7603 # Make sure the other node is gone
7604 self.assertIsNone(dtb.GetNode('/node/other-node'))
7605
7606 def testAlternatesFdtgrepVpl(self):
7607 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7608 self._SetupVplElf()
7609 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7610 U_BOOT_VPL_NODTB_DATA)
7611
7612 def testAlternatesFdtgrepSpl(self):
7613 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7614 self._SetupSplElf()
7615 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7616 U_BOOT_SPL_NODTB_DATA)
7617
7618 def testAlternatesFdtgrepInval(self):
7619 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7620 self._SetupSplElf()
7621 with self.assertRaises(ValueError) as e:
7622 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7623 U_BOOT_SPL_NODTB_DATA)
7624 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7625 str(e.exception))
7626
Simon Glasscd2783e2024-07-20 11:49:46 +01007627 def testFitFdtListDir(self):
7628 """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
Simon Glass1bba8942024-08-26 13:11:34 -06007629 old_dir = os.getcwd()
7630 try:
7631 os.chdir(self._indir)
7632 self.CheckFitFdt('333_fit_fdt_dir.dts', False)
7633 finally:
7634 os.chdir(old_dir)
Simon Glasscd2783e2024-07-20 11:49:46 +01007635
Simon Glass5f7aadf2024-07-20 11:49:47 +01007636 def testFitFdtCompat(self):
7637 """Test an image with an FIT with compatible in the config nodes"""
7638 entry_args = {
7639 'of-list': 'model1 model2',
7640 'default-dt': 'model2',
7641 }
7642 testdir, dtb_list = self.SetupAlternateDts()
7643 data = self._DoReadFileDtb(
7644 '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
7645 entry_args=entry_args, extra_indirs=[testdir])[0]
7646
7647 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7648
7649 fit = fdt.Fdt.FromData(fit_data)
7650 fit.Scan()
7651
7652 cnode = fit.GetNode('/configurations')
7653 self.assertIn('default', cnode.props)
7654 self.assertEqual('config-2', cnode.props['default'].value)
7655
7656 for seq in range(1, 2):
7657 name = f'config-{seq}'
7658 fnode = fit.GetNode('/configurations/%s' % name)
7659 self.assertIsNotNone(fnode)
7660 self.assertIn('compatible', fnode.props.keys())
7661 expected = 'one' if seq == 1 else 'two'
7662 self.assertEqual(f'u-boot,model-{expected}',
7663 fnode.props['compatible'].value)
7664
Simon Glassa04b9942024-07-20 11:49:48 +01007665 def testFitFdtPhase(self):
7666 """Test an image with an FIT with fdt-phase in the fdt nodes"""
7667 phase = 'tpl'
7668 entry_args = {
7669 f'{phase}-dtb': '1',
7670 f'{phase}-bss-pad': 'y',
7671 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7672 'of-list': 'model1 model2',
7673 'default-dt': 'model2',
7674 }
7675 testdir, dtb_list = self.SetupAlternateDts()
7676 data = self._DoReadFileDtb(
7677 '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
7678 entry_args=entry_args, extra_indirs=[testdir])[0]
7679 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7680 fit = fdt.Fdt.FromData(fit_data)
7681 fit.Scan()
7682
7683 # Check that each FDT has only the expected properties for the phase
7684 for seq in range(1, 2):
7685 fnode = fit.GetNode(f'/images/fdt-{seq}')
7686 self.assertIsNotNone(fnode)
7687 dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
7688 dtb.Scan()
7689
7690 # Make sure that the 'bootph-pre-sram' tag in /node protects it from
7691 # removal
7692 node = dtb.GetNode('/node')
7693 self.assertIsNotNone(node)
7694 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7695 node.props.keys())
7696
7697 # Make sure the other node is gone
7698 self.assertIsNone(dtb.GetNode('/node/other-node'))
7699
Simon Glassb553e8a2024-08-26 13:11:29 -06007700 def testMkeficapsuleMissing(self):
7701 """Test that binman complains if mkeficapsule is missing"""
7702 with self.assertRaises(ValueError) as e:
7703 self._DoTestFile('311_capsule.dts',
7704 force_missing_bintools='mkeficapsule')
7705 self.assertIn("Node '/binman/efi-capsule': Missing tool: 'mkeficapsule'",
7706 str(e.exception))
7707
7708 def testMkeficapsuleMissingOk(self):
7709 """Test that binman deals with mkeficapsule being missing"""
7710 with test_util.capture_sys_output() as (stdout, stderr):
7711 ret = self._DoTestFile('311_capsule.dts',
7712 force_missing_bintools='mkeficapsule',
7713 allow_missing=True)
7714 self.assertEqual(103, ret)
7715 err = stderr.getvalue()
7716 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkeficapsule")
7717
Simon Glassa360b8f2024-06-23 11:55:06 -06007718
Simon Glassac599912017-11-12 21:52:22 -07007719if __name__ == "__main__":
7720 unittest.main()