blob: 684e960b58207191ab853610514c89060d4ef261 [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
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530128CAPSULE_IMAGE_GUID = '09d7cf52-0720-4710-91d1-08469b7fe9c8'
129# 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 Glass66152ce2022-01-09 20:14:09 -0700406 force_missing_tools (str): comma-separated list of bintools to
407 regard as missing
Andrew Davis6b463da2023-07-22 00:14:44 +0530408 output_dir: Specific output directory to use for image using -O
Simon Glass9a798402021-11-03 21:09:17 -0600409
410 Returns:
411 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700412 """
Simon Glassf46732a2019-07-08 14:25:29 -0600413 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700414 if debug:
415 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600416 if verbosity is not None:
417 args.append('-v%d' % verbosity)
418 elif self.verbosity:
419 args.append('-v%d' % self.verbosity)
420 if self.toolpath:
421 for path in self.toolpath:
422 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600423 if threads is not None:
424 args.append('-T%d' % threads)
425 if test_section_timeout:
426 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600427 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600428 if map:
429 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600430 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600431 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600432 if not use_real_dtb:
433 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300434 if not use_expanded:
435 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600436 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600437 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600438 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600439 if allow_missing:
440 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700441 if ignore_missing:
442 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100443 if allow_fake_blobs:
444 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700445 if force_missing_bintools:
446 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600447 if update_fdt_in_elf:
448 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600449 if images:
450 for image in images:
451 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600452 if extra_indirs:
453 for indir in extra_indirs:
454 args += ['-I', indir]
Andrew Davis6b463da2023-07-22 00:14:44 +0530455 if output_dir:
456 args += ['-O', output_dir]
Simon Glass075a45c2017-11-13 18:55:00 -0700457 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700458
459 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700460 """Set up a new test device-tree file
461
462 The given file is compiled and set up as the device tree to be used
463 for ths test.
464
465 Args:
466 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600467 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700468
469 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600470 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700471 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600472 tmpdir = tempfile.mkdtemp(prefix='binmant.')
473 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600474 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700475 data = fd.read()
476 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600477 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600478 return data
Simon Glass57454f42016-11-25 20:15:52 -0700479
Simon Glass56d05412022-02-28 07:16:54 -0700480 def _GetDtbContentsForSpls(self, dtb_data, name):
481 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600482
483 For testing we don't actually have different versions of the DTB. With
484 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
485 we don't normally have any unwanted nodes.
486
487 We still want the DTBs for SPL and TPL to be different though, since
488 otherwise it is confusing to know which one we are looking at. So add
489 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600490
491 Args:
492 dtb_data: dtb data to modify (this should be a value devicetree)
493 name: Name of a new property to add
494
495 Returns:
496 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600497 """
498 dtb = fdt.Fdt.FromData(dtb_data)
499 dtb.Scan()
500 dtb.GetNode('/binman').AddZeroProp(name)
501 dtb.Sync(auto_resize=True)
502 dtb.Pack()
503 return dtb.GetContents()
504
Simon Glassed930672021-03-18 20:25:05 +1300505 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
506 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600507 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700508 """Run binman and return the resulting image
509
510 This runs binman with a given test file and then reads the resulting
511 output file. It is a shortcut function since most tests need to do
512 these steps.
513
514 Raises an assertion failure if binman returns a non-zero exit code.
515
516 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600517 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700518 use_real_dtb: True to use the test file as the contents of
519 the u-boot-dtb entry. Normally this is not needed and the
520 test contents (the U_BOOT_DTB_DATA string) can be used.
521 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300522 use_expanded: True to use expanded entries where available, e.g.
523 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600524 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600525 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600526 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600527 entry_args: Dict of entry args to supply to binman
528 key: arg name
529 value: value of that arg
530 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
531 function. If reset_dtbs is True, then the original test dtb
532 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600533 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600534 threads: Number of threads to use (None for default, 0 for
535 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700536
537 Returns:
538 Tuple:
539 Resulting image contents
540 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600541 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600542 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700543 """
Simon Glass72232452016-11-25 20:15:53 -0700544 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700545 # Use the compiled test file as the u-boot-dtb input
546 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700547 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600548
549 # For testing purposes, make a copy of the DT for SPL and TPL. Add
Simon Glassd9e01d22024-07-20 11:49:40 +0100550 # a node indicating which it is, to aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700551 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600552 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
553 outfile = os.path.join(self._indir, dtb_fname)
554 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700555 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700556
557 try:
Simon Glass91710b32018-07-17 13:25:32 -0600558 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600559 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600560 use_expanded=use_expanded, extra_indirs=extra_indirs,
561 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700562 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700563 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700564
565 # Find the (only) image, read it and return its contents
566 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700567 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600568 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600569 if map:
Simon Glass80025522022-01-29 14:14:04 -0700570 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600571 with open(map_fname) as fd:
572 map_data = fd.read()
573 else:
574 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600575 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600576 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700577 finally:
578 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600579 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600580 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700581
Simon Glass5b4bce32019-07-08 14:25:26 -0600582 def _DoReadFileRealDtb(self, fname):
583 """Run binman with a real .dtb file and return the resulting data
584
585 Args:
586 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
587
588 Returns:
589 Resulting image contents
590 """
591 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
592
Simon Glass72232452016-11-25 20:15:53 -0700593 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600594 """Helper function which discards the device-tree binary
595
596 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600597 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600598 use_real_dtb: True to use the test file as the contents of
599 the u-boot-dtb entry. Normally this is not needed and the
600 test contents (the U_BOOT_DTB_DATA string) can be used.
601 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600602
603 Returns:
604 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600605 """
Simon Glass72232452016-11-25 20:15:53 -0700606 return self._DoReadFileDtb(fname, use_real_dtb)[0]
607
Simon Glass57454f42016-11-25 20:15:52 -0700608 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600609 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700610 """Create a new test input file, creating directories as needed
611
612 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600613 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700614 contents: File contents to write in to the file
615 Returns:
616 Full pathname of file created
617 """
Simon Glass862f8e22019-08-24 07:22:43 -0600618 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700619 dirname = os.path.dirname(pathname)
620 if dirname and not os.path.exists(dirname):
621 os.makedirs(dirname)
622 with open(pathname, 'wb') as fd:
623 fd.write(contents)
624 return pathname
625
626 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600627 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600628 """Create a new test input directory, creating directories as needed
629
630 Args:
631 dirname: Directory name to create
632
633 Returns:
634 Full pathname of directory created
635 """
Simon Glass862f8e22019-08-24 07:22:43 -0600636 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600637 if not os.path.exists(pathname):
638 os.makedirs(pathname)
639 return pathname
640
641 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600642 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600643 """Set up an ELF file with a '_dt_ucode_base_size' symbol
644
645 Args:
646 Filename of ELF file to use as SPL
647 """
Simon Glass93a806f2019-08-24 07:22:59 -0600648 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700649 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600650
651 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600652 def _SetupTplElf(cls, src_fname='bss_data'):
653 """Set up an ELF file with a '_dt_ucode_base_size' symbol
654
655 Args:
656 Filename of ELF file to use as TPL
657 """
658 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700659 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600660
661 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700662 def _SetupVplElf(cls, src_fname='bss_data'):
663 """Set up an ELF file with a '_dt_ucode_base_size' symbol
664
665 Args:
666 Filename of ELF file to use as VPL
667 """
668 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
669 tools.read_file(cls.ElfTestFile(src_fname)))
670
671 @classmethod
Lukas Funkee901faf2023-07-18 13:53:13 +0200672 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
673 """Set up an ELF file with a '_dt_ucode_base_size' symbol
674
675 Args:
676 Filename of ELF file to use as VPL
677 """
678 TestFunctional._MakeInputFile('pmu-firmware.elf',
679 tools.read_file(cls.ElfTestFile(src_fname)))
680
681 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600682 def _SetupDescriptor(cls):
683 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
684 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
685
686 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600687 def TestFile(cls, fname):
688 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700689
Simon Glassf6290892019-08-24 07:22:53 -0600690 @classmethod
691 def ElfTestFile(cls, fname):
692 return os.path.join(cls._elf_testdir, fname)
693
Simon Glassad5cfe12023-01-07 14:07:14 -0700694 @classmethod
695 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
696 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
697 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
698 dummy, paged_sz) + U_BOOT_DATA
699 data += extra_data
700 TestFunctional._MakeInputFile(fname, data)
701
Simon Glass57454f42016-11-25 20:15:52 -0700702 def AssertInList(self, grep_list, target):
703 """Assert that at least one of a list of things is in a target
704
705 Args:
706 grep_list: List of strings to check
707 target: Target string
708 """
709 for grep in grep_list:
710 if grep in target:
711 return
Simon Glass848cdb52019-05-17 22:00:50 -0600712 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700713
714 def CheckNoGaps(self, entries):
715 """Check that all entries fit together without gaps
716
717 Args:
718 entries: List of entries to check
719 """
Simon Glasse8561af2018-08-01 15:22:37 -0600720 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700721 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600722 self.assertEqual(offset, entry.offset)
723 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700724
Simon Glass72232452016-11-25 20:15:53 -0700725 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600726 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700727
728 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600729 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700730
731 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600732 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700733 """
734 return struct.unpack('>L', dtb[4:8])[0]
735
Simon Glass0f621332019-07-08 14:25:27 -0600736 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600737 def AddNode(node, path):
738 if node.name != '/':
739 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600740 for prop in node.props.values():
741 if prop.name in prop_names:
742 prop_path = path + ':' + prop.name
743 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
744 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600745 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600746 AddNode(subnode, path)
747
748 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600749 AddNode(dtb.GetRoot(), '')
750 return tree
751
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000752 def _CheckSign(self, fit, key):
753 try:
754 tools.run('fit_check_sign', '-k', key, '-f', fit)
755 except:
756 self.fail('Expected signed FIT container')
757 return False
758 return True
759
Simon Glass57454f42016-11-25 20:15:52 -0700760 def testRun(self):
761 """Test a basic run with valid args"""
762 result = self._RunBinman('-h')
763
764 def testFullHelp(self):
765 """Test that the full help is displayed with -H"""
766 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300767 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500768 # Remove possible extraneous strings
769 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
770 gothelp = result.stdout.replace(extra, '')
771 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700772 self.assertEqual(0, len(result.stderr))
773 self.assertEqual(0, result.return_code)
774
775 def testFullHelpInternal(self):
776 """Test that the full help is displayed with -H"""
777 try:
778 command.test_result = command.CommandResult()
779 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300780 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700781 finally:
782 command.test_result = None
783
784 def testHelp(self):
785 """Test that the basic help is displayed with -h"""
786 result = self._RunBinman('-h')
787 self.assertTrue(len(result.stdout) > 200)
788 self.assertEqual(0, len(result.stderr))
789 self.assertEqual(0, result.return_code)
790
Simon Glass57454f42016-11-25 20:15:52 -0700791 def testBoard(self):
792 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600793 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700794 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300795 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700796 self.assertEqual(0, result)
797
798 def testNeedBoard(self):
799 """Test that we get an error when no board ius supplied"""
800 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600801 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700802 self.assertIn("Must provide a board to process (use -b <board>)",
803 str(e.exception))
804
805 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600806 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700807 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600808 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700809 # We get one error from libfdt, and a different one from fdtget.
810 self.AssertInList(["Couldn't open blob from 'missing_file'",
811 'No such file or directory'], str(e.exception))
812
813 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600814 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700815
816 Since this is a source file it should be compiled and the error
817 will come from the device-tree compiler (dtc).
818 """
819 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600820 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700821 self.assertIn("FATAL ERROR: Unable to parse input tree",
822 str(e.exception))
823
824 def testMissingNode(self):
825 """Test that a device tree without a 'binman' node generates an error"""
826 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600827 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700828 self.assertIn("does not have a 'binman' node", str(e.exception))
829
830 def testEmpty(self):
831 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600832 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700833 self.assertEqual(0, len(result.stderr))
834 self.assertEqual(0, result.return_code)
835
836 def testInvalidEntry(self):
837 """Test that an invalid entry is flagged"""
838 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600839 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600840 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700841 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
842 "'/binman/not-a-valid-type'", str(e.exception))
843
844 def testSimple(self):
845 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600846 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700847 self.assertEqual(U_BOOT_DATA, data)
848
Simon Glass075a45c2017-11-13 18:55:00 -0700849 def testSimpleDebug(self):
850 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600851 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700852
Simon Glass57454f42016-11-25 20:15:52 -0700853 def testDual(self):
854 """Test that we can handle creating two images
855
856 This also tests image padding.
857 """
Simon Glass511f6582018-10-01 12:22:30 -0600858 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700859 self.assertEqual(0, retcode)
860
861 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600862 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700863 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700864 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600865 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700866 data = fd.read()
867 self.assertEqual(U_BOOT_DATA, data)
868
869 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600870 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700871 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700872 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600873 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700874 data = fd.read()
875 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700876 self.assertEqual(tools.get_bytes(0, 3), data[:3])
877 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700878
879 def testBadAlign(self):
880 """Test that an invalid alignment value is detected"""
881 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600882 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700883 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
884 "of two", str(e.exception))
885
886 def testPackSimple(self):
887 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600888 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700889 self.assertEqual(0, retcode)
890 self.assertIn('image', control.images)
891 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600892 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700893 self.assertEqual(5, len(entries))
894
895 # First u-boot
896 self.assertIn('u-boot', entries)
897 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600898 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700899 self.assertEqual(len(U_BOOT_DATA), entry.size)
900
901 # Second u-boot, aligned to 16-byte boundary
902 self.assertIn('u-boot-align', entries)
903 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600904 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700905 self.assertEqual(len(U_BOOT_DATA), entry.size)
906
907 # Third u-boot, size 23 bytes
908 self.assertIn('u-boot-size', entries)
909 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600910 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700911 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
912 self.assertEqual(23, entry.size)
913
914 # Fourth u-boot, placed immediate after the above
915 self.assertIn('u-boot-next', entries)
916 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600917 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700918 self.assertEqual(len(U_BOOT_DATA), entry.size)
919
Simon Glasse8561af2018-08-01 15:22:37 -0600920 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700921 self.assertIn('u-boot-fixed', entries)
922 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600923 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700924 self.assertEqual(len(U_BOOT_DATA), entry.size)
925
Simon Glass39dd2152019-07-08 14:25:47 -0600926 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700927
928 def testPackExtra(self):
929 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600930 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
931 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700932
Simon Glass57454f42016-11-25 20:15:52 -0700933 self.assertIn('image', control.images)
934 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600935 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600936 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700937
Samuel Hollande2574022023-01-21 17:25:16 -0600938 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700939 self.assertIn('u-boot', entries)
940 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600941 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700942 self.assertEqual(3, entry.pad_before)
943 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600944 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700945 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
946 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600947 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700948
949 # Second u-boot has an aligned size, but it has no effect
950 self.assertIn('u-boot-align-size-nop', entries)
951 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600952 self.assertEqual(pos, entry.offset)
953 self.assertEqual(len(U_BOOT_DATA), entry.size)
954 self.assertEqual(U_BOOT_DATA, entry.data)
955 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
956 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700957
958 # Third u-boot has an aligned size too
959 self.assertIn('u-boot-align-size', entries)
960 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600961 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700962 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600963 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700964 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600965 data[pos:pos + entry.size])
966 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700967
968 # Fourth u-boot has an aligned end
969 self.assertIn('u-boot-align-end', entries)
970 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600971 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700972 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600973 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700974 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600975 data[pos:pos + entry.size])
976 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700977
978 # Fifth u-boot immediately afterwards
979 self.assertIn('u-boot-align-both', entries)
980 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600981 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700982 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600983 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700984 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600985 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700986
Samuel Hollande2574022023-01-21 17:25:16 -0600987 # Sixth u-boot with both minimum size and aligned size
988 self.assertIn('u-boot-min-size', entries)
989 entry = entries['u-boot-min-size']
990 self.assertEqual(128, entry.offset)
991 self.assertEqual(32, entry.size)
992 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
993 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
994 data[pos:pos + entry.size])
995
Simon Glass57454f42016-11-25 20:15:52 -0700996 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -0600997 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700998
Simon Glassafb9caa2020-10-26 17:40:10 -0600999 dtb = fdt.Fdt(out_dtb_fname)
1000 dtb.Scan()
1001 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
1002 expected = {
1003 'image-pos': 0,
1004 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -06001005 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -06001006
1007 'u-boot:image-pos': 0,
1008 'u-boot:offset': 0,
1009 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1010
1011 'u-boot-align-size-nop:image-pos': 12,
1012 'u-boot-align-size-nop:offset': 12,
1013 'u-boot-align-size-nop:size': 4,
1014
1015 'u-boot-align-size:image-pos': 16,
1016 'u-boot-align-size:offset': 16,
1017 'u-boot-align-size:size': 32,
1018
1019 'u-boot-align-end:image-pos': 48,
1020 'u-boot-align-end:offset': 48,
1021 'u-boot-align-end:size': 16,
1022
1023 'u-boot-align-both:image-pos': 64,
1024 'u-boot-align-both:offset': 64,
1025 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -06001026
1027 'u-boot-min-size:image-pos': 128,
1028 'u-boot-min-size:offset': 128,
1029 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -06001030 }
1031 self.assertEqual(expected, props)
1032
Simon Glass57454f42016-11-25 20:15:52 -07001033 def testPackAlignPowerOf2(self):
1034 """Test that invalid entry alignment is detected"""
1035 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001036 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001037 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1038 "of two", str(e.exception))
1039
1040 def testPackAlignSizePowerOf2(self):
1041 """Test that invalid entry size alignment is detected"""
1042 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001043 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001044 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1045 "power of two", str(e.exception))
1046
1047 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001048 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001049 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001050 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001051 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001052 "align 0x4 (4)", str(e.exception))
1053
1054 def testPackInvalidSizeAlign(self):
1055 """Test that invalid entry size alignment is detected"""
1056 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001057 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001058 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1059 "align-size 0x4 (4)", str(e.exception))
1060
1061 def testPackOverlap(self):
1062 """Test that overlapping regions are detected"""
1063 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001064 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001065 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001066 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1067 str(e.exception))
1068
1069 def testPackEntryOverflow(self):
1070 """Test that entries that overflow their size are detected"""
1071 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001072 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001073 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1074 "but entry size is 0x3 (3)", str(e.exception))
1075
1076 def testPackImageOverflow(self):
1077 """Test that entries which overflow the image size are detected"""
1078 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001079 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001080 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001081 "size 0x3 (3)", str(e.exception))
1082
1083 def testPackImageSize(self):
1084 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001085 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001086 self.assertEqual(0, retcode)
1087 self.assertIn('image', control.images)
1088 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001089 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001090
1091 def testPackImageSizeAlign(self):
1092 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001093 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001094 self.assertEqual(0, retcode)
1095 self.assertIn('image', control.images)
1096 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001097 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001098
1099 def testPackInvalidImageAlign(self):
1100 """Test that invalid image alignment is detected"""
1101 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001102 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001103 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001104 "align-size 0x8 (8)", str(e.exception))
1105
Simon Glass2a0fa982022-02-11 13:23:21 -07001106 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001107 """Test that invalid image alignment is detected"""
1108 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001109 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001110 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001111 "two", str(e.exception))
1112
1113 def testImagePadByte(self):
1114 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001115 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001116 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001117 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001118 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001119
1120 def testImageName(self):
1121 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001122 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001123 self.assertEqual(0, retcode)
1124 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001125 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001126 self.assertTrue(os.path.exists(fname))
1127
1128 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001129 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001130 self.assertTrue(os.path.exists(fname))
1131
1132 def testBlobFilename(self):
1133 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001134 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001135 self.assertEqual(BLOB_DATA, data)
1136
1137 def testPackSorted(self):
1138 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001139 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001140 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001141 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1142 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001143
Simon Glasse8561af2018-08-01 15:22:37 -06001144 def testPackZeroOffset(self):
1145 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001146 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001147 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001148 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001149 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001150 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1151 str(e.exception))
1152
1153 def testPackUbootDtb(self):
1154 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001155 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001156 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001157
1158 def testPackX86RomNoSize(self):
1159 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001160 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001161 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001162 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001163 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001164 "using end-at-4gb", str(e.exception))
1165
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301166 def test4gbAndSkipAtStartTogether(self):
1167 """Test that the end-at-4gb and skip-at-size property can't be used
1168 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001169 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301170 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001171 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001172 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301173 "'skip-at-start'", str(e.exception))
1174
Simon Glass72232452016-11-25 20:15:53 -07001175 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001176 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001177 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001178 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001179 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001180 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1181 "is outside the section '/binman' starting at "
1182 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001183 str(e.exception))
1184
1185 def testPackX86Rom(self):
1186 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001187 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001188 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001189 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1190 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001191
1192 def testPackX86RomMeNoDesc(self):
1193 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001194 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001195 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001196 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001197 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001198 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1199 str(e.exception))
1200 finally:
1201 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001202
1203 def testPackX86RomBadDesc(self):
1204 """Test that the Intel requires a descriptor entry"""
1205 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001206 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001207 self.assertIn("Node '/binman/intel-me': No offset set with "
1208 "offset-unset: should another entry provide this correct "
1209 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001210
1211 def testPackX86RomMe(self):
1212 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001213 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001214 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001215 if data[:0x1000] != expected_desc:
1216 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001217 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1218
1219 def testPackVga(self):
1220 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001221 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001222 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1223
1224 def testPackStart16(self):
1225 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001226 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001227 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1228
Jagdish Gediya311d4842018-09-03 21:35:08 +05301229 def testPackPowerpcMpc85xxBootpgResetvec(self):
1230 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1231 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001232 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301233 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1234
Simon Glass6ba679c2018-07-06 10:27:17 -06001235 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001236 """Handle running a test for insertion of microcode
1237
1238 Args:
1239 dts_fname: Name of test .dts file
1240 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001241 ucode_second: True if the microsecond entry is second instead of
1242 third
Simon Glass820af1d2018-07-06 10:27:16 -06001243
1244 Returns:
1245 Tuple:
1246 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001247 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001248 in the above (two 4-byte words)
1249 """
Simon Glass3d274232017-11-12 21:52:27 -07001250 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001251
1252 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001253 if ucode_second:
1254 ucode_content = data[len(nodtb_data):]
1255 ucode_pos = len(nodtb_data)
1256 dtb_with_ucode = ucode_content[16:]
1257 fdt_len = self.GetFdtLen(dtb_with_ucode)
1258 else:
1259 dtb_with_ucode = data[len(nodtb_data):]
1260 fdt_len = self.GetFdtLen(dtb_with_ucode)
1261 ucode_content = dtb_with_ucode[fdt_len:]
1262 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001263 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001264 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001265 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001266 dtb = fdt.FdtScan(fname)
1267 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001268 self.assertTrue(ucode)
1269 for node in ucode.subnodes:
1270 self.assertFalse(node.props.get('data'))
1271
Simon Glass72232452016-11-25 20:15:53 -07001272 # Check that the microcode appears immediately after the Fdt
1273 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001274 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001275 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1276 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001277 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001278
1279 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001280 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001281 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1282 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001283 u_boot = data[:len(nodtb_data)]
1284 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001285
1286 def testPackUbootMicrocode(self):
1287 """Test that x86 microcode can be handled correctly
1288
1289 We expect to see the following in the image, in order:
1290 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1291 place
1292 u-boot.dtb with the microcode removed
1293 the microcode
1294 """
Simon Glass511f6582018-10-01 12:22:30 -06001295 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001296 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001297 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1298 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001299
Simon Glassbac25c82017-05-27 07:38:26 -06001300 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001301 """Test that x86 microcode can be handled correctly
1302
1303 We expect to see the following in the image, in order:
1304 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1305 place
1306 u-boot.dtb with the microcode
1307 an empty microcode region
1308 """
1309 # We need the libfdt library to run this test since only that allows
1310 # finding the offset of a property. This is required by
1311 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001312 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001313
1314 second = data[len(U_BOOT_NODTB_DATA):]
1315
1316 fdt_len = self.GetFdtLen(second)
1317 third = second[fdt_len:]
1318 second = second[:fdt_len]
1319
Simon Glassbac25c82017-05-27 07:38:26 -06001320 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1321 self.assertIn(ucode_data, second)
1322 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001323
Simon Glassbac25c82017-05-27 07:38:26 -06001324 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001325 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001326 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1327 len(ucode_data))
1328 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001329 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1330 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001331
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001332 def testPackUbootSingleMicrocode(self):
1333 """Test that x86 microcode can be handled correctly with fdt_normal.
1334 """
Simon Glassbac25c82017-05-27 07:38:26 -06001335 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001336
Simon Glass996021e2016-11-25 20:15:54 -07001337 def testUBootImg(self):
1338 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001339 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001340 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001341
1342 def testNoMicrocode(self):
1343 """Test that a missing microcode region is detected"""
1344 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001345 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001346 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1347 "node found in ", str(e.exception))
1348
1349 def testMicrocodeWithoutNode(self):
1350 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1351 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001352 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001353 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1354 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1355
1356 def testMicrocodeWithoutNode2(self):
1357 """Test that a missing u-boot-ucode node is detected"""
1358 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001359 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001360 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1361 "microcode region u-boot-ucode", str(e.exception))
1362
1363 def testMicrocodeWithoutPtrInElf(self):
1364 """Test that a U-Boot binary without the microcode symbol is detected"""
1365 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001366 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001367 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001368 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001369
1370 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001371 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001372 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1373 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1374
1375 finally:
1376 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001377 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001378 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001379
1380 def testMicrocodeNotInImage(self):
1381 """Test that microcode must be placed within the image"""
1382 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001383 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001384 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1385 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001386 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001387
1388 def testWithoutMicrocode(self):
1389 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001390 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001391 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001392 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001393
1394 # Now check the device tree has no microcode
1395 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1396 second = data[len(U_BOOT_NODTB_DATA):]
1397
1398 fdt_len = self.GetFdtLen(second)
1399 self.assertEqual(dtb, second[:fdt_len])
1400
1401 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1402 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001403 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001404
1405 def testUnknownPosSize(self):
1406 """Test that microcode must be placed within the image"""
1407 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001408 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001409 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001410 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001411
1412 def testPackFsp(self):
1413 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001414 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001415 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1416
1417 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001418 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001419 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001420 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001421
1422 def testPackVbt(self):
1423 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001424 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001425 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001426
Simon Glass7f94e832017-11-12 21:52:25 -07001427 def testSplBssPad(self):
1428 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001429 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001430 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001431 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001432 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001433 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001434
Simon Glass04cda032018-10-01 21:12:42 -06001435 def testSplBssPadMissing(self):
1436 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001437 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001438 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001439 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001440 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1441 str(e.exception))
1442
Simon Glasse83679d2017-11-12 21:52:26 -07001443 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001444 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001445 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001446 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1447
Simon Glass6ba679c2018-07-06 10:27:17 -06001448 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1449 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001450
1451 We expect to see the following in the image, in order:
1452 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1453 correct place
1454 u-boot.dtb with the microcode removed
1455 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001456
1457 Args:
1458 dts: Device tree file to use for test
1459 ucode_second: True if the microsecond entry is second instead of
1460 third
Simon Glass3d274232017-11-12 21:52:27 -07001461 """
Simon Glass7057d022018-10-01 21:12:47 -06001462 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001463 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1464 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001465 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1466 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001467
Simon Glass6ba679c2018-07-06 10:27:17 -06001468 def testPackUbootSplMicrocode(self):
1469 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001470 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001471 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001472
1473 def testPackUbootSplMicrocodeReorder(self):
1474 """Test that order doesn't matter for microcode entries
1475
1476 This is the same as testPackUbootSplMicrocode but when we process the
1477 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1478 entry, so we reply on binman to try later.
1479 """
Simon Glass511f6582018-10-01 12:22:30 -06001480 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001481 ucode_second=True)
1482
Simon Glassa409c932017-11-12 21:52:28 -07001483 def testPackMrc(self):
1484 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001485 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001486 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1487
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001488 def testSplDtb(self):
1489 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001490 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001491 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001492 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1493
Simon Glass0a6da312017-11-13 18:54:56 -07001494 def testSplNoDtb(self):
1495 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001496 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001497 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001498 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1499
Simon Glass7098b7f2021-03-21 18:24:30 +13001500 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4abf7842023-07-18 07:23:54 -06001501 use_expanded=False, no_write_symbols=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001502 """Check the image contains the expected symbol values
1503
1504 Args:
1505 dts: Device tree file to use for test
1506 base_data: Data before and after 'u-boot' section
1507 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001508 entry_args: Dict of entry args to supply to binman
1509 key: arg name
1510 value: value of that arg
1511 use_expanded: True to use expanded entries where available, e.g.
1512 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001513 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001514 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001515 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1516 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001517 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001518 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001519 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001520
Simon Glass7057d022018-10-01 21:12:47 -06001521 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001522 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1523 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001524 # The image should contain the symbols from u_boot_binman_syms.c
1525 # Note that image_pos is adjusted by the base address of the image,
1526 # which is 0x10 in our test image
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001527 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1528 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glass31e04cb2021-03-18 20:24:56 +13001529 0x10 + u_boot_offset, 0x04)
Simon Glass4abf7842023-07-18 07:23:54 -06001530 if no_write_symbols:
1531 expected = (base_data +
1532 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1533 U_BOOT_DATA + base_data)
1534 else:
1535 expected = (sym_values + base_data[24:] +
1536 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1537 base_data[24:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001538 self.assertEqual(expected, data)
1539
Simon Glass31e04cb2021-03-18 20:24:56 +13001540 def testSymbols(self):
1541 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001542 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001543
1544 def testSymbolsNoDtb(self):
1545 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001546 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001547 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1548 0x38)
1549
Simon Glasse76a3e62018-06-01 09:38:11 -06001550 def testPackUnitAddress(self):
1551 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001552 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001553 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1554
Simon Glassa91e1152018-06-01 09:38:16 -06001555 def testSections(self):
1556 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001557 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001558 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1559 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1560 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001561 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001562
Simon Glass30732662018-06-01 09:38:20 -06001563 def testMap(self):
1564 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001565 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001566 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700156700000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600156800000000 00000000 00000010 section@0
156900000000 00000000 00000004 u-boot
157000000010 00000010 00000010 section@1
157100000010 00000000 00000004 u-boot
157200000020 00000020 00000004 section@2
157300000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001574''', map_data)
1575
Simon Glass3b78d532018-06-01 09:38:21 -06001576 def testNamePrefix(self):
1577 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001578 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001579 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700158000000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600158100000000 00000000 00000010 section@0
158200000000 00000000 00000004 ro-u-boot
158300000010 00000010 00000010 section@1
158400000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001585''', map_data)
1586
Simon Glass6ba679c2018-07-06 10:27:17 -06001587 def testUnknownContents(self):
1588 """Test that obtaining the contents works as expected"""
1589 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001590 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001591 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001592 "processing of contents: remaining ["
1593 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001594
Simon Glass2e1169f2018-07-06 10:27:19 -06001595 def testBadChangeSize(self):
1596 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001597 try:
1598 state.SetAllowEntryExpansion(False)
1599 with self.assertRaises(ValueError) as e:
1600 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001601 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001602 str(e.exception))
1603 finally:
1604 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001605
Simon Glassa87014e2018-07-06 10:27:42 -06001606 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001607 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001608 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001609 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001610 dtb = fdt.Fdt(out_dtb_fname)
1611 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001612 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001613 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001614 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001615 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001616 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001617 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001618 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001619 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001620 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001621 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001622 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001623 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001624 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001625
Simon Glasse8561af2018-08-01 15:22:37 -06001626 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001627 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001628 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001629 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001630 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001631 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001632 'size': 40
1633 }, props)
1634
1635 def testUpdateFdtBad(self):
1636 """Test that we detect when ProcessFdt never completes"""
1637 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001638 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001639 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001640 '[<binman.etype._testing.Entry__testing',
1641 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001642
Simon Glass91710b32018-07-17 13:25:32 -06001643 def testEntryArgs(self):
1644 """Test passing arguments to entries from the command line"""
1645 entry_args = {
1646 'test-str-arg': 'test1',
1647 'test-int-arg': '456',
1648 }
Simon Glass511f6582018-10-01 12:22:30 -06001649 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001650 self.assertIn('image', control.images)
1651 entry = control.images['image'].GetEntries()['_testing']
1652 self.assertEqual('test0', entry.test_str_fdt)
1653 self.assertEqual('test1', entry.test_str_arg)
1654 self.assertEqual(123, entry.test_int_fdt)
1655 self.assertEqual(456, entry.test_int_arg)
1656
1657 def testEntryArgsMissing(self):
1658 """Test missing arguments and properties"""
1659 entry_args = {
1660 'test-int-arg': '456',
1661 }
Simon Glass511f6582018-10-01 12:22:30 -06001662 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001663 entry = control.images['image'].GetEntries()['_testing']
1664 self.assertEqual('test0', entry.test_str_fdt)
1665 self.assertEqual(None, entry.test_str_arg)
1666 self.assertEqual(None, entry.test_int_fdt)
1667 self.assertEqual(456, entry.test_int_arg)
1668
1669 def testEntryArgsRequired(self):
1670 """Test missing arguments and properties"""
1671 entry_args = {
1672 'test-int-arg': '456',
1673 }
1674 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001675 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001676 self.assertIn("Node '/binman/_testing': "
1677 'Missing required properties/entry args: test-str-arg, '
1678 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001679 str(e.exception))
1680
1681 def testEntryArgsInvalidFormat(self):
1682 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001683 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1684 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001685 with self.assertRaises(ValueError) as e:
1686 self._DoBinman(*args)
1687 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1688
1689 def testEntryArgsInvalidInteger(self):
1690 """Test that an invalid entry-argument integer is detected"""
1691 entry_args = {
1692 'test-int-arg': 'abc',
1693 }
1694 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001695 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001696 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1697 "'test-int-arg' (value 'abc') to integer",
1698 str(e.exception))
1699
1700 def testEntryArgsInvalidDatatype(self):
1701 """Test that an invalid entry-argument datatype is detected
1702
1703 This test could be written in entry_test.py except that it needs
1704 access to control.entry_args, which seems more than that module should
1705 be able to see.
1706 """
1707 entry_args = {
1708 'test-bad-datatype-arg': '12',
1709 }
1710 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001711 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001712 entry_args=entry_args)
1713 self.assertIn('GetArg() internal error: Unknown data type ',
1714 str(e.exception))
1715
Simon Glass2ca52032018-07-17 13:25:33 -06001716 def testText(self):
1717 """Test for a text entry type"""
1718 entry_args = {
1719 'test-id': TEXT_DATA,
1720 'test-id2': TEXT_DATA2,
1721 'test-id3': TEXT_DATA3,
1722 }
Simon Glass511f6582018-10-01 12:22:30 -06001723 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001724 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001725 expected = (tools.to_bytes(TEXT_DATA) +
1726 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1727 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001728 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001729 self.assertEqual(expected, data)
1730
Simon Glass969616c2018-07-17 13:25:36 -06001731 def testEntryDocs(self):
1732 """Test for creation of entry documentation"""
1733 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001734 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001735 self.assertTrue(len(stdout.getvalue()) > 0)
1736
1737 def testEntryDocsMissing(self):
1738 """Test handling of missing entry documentation"""
1739 with self.assertRaises(ValueError) as e:
1740 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001741 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001742 self.assertIn('Documentation is missing for modules: u_boot',
1743 str(e.exception))
1744
Simon Glass704784b2018-07-17 13:25:38 -06001745 def testFmap(self):
1746 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001747 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001748 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001749 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1750 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001751 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001752 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001753 self.assertEqual(1, fhdr.ver_major)
1754 self.assertEqual(0, fhdr.ver_minor)
1755 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001756 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001757 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001758 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001759 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001760 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001761
Simon Glass82059c22021-04-03 11:05:09 +13001762 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001763 self.assertEqual(b'SECTION0', fentry.name)
1764 self.assertEqual(0, fentry.offset)
1765 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001766 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001767
1768 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001769 self.assertEqual(b'RO_U_BOOT', fentry.name)
1770 self.assertEqual(0, fentry.offset)
1771 self.assertEqual(4, fentry.size)
1772 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001773
Simon Glass82059c22021-04-03 11:05:09 +13001774 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001775 self.assertEqual(b'SECTION1', fentry.name)
1776 self.assertEqual(16, fentry.offset)
1777 self.assertEqual(16, fentry.size)
1778 self.assertEqual(0, fentry.flags)
1779
1780 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001781 self.assertEqual(b'RW_U_BOOT', fentry.name)
1782 self.assertEqual(16, fentry.offset)
1783 self.assertEqual(4, fentry.size)
1784 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001785
Simon Glass82059c22021-04-03 11:05:09 +13001786 fentry = next(fiter)
1787 self.assertEqual(b'FMAP', fentry.name)
1788 self.assertEqual(32, fentry.offset)
1789 self.assertEqual(expect_size, fentry.size)
1790 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001791
Simon Glassdb168d42018-07-17 13:25:39 -06001792 def testBlobNamedByArg(self):
1793 """Test we can add a blob with the filename coming from an entry arg"""
1794 entry_args = {
1795 'cros-ec-rw-path': 'ecrw.bin',
1796 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001797 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001798
Simon Glass53f53992018-07-17 13:25:40 -06001799 def testFill(self):
1800 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001801 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001802 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001803 self.assertEqual(expected, data)
1804
1805 def testFillNoSize(self):
1806 """Test for an fill entry type with no size"""
1807 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001808 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001809 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001810 str(e.exception))
1811
Simon Glassc1ae83c2018-07-17 13:25:44 -06001812 def _HandleGbbCommand(self, pipe_list):
1813 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001814 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001815 fname = pipe_list[0][-1]
1816 # Append our GBB data to the file, which will happen every time the
1817 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001818 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001819 fd.write(GBB_DATA)
1820 return command.CommandResult()
1821
1822 def testGbb(self):
1823 """Test for the Chromium OS Google Binary Block"""
1824 command.test_result = self._HandleGbbCommand
1825 entry_args = {
1826 'keydir': 'devkeys',
1827 'bmpblk': 'bmpblk.bin',
1828 }
Simon Glass511f6582018-10-01 12:22:30 -06001829 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001830
1831 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001832 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1833 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001834 self.assertEqual(expected, data)
1835
1836 def testGbbTooSmall(self):
1837 """Test for the Chromium OS Google Binary Block being large enough"""
1838 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001839 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001840 self.assertIn("Node '/binman/gbb': GBB is too small",
1841 str(e.exception))
1842
1843 def testGbbNoSize(self):
1844 """Test for the Chromium OS Google Binary Block having a size"""
1845 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001846 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001847 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1848 str(e.exception))
1849
Simon Glass66152ce2022-01-09 20:14:09 -07001850 def testGbbMissing(self):
1851 """Test that binman still produces an image if futility is missing"""
1852 entry_args = {
1853 'keydir': 'devkeys',
1854 }
1855 with test_util.capture_sys_output() as (_, stderr):
1856 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1857 entry_args=entry_args)
1858 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001859 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001860
Simon Glass5c350162018-07-17 13:25:47 -06001861 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001862 """Fake calls to the futility utility
1863
1864 The expected pipe is:
1865
1866 [('futility', 'vbutil_firmware', '--vblock',
1867 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1868 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1869 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1870 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1871
1872 This writes to the output file (here, 'vblock.vblock'). If
1873 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1874 of the input data (here, 'input.vblock').
1875 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001876 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001877 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001878 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001879 if self._hash_data:
1880 infile = pipe_list[0][11]
1881 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001882 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001883 m.update(data)
1884 fd.write(m.digest())
1885 else:
1886 fd.write(VBLOCK_DATA)
1887
Simon Glass5c350162018-07-17 13:25:47 -06001888 return command.CommandResult()
1889
1890 def testVblock(self):
1891 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001892 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001893 command.test_result = self._HandleVblockCommand
1894 entry_args = {
1895 'keydir': 'devkeys',
1896 }
Simon Glass511f6582018-10-01 12:22:30 -06001897 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001898 entry_args=entry_args)
1899 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1900 self.assertEqual(expected, data)
1901
1902 def testVblockNoContent(self):
1903 """Test we detect a vblock which has no content to sign"""
1904 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001905 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001906 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001907 'property', str(e.exception))
1908
1909 def testVblockBadPhandle(self):
1910 """Test that we detect a vblock with an invalid phandle in contents"""
1911 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001912 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001913 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1914 '1000', str(e.exception))
1915
1916 def testVblockBadEntry(self):
1917 """Test that we detect an entry that points to a non-entry"""
1918 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001919 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001920 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1921 "'other'", str(e.exception))
1922
Simon Glass220c6222021-01-06 21:35:17 -07001923 def testVblockContent(self):
1924 """Test that the vblock signs the right data"""
1925 self._hash_data = True
1926 command.test_result = self._HandleVblockCommand
1927 entry_args = {
1928 'keydir': 'devkeys',
1929 }
1930 data = self._DoReadFileDtb(
1931 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1932 entry_args=entry_args)[0]
1933 hashlen = 32 # SHA256 hash is 32 bytes
1934 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1935 hashval = data[-hashlen:]
1936 dtb = data[len(U_BOOT_DATA):-hashlen]
1937
1938 expected_data = U_BOOT_DATA + dtb
1939
1940 # The hashval should be a hash of the dtb
1941 m = hashlib.sha256()
1942 m.update(expected_data)
1943 expected_hashval = m.digest()
1944 self.assertEqual(expected_hashval, hashval)
1945
Simon Glass66152ce2022-01-09 20:14:09 -07001946 def testVblockMissing(self):
1947 """Test that binman still produces an image if futility is missing"""
1948 entry_args = {
1949 'keydir': 'devkeys',
1950 }
1951 with test_util.capture_sys_output() as (_, stderr):
1952 self._DoTestFile('074_vblock.dts',
1953 force_missing_bintools='futility',
1954 entry_args=entry_args)
1955 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001956 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001957
Simon Glass8425a1f2018-07-17 13:25:48 -06001958 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001959 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001960 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001961 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001962 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001963 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1964
Simon Glass24b97442018-07-17 13:25:51 -06001965 def testUsesPos(self):
1966 """Test that the 'pos' property cannot be used anymore"""
1967 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001968 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001969 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1970 "'pos'", str(e.exception))
1971
Simon Glass274bf092018-09-14 04:57:08 -06001972 def testFillZero(self):
1973 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001974 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001975 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001976
Simon Glass267de432018-09-14 04:57:09 -06001977 def testTextMissing(self):
1978 """Test for a text entry type where there is no text"""
1979 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001980 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001981 self.assertIn("Node '/binman/text': No value provided for text label "
1982 "'test-id'", str(e.exception))
1983
Simon Glassed40e962018-09-14 04:57:10 -06001984 def testPackStart16Tpl(self):
1985 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001986 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001987 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1988
Simon Glass3b376c32018-09-14 04:57:12 -06001989 def testSelectImage(self):
1990 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001991 expected = 'Skipping images: image1'
1992
1993 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001994 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001995 with test_util.capture_sys_output() as (stdout, stderr):
1996 retcode = self._DoTestFile('006_dual_image.dts',
1997 verbosity=verbosity,
1998 images=['image2'])
1999 self.assertEqual(0, retcode)
2000 if verbosity:
2001 self.assertIn(expected, stdout.getvalue())
2002 else:
2003 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06002004
Simon Glass80025522022-01-29 14:14:04 -07002005 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2006 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06002007 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06002008
Simon Glasse219aa42018-09-14 04:57:24 -06002009 def testUpdateFdtAll(self):
2010 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06002011 self._SetupSplElf()
2012 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06002013 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06002014
2015 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06002016 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002017 'image-pos': 0,
2018 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06002019 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002020 'section:image-pos': 0,
2021 'section:size': 565,
2022 'section/u-boot-dtb:offset': 0,
2023 'section/u-boot-dtb:image-pos': 0,
2024 'section/u-boot-dtb:size': 565,
2025 'u-boot-spl-dtb:offset': 565,
2026 'u-boot-spl-dtb:image-pos': 565,
2027 'u-boot-spl-dtb:size': 585,
2028 'u-boot-tpl-dtb:offset': 1150,
2029 'u-boot-tpl-dtb:image-pos': 1150,
2030 'u-boot-tpl-dtb:size': 585,
2031 'u-boot-vpl-dtb:image-pos': 1735,
2032 'u-boot-vpl-dtb:offset': 1735,
2033 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002034 }
2035
2036 # We expect three device-tree files in the output, one after the other.
2037 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2038 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2039 # main U-Boot tree. All three should have the same postions and offset.
2040 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002041 self.maxDiff = None
2042 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002043 dtb = fdt.Fdt.FromData(data[start:])
2044 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002045 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002046 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002047 expected = dict(base_expected)
2048 if item:
2049 expected[item] = 0
2050 self.assertEqual(expected, props)
2051 start += dtb._fdt_obj.totalsize()
2052
2053 def testUpdateFdtOutput(self):
2054 """Test that output DTB files are updated"""
2055 try:
Simon Glass511f6582018-10-01 12:22:30 -06002056 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002057 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2058
2059 # Unfortunately, compiling a source file always results in a file
2060 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002061 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002062 # binman as a file called u-boot.dtb. To fix this, copy the file
2063 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002064 start = 0
2065 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002066 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002067 dtb = fdt.Fdt.FromData(data[start:])
2068 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002069 pathname = tools.get_output_filename(os.path.split(fname)[1])
2070 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002071 name = os.path.split(fname)[0]
2072
2073 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002074 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002075 else:
2076 orig_indata = dtb_data
2077 self.assertNotEqual(outdata, orig_indata,
2078 "Expected output file '%s' be updated" % pathname)
2079 self.assertEqual(outdata, data[start:start + size],
2080 "Expected output file '%s' to match output image" %
2081 pathname)
2082 start += size
2083 finally:
2084 self._ResetDtbs()
2085
Simon Glass7ba33592018-09-14 04:57:26 -06002086 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002087 bintool = self.comp_bintools['lz4']
2088 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002089
2090 def testCompress(self):
2091 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002092 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002093 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002094 use_real_dtb=True, update_dtb=True)
2095 dtb = fdt.Fdt(out_dtb_fname)
2096 dtb.Scan()
2097 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2098 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00002099 self.assertEqual(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002100
2101 # Do a sanity check on various fields
2102 image = control.images['image']
2103 entries = image.GetEntries()
2104 self.assertEqual(1, len(entries))
2105
2106 entry = entries['blob']
2107 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2108 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2109 orig = self._decompress(entry.data)
2110 self.assertEqual(orig, entry.uncomp_data)
2111
Simon Glass72eeff12020-10-26 17:40:16 -06002112 self.assertEqual(image.data, entry.data)
2113
Simon Glass7ba33592018-09-14 04:57:26 -06002114 expected = {
2115 'blob:uncomp-size': len(COMPRESS_DATA),
2116 'blob:size': len(data),
2117 'size': len(data),
2118 }
2119 self.assertEqual(expected, props)
2120
Simon Glassac6328c2018-09-14 04:57:28 -06002121 def testFiles(self):
2122 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002123 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002124 self.assertEqual(FILES_DATA, data)
2125
2126 def testFilesCompress(self):
2127 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002128 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002129 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002130
2131 image = control.images['image']
2132 entries = image.GetEntries()
2133 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002134 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002135
Simon Glass303f62f2019-05-17 22:00:46 -06002136 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002137 for i in range(1, 3):
2138 key = '%d.dat' % i
2139 start = entries[key].image_pos
2140 len = entries[key].size
2141 chunk = data[start:start + len]
2142 orig += self._decompress(chunk)
2143
2144 self.assertEqual(FILES_DATA, orig)
2145
2146 def testFilesMissing(self):
2147 """Test missing files"""
2148 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002149 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002150 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2151 'no files', str(e.exception))
2152
2153 def testFilesNoPattern(self):
2154 """Test missing files"""
2155 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002156 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002157 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2158 str(e.exception))
2159
Simon Glassdd156a42022-03-05 20:18:59 -07002160 def testExtendSize(self):
2161 """Test an extending entry"""
2162 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002163 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002164 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2165 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2166 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2167 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002168 self.assertEqual(expect, data)
2169 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700217000000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600217100000000 00000000 00000008 fill
217200000008 00000008 00000004 u-boot
21730000000c 0000000c 00000004 section
21740000000c 00000000 00000003 intel-mrc
217500000010 00000010 00000004 u-boot2
217600000014 00000014 0000000c section2
217700000014 00000000 00000008 fill
21780000001c 00000008 00000004 u-boot
217900000020 00000020 00000008 fill2
2180''', map_data)
2181
Simon Glassdd156a42022-03-05 20:18:59 -07002182 def testExtendSizeBad(self):
2183 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002184 with test_util.capture_sys_output() as (stdout, stderr):
2185 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002186 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002187 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2188 'expanding entry', str(e.exception))
2189
Simon Glassae7cf032018-09-14 04:57:31 -06002190 def testHash(self):
2191 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002192 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002193 use_real_dtb=True, update_dtb=True)
2194 dtb = fdt.Fdt(out_dtb_fname)
2195 dtb.Scan()
2196 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2197 m = hashlib.sha256()
2198 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002199 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002200
2201 def testHashNoAlgo(self):
2202 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002203 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002204 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2205 'hash node', str(e.exception))
2206
2207 def testHashBadAlgo(self):
2208 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002209 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002210 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002211 str(e.exception))
2212
2213 def testHashSection(self):
2214 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002215 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002216 use_real_dtb=True, update_dtb=True)
2217 dtb = fdt.Fdt(out_dtb_fname)
2218 dtb.Scan()
2219 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2220 m = hashlib.sha256()
2221 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002222 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002223 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002224
Simon Glass3fb4f422018-09-14 04:57:32 -06002225 def testPackUBootTplMicrocode(self):
2226 """Test that x86 microcode can be handled correctly in TPL
2227
2228 We expect to see the following in the image, in order:
2229 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2230 place
2231 u-boot-tpl.dtb with the microcode removed
2232 the microcode
2233 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002234 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002235 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002236 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002237 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2238 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002239
Simon Glassc64aea52018-09-14 04:57:34 -06002240 def testFmapX86(self):
2241 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002242 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002243 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002244 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002245 self.assertEqual(expected, data[:32])
2246 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2247
2248 self.assertEqual(0x100, fhdr.image_size)
2249
2250 self.assertEqual(0, fentries[0].offset)
2251 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002252 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002253
2254 self.assertEqual(4, fentries[1].offset)
2255 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002256 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002257
2258 self.assertEqual(32, fentries[2].offset)
2259 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2260 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002261 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002262
2263 def testFmapX86Section(self):
2264 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002265 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002266 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002267 self.assertEqual(expected, data[:32])
2268 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2269
Simon Glassb1d414c2021-04-03 11:05:10 +13002270 self.assertEqual(0x180, fhdr.image_size)
2271 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002272 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002273
Simon Glass82059c22021-04-03 11:05:09 +13002274 fentry = next(fiter)
2275 self.assertEqual(b'U_BOOT', fentry.name)
2276 self.assertEqual(0, fentry.offset)
2277 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002278
Simon Glass82059c22021-04-03 11:05:09 +13002279 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002280 self.assertEqual(b'SECTION', fentry.name)
2281 self.assertEqual(4, fentry.offset)
2282 self.assertEqual(0x20 + expect_size, fentry.size)
2283
2284 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002285 self.assertEqual(b'INTEL_MRC', fentry.name)
2286 self.assertEqual(4, fentry.offset)
2287 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002288
Simon Glass82059c22021-04-03 11:05:09 +13002289 fentry = next(fiter)
2290 self.assertEqual(b'FMAP', fentry.name)
2291 self.assertEqual(36, fentry.offset)
2292 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002293
Simon Glassb1714232018-09-14 04:57:35 -06002294 def testElf(self):
2295 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002296 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002297 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002298 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002299 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002300 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002301
Simon Glass0d673792019-07-08 13:18:25 -06002302 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002303 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002304 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002305 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002306 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002307 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002308
Simon Glasscd817d52018-09-14 04:57:36 -06002309 def testPackOverlapMap(self):
2310 """Test that overlapping regions are detected"""
2311 with test_util.capture_sys_output() as (stdout, stderr):
2312 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002313 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002314 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002315 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2316 stdout.getvalue())
2317
2318 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002319 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002320 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002321 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002322 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002323<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002324<none> 00000000 00000004 u-boot
2325<none> 00000003 00000004 u-boot-align
2326''', map_data)
2327
Simon Glass0d673792019-07-08 13:18:25 -06002328 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002329 """Test that an image with an Intel Reference code binary works"""
2330 data = self._DoReadFile('100_intel_refcode.dts')
2331 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2332
Simon Glasseb023b32019-04-25 21:58:39 -06002333 def testSectionOffset(self):
2334 """Tests use of a section with an offset"""
2335 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2336 map=True)
2337 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700233800000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600233900000004 00000004 00000010 section@0
234000000004 00000000 00000004 u-boot
234100000018 00000018 00000010 section@1
234200000018 00000000 00000004 u-boot
23430000002c 0000002c 00000004 section@2
23440000002c 00000000 00000004 u-boot
2345''', map_data)
2346 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002347 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2348 tools.get_bytes(0x21, 12) +
2349 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2350 tools.get_bytes(0x61, 12) +
2351 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2352 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002353
Simon Glass1de34482019-07-08 13:18:53 -06002354 def testCbfsRaw(self):
2355 """Test base handling of a Coreboot Filesystem (CBFS)
2356
2357 The exact contents of the CBFS is verified by similar tests in
2358 cbfs_util_test.py. The tests here merely check that the files added to
2359 the CBFS can be found in the final image.
2360 """
2361 data = self._DoReadFile('102_cbfs_raw.dts')
2362 size = 0xb0
2363
2364 cbfs = cbfs_util.CbfsReader(data)
2365 self.assertEqual(size, cbfs.rom_size)
2366
2367 self.assertIn('u-boot-dtb', cbfs.files)
2368 cfile = cbfs.files['u-boot-dtb']
2369 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2370
2371 def testCbfsArch(self):
2372 """Test on non-x86 architecture"""
2373 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2374 size = 0x100
2375
2376 cbfs = cbfs_util.CbfsReader(data)
2377 self.assertEqual(size, cbfs.rom_size)
2378
2379 self.assertIn('u-boot-dtb', cbfs.files)
2380 cfile = cbfs.files['u-boot-dtb']
2381 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2382
2383 def testCbfsStage(self):
2384 """Tests handling of a Coreboot Filesystem (CBFS)"""
2385 if not elf.ELF_TOOLS:
2386 self.skipTest('Python elftools not available')
2387 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2388 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2389 size = 0xb0
2390
2391 data = self._DoReadFile('104_cbfs_stage.dts')
2392 cbfs = cbfs_util.CbfsReader(data)
2393 self.assertEqual(size, cbfs.rom_size)
2394
2395 self.assertIn('u-boot', cbfs.files)
2396 cfile = cbfs.files['u-boot']
2397 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2398
2399 def testCbfsRawCompress(self):
2400 """Test handling of compressing raw files"""
2401 self._CheckLz4()
2402 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2403 size = 0x140
2404
2405 cbfs = cbfs_util.CbfsReader(data)
2406 self.assertIn('u-boot', cbfs.files)
2407 cfile = cbfs.files['u-boot']
2408 self.assertEqual(COMPRESS_DATA, cfile.data)
2409
2410 def testCbfsBadArch(self):
2411 """Test handling of a bad architecture"""
2412 with self.assertRaises(ValueError) as e:
2413 self._DoReadFile('106_cbfs_bad_arch.dts')
2414 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2415
2416 def testCbfsNoSize(self):
2417 """Test handling of a missing size property"""
2418 with self.assertRaises(ValueError) as e:
2419 self._DoReadFile('107_cbfs_no_size.dts')
2420 self.assertIn('entry must have a size property', str(e.exception))
2421
Simon Glass3e28f4f2021-11-23 11:03:54 -07002422 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002423 """Test handling of a CBFS entry which does not provide contentsy"""
2424 with self.assertRaises(ValueError) as e:
2425 self._DoReadFile('108_cbfs_no_contents.dts')
2426 self.assertIn('Could not complete processing of contents',
2427 str(e.exception))
2428
2429 def testCbfsBadCompress(self):
2430 """Test handling of a bad architecture"""
2431 with self.assertRaises(ValueError) as e:
2432 self._DoReadFile('109_cbfs_bad_compress.dts')
2433 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2434 str(e.exception))
2435
2436 def testCbfsNamedEntries(self):
2437 """Test handling of named entries"""
2438 data = self._DoReadFile('110_cbfs_name.dts')
2439
2440 cbfs = cbfs_util.CbfsReader(data)
2441 self.assertIn('FRED', cbfs.files)
2442 cfile1 = cbfs.files['FRED']
2443 self.assertEqual(U_BOOT_DATA, cfile1.data)
2444
2445 self.assertIn('hello', cbfs.files)
2446 cfile2 = cbfs.files['hello']
2447 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2448
Simon Glass759af872019-07-08 13:18:54 -06002449 def _SetupIfwi(self, fname):
2450 """Set up to run an IFWI test
2451
2452 Args:
2453 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2454 """
2455 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002456 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002457
2458 # Intel Integrated Firmware Image (IFWI) file
2459 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2460 data = fd.read()
2461 TestFunctional._MakeInputFile(fname,data)
2462
2463 def _CheckIfwi(self, data):
2464 """Check that an image with an IFWI contains the correct output
2465
2466 Args:
2467 data: Conents of output file
2468 """
Simon Glass80025522022-01-29 14:14:04 -07002469 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002470 if data[:0x1000] != expected_desc:
2471 self.fail('Expected descriptor binary at start of image')
2472
2473 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002474 image_fname = tools.get_output_filename('image.bin')
2475 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002476 ifwitool = bintool.Bintool.create('ifwitool')
2477 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002478
Simon Glass80025522022-01-29 14:14:04 -07002479 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002480 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002481
2482 def testPackX86RomIfwi(self):
2483 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2484 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002485 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002486 self._CheckIfwi(data)
2487
2488 def testPackX86RomIfwiNoDesc(self):
2489 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2490 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002491 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002492 self._CheckIfwi(data)
2493
2494 def testPackX86RomIfwiNoData(self):
2495 """Test that an x86 ROM with IFWI handles missing data"""
2496 self._SetupIfwi('ifwi.bin')
2497 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002498 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002499 self.assertIn('Could not complete processing of contents',
2500 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002501
Simon Glass66152ce2022-01-09 20:14:09 -07002502 def testIfwiMissing(self):
2503 """Test that binman still produces an image if ifwitool is missing"""
2504 self._SetupIfwi('fitimage.bin')
2505 with test_util.capture_sys_output() as (_, stderr):
2506 self._DoTestFile('111_x86_rom_ifwi.dts',
2507 force_missing_bintools='ifwitool')
2508 err = stderr.getvalue()
2509 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002510 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002511
Simon Glassc2f1aed2019-07-08 13:18:56 -06002512 def testCbfsOffset(self):
2513 """Test a CBFS with files at particular offsets
2514
2515 Like all CFBS tests, this is just checking the logic that calls
2516 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2517 """
2518 data = self._DoReadFile('114_cbfs_offset.dts')
2519 size = 0x200
2520
2521 cbfs = cbfs_util.CbfsReader(data)
2522 self.assertEqual(size, cbfs.rom_size)
2523
2524 self.assertIn('u-boot', cbfs.files)
2525 cfile = cbfs.files['u-boot']
2526 self.assertEqual(U_BOOT_DATA, cfile.data)
2527 self.assertEqual(0x40, cfile.cbfs_offset)
2528
2529 self.assertIn('u-boot-dtb', cbfs.files)
2530 cfile2 = cbfs.files['u-boot-dtb']
2531 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2532 self.assertEqual(0x140, cfile2.cbfs_offset)
2533
Simon Glass0f621332019-07-08 14:25:27 -06002534 def testFdtmap(self):
2535 """Test an FDT map can be inserted in the image"""
2536 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2537 fdtmap_data = data[len(U_BOOT_DATA):]
2538 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002539 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002540 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002541
2542 fdt_data = fdtmap_data[16:]
2543 dtb = fdt.Fdt.FromData(fdt_data)
2544 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002545 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002546 self.assertEqual({
2547 'image-pos': 0,
2548 'offset': 0,
2549 'u-boot:offset': 0,
2550 'u-boot:size': len(U_BOOT_DATA),
2551 'u-boot:image-pos': 0,
2552 'fdtmap:image-pos': 4,
2553 'fdtmap:offset': 4,
2554 'fdtmap:size': len(fdtmap_data),
2555 'size': len(data),
2556 }, props)
2557
2558 def testFdtmapNoMatch(self):
2559 """Check handling of an FDT map when the section cannot be found"""
2560 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2561
2562 # Mangle the section name, which should cause a mismatch between the
2563 # correct FDT path and the one expected by the section
2564 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002565 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002566 entries = image.GetEntries()
2567 fdtmap = entries['fdtmap']
2568 with self.assertRaises(ValueError) as e:
2569 fdtmap._GetFdtmap()
2570 self.assertIn("Cannot locate node for path '/binman-suffix'",
2571 str(e.exception))
2572
Simon Glasscec34ba2019-07-08 14:25:28 -06002573 def testFdtmapHeader(self):
2574 """Test an FDT map and image header can be inserted in the image"""
2575 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2576 fdtmap_pos = len(U_BOOT_DATA)
2577 fdtmap_data = data[fdtmap_pos:]
2578 fdt_data = fdtmap_data[16:]
2579 dtb = fdt.Fdt.FromData(fdt_data)
2580 fdt_size = dtb.GetFdtObj().totalsize()
2581 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002582 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002583 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2584 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2585
2586 def testFdtmapHeaderStart(self):
2587 """Test an image header can be inserted at the image start"""
2588 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2589 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2590 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002591 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002592 offset = struct.unpack('<I', hdr_data[4:])[0]
2593 self.assertEqual(fdtmap_pos, offset)
2594
2595 def testFdtmapHeaderPos(self):
2596 """Test an image header can be inserted at a chosen position"""
2597 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2598 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2599 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002600 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002601 offset = struct.unpack('<I', hdr_data[4:])[0]
2602 self.assertEqual(fdtmap_pos, offset)
2603
2604 def testHeaderMissingFdtmap(self):
2605 """Test an image header requires an fdtmap"""
2606 with self.assertRaises(ValueError) as e:
2607 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2608 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2609 str(e.exception))
2610
2611 def testHeaderNoLocation(self):
2612 """Test an image header with a no specified location is detected"""
2613 with self.assertRaises(ValueError) as e:
2614 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2615 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2616 str(e.exception))
2617
Simon Glasse61b6f62019-07-08 14:25:37 -06002618 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002619 """Test extending an entry after it is packed"""
2620 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002621 self.assertEqual(b'aaa', data[:3])
2622 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2623 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002624
Simon Glassdd156a42022-03-05 20:18:59 -07002625 def testEntryExtendBad(self):
2626 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002627 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002628 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002629 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002630 str(e.exception))
2631
Simon Glassdd156a42022-03-05 20:18:59 -07002632 def testEntryExtendSection(self):
2633 """Test extending an entry within a section after it is packed"""
2634 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002635 self.assertEqual(b'aaa', data[:3])
2636 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2637 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002638
Simon Glass90d29682019-07-08 14:25:38 -06002639 def testCompressDtb(self):
2640 """Test that compress of device-tree files is supported"""
2641 self._CheckLz4()
2642 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2643 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2644 comp_data = data[len(U_BOOT_DATA):]
2645 orig = self._decompress(comp_data)
2646 dtb = fdt.Fdt.FromData(orig)
2647 dtb.Scan()
2648 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2649 expected = {
2650 'u-boot:size': len(U_BOOT_DATA),
2651 'u-boot-dtb:uncomp-size': len(orig),
2652 'u-boot-dtb:size': len(comp_data),
2653 'size': len(data),
2654 }
2655 self.assertEqual(expected, props)
2656
Simon Glass151bbbf2019-07-08 14:25:41 -06002657 def testCbfsUpdateFdt(self):
2658 """Test that we can update the device tree with CBFS offset/size info"""
2659 self._CheckLz4()
2660 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2661 update_dtb=True)
2662 dtb = fdt.Fdt(out_dtb_fname)
2663 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002664 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002665 del props['cbfs/u-boot:size']
2666 self.assertEqual({
2667 'offset': 0,
2668 'size': len(data),
2669 'image-pos': 0,
2670 'cbfs:offset': 0,
2671 'cbfs:size': len(data),
2672 'cbfs:image-pos': 0,
Simon Glassfa144222023-10-14 14:40:28 -06002673 'cbfs/u-boot:offset': 0x30,
Simon Glass151bbbf2019-07-08 14:25:41 -06002674 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002675 'cbfs/u-boot:image-pos': 0x30,
2676 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002677 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002678 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002679 }, props)
2680
Simon Glass3c9b4f22019-07-08 14:25:42 -06002681 def testCbfsBadType(self):
2682 """Test an image header with a no specified location is detected"""
2683 with self.assertRaises(ValueError) as e:
2684 self._DoReadFile('126_cbfs_bad_type.dts')
2685 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2686
Simon Glass6b156f82019-07-08 14:25:43 -06002687 def testList(self):
2688 """Test listing the files in an image"""
2689 self._CheckLz4()
2690 data = self._DoReadFile('127_list.dts')
2691 image = control.images['image']
2692 entries = image.BuildEntryList()
2693 self.assertEqual(7, len(entries))
2694
2695 ent = entries[0]
2696 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002697 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002698 self.assertEqual('section', ent.etype)
2699 self.assertEqual(len(data), ent.size)
2700 self.assertEqual(0, ent.image_pos)
2701 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002702 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002703
2704 ent = entries[1]
2705 self.assertEqual(1, ent.indent)
2706 self.assertEqual('u-boot', ent.name)
2707 self.assertEqual('u-boot', ent.etype)
2708 self.assertEqual(len(U_BOOT_DATA), ent.size)
2709 self.assertEqual(0, ent.image_pos)
2710 self.assertEqual(None, ent.uncomp_size)
2711 self.assertEqual(0, ent.offset)
2712
2713 ent = entries[2]
2714 self.assertEqual(1, ent.indent)
2715 self.assertEqual('section', ent.name)
2716 self.assertEqual('section', ent.etype)
2717 section_size = ent.size
2718 self.assertEqual(0x100, ent.image_pos)
2719 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002720 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002721
2722 ent = entries[3]
2723 self.assertEqual(2, ent.indent)
2724 self.assertEqual('cbfs', ent.name)
2725 self.assertEqual('cbfs', ent.etype)
2726 self.assertEqual(0x400, ent.size)
2727 self.assertEqual(0x100, ent.image_pos)
2728 self.assertEqual(None, ent.uncomp_size)
2729 self.assertEqual(0, ent.offset)
2730
2731 ent = entries[4]
2732 self.assertEqual(3, ent.indent)
2733 self.assertEqual('u-boot', ent.name)
2734 self.assertEqual('u-boot', ent.etype)
2735 self.assertEqual(len(U_BOOT_DATA), ent.size)
2736 self.assertEqual(0x138, ent.image_pos)
2737 self.assertEqual(None, ent.uncomp_size)
2738 self.assertEqual(0x38, ent.offset)
2739
2740 ent = entries[5]
2741 self.assertEqual(3, ent.indent)
2742 self.assertEqual('u-boot-dtb', ent.name)
2743 self.assertEqual('text', ent.etype)
2744 self.assertGreater(len(COMPRESS_DATA), ent.size)
2745 self.assertEqual(0x178, ent.image_pos)
2746 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2747 self.assertEqual(0x78, ent.offset)
2748
2749 ent = entries[6]
2750 self.assertEqual(2, ent.indent)
2751 self.assertEqual('u-boot-dtb', ent.name)
2752 self.assertEqual('u-boot-dtb', ent.etype)
2753 self.assertEqual(0x500, ent.image_pos)
2754 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2755 dtb_size = ent.size
2756 # Compressing this data expands it since headers are added
2757 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2758 self.assertEqual(0x400, ent.offset)
2759
2760 self.assertEqual(len(data), 0x100 + section_size)
2761 self.assertEqual(section_size, 0x400 + dtb_size)
2762
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002763 def testFindFdtmap(self):
2764 """Test locating an FDT map in an image"""
2765 self._CheckLz4()
2766 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2767 image = control.images['image']
2768 entries = image.GetEntries()
2769 entry = entries['fdtmap']
2770 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2771
2772 def testFindFdtmapMissing(self):
2773 """Test failing to locate an FDP map"""
2774 data = self._DoReadFile('005_simple.dts')
2775 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2776
Simon Glassed39a3c2019-07-08 14:25:45 -06002777 def testFindImageHeader(self):
2778 """Test locating a image header"""
2779 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002780 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002781 image = control.images['image']
2782 entries = image.GetEntries()
2783 entry = entries['fdtmap']
2784 # The header should point to the FDT map
2785 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2786
2787 def testFindImageHeaderStart(self):
2788 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002789 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002790 image = control.images['image']
2791 entries = image.GetEntries()
2792 entry = entries['fdtmap']
2793 # The header should point to the FDT map
2794 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2795
2796 def testFindImageHeaderMissing(self):
2797 """Test failing to locate an image header"""
2798 data = self._DoReadFile('005_simple.dts')
2799 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2800
Simon Glassb8424fa2019-07-08 14:25:46 -06002801 def testReadImage(self):
2802 """Test reading an image and accessing its FDT map"""
2803 self._CheckLz4()
2804 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002805 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002806 orig_image = control.images['image']
2807 image = Image.FromFile(image_fname)
2808 self.assertEqual(orig_image.GetEntries().keys(),
2809 image.GetEntries().keys())
2810
2811 orig_entry = orig_image.GetEntries()['fdtmap']
2812 entry = image.GetEntries()['fdtmap']
Brandon Maiera657bc62024-06-04 16:16:05 +00002813 self.assertEqual(orig_entry.offset, entry.offset)
2814 self.assertEqual(orig_entry.size, entry.size)
2815 self.assertEqual(orig_entry.image_pos, entry.image_pos)
Simon Glassb8424fa2019-07-08 14:25:46 -06002816
2817 def testReadImageNoHeader(self):
2818 """Test accessing an image's FDT map without an image header"""
2819 self._CheckLz4()
2820 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002821 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002822 image = Image.FromFile(image_fname)
2823 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002824 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002825
2826 def testReadImageFail(self):
2827 """Test failing to read an image image's FDT map"""
2828 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002829 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002830 with self.assertRaises(ValueError) as e:
2831 image = Image.FromFile(image_fname)
2832 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002833
Simon Glassb2fd11d2019-07-08 14:25:48 -06002834 def testListCmd(self):
2835 """Test listing the files in an image using an Fdtmap"""
2836 self._CheckLz4()
2837 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2838
2839 # lz4 compression size differs depending on the version
2840 image = control.images['image']
2841 entries = image.GetEntries()
2842 section_size = entries['section'].size
2843 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2844 fdtmap_offset = entries['fdtmap'].offset
2845
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002846 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002847 try:
2848 tmpdir, updated_fname = self._SetupImageInTmpdir()
2849 with test_util.capture_sys_output() as (stdout, stderr):
2850 self._DoBinman('ls', '-i', updated_fname)
2851 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002852 if tmpdir:
2853 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002854 lines = stdout.getvalue().splitlines()
2855 expected = [
2856'Name Image-pos Size Entry-type Offset Uncomp-size',
2857'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002858'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002859' u-boot 0 4 u-boot 0',
2860' section 100 %x section 100' % section_size,
2861' cbfs 100 400 cbfs 0',
Simon Glassfa144222023-10-14 14:40:28 -06002862' u-boot 120 4 u-boot 20',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002863' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002864' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002865' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002866 (fdtmap_offset, fdtmap_offset),
2867' image-header bf8 8 image-header bf8',
2868 ]
2869 self.assertEqual(expected, lines)
2870
2871 def testListCmdFail(self):
2872 """Test failing to list an image"""
2873 self._DoReadFile('005_simple.dts')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002874 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002875 try:
2876 tmpdir, updated_fname = self._SetupImageInTmpdir()
2877 with self.assertRaises(ValueError) as e:
2878 self._DoBinman('ls', '-i', updated_fname)
2879 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002880 if tmpdir:
2881 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002882 self.assertIn("Cannot find FDT map in image", str(e.exception))
2883
2884 def _RunListCmd(self, paths, expected):
2885 """List out entries and check the result
2886
2887 Args:
2888 paths: List of paths to pass to the list command
2889 expected: Expected list of filenames to be returned, in order
2890 """
2891 self._CheckLz4()
2892 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002893 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002894 image = Image.FromFile(image_fname)
2895 lines = image.GetListEntries(paths)[1]
2896 files = [line[0].strip() for line in lines[1:]]
2897 self.assertEqual(expected, files)
2898
2899 def testListCmdSection(self):
2900 """Test listing the files in a section"""
2901 self._RunListCmd(['section'],
2902 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2903
2904 def testListCmdFile(self):
2905 """Test listing a particular file"""
2906 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2907
2908 def testListCmdWildcard(self):
2909 """Test listing a wildcarded file"""
2910 self._RunListCmd(['*boot*'],
2911 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2912
2913 def testListCmdWildcardMulti(self):
2914 """Test listing a wildcarded file"""
2915 self._RunListCmd(['*cb*', '*head*'],
2916 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2917
2918 def testListCmdEmpty(self):
2919 """Test listing a wildcarded file"""
2920 self._RunListCmd(['nothing'], [])
2921
2922 def testListCmdPath(self):
2923 """Test listing the files in a sub-entry of a section"""
2924 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2925
Simon Glass4c613bf2019-07-08 14:25:50 -06002926 def _RunExtractCmd(self, entry_name, decomp=True):
2927 """Extract an entry from an image
2928
2929 Args:
2930 entry_name: Entry name to extract
2931 decomp: True to decompress the data if compressed, False to leave
2932 it in its raw uncompressed format
2933
2934 Returns:
2935 data from entry
2936 """
2937 self._CheckLz4()
2938 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002939 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002940 return control.ReadEntry(image_fname, entry_name, decomp)
2941
2942 def testExtractSimple(self):
2943 """Test extracting a single file"""
2944 data = self._RunExtractCmd('u-boot')
2945 self.assertEqual(U_BOOT_DATA, data)
2946
Simon Glass980a2842019-07-08 14:25:52 -06002947 def testExtractSection(self):
2948 """Test extracting the files in a section"""
2949 data = self._RunExtractCmd('section')
2950 cbfs_data = data[:0x400]
2951 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002952 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002953 dtb_data = data[0x400:]
2954 dtb = self._decompress(dtb_data)
2955 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2956
2957 def testExtractCompressed(self):
2958 """Test extracting compressed data"""
2959 data = self._RunExtractCmd('section/u-boot-dtb')
2960 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2961
2962 def testExtractRaw(self):
2963 """Test extracting compressed data without decompressing it"""
2964 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2965 dtb = self._decompress(data)
2966 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2967
2968 def testExtractCbfs(self):
2969 """Test extracting CBFS data"""
2970 data = self._RunExtractCmd('section/cbfs/u-boot')
2971 self.assertEqual(U_BOOT_DATA, data)
2972
2973 def testExtractCbfsCompressed(self):
2974 """Test extracting CBFS compressed data"""
2975 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2976 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2977
2978 def testExtractCbfsRaw(self):
2979 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002980 bintool = self.comp_bintools['lzma_alone']
2981 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06002982 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002983 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06002984 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2985
Simon Glass4c613bf2019-07-08 14:25:50 -06002986 def testExtractBadEntry(self):
2987 """Test extracting a bad section path"""
2988 with self.assertRaises(ValueError) as e:
2989 self._RunExtractCmd('section/does-not-exist')
2990 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2991 str(e.exception))
2992
2993 def testExtractMissingFile(self):
2994 """Test extracting file that does not exist"""
2995 with self.assertRaises(IOError) as e:
2996 control.ReadEntry('missing-file', 'name')
2997
2998 def testExtractBadFile(self):
2999 """Test extracting an invalid file"""
3000 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07003001 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06003002 with self.assertRaises(ValueError) as e:
3003 control.ReadEntry(fname, 'name')
3004
Simon Glass980a2842019-07-08 14:25:52 -06003005 def testExtractCmd(self):
3006 """Test extracting a file fron an image on the command line"""
3007 self._CheckLz4()
3008 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06003009 fname = os.path.join(self._indir, 'output.extact')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003010 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06003011 try:
3012 tmpdir, updated_fname = self._SetupImageInTmpdir()
3013 with test_util.capture_sys_output() as (stdout, stderr):
3014 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3015 '-f', fname)
3016 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003017 if tmpdir:
3018 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07003019 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003020 self.assertEqual(U_BOOT_DATA, data)
3021
3022 def testExtractOneEntry(self):
3023 """Test extracting a single entry fron an image """
3024 self._CheckLz4()
3025 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003026 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003027 fname = os.path.join(self._indir, 'output.extact')
3028 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003029 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003030 self.assertEqual(U_BOOT_DATA, data)
3031
3032 def _CheckExtractOutput(self, decomp):
3033 """Helper to test file output with and without decompression
3034
3035 Args:
3036 decomp: True to decompress entry data, False to output it raw
3037 """
3038 def _CheckPresent(entry_path, expect_data, expect_size=None):
3039 """Check and remove expected file
3040
3041 This checks the data/size of a file and removes the file both from
3042 the outfiles set and from the output directory. Once all files are
3043 processed, both the set and directory should be empty.
3044
3045 Args:
3046 entry_path: Entry path
3047 expect_data: Data to expect in file, or None to skip check
3048 expect_size: Size of data to expect in file, or None to skip
3049 """
3050 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003051 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003052 os.remove(path)
3053 if expect_data:
3054 self.assertEqual(expect_data, data)
3055 elif expect_size:
3056 self.assertEqual(expect_size, len(data))
3057 outfiles.remove(path)
3058
3059 def _CheckDirPresent(name):
3060 """Remove expected directory
3061
3062 This gives an error if the directory does not exist as expected
3063
3064 Args:
3065 name: Name of directory to remove
3066 """
3067 path = os.path.join(outdir, name)
3068 os.rmdir(path)
3069
3070 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003071 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003072 outdir = os.path.join(self._indir, 'extract')
3073 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3074
3075 # Create a set of all file that were output (should be 9)
3076 outfiles = set()
3077 for root, dirs, files in os.walk(outdir):
3078 outfiles |= set([os.path.join(root, fname) for fname in files])
3079 self.assertEqual(9, len(outfiles))
3080 self.assertEqual(9, len(einfos))
3081
3082 image = control.images['image']
3083 entries = image.GetEntries()
3084
3085 # Check the 9 files in various ways
3086 section = entries['section']
3087 section_entries = section.GetEntries()
3088 cbfs_entries = section_entries['cbfs'].GetEntries()
3089 _CheckPresent('u-boot', U_BOOT_DATA)
3090 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3091 dtb_len = EXTRACT_DTB_SIZE
3092 if not decomp:
3093 dtb_len = cbfs_entries['u-boot-dtb'].size
3094 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3095 if not decomp:
3096 dtb_len = section_entries['u-boot-dtb'].size
3097 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3098
3099 fdtmap = entries['fdtmap']
3100 _CheckPresent('fdtmap', fdtmap.data)
3101 hdr = entries['image-header']
3102 _CheckPresent('image-header', hdr.data)
3103
3104 _CheckPresent('section/root', section.data)
3105 cbfs = section_entries['cbfs']
3106 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003107 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003108 _CheckPresent('root', data)
3109
3110 # There should be no files left. Remove all the directories to check.
3111 # If there are any files/dirs remaining, one of these checks will fail.
3112 self.assertEqual(0, len(outfiles))
3113 _CheckDirPresent('section/cbfs')
3114 _CheckDirPresent('section')
3115 _CheckDirPresent('')
3116 self.assertFalse(os.path.exists(outdir))
3117
3118 def testExtractAllEntries(self):
3119 """Test extracting all entries"""
3120 self._CheckLz4()
3121 self._CheckExtractOutput(decomp=True)
3122
3123 def testExtractAllEntriesRaw(self):
3124 """Test extracting all entries without decompressing them"""
3125 self._CheckLz4()
3126 self._CheckExtractOutput(decomp=False)
3127
3128 def testExtractSelectedEntries(self):
3129 """Test extracting some entries"""
3130 self._CheckLz4()
3131 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003132 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003133 outdir = os.path.join(self._indir, 'extract')
3134 einfos = control.ExtractEntries(image_fname, None, outdir,
3135 ['*cb*', '*head*'])
3136
3137 # File output is tested by testExtractAllEntries(), so just check that
3138 # the expected entries are selected
3139 names = [einfo.name for einfo in einfos]
3140 self.assertEqual(names,
3141 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3142
3143 def testExtractNoEntryPaths(self):
3144 """Test extracting some entries"""
3145 self._CheckLz4()
3146 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003147 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003148 with self.assertRaises(ValueError) as e:
3149 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003150 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003151 str(e.exception))
3152
3153 def testExtractTooManyEntryPaths(self):
3154 """Test extracting some entries"""
3155 self._CheckLz4()
3156 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003157 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003158 with self.assertRaises(ValueError) as e:
3159 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003160 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003161 str(e.exception))
3162
Simon Glass52d06212019-07-08 14:25:53 -06003163 def testPackAlignSection(self):
3164 """Test that sections can have alignment"""
3165 self._DoReadFile('131_pack_align_section.dts')
3166
3167 self.assertIn('image', control.images)
3168 image = control.images['image']
3169 entries = image.GetEntries()
3170 self.assertEqual(3, len(entries))
3171
3172 # First u-boot
3173 self.assertIn('u-boot', entries)
3174 entry = entries['u-boot']
3175 self.assertEqual(0, entry.offset)
3176 self.assertEqual(0, entry.image_pos)
3177 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3178 self.assertEqual(len(U_BOOT_DATA), entry.size)
3179
3180 # Section0
3181 self.assertIn('section0', entries)
3182 section0 = entries['section0']
3183 self.assertEqual(0x10, section0.offset)
3184 self.assertEqual(0x10, section0.image_pos)
3185 self.assertEqual(len(U_BOOT_DATA), section0.size)
3186
3187 # Second u-boot
3188 section_entries = section0.GetEntries()
3189 self.assertIn('u-boot', section_entries)
3190 entry = section_entries['u-boot']
3191 self.assertEqual(0, entry.offset)
3192 self.assertEqual(0x10, entry.image_pos)
3193 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3194 self.assertEqual(len(U_BOOT_DATA), entry.size)
3195
3196 # Section1
3197 self.assertIn('section1', entries)
3198 section1 = entries['section1']
3199 self.assertEqual(0x14, section1.offset)
3200 self.assertEqual(0x14, section1.image_pos)
3201 self.assertEqual(0x20, section1.size)
3202
3203 # Second u-boot
3204 section_entries = section1.GetEntries()
3205 self.assertIn('u-boot', section_entries)
3206 entry = section_entries['u-boot']
3207 self.assertEqual(0, entry.offset)
3208 self.assertEqual(0x14, entry.image_pos)
3209 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3210 self.assertEqual(len(U_BOOT_DATA), entry.size)
3211
3212 # Section2
3213 self.assertIn('section2', section_entries)
3214 section2 = section_entries['section2']
3215 self.assertEqual(0x4, section2.offset)
3216 self.assertEqual(0x18, section2.image_pos)
3217 self.assertEqual(4, section2.size)
3218
3219 # Third u-boot
3220 section_entries = section2.GetEntries()
3221 self.assertIn('u-boot', section_entries)
3222 entry = section_entries['u-boot']
3223 self.assertEqual(0, entry.offset)
3224 self.assertEqual(0x18, entry.image_pos)
3225 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3226 self.assertEqual(len(U_BOOT_DATA), entry.size)
3227
Simon Glassf8a54bc2019-07-20 12:23:56 -06003228 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3229 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003230 """Replace an entry in an image
3231
3232 This writes the entry data to update it, then opens the updated file and
3233 returns the value that it now finds there.
3234
3235 Args:
3236 entry_name: Entry name to replace
3237 data: Data to replace it with
3238 decomp: True to compress the data if needed, False if data is
3239 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003240 allow_resize: True to allow entries to change size, False to raise
3241 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003242
3243 Returns:
3244 Tuple:
3245 data from entry
3246 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003247 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003248 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003249 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003250 update_dtb=True)[1]
3251
3252 self.assertIn('image', control.images)
3253 image = control.images['image']
3254 entries = image.GetEntries()
3255 orig_dtb_data = entries['u-boot-dtb'].data
3256 orig_fdtmap_data = entries['fdtmap'].data
3257
Simon Glass80025522022-01-29 14:14:04 -07003258 image_fname = tools.get_output_filename('image.bin')
3259 updated_fname = tools.get_output_filename('image-updated.bin')
3260 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003261 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3262 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003263 data = control.ReadEntry(updated_fname, entry_name, decomp)
3264
Simon Glassf8a54bc2019-07-20 12:23:56 -06003265 # The DT data should not change unless resized:
3266 if not allow_resize:
3267 new_dtb_data = entries['u-boot-dtb'].data
3268 self.assertEqual(new_dtb_data, orig_dtb_data)
3269 new_fdtmap_data = entries['fdtmap'].data
3270 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003271
Simon Glassf8a54bc2019-07-20 12:23:56 -06003272 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003273
3274 def testReplaceSimple(self):
3275 """Test replacing a single file"""
3276 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003277 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3278 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003279 self.assertEqual(expected, data)
3280
3281 # Test that the state looks right. There should be an FDT for the fdtmap
3282 # that we jsut read back in, and it should match what we find in the
3283 # 'control' tables. Checking for an FDT that does not exist should
3284 # return None.
3285 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003286 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003287 self.assertEqual(expected_fdtmap, fdtmap)
3288
3289 dtb = state.GetFdtForEtype('fdtmap')
3290 self.assertEqual(dtb.GetContents(), fdtmap)
3291
3292 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3293 self.assertIsNone(missing_path)
3294 self.assertIsNone(missing_fdtmap)
3295
3296 missing_dtb = state.GetFdtForEtype('missing')
3297 self.assertIsNone(missing_dtb)
3298
3299 self.assertEqual('/binman', state.fdt_path_prefix)
3300
3301 def testReplaceResizeFail(self):
3302 """Test replacing a file by something larger"""
3303 expected = U_BOOT_DATA + b'x'
3304 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003305 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3306 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003307 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3308 str(e.exception))
3309
3310 def testReplaceMulti(self):
3311 """Test replacing entry data where multiple images are generated"""
3312 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3313 update_dtb=True)[0]
3314 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003315 updated_fname = tools.get_output_filename('image-updated.bin')
3316 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003317 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003318 control.WriteEntry(updated_fname, entry_name, expected,
3319 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003320 data = control.ReadEntry(updated_fname, entry_name)
3321 self.assertEqual(expected, data)
3322
3323 # Check the state looks right.
3324 self.assertEqual('/binman/image', state.fdt_path_prefix)
3325
3326 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003327 image_fname = tools.get_output_filename('first-image.bin')
3328 updated_fname = tools.get_output_filename('first-updated.bin')
3329 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003330 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003331 control.WriteEntry(updated_fname, entry_name, expected,
3332 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003333 data = control.ReadEntry(updated_fname, entry_name)
3334 self.assertEqual(expected, data)
3335
3336 # Check the state looks right.
3337 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003338
Simon Glassfb30e292019-07-20 12:23:51 -06003339 def testUpdateFdtAllRepack(self):
3340 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003341 self._SetupSplElf()
3342 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003343 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3344 SECTION_SIZE = 0x300
3345 DTB_SIZE = 602
3346 FDTMAP_SIZE = 608
3347 base_expected = {
3348 'offset': 0,
3349 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3350 'image-pos': 0,
3351 'section:offset': 0,
3352 'section:size': SECTION_SIZE,
3353 'section:image-pos': 0,
3354 'section/u-boot-dtb:offset': 4,
3355 'section/u-boot-dtb:size': 636,
3356 'section/u-boot-dtb:image-pos': 4,
3357 'u-boot-spl-dtb:offset': SECTION_SIZE,
3358 'u-boot-spl-dtb:size': DTB_SIZE,
3359 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3360 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3361 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3362 'u-boot-tpl-dtb:size': DTB_SIZE,
3363 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3364 'fdtmap:size': FDTMAP_SIZE,
3365 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3366 }
3367 main_expected = {
3368 'section:orig-size': SECTION_SIZE,
3369 'section/u-boot-dtb:orig-offset': 4,
3370 }
3371
3372 # We expect three device-tree files in the output, with the first one
3373 # within a fixed-size section.
3374 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3375 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3376 # main U-Boot tree. All three should have the same positions and offset
3377 # except that the main tree should include the main_expected properties
3378 start = 4
3379 for item in ['', 'spl', 'tpl', None]:
3380 if item is None:
3381 start += 16 # Move past fdtmap header
3382 dtb = fdt.Fdt.FromData(data[start:])
3383 dtb.Scan()
3384 props = self._GetPropTree(dtb,
3385 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3386 prefix='/' if item is None else '/binman/')
3387 expected = dict(base_expected)
3388 if item:
3389 expected[item] = 0
3390 else:
3391 # Main DTB and fdtdec should include the 'orig-' properties
3392 expected.update(main_expected)
3393 # Helpful for debugging:
3394 #for prop in sorted(props):
3395 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3396 self.assertEqual(expected, props)
3397 if item == '':
3398 start = SECTION_SIZE
3399 else:
3400 start += dtb._fdt_obj.totalsize()
3401
Simon Glass11453762019-07-20 12:23:55 -06003402 def testFdtmapHeaderMiddle(self):
3403 """Test an FDT map in the middle of an image when it should be at end"""
3404 with self.assertRaises(ValueError) as e:
3405 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3406 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3407 str(e.exception))
3408
3409 def testFdtmapHeaderStartBad(self):
3410 """Test an FDT map in middle of an image when it should be at start"""
3411 with self.assertRaises(ValueError) as e:
3412 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3413 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3414 str(e.exception))
3415
3416 def testFdtmapHeaderEndBad(self):
3417 """Test an FDT map at the start of an image when it should be at end"""
3418 with self.assertRaises(ValueError) as e:
3419 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3420 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3421 str(e.exception))
3422
3423 def testFdtmapHeaderNoSize(self):
3424 """Test an image header at the end of an image with undefined size"""
3425 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3426
Simon Glassf8a54bc2019-07-20 12:23:56 -06003427 def testReplaceResize(self):
3428 """Test replacing a single file in an entry with a larger file"""
3429 expected = U_BOOT_DATA + b'x'
3430 data, _, image = self._RunReplaceCmd('u-boot', expected,
3431 dts='139_replace_repack.dts')
3432 self.assertEqual(expected, data)
3433
3434 entries = image.GetEntries()
3435 dtb_data = entries['u-boot-dtb'].data
3436 dtb = fdt.Fdt.FromData(dtb_data)
3437 dtb.Scan()
3438
3439 # The u-boot section should now be larger in the dtb
3440 node = dtb.GetNode('/binman/u-boot')
3441 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3442
3443 # Same for the fdtmap
3444 fdata = entries['fdtmap'].data
3445 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3446 fdtb.Scan()
3447 fnode = fdtb.GetNode('/u-boot')
3448 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3449
3450 def testReplaceResizeNoRepack(self):
3451 """Test replacing an entry with a larger file when not allowed"""
3452 expected = U_BOOT_DATA + b'x'
3453 with self.assertRaises(ValueError) as e:
3454 self._RunReplaceCmd('u-boot', expected)
3455 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3456 str(e.exception))
3457
Simon Glass9d8ee322019-07-20 12:23:58 -06003458 def testEntryShrink(self):
3459 """Test contracting an entry after it is packed"""
3460 try:
3461 state.SetAllowEntryContraction(True)
3462 data = self._DoReadFileDtb('140_entry_shrink.dts',
3463 update_dtb=True)[0]
3464 finally:
3465 state.SetAllowEntryContraction(False)
3466 self.assertEqual(b'a', data[:1])
3467 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3468 self.assertEqual(b'a', data[-1:])
3469
3470 def testEntryShrinkFail(self):
3471 """Test not being allowed to contract an entry after it is packed"""
3472 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3473
3474 # In this case there is a spare byte at the end of the data. The size of
3475 # the contents is only 1 byte but we still have the size before it
3476 # shrunk.
3477 self.assertEqual(b'a\0', data[:2])
3478 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3479 self.assertEqual(b'a\0', data[-2:])
3480
Simon Glass70e32982019-07-20 12:24:01 -06003481 def testDescriptorOffset(self):
3482 """Test that the Intel descriptor is always placed at at the start"""
3483 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3484 image = control.images['image']
3485 entries = image.GetEntries()
3486 desc = entries['intel-descriptor']
3487 self.assertEqual(0xff800000, desc.offset);
3488 self.assertEqual(0xff800000, desc.image_pos);
3489
Simon Glass37fdd142019-07-20 12:24:06 -06003490 def testReplaceCbfs(self):
3491 """Test replacing a single file in CBFS without changing the size"""
3492 self._CheckLz4()
3493 expected = b'x' * len(U_BOOT_DATA)
3494 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003495 updated_fname = tools.get_output_filename('image-updated.bin')
3496 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003497 entry_name = 'section/cbfs/u-boot'
3498 control.WriteEntry(updated_fname, entry_name, expected,
3499 allow_resize=True)
3500 data = control.ReadEntry(updated_fname, entry_name)
3501 self.assertEqual(expected, data)
3502
3503 def testReplaceResizeCbfs(self):
3504 """Test replacing a single file in CBFS with one of a different size"""
3505 self._CheckLz4()
3506 expected = U_BOOT_DATA + b'x'
3507 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003508 updated_fname = tools.get_output_filename('image-updated.bin')
3509 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003510 entry_name = 'section/cbfs/u-boot'
3511 control.WriteEntry(updated_fname, entry_name, expected,
3512 allow_resize=True)
3513 data = control.ReadEntry(updated_fname, entry_name)
3514 self.assertEqual(expected, data)
3515
Simon Glass30033c22019-07-20 12:24:15 -06003516 def _SetupForReplace(self):
3517 """Set up some files to use to replace entries
3518
3519 This generates an image, copies it to a new file, extracts all the files
3520 in it and updates some of them
3521
3522 Returns:
3523 List
3524 Image filename
3525 Output directory
3526 Expected values for updated entries, each a string
3527 """
3528 data = self._DoReadFileRealDtb('143_replace_all.dts')
3529
Simon Glass80025522022-01-29 14:14:04 -07003530 updated_fname = tools.get_output_filename('image-updated.bin')
3531 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003532
3533 outdir = os.path.join(self._indir, 'extract')
3534 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3535
3536 expected1 = b'x' + U_BOOT_DATA + b'y'
3537 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003538 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003539
3540 expected2 = b'a' + U_BOOT_DATA + b'b'
3541 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003542 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003543
3544 expected_text = b'not the same text'
3545 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003546 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003547
3548 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3549 dtb = fdt.FdtScan(dtb_fname)
3550 node = dtb.GetNode('/binman/text')
3551 node.AddString('my-property', 'the value')
3552 dtb.Sync(auto_resize=True)
3553 dtb.Flush()
3554
3555 return updated_fname, outdir, expected1, expected2, expected_text
3556
3557 def _CheckReplaceMultiple(self, entry_paths):
3558 """Handle replacing the contents of multiple entries
3559
3560 Args:
3561 entry_paths: List of entry paths to replace
3562
3563 Returns:
3564 List
3565 Dict of entries in the image:
3566 key: Entry name
3567 Value: Entry object
3568 Expected values for updated entries, each a string
3569 """
3570 updated_fname, outdir, expected1, expected2, expected_text = (
3571 self._SetupForReplace())
3572 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3573
3574 image = Image.FromFile(updated_fname)
3575 image.LoadData()
3576 return image.GetEntries(), expected1, expected2, expected_text
3577
3578 def testReplaceAll(self):
3579 """Test replacing the contents of all entries"""
3580 entries, expected1, expected2, expected_text = (
3581 self._CheckReplaceMultiple([]))
3582 data = entries['u-boot'].data
3583 self.assertEqual(expected1, data)
3584
3585 data = entries['u-boot2'].data
3586 self.assertEqual(expected2, data)
3587
3588 data = entries['text'].data
3589 self.assertEqual(expected_text, data)
3590
3591 # Check that the device tree is updated
3592 data = entries['u-boot-dtb'].data
3593 dtb = fdt.Fdt.FromData(data)
3594 dtb.Scan()
3595 node = dtb.GetNode('/binman/text')
3596 self.assertEqual('the value', node.props['my-property'].value)
3597
3598 def testReplaceSome(self):
3599 """Test replacing the contents of a few entries"""
3600 entries, expected1, expected2, expected_text = (
3601 self._CheckReplaceMultiple(['u-boot2', 'text']))
3602
3603 # This one should not change
3604 data = entries['u-boot'].data
3605 self.assertEqual(U_BOOT_DATA, data)
3606
3607 data = entries['u-boot2'].data
3608 self.assertEqual(expected2, data)
3609
3610 data = entries['text'].data
3611 self.assertEqual(expected_text, data)
3612
3613 def testReplaceCmd(self):
3614 """Test replacing a file fron an image on the command line"""
3615 self._DoReadFileRealDtb('143_replace_all.dts')
3616
3617 try:
3618 tmpdir, updated_fname = self._SetupImageInTmpdir()
3619
3620 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3621 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003622 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003623
3624 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003625 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003626 self.assertEqual(expected, data[:len(expected)])
3627 map_fname = os.path.join(tmpdir, 'image-updated.map')
3628 self.assertFalse(os.path.exists(map_fname))
3629 finally:
3630 shutil.rmtree(tmpdir)
3631
3632 def testReplaceCmdSome(self):
3633 """Test replacing some files fron an image on the command line"""
3634 updated_fname, outdir, expected1, expected2, expected_text = (
3635 self._SetupForReplace())
3636
3637 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3638 'u-boot2', 'text')
3639
Simon Glass80025522022-01-29 14:14:04 -07003640 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003641 image = Image.FromFile(updated_fname)
3642 image.LoadData()
3643 entries = image.GetEntries()
3644
3645 # This one should not change
3646 data = entries['u-boot'].data
3647 self.assertEqual(U_BOOT_DATA, data)
3648
3649 data = entries['u-boot2'].data
3650 self.assertEqual(expected2, data)
3651
3652 data = entries['text'].data
3653 self.assertEqual(expected_text, data)
3654
3655 def testReplaceMissing(self):
3656 """Test replacing entries where the file is missing"""
3657 updated_fname, outdir, expected1, expected2, expected_text = (
3658 self._SetupForReplace())
3659
3660 # Remove one of the files, to generate a warning
3661 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3662 os.remove(u_boot_fname1)
3663
3664 with test_util.capture_sys_output() as (stdout, stderr):
3665 control.ReplaceEntries(updated_fname, None, outdir, [])
3666 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003667 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003668
3669 def testReplaceCmdMap(self):
3670 """Test replacing a file fron an image on the command line"""
3671 self._DoReadFileRealDtb('143_replace_all.dts')
3672
3673 try:
3674 tmpdir, updated_fname = self._SetupImageInTmpdir()
3675
3676 fname = os.path.join(self._indir, 'update-u-boot.bin')
3677 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003678 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003679
3680 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3681 '-f', fname, '-m')
3682 map_fname = os.path.join(tmpdir, 'image-updated.map')
3683 self.assertTrue(os.path.exists(map_fname))
3684 finally:
3685 shutil.rmtree(tmpdir)
3686
3687 def testReplaceNoEntryPaths(self):
3688 """Test replacing an entry without an entry path"""
3689 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003690 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003691 with self.assertRaises(ValueError) as e:
3692 control.ReplaceEntries(image_fname, 'fname', None, [])
3693 self.assertIn('Must specify an entry path to read with -f',
3694 str(e.exception))
3695
3696 def testReplaceTooManyEntryPaths(self):
3697 """Test extracting some entries"""
3698 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003699 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003700 with self.assertRaises(ValueError) as e:
3701 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3702 self.assertIn('Must specify exactly one entry path to write with -f',
3703 str(e.exception))
3704
Simon Glass0b074d62019-08-24 07:22:48 -06003705 def testPackReset16(self):
3706 """Test that an image with an x86 reset16 region can be created"""
3707 data = self._DoReadFile('144_x86_reset16.dts')
3708 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3709
3710 def testPackReset16Spl(self):
3711 """Test that an image with an x86 reset16-spl region can be created"""
3712 data = self._DoReadFile('145_x86_reset16_spl.dts')
3713 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3714
3715 def testPackReset16Tpl(self):
3716 """Test that an image with an x86 reset16-tpl region can be created"""
3717 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3718 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3719
Simon Glass232f90c2019-08-24 07:22:50 -06003720 def testPackIntelFit(self):
3721 """Test that an image with an Intel FIT and pointer can be created"""
3722 data = self._DoReadFile('147_intel_fit.dts')
3723 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3724 fit = data[16:32];
3725 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3726 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3727
3728 image = control.images['image']
3729 entries = image.GetEntries()
3730 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3731 self.assertEqual(expected_ptr, ptr)
3732
3733 def testPackIntelFitMissing(self):
3734 """Test detection of a FIT pointer with not FIT region"""
3735 with self.assertRaises(ValueError) as e:
3736 self._DoReadFile('148_intel_fit_missing.dts')
3737 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3738 str(e.exception))
3739
Simon Glass72555fa2019-11-06 17:22:44 -07003740 def _CheckSymbolsTplSection(self, dts, expected_vals):
3741 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003742 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003743 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003744 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003745 self.assertEqual(expected1, data[:upto1])
3746
3747 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003748 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003749 self.assertEqual(expected2, data[upto1:upto2])
3750
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003751 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003752 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003753 self.assertEqual(expected3, data[upto2:upto3])
3754
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003755 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003756 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3757
3758 def testSymbolsTplSection(self):
3759 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3760 self._SetupSplElf('u_boot_binman_syms')
3761 self._SetupTplElf('u_boot_binman_syms')
3762 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003763 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003764
3765 def testSymbolsTplSectionX86(self):
3766 """Test binman can assign symbols in a section with end-at-4gb"""
3767 self._SetupSplElf('u_boot_binman_syms_x86')
3768 self._SetupTplElf('u_boot_binman_syms_x86')
3769 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003770 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003771 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003772
Simon Glass98c59572019-08-24 07:23:03 -06003773 def testPackX86RomIfwiSectiom(self):
3774 """Test that a section can be placed in an IFWI region"""
3775 self._SetupIfwi('fitimage.bin')
3776 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3777 self._CheckIfwi(data)
3778
Simon Glassba7985d2019-08-24 07:23:07 -06003779 def testPackFspM(self):
3780 """Test that an image with a FSP memory-init binary can be created"""
3781 data = self._DoReadFile('152_intel_fsp_m.dts')
3782 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3783
Simon Glass4d9086d2019-10-20 21:31:35 -06003784 def testPackFspS(self):
3785 """Test that an image with a FSP silicon-init binary can be created"""
3786 data = self._DoReadFile('153_intel_fsp_s.dts')
3787 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003788
Simon Glass9ea87b22019-10-20 21:31:36 -06003789 def testPackFspT(self):
3790 """Test that an image with a FSP temp-ram-init binary can be created"""
3791 data = self._DoReadFile('154_intel_fsp_t.dts')
3792 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3793
Simon Glass48f3aad2020-07-09 18:39:31 -06003794 def testMkimage(self):
3795 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003796 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003797 data = self._DoReadFile('156_mkimage.dts')
3798
3799 # Just check that the data appears in the file somewhere
3800 self.assertIn(U_BOOT_SPL_DATA, data)
3801
Simon Glass66152ce2022-01-09 20:14:09 -07003802 def testMkimageMissing(self):
3803 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003804 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003805 with test_util.capture_sys_output() as (_, stderr):
3806 self._DoTestFile('156_mkimage.dts',
3807 force_missing_bintools='mkimage')
3808 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003809 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003810
Simon Glass5e560182020-07-09 18:39:36 -06003811 def testExtblob(self):
3812 """Test an image with an external blob"""
3813 data = self._DoReadFile('157_blob_ext.dts')
3814 self.assertEqual(REFCODE_DATA, data)
3815
3816 def testExtblobMissing(self):
3817 """Test an image with a missing external blob"""
3818 with self.assertRaises(ValueError) as e:
3819 self._DoReadFile('158_blob_ext_missing.dts')
3820 self.assertIn("Filename 'missing-file' not found in input path",
3821 str(e.exception))
3822
Simon Glass5d94cc62020-07-09 18:39:38 -06003823 def testExtblobMissingOk(self):
3824 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003825 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003826 ret = self._DoTestFile('158_blob_ext_missing.dts',
3827 allow_missing=True)
3828 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003829 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003830 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003831 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003832 self.assertIn('Some images are invalid', err)
3833
3834 def testExtblobMissingOkFlag(self):
3835 """Test an image with an missing external blob allowed with -W"""
3836 with test_util.capture_sys_output() as (stdout, stderr):
3837 ret = self._DoTestFile('158_blob_ext_missing.dts',
3838 allow_missing=True, ignore_missing=True)
3839 self.assertEqual(0, ret)
3840 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003841 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003842 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003843 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003844
3845 def testExtblobMissingOkSect(self):
3846 """Test an image with an missing external blob that is allowed"""
3847 with test_util.capture_sys_output() as (stdout, stderr):
3848 self._DoTestFile('159_blob_ext_missing_sect.dts',
3849 allow_missing=True)
3850 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003851 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003852
Simon Glasse88cef92020-07-09 18:39:41 -06003853 def testPackX86RomMeMissingDesc(self):
3854 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003855 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003856 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003857 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003858 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003859
3860 def testPackX86RomMissingIfwi(self):
3861 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3862 self._SetupIfwi('fitimage.bin')
3863 pathname = os.path.join(self._indir, 'fitimage.bin')
3864 os.remove(pathname)
3865 with test_util.capture_sys_output() as (stdout, stderr):
3866 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3867 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003868 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003869
Simon Glass2a0fa982022-02-11 13:23:21 -07003870 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003871 """Test that zero-size overlapping regions are ignored"""
3872 self._DoTestFile('160_pack_overlap_zero.dts')
3873
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003874 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003875 # The data should be inside the FIT
3876 dtb = fdt.Fdt.FromData(fit_data)
3877 dtb.Scan()
3878 fnode = dtb.GetNode('/images/kernel')
3879 self.assertIn('data', fnode.props)
3880
3881 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003882 tools.write_file(fname, fit_data)
3883 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003884
3885 # Check a few features to make sure the plumbing works. We don't need
3886 # to test the operation of mkimage or dumpimage here. First convert the
3887 # output into a dict where the keys are the fields printed by dumpimage
3888 # and the values are a list of values for each field
3889 lines = out.splitlines()
3890
3891 # Converts "Compression: gzip compressed" into two groups:
3892 # 'Compression' and 'gzip compressed'
3893 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3894 vals = collections.defaultdict(list)
3895 for line in lines:
3896 mat = re_line.match(line)
3897 vals[mat.group(1)].append(mat.group(2))
3898
Brandon Maiera657bc62024-06-04 16:16:05 +00003899 self.assertEqual('FIT description: test-desc', lines[0])
Simon Glass45d556d2020-07-09 18:39:45 -06003900 self.assertIn('Created:', lines[1])
3901 self.assertIn('Image 0 (kernel)', vals)
3902 self.assertIn('Hash value', vals)
3903 data_sizes = vals.get('Data Size')
3904 self.assertIsNotNone(data_sizes)
3905 self.assertEqual(2, len(data_sizes))
3906 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003907 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3908 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3909
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003910 # Check if entry listing correctly omits /images/
3911 image = control.images['image']
3912 fit_entry = image.GetEntries()['fit']
3913 subentries = list(fit_entry.GetEntries().keys())
3914 expected = ['kernel', 'fdt-1']
3915 self.assertEqual(expected, subentries)
3916
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003917 def testSimpleFit(self):
3918 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003919 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003920 data = self._DoReadFile('161_fit.dts')
3921 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3922 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3923 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3924
3925 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3926
3927 def testSimpleFitExpandsSubentries(self):
3928 """Test that FIT images expand their subentries"""
3929 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3930 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3931 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3932 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3933
3934 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003935
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003936 def testSimpleFitImagePos(self):
3937 """Test that we have correct image-pos for FIT subentries"""
3938 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3939 update_dtb=True)
3940 dtb = fdt.Fdt(out_dtb_fname)
3941 dtb.Scan()
3942 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3943
Simon Glassb7bad182022-03-05 20:19:01 -07003944 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003945 self.assertEqual({
3946 'image-pos': 0,
3947 'offset': 0,
3948 'size': 1890,
3949
3950 'u-boot:image-pos': 0,
3951 'u-boot:offset': 0,
3952 'u-boot:size': 4,
3953
3954 'fit:image-pos': 4,
3955 'fit:offset': 4,
3956 'fit:size': 1840,
3957
Simon Glassb7bad182022-03-05 20:19:01 -07003958 'fit/images/kernel:image-pos': 304,
3959 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003960 'fit/images/kernel:size': 4,
3961
Simon Glassb7bad182022-03-05 20:19:01 -07003962 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003963 'fit/images/kernel/u-boot:offset': 0,
3964 'fit/images/kernel/u-boot:size': 4,
3965
Simon Glassb7bad182022-03-05 20:19:01 -07003966 'fit/images/fdt-1:image-pos': 552,
3967 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003968 'fit/images/fdt-1:size': 6,
3969
Simon Glassb7bad182022-03-05 20:19:01 -07003970 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003971 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3972 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3973
3974 'u-boot-nodtb:image-pos': 1844,
3975 'u-boot-nodtb:offset': 1844,
3976 'u-boot-nodtb:size': 46,
3977 }, props)
3978
3979 # Actually check the data is where we think it is
3980 for node, expected in [
3981 ("u-boot", U_BOOT_DATA),
3982 ("fit/images/kernel", U_BOOT_DATA),
3983 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3984 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3985 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3986 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3987 ]:
3988 image_pos = props[f"{node}:image-pos"]
3989 size = props[f"{node}:size"]
3990 self.assertEqual(len(expected), size)
3991 self.assertEqual(expected, data[image_pos:image_pos+size])
3992
Simon Glass45d556d2020-07-09 18:39:45 -06003993 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003994 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003995 data = self._DoReadFile('162_fit_external.dts')
3996 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3997
Simon Glass7932c882022-01-09 20:13:39 -07003998 # Size of the external-data region as set up by mkimage
3999 external_data_size = len(U_BOOT_DATA) + 2
4000 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07004001 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07004002 len(U_BOOT_NODTB_DATA))
4003
Simon Glass45d556d2020-07-09 18:39:45 -06004004 # The data should be outside the FIT
4005 dtb = fdt.Fdt.FromData(fit_data)
4006 dtb.Scan()
4007 fnode = dtb.GetNode('/images/kernel')
4008 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07004009 self.assertEqual(len(U_BOOT_DATA),
4010 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4011 fit_pos = 0x400;
4012 self.assertEqual(
4013 fit_pos,
4014 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4015
Brandon Maiera657bc62024-06-04 16:16:05 +00004016 self.assertEqual(expected_size, len(data))
Simon Glass7932c882022-01-09 20:13:39 -07004017 actual_pos = len(U_BOOT_DATA) + fit_pos
4018 self.assertEqual(U_BOOT_DATA + b'aa',
4019 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004020
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004021 def testFitExternalImagePos(self):
4022 """Test that we have correct image-pos for external FIT subentries"""
4023 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4024 update_dtb=True)
4025 dtb = fdt.Fdt(out_dtb_fname)
4026 dtb.Scan()
4027 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4028
4029 self.assertEqual({
4030 'image-pos': 0,
4031 'offset': 0,
4032 'size': 1082,
4033
4034 'u-boot:image-pos': 0,
4035 'u-boot:offset': 0,
4036 'u-boot:size': 4,
4037
4038 'fit:size': 1032,
4039 'fit:offset': 4,
4040 'fit:image-pos': 4,
4041
4042 'fit/images/kernel:size': 4,
4043 'fit/images/kernel:offset': 1024,
4044 'fit/images/kernel:image-pos': 1028,
4045
4046 'fit/images/kernel/u-boot:size': 4,
4047 'fit/images/kernel/u-boot:offset': 0,
4048 'fit/images/kernel/u-boot:image-pos': 1028,
4049
4050 'fit/images/fdt-1:size': 2,
4051 'fit/images/fdt-1:offset': 1028,
4052 'fit/images/fdt-1:image-pos': 1032,
4053
4054 'fit/images/fdt-1/_testing:size': 2,
4055 'fit/images/fdt-1/_testing:offset': 0,
4056 'fit/images/fdt-1/_testing:image-pos': 1032,
4057
4058 'u-boot-nodtb:image-pos': 1036,
4059 'u-boot-nodtb:offset': 1036,
4060 'u-boot-nodtb:size': 46,
4061 }, props)
4062
4063 # Actually check the data is where we think it is
4064 for node, expected in [
4065 ("u-boot", U_BOOT_DATA),
4066 ("fit/images/kernel", U_BOOT_DATA),
4067 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4068 ("fit/images/fdt-1", b'aa'),
4069 ("fit/images/fdt-1/_testing", b'aa'),
4070 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4071 ]:
4072 image_pos = props[f"{node}:image-pos"]
4073 size = props[f"{node}:size"]
4074 self.assertEqual(len(expected), size)
4075 self.assertEqual(expected, data[image_pos:image_pos+size])
4076
Simon Glass66152ce2022-01-09 20:14:09 -07004077 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004078 """Test that binman complains if mkimage is missing"""
4079 with self.assertRaises(ValueError) as e:
4080 self._DoTestFile('162_fit_external.dts',
4081 force_missing_bintools='mkimage')
4082 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4083 str(e.exception))
4084
4085 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004086 """Test that binman still produces a FIT image if mkimage is missing"""
4087 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004088 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004089 force_missing_bintools='mkimage')
4090 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004091 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004092
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004093 def testSectionIgnoreHashSignature(self):
4094 """Test that sections ignore hash, signature nodes for its data"""
4095 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4096 expected = (U_BOOT_DATA + U_BOOT_DATA)
4097 self.assertEqual(expected, data)
4098
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004099 def testPadInSections(self):
4100 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004101 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4102 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004103 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4104 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004105 U_BOOT_DATA)
4106 self.assertEqual(expected, data)
4107
Simon Glassd12599d2020-10-26 17:40:09 -06004108 dtb = fdt.Fdt(out_dtb_fname)
4109 dtb.Scan()
4110 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4111 expected = {
4112 'image-pos': 0,
4113 'offset': 0,
4114 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4115
4116 'section:image-pos': 0,
4117 'section:offset': 0,
4118 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4119
4120 'section/before:image-pos': 0,
4121 'section/before:offset': 0,
4122 'section/before:size': len(U_BOOT_DATA),
4123
4124 'section/u-boot:image-pos': 4,
4125 'section/u-boot:offset': 4,
4126 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4127
4128 'section/after:image-pos': 26,
4129 'section/after:offset': 26,
4130 'section/after:size': len(U_BOOT_DATA),
4131 }
4132 self.assertEqual(expected, props)
4133
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004134 def testFitImageSubentryAlignment(self):
4135 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004136 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004137 entry_args = {
4138 'test-id': TEXT_DATA,
4139 }
4140 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4141 entry_args=entry_args)
4142 dtb = fdt.Fdt.FromData(data)
4143 dtb.Scan()
4144
4145 node = dtb.GetNode('/images/kernel')
4146 data = dtb.GetProps(node)["data"].bytes
4147 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004148 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4149 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004150 self.assertEqual(expected, data)
4151
4152 node = dtb.GetNode('/images/fdt-1')
4153 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004154 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4155 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004156 U_BOOT_DTB_DATA)
4157 self.assertEqual(expected, data)
4158
4159 def testFitExtblobMissingOk(self):
4160 """Test a FIT with a missing external blob that is allowed"""
4161 with test_util.capture_sys_output() as (stdout, stderr):
4162 self._DoTestFile('168_fit_missing_blob.dts',
4163 allow_missing=True)
4164 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004165 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004166
Simon Glass21db0ff2020-09-01 05:13:54 -06004167 def testBlobNamedByArgMissing(self):
4168 """Test handling of a missing entry arg"""
4169 with self.assertRaises(ValueError) as e:
4170 self._DoReadFile('068_blob_named_by_arg.dts')
4171 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4172 str(e.exception))
4173
Simon Glass559c4de2020-09-01 05:13:58 -06004174 def testPackBl31(self):
4175 """Test that an image with an ATF BL31 binary can be created"""
4176 data = self._DoReadFile('169_atf_bl31.dts')
4177 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4178
Samuel Holland9d8cc632020-10-21 21:12:15 -05004179 def testPackScp(self):
4180 """Test that an image with an SCP binary can be created"""
4181 data = self._DoReadFile('172_scp.dts')
4182 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4183
Simon Glassa435cd12020-09-01 05:13:59 -06004184 def testFitFdt(self):
4185 """Test an image with an FIT with multiple FDT images"""
4186 def _CheckFdt(seq, expected_data):
4187 """Check the FDT nodes
4188
4189 Args:
4190 seq: Sequence number to check (0 or 1)
4191 expected_data: Expected contents of 'data' property
4192 """
4193 name = 'fdt-%d' % seq
4194 fnode = dtb.GetNode('/images/%s' % name)
4195 self.assertIsNotNone(fnode)
4196 self.assertEqual({'description','type', 'compression', 'data'},
4197 set(fnode.props.keys()))
4198 self.assertEqual(expected_data, fnode.props['data'].bytes)
4199 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4200 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004201 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004202
4203 def _CheckConfig(seq, expected_data):
4204 """Check the configuration nodes
4205
4206 Args:
4207 seq: Sequence number to check (0 or 1)
4208 expected_data: Expected contents of 'data' property
4209 """
4210 cnode = dtb.GetNode('/configurations')
4211 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004212 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004213
4214 name = 'config-%d' % seq
4215 fnode = dtb.GetNode('/configurations/%s' % name)
4216 self.assertIsNotNone(fnode)
4217 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4218 set(fnode.props.keys()))
4219 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4220 fnode.props['description'].value)
4221 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4222
4223 entry_args = {
4224 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004225 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004226 }
4227 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004228 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004229 entry_args=entry_args,
4230 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4231 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4232 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4233
4234 dtb = fdt.Fdt.FromData(fit_data)
4235 dtb.Scan()
4236 fnode = dtb.GetNode('/images/kernel')
4237 self.assertIn('data', fnode.props)
4238
4239 # Check all the properties in fdt-1 and fdt-2
4240 _CheckFdt(1, TEST_FDT1_DATA)
4241 _CheckFdt(2, TEST_FDT2_DATA)
4242
4243 # Check configurations
4244 _CheckConfig(1, TEST_FDT1_DATA)
4245 _CheckConfig(2, TEST_FDT2_DATA)
4246
4247 def testFitFdtMissingList(self):
4248 """Test handling of a missing 'of-list' entry arg"""
4249 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004250 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004251 self.assertIn("Generator node requires 'of-list' entry argument",
4252 str(e.exception))
4253
4254 def testFitFdtEmptyList(self):
4255 """Test handling of an empty 'of-list' entry arg"""
4256 entry_args = {
4257 'of-list': '',
4258 }
4259 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4260
4261 def testFitFdtMissingProp(self):
4262 """Test handling of a missing 'fit,fdt-list' property"""
4263 with self.assertRaises(ValueError) as e:
4264 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4265 self.assertIn("Generator node requires 'fit,fdt-list' property",
4266 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004267
Simon Glass1032acc2020-09-06 10:39:08 -06004268 def testFitFdtMissing(self):
4269 """Test handling of a missing 'default-dt' entry arg"""
4270 entry_args = {
4271 'of-list': 'test-fdt1 test-fdt2',
4272 }
4273 with self.assertRaises(ValueError) as e:
4274 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004275 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004276 entry_args=entry_args,
4277 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4278 self.assertIn("Generated 'default' node requires default-dt entry argument",
4279 str(e.exception))
4280
4281 def testFitFdtNotInList(self):
4282 """Test handling of a default-dt that is not in the of-list"""
4283 entry_args = {
4284 'of-list': 'test-fdt1 test-fdt2',
4285 'default-dt': 'test-fdt3',
4286 }
4287 with self.assertRaises(ValueError) as e:
4288 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004289 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004290 entry_args=entry_args,
4291 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4292 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4293 str(e.exception))
4294
Simon Glassa820af72020-09-06 10:39:09 -06004295 def testFitExtblobMissingHelp(self):
4296 """Test display of help messages when an external blob is missing"""
4297 control.missing_blob_help = control._ReadMissingBlobHelp()
4298 control.missing_blob_help['wibble'] = 'Wibble test'
4299 control.missing_blob_help['another'] = 'Another test'
4300 with test_util.capture_sys_output() as (stdout, stderr):
4301 self._DoTestFile('168_fit_missing_blob.dts',
4302 allow_missing=True)
4303 err = stderr.getvalue()
4304
4305 # We can get the tag from the name, the type or the missing-msg
4306 # property. Check all three.
4307 self.assertIn('You may need to build ARM Trusted', err)
4308 self.assertIn('Wibble test', err)
4309 self.assertIn('Another test', err)
4310
Simon Glass6f1f4d42020-09-06 10:35:32 -06004311 def testMissingBlob(self):
4312 """Test handling of a blob containing a missing file"""
4313 with self.assertRaises(ValueError) as e:
4314 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4315 self.assertIn("Filename 'missing' not found in input path",
4316 str(e.exception))
4317
Simon Glassa0729502020-09-06 10:35:33 -06004318 def testEnvironment(self):
4319 """Test adding a U-Boot environment"""
4320 data = self._DoReadFile('174_env.dts')
4321 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4322 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4323 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4324 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4325 env)
4326
4327 def testEnvironmentNoSize(self):
4328 """Test that a missing 'size' property is detected"""
4329 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004330 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004331 self.assertIn("'u-boot-env' entry must have a size property",
4332 str(e.exception))
4333
4334 def testEnvironmentTooSmall(self):
4335 """Test handling of an environment that does not fit"""
4336 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004337 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004338
4339 # checksum, start byte, environment with \0 terminator, final \0
4340 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4341 short = need - 0x8
4342 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4343 str(e.exception))
4344
Simon Glassd1fdf752020-10-26 17:40:01 -06004345 def testSkipAtStart(self):
4346 """Test handling of skip-at-start section"""
4347 data = self._DoReadFile('177_skip_at_start.dts')
4348 self.assertEqual(U_BOOT_DATA, data)
4349
4350 image = control.images['image']
4351 entries = image.GetEntries()
4352 section = entries['section']
4353 self.assertEqual(0, section.offset)
4354 self.assertEqual(len(U_BOOT_DATA), section.size)
4355 self.assertEqual(U_BOOT_DATA, section.GetData())
4356
4357 entry = section.GetEntries()['u-boot']
4358 self.assertEqual(16, entry.offset)
4359 self.assertEqual(len(U_BOOT_DATA), entry.size)
4360 self.assertEqual(U_BOOT_DATA, entry.data)
4361
4362 def testSkipAtStartPad(self):
4363 """Test handling of skip-at-start section with padded entry"""
4364 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004365 before = tools.get_bytes(0, 8)
4366 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004367 all = before + U_BOOT_DATA + after
4368 self.assertEqual(all, data)
4369
4370 image = control.images['image']
4371 entries = image.GetEntries()
4372 section = entries['section']
4373 self.assertEqual(0, section.offset)
4374 self.assertEqual(len(all), section.size)
4375 self.assertEqual(all, section.GetData())
4376
4377 entry = section.GetEntries()['u-boot']
4378 self.assertEqual(16, entry.offset)
4379 self.assertEqual(len(all), entry.size)
4380 self.assertEqual(U_BOOT_DATA, entry.data)
4381
4382 def testSkipAtStartSectionPad(self):
4383 """Test handling of skip-at-start section with padding"""
4384 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004385 before = tools.get_bytes(0, 8)
4386 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004387 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004388 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004389
4390 image = control.images['image']
4391 entries = image.GetEntries()
4392 section = entries['section']
4393 self.assertEqual(0, section.offset)
4394 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004395 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004396 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004397
4398 entry = section.GetEntries()['u-boot']
4399 self.assertEqual(16, entry.offset)
4400 self.assertEqual(len(U_BOOT_DATA), entry.size)
4401 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004402
Simon Glassbb395742020-10-26 17:40:14 -06004403 def testSectionPad(self):
4404 """Testing padding with sections"""
4405 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004406 expected = (tools.get_bytes(ord('&'), 3) +
4407 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004408 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004409 tools.get_bytes(ord('!'), 1) +
4410 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004411 self.assertEqual(expected, data)
4412
4413 def testSectionAlign(self):
4414 """Testing alignment with sections"""
4415 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4416 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004417 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004418 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004419 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004420 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004421 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4422 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004423 self.assertEqual(expected, data)
4424
Simon Glassd92c8362020-10-26 17:40:25 -06004425 def testCompressImage(self):
4426 """Test compression of the entire image"""
4427 self._CheckLz4()
4428 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4429 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4430 dtb = fdt.Fdt(out_dtb_fname)
4431 dtb.Scan()
4432 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4433 'uncomp-size'])
4434 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004435 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004436
4437 # Do a sanity check on various fields
4438 image = control.images['image']
4439 entries = image.GetEntries()
4440 self.assertEqual(2, len(entries))
4441
4442 entry = entries['blob']
4443 self.assertEqual(COMPRESS_DATA, entry.data)
4444 self.assertEqual(len(COMPRESS_DATA), entry.size)
4445
4446 entry = entries['u-boot']
4447 self.assertEqual(U_BOOT_DATA, entry.data)
4448 self.assertEqual(len(U_BOOT_DATA), entry.size)
4449
4450 self.assertEqual(len(data), image.size)
4451 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4452 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4453 orig = self._decompress(image.data)
4454 self.assertEqual(orig, image.uncomp_data)
4455
4456 expected = {
4457 'blob:offset': 0,
4458 'blob:size': len(COMPRESS_DATA),
4459 'u-boot:offset': len(COMPRESS_DATA),
4460 'u-boot:size': len(U_BOOT_DATA),
4461 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4462 'offset': 0,
4463 'image-pos': 0,
4464 'size': len(data),
4465 }
4466 self.assertEqual(expected, props)
4467
4468 def testCompressImageLess(self):
4469 """Test compression where compression reduces the image size"""
4470 self._CheckLz4()
4471 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4472 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4473 dtb = fdt.Fdt(out_dtb_fname)
4474 dtb.Scan()
4475 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4476 'uncomp-size'])
4477 orig = self._decompress(data)
4478
Brandon Maiera657bc62024-06-04 16:16:05 +00004479 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004480
4481 # Do a sanity check on various fields
4482 image = control.images['image']
4483 entries = image.GetEntries()
4484 self.assertEqual(2, len(entries))
4485
4486 entry = entries['blob']
4487 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4488 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4489
4490 entry = entries['u-boot']
4491 self.assertEqual(U_BOOT_DATA, entry.data)
4492 self.assertEqual(len(U_BOOT_DATA), entry.size)
4493
4494 self.assertEqual(len(data), image.size)
4495 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4496 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4497 image.uncomp_size)
4498 orig = self._decompress(image.data)
4499 self.assertEqual(orig, image.uncomp_data)
4500
4501 expected = {
4502 'blob:offset': 0,
4503 'blob:size': len(COMPRESS_DATA_BIG),
4504 'u-boot:offset': len(COMPRESS_DATA_BIG),
4505 'u-boot:size': len(U_BOOT_DATA),
4506 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4507 'offset': 0,
4508 'image-pos': 0,
4509 'size': len(data),
4510 }
4511 self.assertEqual(expected, props)
4512
4513 def testCompressSectionSize(self):
4514 """Test compression of a section with a fixed size"""
4515 self._CheckLz4()
4516 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4517 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4518 dtb = fdt.Fdt(out_dtb_fname)
4519 dtb.Scan()
4520 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4521 'uncomp-size'])
4522 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004523 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004524 expected = {
4525 'section/blob:offset': 0,
4526 'section/blob:size': len(COMPRESS_DATA),
4527 'section/u-boot:offset': len(COMPRESS_DATA),
4528 'section/u-boot:size': len(U_BOOT_DATA),
4529 'section:offset': 0,
4530 'section:image-pos': 0,
4531 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4532 'section:size': 0x30,
4533 'offset': 0,
4534 'image-pos': 0,
4535 'size': 0x30,
4536 }
4537 self.assertEqual(expected, props)
4538
4539 def testCompressSection(self):
4540 """Test compression of a section with no fixed size"""
4541 self._CheckLz4()
4542 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4543 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4544 dtb = fdt.Fdt(out_dtb_fname)
4545 dtb.Scan()
4546 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4547 'uncomp-size'])
4548 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004549 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004550 expected = {
4551 'section/blob:offset': 0,
4552 'section/blob:size': len(COMPRESS_DATA),
4553 'section/u-boot:offset': len(COMPRESS_DATA),
4554 'section/u-boot:size': len(U_BOOT_DATA),
4555 'section:offset': 0,
4556 'section:image-pos': 0,
4557 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4558 'section:size': len(data),
4559 'offset': 0,
4560 'image-pos': 0,
4561 'size': len(data),
4562 }
4563 self.assertEqual(expected, props)
4564
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004565 def testLz4Missing(self):
4566 """Test that binman still produces an image if lz4 is missing"""
4567 with test_util.capture_sys_output() as (_, stderr):
4568 self._DoTestFile('185_compress_section.dts',
4569 force_missing_bintools='lz4')
4570 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004571 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004572
Simon Glassd92c8362020-10-26 17:40:25 -06004573 def testCompressExtra(self):
4574 """Test compression of a section with no fixed size"""
4575 self._CheckLz4()
4576 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4577 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4578 dtb = fdt.Fdt(out_dtb_fname)
4579 dtb.Scan()
4580 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4581 'uncomp-size'])
4582
4583 base = data[len(U_BOOT_DATA):]
Brandon Maiera657bc62024-06-04 16:16:05 +00004584 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glassd92c8362020-10-26 17:40:25 -06004585 rest = base[len(U_BOOT_DATA):]
4586
4587 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004588 bintool = self.comp_bintools['lz4']
4589 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004590 data1 = rest[:len(expect1)]
4591 section1 = self._decompress(data1)
Brandon Maiera657bc62024-06-04 16:16:05 +00004592 self.assertEqual(expect1, data1)
4593 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glassd92c8362020-10-26 17:40:25 -06004594 rest1 = rest[len(expect1):]
4595
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004596 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004597 data2 = rest1[:len(expect2)]
4598 section2 = self._decompress(data2)
Brandon Maiera657bc62024-06-04 16:16:05 +00004599 self.assertEqual(expect2, data2)
4600 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glassd92c8362020-10-26 17:40:25 -06004601 rest2 = rest1[len(expect2):]
4602
4603 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4604 len(expect2) + len(U_BOOT_DATA))
Brandon Maiera657bc62024-06-04 16:16:05 +00004605 #self.assertEqual(expect_size, len(data))
Simon Glassd92c8362020-10-26 17:40:25 -06004606
Brandon Maiera657bc62024-06-04 16:16:05 +00004607 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glassd92c8362020-10-26 17:40:25 -06004608
4609 self.maxDiff = None
4610 expected = {
4611 'u-boot:offset': 0,
4612 'u-boot:image-pos': 0,
4613 'u-boot:size': len(U_BOOT_DATA),
4614
4615 'base:offset': len(U_BOOT_DATA),
4616 'base:image-pos': len(U_BOOT_DATA),
4617 'base:size': len(data) - len(U_BOOT_DATA),
4618 'base/u-boot:offset': 0,
4619 'base/u-boot:image-pos': len(U_BOOT_DATA),
4620 'base/u-boot:size': len(U_BOOT_DATA),
4621 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4622 len(expect2),
4623 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4624 len(expect2),
4625 'base/u-boot2:size': len(U_BOOT_DATA),
4626
4627 'base/section:offset': len(U_BOOT_DATA),
4628 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4629 'base/section:size': len(expect1),
4630 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4631 'base/section/blob:offset': 0,
4632 'base/section/blob:size': len(COMPRESS_DATA),
4633 'base/section/u-boot:offset': len(COMPRESS_DATA),
4634 'base/section/u-boot:size': len(U_BOOT_DATA),
4635
4636 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4637 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4638 'base/section2:size': len(expect2),
4639 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4640 'base/section2/blob:offset': 0,
4641 'base/section2/blob:size': len(COMPRESS_DATA),
4642 'base/section2/blob2:offset': len(COMPRESS_DATA),
4643 'base/section2/blob2:size': len(COMPRESS_DATA),
4644
4645 'offset': 0,
4646 'image-pos': 0,
4647 'size': len(data),
4648 }
4649 self.assertEqual(expected, props)
4650
Simon Glassecbe4732021-01-06 21:35:15 -07004651 def testSymbolsSubsection(self):
4652 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004653 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004654
Simon Glass3fb25402021-01-06 21:35:16 -07004655 def testReadImageEntryArg(self):
4656 """Test reading an image that would need an entry arg to generate"""
4657 entry_args = {
4658 'cros-ec-rw-path': 'ecrw.bin',
4659 }
4660 data = self.data = self._DoReadFileDtb(
4661 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4662 entry_args=entry_args)
4663
Simon Glass80025522022-01-29 14:14:04 -07004664 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004665 orig_image = control.images['image']
4666
4667 # This should not generate an error about the missing 'cros-ec-rw-path'
4668 # since we are reading the image from a file. Compare with
4669 # testEntryArgsRequired()
4670 image = Image.FromFile(image_fname)
4671 self.assertEqual(orig_image.GetEntries().keys(),
4672 image.GetEntries().keys())
4673
Simon Glassa2af7302021-01-06 21:35:18 -07004674 def testFilesAlign(self):
4675 """Test alignment with files"""
4676 data = self._DoReadFile('190_files_align.dts')
4677
4678 # The first string is 15 bytes so will align to 16
4679 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4680 self.assertEqual(expect, data)
4681
Simon Glassdb84b562021-01-06 21:35:19 -07004682 def testReadImageSkip(self):
4683 """Test reading an image and accessing its FDT map"""
4684 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004685 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004686 orig_image = control.images['image']
4687 image = Image.FromFile(image_fname)
4688 self.assertEqual(orig_image.GetEntries().keys(),
4689 image.GetEntries().keys())
4690
4691 orig_entry = orig_image.GetEntries()['fdtmap']
4692 entry = image.GetEntries()['fdtmap']
4693 self.assertEqual(orig_entry.offset, entry.offset)
4694 self.assertEqual(orig_entry.size, entry.size)
4695 self.assertEqual(16, entry.image_pos)
4696
4697 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4698
Brandon Maiera657bc62024-06-04 16:16:05 +00004699 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glassdb84b562021-01-06 21:35:19 -07004700
Simon Glassc98de972021-03-18 20:24:57 +13004701 def testTplNoDtb(self):
4702 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004703 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004704 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4705 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4706 data[:len(U_BOOT_TPL_NODTB_DATA)])
4707
Simon Glass63f41d42021-03-18 20:24:58 +13004708 def testTplBssPad(self):
4709 """Test that we can pad TPL's BSS with zeros"""
4710 # ELF file with a '__bss_size' symbol
4711 self._SetupTplElf()
4712 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004713 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004714 data)
4715
4716 def testTplBssPadMissing(self):
4717 """Test that a missing symbol is detected"""
4718 self._SetupTplElf('u_boot_ucode_ptr')
4719 with self.assertRaises(ValueError) as e:
4720 self._DoReadFile('193_tpl_bss_pad.dts')
4721 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4722 str(e.exception))
4723
Simon Glass718b5292021-03-18 20:25:07 +13004724 def checkDtbSizes(self, data, pad_len, start):
4725 """Check the size arguments in a dtb embedded in an image
4726
4727 Args:
4728 data: The image data
4729 pad_len: Length of the pad section in the image, in bytes
4730 start: Start offset of the devicetree to examine, within the image
4731
4732 Returns:
4733 Size of the devicetree in bytes
4734 """
4735 dtb_data = data[start:]
4736 dtb = fdt.Fdt.FromData(dtb_data)
4737 fdt_size = dtb.GetFdtObj().totalsize()
4738 dtb.Scan()
4739 props = self._GetPropTree(dtb, 'size')
4740 self.assertEqual({
4741 'size': len(data),
4742 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4743 'u-boot-spl/u-boot-spl-dtb:size': 801,
4744 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4745 'u-boot-spl:size': 860,
4746 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4747 'u-boot/u-boot-dtb:size': 781,
4748 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4749 'u-boot:size': 827,
4750 }, props)
4751 return fdt_size
4752
4753 def testExpanded(self):
4754 """Test that an expanded entry type is selected when needed"""
4755 self._SetupSplElf()
4756 self._SetupTplElf()
4757
4758 # SPL has a devicetree, TPL does not
4759 entry_args = {
4760 'spl-dtb': '1',
4761 'spl-bss-pad': 'y',
4762 'tpl-dtb': '',
4763 }
4764 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4765 entry_args=entry_args)
4766 image = control.images['image']
4767 entries = image.GetEntries()
4768 self.assertEqual(3, len(entries))
4769
4770 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4771 self.assertIn('u-boot', entries)
4772 entry = entries['u-boot']
4773 self.assertEqual('u-boot-expanded', entry.etype)
4774 subent = entry.GetEntries()
4775 self.assertEqual(2, len(subent))
4776 self.assertIn('u-boot-nodtb', subent)
4777 self.assertIn('u-boot-dtb', subent)
4778
4779 # Second, u-boot-spl, which should be expanded into three parts
4780 self.assertIn('u-boot-spl', entries)
4781 entry = entries['u-boot-spl']
4782 self.assertEqual('u-boot-spl-expanded', entry.etype)
4783 subent = entry.GetEntries()
4784 self.assertEqual(3, len(subent))
4785 self.assertIn('u-boot-spl-nodtb', subent)
4786 self.assertIn('u-boot-spl-bss-pad', subent)
4787 self.assertIn('u-boot-spl-dtb', subent)
4788
4789 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4790 # devicetree
4791 self.assertIn('u-boot-tpl', entries)
4792 entry = entries['u-boot-tpl']
4793 self.assertEqual('u-boot-tpl', entry.etype)
4794 self.assertEqual(None, entry.GetEntries())
4795
4796 def testExpandedTpl(self):
4797 """Test that an expanded entry type is selected for TPL when needed"""
4798 self._SetupTplElf()
4799
4800 entry_args = {
4801 'tpl-bss-pad': 'y',
4802 'tpl-dtb': 'y',
4803 }
4804 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4805 entry_args=entry_args)
4806 image = control.images['image']
4807 entries = image.GetEntries()
4808 self.assertEqual(1, len(entries))
4809
4810 # We only have u-boot-tpl, which be expanded
4811 self.assertIn('u-boot-tpl', entries)
4812 entry = entries['u-boot-tpl']
4813 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4814 subent = entry.GetEntries()
4815 self.assertEqual(3, len(subent))
4816 self.assertIn('u-boot-tpl-nodtb', subent)
4817 self.assertIn('u-boot-tpl-bss-pad', subent)
4818 self.assertIn('u-boot-tpl-dtb', subent)
4819
4820 def testExpandedNoPad(self):
4821 """Test an expanded entry without BSS pad enabled"""
4822 self._SetupSplElf()
4823 self._SetupTplElf()
4824
4825 # SPL has a devicetree, TPL does not
4826 entry_args = {
4827 'spl-dtb': 'something',
4828 'spl-bss-pad': 'n',
4829 'tpl-dtb': '',
4830 }
4831 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4832 entry_args=entry_args)
4833 image = control.images['image']
4834 entries = image.GetEntries()
4835
4836 # Just check u-boot-spl, which should be expanded into two parts
4837 self.assertIn('u-boot-spl', entries)
4838 entry = entries['u-boot-spl']
4839 self.assertEqual('u-boot-spl-expanded', entry.etype)
4840 subent = entry.GetEntries()
4841 self.assertEqual(2, len(subent))
4842 self.assertIn('u-boot-spl-nodtb', subent)
4843 self.assertIn('u-boot-spl-dtb', subent)
4844
4845 def testExpandedTplNoPad(self):
4846 """Test that an expanded entry type with padding disabled in TPL"""
4847 self._SetupTplElf()
4848
4849 entry_args = {
4850 'tpl-bss-pad': '',
4851 'tpl-dtb': 'y',
4852 }
4853 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4854 entry_args=entry_args)
4855 image = control.images['image']
4856 entries = image.GetEntries()
4857 self.assertEqual(1, len(entries))
4858
4859 # We only have u-boot-tpl, which be expanded
4860 self.assertIn('u-boot-tpl', entries)
4861 entry = entries['u-boot-tpl']
4862 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4863 subent = entry.GetEntries()
4864 self.assertEqual(2, len(subent))
4865 self.assertIn('u-boot-tpl-nodtb', subent)
4866 self.assertIn('u-boot-tpl-dtb', subent)
4867
4868 def testFdtInclude(self):
4869 """Test that an Fdt is update within all binaries"""
4870 self._SetupSplElf()
4871 self._SetupTplElf()
4872
4873 # SPL has a devicetree, TPL does not
4874 self.maxDiff = None
4875 entry_args = {
4876 'spl-dtb': '1',
4877 'spl-bss-pad': 'y',
4878 'tpl-dtb': '',
4879 }
4880 # Build the image. It includes two separate devicetree binaries, each
4881 # with their own contents, but all contain the binman definition.
4882 data = self._DoReadFileDtb(
4883 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4884 update_dtb=True, entry_args=entry_args)[0]
4885 pad_len = 10
4886
4887 # Check the U-Boot dtb
4888 start = len(U_BOOT_NODTB_DATA)
4889 fdt_size = self.checkDtbSizes(data, pad_len, start)
4890
4891 # Now check SPL
4892 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4893 fdt_size = self.checkDtbSizes(data, pad_len, start)
4894
4895 # TPL has no devicetree
4896 start += fdt_size + len(U_BOOT_TPL_DATA)
4897 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004898
Simon Glass7098b7f2021-03-21 18:24:30 +13004899 def testSymbolsExpanded(self):
4900 """Test binman can assign symbols in expanded entries"""
4901 entry_args = {
4902 'spl-dtb': '1',
4903 }
4904 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4905 U_BOOT_SPL_DTB_DATA, 0x38,
4906 entry_args=entry_args, use_expanded=True)
4907
Simon Glasse1915782021-03-21 18:24:31 +13004908 def testCollection(self):
4909 """Test a collection"""
4910 data = self._DoReadFile('198_collection.dts')
4911 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004912 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4913 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004914 data)
4915
Simon Glass27a7f772021-03-21 18:24:32 +13004916 def testCollectionSection(self):
4917 """Test a collection where a section must be built first"""
4918 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004919 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004920 # building the contents, producing an error is anything is still
4921 # missing.
4922 data = self._DoReadFile('199_collection_section.dts')
4923 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004924 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4925 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004926 data)
4927
Simon Glassf427c5f2021-03-21 18:24:33 +13004928 def testAlignDefault(self):
4929 """Test that default alignment works on sections"""
4930 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004931 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004932 U_BOOT_DATA)
4933 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004934 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004935 # No alignment within the nested section
4936 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4937 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004938 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004939 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004940
Bin Mengc0b15742021-05-10 20:23:33 +08004941 def testPackOpenSBI(self):
4942 """Test that an image with an OpenSBI binary can be created"""
4943 data = self._DoReadFile('201_opensbi.dts')
4944 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4945
Simon Glass76f496d2021-07-06 10:36:37 -06004946 def testSectionsSingleThread(self):
4947 """Test sections without multithreading"""
4948 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004949 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4950 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4951 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004952 self.assertEqual(expected, data)
4953
4954 def testThreadTimeout(self):
4955 """Test handling a thread that takes too long"""
4956 with self.assertRaises(ValueError) as e:
4957 self._DoTestFile('202_section_timeout.dts',
4958 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004959 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004960
Simon Glass748a1d42021-07-06 10:36:41 -06004961 def testTiming(self):
4962 """Test output of timing information"""
4963 data = self._DoReadFile('055_sections.dts')
4964 with test_util.capture_sys_output() as (stdout, stderr):
4965 state.TimingShow()
4966 self.assertIn('read:', stdout.getvalue())
4967 self.assertIn('compress:', stdout.getvalue())
4968
Simon Glassadfb8492021-11-03 21:09:18 -06004969 def testUpdateFdtInElf(self):
4970 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004971 if not elf.ELF_TOOLS:
4972 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004973 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4974 outfile = os.path.join(self._indir, 'u-boot.out')
4975 begin_sym = 'dtb_embed_begin'
4976 end_sym = 'dtb_embed_end'
4977 retcode = self._DoTestFile(
4978 '060_fdt_update.dts', update_dtb=True,
4979 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4980 self.assertEqual(0, retcode)
4981
4982 # Check that the output file does in fact contact a dtb with the binman
4983 # definition in the correct place
4984 syms = elf.GetSymbolFileOffset(infile,
4985 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004986 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004987 dtb_data = data[syms['dtb_embed_begin'].offset:
4988 syms['dtb_embed_end'].offset]
4989
4990 dtb = fdt.Fdt.FromData(dtb_data)
4991 dtb.Scan()
4992 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4993 self.assertEqual({
4994 'image-pos': 0,
4995 'offset': 0,
4996 '_testing:offset': 32,
4997 '_testing:size': 2,
4998 '_testing:image-pos': 32,
4999 'section@0/u-boot:offset': 0,
5000 'section@0/u-boot:size': len(U_BOOT_DATA),
5001 'section@0/u-boot:image-pos': 0,
5002 'section@0:offset': 0,
5003 'section@0:size': 16,
5004 'section@0:image-pos': 0,
5005
5006 'section@1/u-boot:offset': 0,
5007 'section@1/u-boot:size': len(U_BOOT_DATA),
5008 'section@1/u-boot:image-pos': 16,
5009 'section@1:offset': 16,
5010 'section@1:size': 16,
5011 'section@1:image-pos': 16,
5012 'size': 40
5013 }, props)
5014
5015 def testUpdateFdtInElfInvalid(self):
5016 """Test that invalid args are detected with --update-fdt-in-elf"""
5017 with self.assertRaises(ValueError) as e:
5018 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5019 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5020 str(e.exception))
5021
5022 def testUpdateFdtInElfNoSyms(self):
5023 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005024 if not elf.ELF_TOOLS:
5025 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005026 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5027 outfile = ''
5028 begin_sym = 'wrong_begin'
5029 end_sym = 'wrong_end'
5030 with self.assertRaises(ValueError) as e:
5031 self._DoTestFile(
5032 '060_fdt_update.dts',
5033 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5034 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5035 str(e.exception))
5036
5037 def testUpdateFdtInElfTooSmall(self):
5038 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005039 if not elf.ELF_TOOLS:
5040 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005041 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5042 outfile = os.path.join(self._indir, 'u-boot.out')
5043 begin_sym = 'dtb_embed_begin'
5044 end_sym = 'dtb_embed_end'
5045 with self.assertRaises(ValueError) as e:
5046 self._DoTestFile(
5047 '060_fdt_update.dts', update_dtb=True,
5048 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5049 self.assertRegex(
5050 str(e.exception),
5051 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5052
Simon Glass88e04da2021-11-23 11:03:42 -07005053 def testVersion(self):
5054 """Test we can get the binman version"""
5055 version = '(unreleased)'
5056 self.assertEqual(version, state.GetVersion(self._indir))
5057
5058 with self.assertRaises(SystemExit):
5059 with test_util.capture_sys_output() as (_, stderr):
5060 self._DoBinman('-V')
5061 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5062
5063 # Try running the tool too, just to be safe
5064 result = self._RunBinman('-V')
5065 self.assertEqual('Binman %s\n' % version, result.stderr)
5066
5067 # Set up a version file to make sure that works
5068 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005069 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005070 binary=False)
5071 self.assertEqual(version, state.GetVersion(self._indir))
5072
Simon Glass637958f2021-11-23 21:09:50 -07005073 def testAltFormat(self):
5074 """Test that alternative formats can be used to extract"""
5075 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5076
5077 try:
5078 tmpdir, updated_fname = self._SetupImageInTmpdir()
5079 with test_util.capture_sys_output() as (stdout, _):
5080 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5081 self.assertEqual(
5082 '''Flag (-F) Entry type Description
5083fdt fdtmap Extract the devicetree blob from the fdtmap
5084''',
5085 stdout.getvalue())
5086
5087 dtb = os.path.join(tmpdir, 'fdt.dtb')
5088 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5089 dtb, 'fdtmap')
5090
5091 # Check that we can read it and it can be scanning, meaning it does
5092 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005093 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005094 dtb = fdt.Fdt.FromData(data)
5095 dtb.Scan()
5096
5097 # Now check u-boot which has no alt_format
5098 fname = os.path.join(tmpdir, 'fdt.dtb')
5099 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5100 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005101 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005102 self.assertEqual(U_BOOT_DATA, data)
5103
5104 finally:
5105 shutil.rmtree(tmpdir)
5106
Simon Glass0b00ae62021-11-23 21:09:52 -07005107 def testExtblobList(self):
5108 """Test an image with an external blob list"""
5109 data = self._DoReadFile('215_blob_ext_list.dts')
5110 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5111
5112 def testExtblobListMissing(self):
5113 """Test an image with a missing external blob"""
5114 with self.assertRaises(ValueError) as e:
5115 self._DoReadFile('216_blob_ext_list_missing.dts')
5116 self.assertIn("Filename 'missing-file' not found in input path",
5117 str(e.exception))
5118
5119 def testExtblobListMissingOk(self):
5120 """Test an image with an missing external blob that is allowed"""
5121 with test_util.capture_sys_output() as (stdout, stderr):
5122 self._DoTestFile('216_blob_ext_list_missing.dts',
5123 allow_missing=True)
5124 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005125 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005126
Simon Glass3efb2972021-11-23 21:08:59 -07005127 def testFip(self):
5128 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5129 data = self._DoReadFile('203_fip.dts')
5130 hdr, fents = fip_util.decode_fip(data)
5131 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5132 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5133 self.assertEqual(0x123, hdr.flags)
5134
5135 self.assertEqual(2, len(fents))
5136
5137 fent = fents[0]
5138 self.assertEqual(
5139 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5140 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5141 self.assertEqual('soc-fw', fent.fip_type)
5142 self.assertEqual(0x88, fent.offset)
5143 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5144 self.assertEqual(0x123456789abcdef, fent.flags)
5145 self.assertEqual(ATF_BL31_DATA, fent.data)
5146 self.assertEqual(True, fent.valid)
5147
5148 fent = fents[1]
5149 self.assertEqual(
5150 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5151 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5152 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5153 self.assertEqual(0x8c, fent.offset)
5154 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5155 self.assertEqual(0, fent.flags)
5156 self.assertEqual(ATF_BL2U_DATA, fent.data)
5157 self.assertEqual(True, fent.valid)
5158
5159 def testFipOther(self):
5160 """Basic FIP with something that isn't a external blob"""
5161 data = self._DoReadFile('204_fip_other.dts')
5162 hdr, fents = fip_util.decode_fip(data)
5163
5164 self.assertEqual(2, len(fents))
5165 fent = fents[1]
5166 self.assertEqual('rot-cert', fent.fip_type)
5167 self.assertEqual(b'aa', fent.data)
5168
Simon Glass3efb2972021-11-23 21:08:59 -07005169 def testFipNoType(self):
5170 """FIP with an entry of an unknown type"""
5171 with self.assertRaises(ValueError) as e:
5172 self._DoReadFile('205_fip_no_type.dts')
5173 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5174 str(e.exception))
5175
5176 def testFipUuid(self):
5177 """Basic FIP with a manual uuid"""
5178 data = self._DoReadFile('206_fip_uuid.dts')
5179 hdr, fents = fip_util.decode_fip(data)
5180
5181 self.assertEqual(2, len(fents))
5182 fent = fents[1]
5183 self.assertEqual(None, fent.fip_type)
5184 self.assertEqual(
5185 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5186 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5187 fent.uuid)
5188 self.assertEqual(U_BOOT_DATA, fent.data)
5189
5190 def testFipLs(self):
5191 """Test listing a FIP"""
5192 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5193 hdr, fents = fip_util.decode_fip(data)
5194
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005195 tmpdir = None
Simon Glass3efb2972021-11-23 21:08:59 -07005196 try:
5197 tmpdir, updated_fname = self._SetupImageInTmpdir()
5198 with test_util.capture_sys_output() as (stdout, stderr):
5199 self._DoBinman('ls', '-i', updated_fname)
5200 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005201 if tmpdir:
5202 shutil.rmtree(tmpdir)
Simon Glass3efb2972021-11-23 21:08:59 -07005203 lines = stdout.getvalue().splitlines()
5204 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005205'Name Image-pos Size Entry-type Offset Uncomp-size',
5206'--------------------------------------------------------------',
5207'image 0 2d3 section 0',
5208' atf-fip 0 90 atf-fip 0',
5209' soc-fw 88 4 blob-ext 88',
5210' u-boot 8c 4 u-boot 8c',
5211' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005212]
5213 self.assertEqual(expected, lines)
5214
5215 image = control.images['image']
5216 entries = image.GetEntries()
5217 fdtmap = entries['fdtmap']
5218
5219 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5220 magic = fdtmap_data[:8]
5221 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005222 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005223
5224 fdt_data = fdtmap_data[16:]
5225 dtb = fdt.Fdt.FromData(fdt_data)
5226 dtb.Scan()
5227 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5228 self.assertEqual({
5229 'atf-fip/soc-fw:image-pos': 136,
5230 'atf-fip/soc-fw:offset': 136,
5231 'atf-fip/soc-fw:size': 4,
5232 'atf-fip/u-boot:image-pos': 140,
5233 'atf-fip/u-boot:offset': 140,
5234 'atf-fip/u-boot:size': 4,
5235 'atf-fip:image-pos': 0,
5236 'atf-fip:offset': 0,
5237 'atf-fip:size': 144,
5238 'image-pos': 0,
5239 'offset': 0,
5240 'fdtmap:image-pos': fdtmap.image_pos,
5241 'fdtmap:offset': fdtmap.offset,
5242 'fdtmap:size': len(fdtmap_data),
5243 'size': len(data),
5244 }, props)
5245
5246 def testFipExtractOneEntry(self):
5247 """Test extracting a single entry fron an FIP"""
5248 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005249 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005250 fname = os.path.join(self._indir, 'output.extact')
5251 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005252 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005253 self.assertEqual(U_BOOT_DATA, data)
5254
5255 def testFipReplace(self):
5256 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005257 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005258 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005259 updated_fname = tools.get_output_filename('image-updated.bin')
5260 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005261 entry_name = 'atf-fip/u-boot'
5262 control.WriteEntry(updated_fname, entry_name, expected,
5263 allow_resize=True)
5264 actual = control.ReadEntry(updated_fname, entry_name)
5265 self.assertEqual(expected, actual)
5266
Simon Glass80025522022-01-29 14:14:04 -07005267 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005268 hdr, fents = fip_util.decode_fip(new_data)
5269
5270 self.assertEqual(2, len(fents))
5271
5272 # Check that the FIP entry is updated
5273 fent = fents[1]
5274 self.assertEqual(0x8c, fent.offset)
5275 self.assertEqual(len(expected), fent.size)
5276 self.assertEqual(0, fent.flags)
5277 self.assertEqual(expected, fent.data)
5278 self.assertEqual(True, fent.valid)
5279
5280 def testFipMissing(self):
5281 with test_util.capture_sys_output() as (stdout, stderr):
5282 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5283 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005284 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005285
5286 def testFipSize(self):
5287 """Test a FIP with a size property"""
5288 data = self._DoReadFile('210_fip_size.dts')
5289 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5290 hdr, fents = fip_util.decode_fip(data)
5291 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5292 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5293
5294 self.assertEqual(1, len(fents))
5295
5296 fent = fents[0]
5297 self.assertEqual('soc-fw', fent.fip_type)
5298 self.assertEqual(0x60, fent.offset)
5299 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5300 self.assertEqual(ATF_BL31_DATA, fent.data)
5301 self.assertEqual(True, fent.valid)
5302
5303 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005304 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005305
5306 def testFipBadAlign(self):
5307 """Test that an invalid alignment value in a FIP is detected"""
5308 with self.assertRaises(ValueError) as e:
5309 self._DoTestFile('211_fip_bad_align.dts')
5310 self.assertIn(
5311 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5312 str(e.exception))
5313
5314 def testFipCollection(self):
5315 """Test using a FIP in a collection"""
5316 data = self._DoReadFile('212_fip_collection.dts')
5317 entry1 = control.images['image'].GetEntries()['collection']
5318 data1 = data[:entry1.size]
5319 hdr1, fents2 = fip_util.decode_fip(data1)
5320
5321 entry2 = control.images['image'].GetEntries()['atf-fip']
5322 data2 = data[entry2.offset:entry2.offset + entry2.size]
5323 hdr1, fents2 = fip_util.decode_fip(data2)
5324
5325 # The 'collection' entry should have U-Boot included at the end
5326 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5327 self.assertEqual(data1, data2 + U_BOOT_DATA)
5328 self.assertEqual(U_BOOT_DATA, data1[-4:])
5329
5330 # There should be a U-Boot after the final FIP
5331 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005332
Simon Glassccae6862022-01-12 13:10:35 -07005333 def testFakeBlob(self):
5334 """Test handling of faking an external blob"""
5335 with test_util.capture_sys_output() as (stdout, stderr):
5336 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5337 allow_fake_blobs=True)
5338 err = stderr.getvalue()
5339 self.assertRegex(
5340 err,
5341 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005342
Simon Glassceb5f912022-01-09 20:13:46 -07005343 def testExtblobListFaked(self):
5344 """Test an extblob with missing external blob that are faked"""
5345 with test_util.capture_sys_output() as (stdout, stderr):
5346 self._DoTestFile('216_blob_ext_list_missing.dts',
5347 allow_fake_blobs=True)
5348 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005349 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005350
Simon Glass162017b2022-01-09 20:13:57 -07005351 def testListBintools(self):
5352 args = ['tool', '--list']
5353 with test_util.capture_sys_output() as (stdout, _):
5354 self._DoBinman(*args)
5355 out = stdout.getvalue().splitlines()
5356 self.assertTrue(len(out) >= 2)
5357
5358 def testFetchBintools(self):
5359 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005360 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005361 raise urllib.error.URLError('my error')
5362
5363 args = ['tool']
5364 with self.assertRaises(ValueError) as e:
5365 self._DoBinman(*args)
5366 self.assertIn("Invalid arguments to 'tool' subcommand",
5367 str(e.exception))
5368
5369 args = ['tool', '--fetch']
5370 with self.assertRaises(ValueError) as e:
5371 self._DoBinman(*args)
5372 self.assertIn('Please specify bintools to fetch', str(e.exception))
5373
5374 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005375 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005376 side_effect=fail_download):
5377 with test_util.capture_sys_output() as (stdout, _):
5378 self._DoBinman(*args)
5379 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5380
Simon Glass620c4462022-01-09 20:14:11 -07005381 def testBintoolDocs(self):
5382 """Test for creation of bintool documentation"""
5383 with test_util.capture_sys_output() as (stdout, stderr):
5384 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5385 self.assertTrue(len(stdout.getvalue()) > 0)
5386
5387 def testBintoolDocsMissing(self):
5388 """Test handling of missing bintool documentation"""
5389 with self.assertRaises(ValueError) as e:
5390 with test_util.capture_sys_output() as (stdout, stderr):
5391 control.write_bintool_docs(
5392 control.bintool.Bintool.get_tool_list(), 'mkimage')
5393 self.assertIn('Documentation is missing for modules: mkimage',
5394 str(e.exception))
5395
Jan Kiszka58c407f2022-01-28 20:37:53 +01005396 def testListWithGenNode(self):
5397 """Check handling of an FDT map when the section cannot be found"""
5398 entry_args = {
5399 'of-list': 'test-fdt1 test-fdt2',
5400 }
5401 data = self._DoReadFileDtb(
5402 '219_fit_gennode.dts',
5403 entry_args=entry_args,
5404 use_real_dtb=True,
5405 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5406
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005407 tmpdir = None
Jan Kiszka58c407f2022-01-28 20:37:53 +01005408 try:
5409 tmpdir, updated_fname = self._SetupImageInTmpdir()
5410 with test_util.capture_sys_output() as (stdout, stderr):
5411 self._RunBinman('ls', '-i', updated_fname)
5412 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005413 if tmpdir:
5414 shutil.rmtree(tmpdir)
Jan Kiszka58c407f2022-01-28 20:37:53 +01005415
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005416 def testFitSubentryUsesBintool(self):
5417 """Test that binman FIT subentries can use bintools"""
5418 command.test_result = self._HandleGbbCommand
5419 entry_args = {
5420 'keydir': 'devkeys',
5421 'bmpblk': 'bmpblk.bin',
5422 }
5423 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5424 entry_args=entry_args)
5425
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005426 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5427 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005428 self.assertIn(expected, data)
5429
5430 def testFitSubentryMissingBintool(self):
5431 """Test that binman reports missing bintools for FIT subentries"""
5432 entry_args = {
5433 'keydir': 'devkeys',
5434 }
5435 with test_util.capture_sys_output() as (_, stderr):
5436 self._DoTestFile('220_fit_subentry_bintool.dts',
5437 force_missing_bintools='futility', entry_args=entry_args)
5438 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005439 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005440
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005441 def testFitSubentryHashSubnode(self):
5442 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005443 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005444 data, _, _, out_dtb_name = self._DoReadFileDtb(
5445 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5446
5447 mkimage_dtb = fdt.Fdt.FromData(data)
5448 mkimage_dtb.Scan()
5449 binman_dtb = fdt.Fdt(out_dtb_name)
5450 binman_dtb.Scan()
5451
5452 # Check that binman didn't add hash values
5453 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5454 self.assertNotIn('value', fnode.props)
5455
5456 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5457 self.assertNotIn('value', fnode.props)
5458
5459 # Check that mkimage added hash values
5460 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5461 self.assertIn('value', fnode.props)
5462
5463 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5464 self.assertIn('value', fnode.props)
5465
Roger Quadros5cdcea02022-02-19 20:50:04 +02005466 def testPackTeeOs(self):
5467 """Test that an image with an TEE binary can be created"""
5468 data = self._DoReadFile('222_tee_os.dts')
5469 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5470
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305471 def testPackTiDm(self):
5472 """Test that an image with a TI DM binary can be created"""
5473 data = self._DoReadFile('225_ti_dm.dts')
5474 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5475
Simon Glass912339f2022-02-08 11:50:03 -07005476 def testFitFdtOper(self):
5477 """Check handling of a specified FIT operation"""
5478 entry_args = {
5479 'of-list': 'test-fdt1 test-fdt2',
5480 'default-dt': 'test-fdt2',
5481 }
5482 self._DoReadFileDtb(
5483 '223_fit_fdt_oper.dts',
5484 entry_args=entry_args,
5485 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5486
5487 def testFitFdtBadOper(self):
5488 """Check handling of an FDT map when the section cannot be found"""
5489 with self.assertRaises(ValueError) as exc:
5490 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005491 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005492 str(exc.exception))
5493
Simon Glassdd156a42022-03-05 20:18:59 -07005494 def test_uses_expand_size(self):
5495 """Test that the 'expand-size' property cannot be used anymore"""
5496 with self.assertRaises(ValueError) as e:
5497 data = self._DoReadFile('225_expand_size_bad.dts')
5498 self.assertIn(
5499 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5500 str(e.exception))
5501
Simon Glass5f423422022-03-05 20:19:12 -07005502 def testFitSplitElf(self):
5503 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005504 if not elf.ELF_TOOLS:
5505 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005506 entry_args = {
5507 'of-list': 'test-fdt1 test-fdt2',
5508 'default-dt': 'test-fdt2',
5509 'atf-bl31-path': 'bl31.elf',
5510 'tee-os-path': 'tee.elf',
5511 }
5512 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5513 data = self._DoReadFileDtb(
5514 '226_fit_split_elf.dts',
5515 entry_args=entry_args,
5516 extra_indirs=[test_subdir])[0]
5517
5518 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5519 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5520
5521 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5522 'data', 'load'}
5523 dtb = fdt.Fdt.FromData(fit_data)
5524 dtb.Scan()
5525
5526 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5527 segments, entry = elf.read_loadable_segments(elf_data)
5528
5529 # We assume there are two segments
Brandon Maiera657bc62024-06-04 16:16:05 +00005530 self.assertEqual(2, len(segments))
Simon Glass5f423422022-03-05 20:19:12 -07005531
5532 atf1 = dtb.GetNode('/images/atf-1')
5533 _, start, data = segments[0]
5534 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5535 self.assertEqual(entry,
5536 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5537 self.assertEqual(start,
5538 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5539 self.assertEqual(data, atf1.props['data'].bytes)
5540
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005541 hash_node = atf1.FindNode('hash')
5542 self.assertIsNotNone(hash_node)
5543 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5544
Simon Glass5f423422022-03-05 20:19:12 -07005545 atf2 = dtb.GetNode('/images/atf-2')
5546 self.assertEqual(base_keys, atf2.props.keys())
5547 _, start, data = segments[1]
5548 self.assertEqual(start,
5549 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5550 self.assertEqual(data, atf2.props['data'].bytes)
5551
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005552 hash_node = atf2.FindNode('hash')
5553 self.assertIsNotNone(hash_node)
5554 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5555
5556 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5557 self.assertIsNotNone(hash_node)
5558 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5559
Simon Glass5f423422022-03-05 20:19:12 -07005560 conf = dtb.GetNode('/configurations')
5561 self.assertEqual({'default'}, conf.props.keys())
5562
5563 for subnode in conf.subnodes:
5564 self.assertEqual({'description', 'fdt', 'loadables'},
5565 subnode.props.keys())
5566 self.assertEqual(
5567 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5568 fdt_util.GetStringList(subnode, 'loadables'))
5569
5570 def _check_bad_fit(self, dts):
5571 """Check a bad FIT
5572
5573 This runs with the given dts and returns the assertion raised
5574
5575 Args:
5576 dts (str): dts filename to use
5577
5578 Returns:
5579 str: Assertion string raised
5580 """
5581 entry_args = {
5582 'of-list': 'test-fdt1 test-fdt2',
5583 'default-dt': 'test-fdt2',
5584 'atf-bl31-path': 'bl31.elf',
5585 'tee-os-path': 'tee.elf',
5586 }
5587 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5588 with self.assertRaises(ValueError) as exc:
5589 self._DoReadFileDtb(dts, entry_args=entry_args,
5590 extra_indirs=[test_subdir])[0]
5591 return str(exc.exception)
5592
5593 def testFitSplitElfBadElf(self):
5594 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005595 if not elf.ELF_TOOLS:
5596 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005597 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5598 entry_args = {
5599 'of-list': 'test-fdt1 test-fdt2',
5600 'default-dt': 'test-fdt2',
5601 'atf-bl31-path': 'bad.elf',
5602 'tee-os-path': 'tee.elf',
5603 }
5604 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5605 with self.assertRaises(ValueError) as exc:
5606 self._DoReadFileDtb(
5607 '226_fit_split_elf.dts',
5608 entry_args=entry_args,
5609 extra_indirs=[test_subdir])[0]
5610 self.assertIn(
5611 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5612 str(exc.exception))
5613
Simon Glass5f423422022-03-05 20:19:12 -07005614 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005615 """Test an split-elf FIT with a missing ELF file
5616
5617 Args:
5618 kwargs (dict of str): Arguments to pass to _DoTestFile()
5619
5620 Returns:
5621 tuple:
5622 str: stdout result
5623 str: stderr result
5624 """
Simon Glass5f423422022-03-05 20:19:12 -07005625 entry_args = {
5626 'of-list': 'test-fdt1 test-fdt2',
5627 'default-dt': 'test-fdt2',
5628 'atf-bl31-path': 'bl31.elf',
5629 'tee-os-path': 'missing.elf',
5630 }
5631 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5632 with test_util.capture_sys_output() as (stdout, stderr):
5633 self._DoTestFile(
5634 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005635 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5636 out = stdout.getvalue()
5637 err = stderr.getvalue()
5638 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005639
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005640 def testFitSplitElfBadDirective(self):
5641 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5642 if not elf.ELF_TOOLS:
5643 self.skipTest('Python elftools not available')
5644 err = self._check_bad_fit('227_fit_bad_dir.dts')
5645 self.assertIn(
5646 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5647 err)
5648
5649 def testFitSplitElfBadDirectiveConfig(self):
5650 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5651 if not elf.ELF_TOOLS:
5652 self.skipTest('Python elftools not available')
5653 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5654 self.assertEqual(
5655 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5656 err)
5657
5658
Simon Glass5f423422022-03-05 20:19:12 -07005659 def testFitSplitElfMissing(self):
5660 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005661 if not elf.ELF_TOOLS:
5662 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005663 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005664 self.assertRegex(
5665 err,
5666 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005667 self.assertNotRegex(out, '.*Faked blob.*')
5668 fname = tools.get_output_filename('binman-fake/missing.elf')
5669 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005670
5671 def testFitSplitElfFaked(self):
5672 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005673 if not elf.ELF_TOOLS:
5674 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005675 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005676 self.assertRegex(
5677 err,
5678 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005679 self.assertRegex(
5680 out,
5681 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5682 fname = tools.get_output_filename('binman-fake/missing.elf')
5683 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005684
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005685 def testMkimageMissingBlob(self):
5686 """Test using mkimage to build an image"""
5687 with test_util.capture_sys_output() as (stdout, stderr):
5688 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5689 allow_fake_blobs=True)
5690 err = stderr.getvalue()
5691 self.assertRegex(
5692 err,
5693 "Image '.*' has faked external blobs and is non-functional: .*")
5694
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005695 def testPreLoad(self):
5696 """Test an image with a pre-load header"""
5697 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005698 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005699 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005700 data = self._DoReadFileDtb(
5701 '230_pre_load.dts', entry_args=entry_args,
5702 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005703 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5704 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5705 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Simon Glasse2dfb962023-07-24 09:19:57 -06005706
5707 def testPreLoadNoKey(self):
5708 """Test an image with a pre-load heade0r with missing key"""
5709 with self.assertRaises(FileNotFoundError) as exc:
5710 self._DoReadFile('230_pre_load.dts')
5711 self.assertIn("No such file or directory: 'dev.key'",
5712 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005713
5714 def testPreLoadPkcs(self):
5715 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005716 entry_args = {
5717 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5718 }
5719 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5720 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005721 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5722 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5723 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5724
5725 def testPreLoadPss(self):
5726 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005727 entry_args = {
5728 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5729 }
5730 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5731 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005732 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5733 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5734 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5735
5736 def testPreLoadInvalidPadding(self):
5737 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005738 entry_args = {
5739 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5740 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005741 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005742 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5743 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005744
5745 def testPreLoadInvalidSha(self):
5746 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005747 entry_args = {
5748 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5749 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005750 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005751 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5752 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005753
5754 def testPreLoadInvalidAlgo(self):
5755 """Test an image with a pre-load header with an invalid algo"""
5756 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005757 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005758
5759 def testPreLoadInvalidKey(self):
5760 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005761 entry_args = {
5762 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5763 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005764 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005765 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5766 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005767
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005768 def _CheckSafeUniqueNames(self, *images):
5769 """Check all entries of given images for unsafe unique names"""
5770 for image in images:
5771 entries = {}
5772 image._CollectEntries(entries, {}, image)
5773 for entry in entries.values():
5774 uniq = entry.GetUniqueName()
5775
5776 # Used as part of a filename, so must not be absolute paths.
5777 self.assertFalse(os.path.isabs(uniq))
5778
5779 def testSafeUniqueNames(self):
5780 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005781 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005782
5783 orig_image = control.images['image']
5784 image_fname = tools.get_output_filename('image.bin')
5785 image = Image.FromFile(image_fname)
5786
5787 self._CheckSafeUniqueNames(orig_image, image)
5788
5789 def testSafeUniqueNamesMulti(self):
5790 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005791 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005792
5793 orig_image = control.images['image']
5794 image_fname = tools.get_output_filename('image.bin')
5795 image = Image.FromFile(image_fname)
5796
5797 self._CheckSafeUniqueNames(orig_image, image)
5798
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005799 def testReplaceCmdWithBintool(self):
5800 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005801 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005802 expected = U_BOOT_DATA + b'aa'
5803 self.assertEqual(expected, data[:len(expected)])
5804
5805 try:
5806 tmpdir, updated_fname = self._SetupImageInTmpdir()
5807 fname = os.path.join(tmpdir, 'update-testing.bin')
5808 tools.write_file(fname, b'zz')
5809 self._DoBinman('replace', '-i', updated_fname,
5810 '_testing', '-f', fname)
5811
5812 data = tools.read_file(updated_fname)
5813 expected = U_BOOT_DATA + b'zz'
5814 self.assertEqual(expected, data[:len(expected)])
5815 finally:
5816 shutil.rmtree(tmpdir)
5817
5818 def testReplaceCmdOtherWithBintool(self):
5819 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005820 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005821 expected = U_BOOT_DATA + b'aa'
5822 self.assertEqual(expected, data[:len(expected)])
5823
5824 try:
5825 tmpdir, updated_fname = self._SetupImageInTmpdir()
5826 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5827 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5828 self._DoBinman('replace', '-i', updated_fname,
5829 'u-boot', '-f', fname)
5830
5831 data = tools.read_file(updated_fname)
5832 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5833 self.assertEqual(expected, data[:len(expected)])
5834 finally:
5835 shutil.rmtree(tmpdir)
5836
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005837 def testReplaceResizeNoRepackSameSize(self):
5838 """Test replacing entries with same-size data without repacking"""
5839 expected = b'x' * len(U_BOOT_DATA)
5840 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5841 self.assertEqual(expected, data)
5842
5843 path, fdtmap = state.GetFdtContents('fdtmap')
5844 self.assertIsNotNone(path)
5845 self.assertEqual(expected_fdtmap, fdtmap)
5846
5847 def testReplaceResizeNoRepackSmallerSize(self):
5848 """Test replacing entries with smaller-size data without repacking"""
5849 new_data = b'x'
5850 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5851 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5852 self.assertEqual(expected, data)
5853
5854 path, fdtmap = state.GetFdtContents('fdtmap')
5855 self.assertIsNotNone(path)
5856 self.assertEqual(expected_fdtmap, fdtmap)
5857
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005858 def testExtractFit(self):
5859 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005860 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005861 image_fname = tools.get_output_filename('image.bin')
5862
5863 fit_data = control.ReadEntry(image_fname, 'fit')
5864 fit = fdt.Fdt.FromData(fit_data)
5865 fit.Scan()
5866
5867 # Check subentry data inside the extracted fit
5868 for node_path, expected in [
5869 ('/images/kernel', U_BOOT_DATA),
5870 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5871 ('/images/scr-1', COMPRESS_DATA),
5872 ]:
5873 node = fit.GetNode(node_path)
5874 data = fit.GetProps(node)['data'].bytes
5875 self.assertEqual(expected, data)
5876
5877 def testExtractFitSubentries(self):
5878 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005879 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005880 image_fname = tools.get_output_filename('image.bin')
5881
5882 for entry_path, expected in [
5883 ('fit/kernel', U_BOOT_DATA),
5884 ('fit/kernel/u-boot', U_BOOT_DATA),
5885 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5886 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5887 ('fit/scr-1', COMPRESS_DATA),
5888 ('fit/scr-1/blob', COMPRESS_DATA),
5889 ]:
5890 data = control.ReadEntry(image_fname, entry_path)
5891 self.assertEqual(expected, data)
5892
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005893 def testReplaceFitSubentryLeafSameSize(self):
5894 """Test replacing a FIT leaf subentry with same-size data"""
5895 new_data = b'x' * len(U_BOOT_DATA)
5896 data, expected_fdtmap, _ = self._RunReplaceCmd(
5897 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005898 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005899 self.assertEqual(new_data, data)
5900
5901 path, fdtmap = state.GetFdtContents('fdtmap')
5902 self.assertIsNotNone(path)
5903 self.assertEqual(expected_fdtmap, fdtmap)
5904
5905 def testReplaceFitSubentryLeafBiggerSize(self):
5906 """Test replacing a FIT leaf subentry with bigger-size data"""
5907 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5908 data, expected_fdtmap, _ = self._RunReplaceCmd(
5909 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005910 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005911 self.assertEqual(new_data, data)
5912
5913 # Will be repacked, so fdtmap must change
5914 path, fdtmap = state.GetFdtContents('fdtmap')
5915 self.assertIsNotNone(path)
5916 self.assertNotEqual(expected_fdtmap, fdtmap)
5917
5918 def testReplaceFitSubentryLeafSmallerSize(self):
5919 """Test replacing a FIT leaf subentry with smaller-size data"""
5920 new_data = b'x'
5921 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5922 data, expected_fdtmap, _ = self._RunReplaceCmd(
5923 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005924 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005925 self.assertEqual(expected, data)
5926
5927 path, fdtmap = state.GetFdtContents('fdtmap')
5928 self.assertIsNotNone(path)
5929 self.assertEqual(expected_fdtmap, fdtmap)
5930
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005931 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005932 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005933 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005934 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5935 new_data, dts='241_replace_section_simple.dts')
5936 self.assertEqual(new_data, data)
5937
5938 entries = image.GetEntries()
5939 self.assertIn('section', entries)
5940 entry = entries['section']
5941 self.assertEqual(len(new_data), entry.size)
5942
5943 def testReplaceSectionLarger(self):
5944 """Test replacing a simple section with larger data"""
5945 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5946 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5947 new_data, dts='241_replace_section_simple.dts')
5948 self.assertEqual(new_data, data)
5949
5950 entries = image.GetEntries()
5951 self.assertIn('section', entries)
5952 entry = entries['section']
5953 self.assertEqual(len(new_data), entry.size)
5954 fentry = entries['fdtmap']
5955 self.assertEqual(entry.offset + entry.size, fentry.offset)
5956
5957 def testReplaceSectionSmaller(self):
5958 """Test replacing a simple section with smaller data"""
5959 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5960 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5961 new_data, dts='241_replace_section_simple.dts')
5962 self.assertEqual(new_data, data)
5963
5964 # The new size is the same as the old, just with a pad byte at the end
5965 entries = image.GetEntries()
5966 self.assertIn('section', entries)
5967 entry = entries['section']
5968 self.assertEqual(len(new_data), entry.size)
5969
5970 def testReplaceSectionSmallerAllow(self):
5971 """Test failing to replace a simple section with smaller data"""
5972 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5973 try:
5974 state.SetAllowEntryContraction(True)
5975 with self.assertRaises(ValueError) as exc:
5976 self._RunReplaceCmd('section', new_data,
5977 dts='241_replace_section_simple.dts')
5978 finally:
5979 state.SetAllowEntryContraction(False)
5980
5981 # Since we have no information about the position of things within the
5982 # section, we cannot adjust the position of /section-u-boot so it ends
5983 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06005984 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07005985 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5986 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06005987 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005988
Simon Glass8fbca772022-08-13 11:40:48 -06005989 def testMkimageImagename(self):
5990 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005991 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005992 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005993
5994 # Check that the data appears in the file somewhere
5995 self.assertIn(U_BOOT_SPL_DATA, data)
5996
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005997 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005998 name = data[0x20:0x40]
5999
6000 # Build the filename that we expect to be placed in there, by virtue of
6001 # the -n paraameter
6002 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6003
6004 # Check that the image name is set to the temporary filename used
6005 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6006
Simon Glassb1669752022-08-13 11:40:49 -06006007 def testMkimageImage(self):
6008 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006009 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006010 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006011
6012 # Check that the data appears in the file somewhere
6013 self.assertIn(U_BOOT_SPL_DATA, data)
6014
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006015 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006016 name = data[0x20:0x40]
6017
6018 # Build the filename that we expect to be placed in there, by virtue of
6019 # the -n paraameter
6020 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6021
6022 # Check that the image name is set to the temporary filename used
6023 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6024
6025 # Check the corect data is in the imagename file
6026 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6027
6028 def testMkimageImageNoContent(self):
6029 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006030 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006031 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006032 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006033 self.assertIn('Could not complete processing of contents',
6034 str(exc.exception))
6035
6036 def testMkimageImageBad(self):
6037 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006038 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006039 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006040 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006041 self.assertIn('Cannot use both imagename node and data-to-imagename',
6042 str(exc.exception))
6043
Simon Glassbd5cd882022-08-13 11:40:50 -06006044 def testCollectionOther(self):
6045 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006046 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006047 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6048 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6049 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6050 data)
6051
6052 def testMkimageCollection(self):
6053 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006054 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006055 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006056 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6057 self.assertEqual(expect, data[:len(expect)])
6058
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006059 def testCompressDtbPrependInvalid(self):
6060 """Test that invalid header is detected"""
6061 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006062 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006063 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6064 "'u-boot-dtb': 'invalid'", str(e.exception))
6065
6066 def testCompressDtbPrependLength(self):
6067 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006068 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006069 image = control.images['image']
6070 entries = image.GetEntries()
6071 self.assertIn('u-boot-dtb', entries)
6072 u_boot_dtb = entries['u-boot-dtb']
6073 self.assertIn('fdtmap', entries)
6074 fdtmap = entries['fdtmap']
6075
6076 image_fname = tools.get_output_filename('image.bin')
6077 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6078 dtb = fdt.Fdt.FromData(orig)
6079 dtb.Scan()
6080 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6081 expected = {
6082 'u-boot:size': len(U_BOOT_DATA),
6083 'u-boot-dtb:uncomp-size': len(orig),
6084 'u-boot-dtb:size': u_boot_dtb.size,
6085 'fdtmap:size': fdtmap.size,
6086 'size': len(data),
6087 }
6088 self.assertEqual(expected, props)
6089
6090 # Check implementation
6091 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6092 rest = data[len(U_BOOT_DATA):]
6093 comp_data_len = struct.unpack('<I', rest[:4])[0]
6094 comp_data = rest[4:4 + comp_data_len]
6095 orig2 = self._decompress(comp_data)
6096 self.assertEqual(orig, orig2)
6097
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006098 def testInvalidCompress(self):
6099 """Test that invalid compress algorithm is detected"""
6100 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006101 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006102 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6103
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006104 def testCompUtilCompressions(self):
6105 """Test compression algorithms"""
6106 for bintool in self.comp_bintools.values():
6107 self._CheckBintool(bintool)
6108 data = bintool.compress(COMPRESS_DATA)
6109 self.assertNotEqual(COMPRESS_DATA, data)
6110 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006111 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006112
6113 def testCompUtilVersions(self):
6114 """Test tool version of compression algorithms"""
6115 for bintool in self.comp_bintools.values():
6116 self._CheckBintool(bintool)
6117 version = bintool.version()
6118 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6119
6120 def testCompUtilPadding(self):
6121 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006122 # Skip zstd because it doesn't support padding
6123 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006124 self._CheckBintool(bintool)
6125 data = bintool.compress(COMPRESS_DATA)
6126 self.assertNotEqual(COMPRESS_DATA, data)
6127 data += tools.get_bytes(0, 64)
6128 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006129 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006130
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006131 def testCompressDtbZstd(self):
6132 """Test that zstd compress of device-tree files failed"""
6133 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006134 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006135 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6136 "requires a length header", str(e.exception))
6137
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006138 def testMkimageMultipleDataFiles(self):
6139 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006140 self._SetupSplElf()
6141 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006142 data = self._DoReadFile('252_mkimage_mult_data.dts')
6143 # Size of files are packed in their 4B big-endian format
6144 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6145 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6146 # Size info is always followed by a 4B zero value.
6147 expect += tools.get_bytes(0, 4)
6148 expect += U_BOOT_TPL_DATA
6149 # All but last files are 4B-aligned
6150 align_pad = len(U_BOOT_TPL_DATA) % 4
6151 if align_pad:
6152 expect += tools.get_bytes(0, align_pad)
6153 expect += U_BOOT_SPL_DATA
6154 self.assertEqual(expect, data[-len(expect):])
6155
Marek Vasutf7413f02023-07-18 07:23:58 -06006156 def testMkimageMultipleExpanded(self):
6157 """Test passing multiple files to mkimage in a mkimage entry"""
6158 self._SetupSplElf()
6159 self._SetupTplElf()
6160 entry_args = {
6161 'spl-bss-pad': 'y',
6162 'spl-dtb': 'y',
6163 }
6164 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6165 use_expanded=True, entry_args=entry_args)[0]
6166 pad_len = 10
6167 tpl_expect = U_BOOT_TPL_DATA
6168 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6169 spl_expect += U_BOOT_SPL_DTB_DATA
6170
6171 content = data[0x40:]
6172 lens = struct.unpack('>III', content[:12])
6173
6174 # Size of files are packed in their 4B big-endian format
6175 # Size info is always followed by a 4B zero value.
6176 self.assertEqual(len(tpl_expect), lens[0])
6177 self.assertEqual(len(spl_expect), lens[1])
6178 self.assertEqual(0, lens[2])
6179
6180 rest = content[12:]
6181 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6182
6183 rest = rest[len(tpl_expect):]
6184 align_pad = len(tpl_expect) % 4
6185 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6186 rest = rest[align_pad:]
6187 self.assertEqual(spl_expect, rest)
6188
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006189 def testMkimageMultipleNoContent(self):
6190 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006191 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006192 with self.assertRaises(ValueError) as exc:
6193 self._DoReadFile('253_mkimage_mult_no_content.dts')
6194 self.assertIn('Could not complete processing of contents',
6195 str(exc.exception))
6196
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006197 def testMkimageFilename(self):
6198 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006199 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006200 retcode = self._DoTestFile('254_mkimage_filename.dts')
6201 self.assertEqual(0, retcode)
6202 fname = tools.get_output_filename('mkimage-test.bin')
6203 self.assertTrue(os.path.exists(fname))
6204
Simon Glass56d05412022-02-28 07:16:54 -07006205 def testVpl(self):
6206 """Test that an image with VPL and its device tree can be created"""
6207 # ELF file with a '__bss_size' symbol
6208 self._SetupVplElf()
6209 data = self._DoReadFile('255_u_boot_vpl.dts')
6210 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6211
6212 def testVplNoDtb(self):
6213 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6214 self._SetupVplElf()
6215 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6216 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6217 data[:len(U_BOOT_VPL_NODTB_DATA)])
6218
6219 def testExpandedVpl(self):
6220 """Test that an expanded entry type is selected for TPL when needed"""
6221 self._SetupVplElf()
6222
6223 entry_args = {
6224 'vpl-bss-pad': 'y',
6225 'vpl-dtb': 'y',
6226 }
6227 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6228 entry_args=entry_args)
6229 image = control.images['image']
6230 entries = image.GetEntries()
6231 self.assertEqual(1, len(entries))
6232
6233 # We only have u-boot-vpl, which be expanded
6234 self.assertIn('u-boot-vpl', entries)
6235 entry = entries['u-boot-vpl']
6236 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6237 subent = entry.GetEntries()
6238 self.assertEqual(3, len(subent))
6239 self.assertIn('u-boot-vpl-nodtb', subent)
6240 self.assertIn('u-boot-vpl-bss-pad', subent)
6241 self.assertIn('u-boot-vpl-dtb', subent)
6242
6243 def testVplBssPadMissing(self):
6244 """Test that a missing symbol is detected"""
6245 self._SetupVplElf('u_boot_ucode_ptr')
6246 with self.assertRaises(ValueError) as e:
6247 self._DoReadFile('258_vpl_bss_pad.dts')
6248 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6249 str(e.exception))
6250
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306251 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306252 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306253 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6254 self.assertEqual(0, retcode)
6255 image = control.images['test_image']
6256 fname = tools.get_output_filename('test_image.bin')
6257 sname = tools.get_output_filename('symlink_to_test.bin')
6258 self.assertTrue(os.path.islink(sname))
6259 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006260
Andrew Davis6b463da2023-07-22 00:14:44 +05306261 def testSymlinkOverwrite(self):
6262 """Test that symlinked images can be overwritten"""
6263 testdir = TestFunctional._MakeInputDir('symlinktest')
6264 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6265 # build the same image again in the same directory so that existing symlink is present
6266 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6267 fname = tools.get_output_filename('test_image.bin')
6268 sname = tools.get_output_filename('symlink_to_test.bin')
6269 self.assertTrue(os.path.islink(sname))
6270 self.assertEqual(os.readlink(sname), fname)
6271
Simon Glass37f85de2022-10-20 18:22:47 -06006272 def testSymbolsElf(self):
6273 """Test binman can assign symbols embedded in an ELF file"""
6274 if not elf.ELF_TOOLS:
6275 self.skipTest('Python elftools not available')
6276 self._SetupTplElf('u_boot_binman_syms')
6277 self._SetupVplElf('u_boot_binman_syms')
6278 self._SetupSplElf('u_boot_binman_syms')
6279 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6280 image_fname = tools.get_output_filename('image.bin')
6281
6282 image = control.images['image']
6283 entries = image.GetEntries()
6284
6285 for entry in entries.values():
6286 # No symbols in u-boot and it has faked contents anyway
6287 if entry.name == 'u-boot':
6288 continue
6289 edata = data[entry.image_pos:entry.image_pos + entry.size]
6290 efname = tools.get_output_filename(f'edata-{entry.name}')
6291 tools.write_file(efname, edata)
6292
6293 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6294 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6295 for name, sym in syms.items():
6296 msg = 'test'
6297 val = elf.GetSymbolValue(sym, edata, msg)
6298 entry_m = re_name.match(name)
6299 if entry_m:
6300 ename, prop = entry_m.group(1), entry_m.group(3)
6301 entry, entry_name, prop_name = image.LookupEntry(entries,
6302 name, msg)
6303 if prop_name == 'offset':
6304 expect_val = entry.offset
6305 elif prop_name == 'image_pos':
6306 expect_val = entry.image_pos
6307 elif prop_name == 'size':
6308 expect_val = entry.size
6309 self.assertEqual(expect_val, val)
6310
6311 def testSymbolsElfBad(self):
6312 """Check error when trying to write symbols without the elftools lib"""
6313 if not elf.ELF_TOOLS:
6314 self.skipTest('Python elftools not available')
6315 self._SetupTplElf('u_boot_binman_syms')
6316 self._SetupVplElf('u_boot_binman_syms')
6317 self._SetupSplElf('u_boot_binman_syms')
6318 try:
6319 elf.ELF_TOOLS = False
6320 with self.assertRaises(ValueError) as exc:
6321 self._DoReadFileDtb('260_symbols_elf.dts')
6322 finally:
6323 elf.ELF_TOOLS = True
6324 self.assertIn(
6325 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6326 'Cannot write symbols to an ELF file without Python elftools',
6327 str(exc.exception))
6328
Simon Glassde244162023-01-07 14:07:08 -07006329 def testSectionFilename(self):
6330 """Check writing of section contents to a file"""
6331 data = self._DoReadFile('261_section_fname.dts')
6332 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6333 tools.get_bytes(ord('!'), 7) +
6334 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6335 self.assertEqual(expected, data)
6336
6337 sect_fname = tools.get_output_filename('outfile.bin')
6338 self.assertTrue(os.path.exists(sect_fname))
6339 sect_data = tools.read_file(sect_fname)
6340 self.assertEqual(U_BOOT_DATA, sect_data)
6341
Simon Glass1e9e61c2023-01-07 14:07:12 -07006342 def testAbsent(self):
6343 """Check handling of absent entries"""
6344 data = self._DoReadFile('262_absent.dts')
6345 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6346
Simon Glassad5cfe12023-01-07 14:07:14 -07006347 def testPackTeeOsOptional(self):
6348 """Test that an image with an optional TEE binary can be created"""
6349 entry_args = {
6350 'tee-os-path': 'tee.elf',
6351 }
6352 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6353 entry_args=entry_args)[0]
6354 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6355
6356 def checkFitTee(self, dts, tee_fname):
6357 """Check that a tee-os entry works and returns data
6358
6359 Args:
6360 dts (str): Device tree filename to use
6361 tee_fname (str): filename containing tee-os
6362
6363 Returns:
6364 bytes: Image contents
6365 """
6366 if not elf.ELF_TOOLS:
6367 self.skipTest('Python elftools not available')
6368 entry_args = {
6369 'of-list': 'test-fdt1 test-fdt2',
6370 'default-dt': 'test-fdt2',
6371 'tee-os-path': tee_fname,
6372 }
6373 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6374 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6375 extra_indirs=[test_subdir])[0]
6376 return data
6377
6378 def testFitTeeOsOptionalFit(self):
6379 """Test an image with a FIT with an optional OP-TEE binary"""
6380 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6381
6382 # There should be only one node, holding the data set up in SetUpClass()
6383 # for tee.bin
6384 dtb = fdt.Fdt.FromData(data)
6385 dtb.Scan()
6386 node = dtb.GetNode('/images/tee-1')
6387 self.assertEqual(TEE_ADDR,
6388 fdt_util.fdt32_to_cpu(node.props['load'].value))
6389 self.assertEqual(TEE_ADDR,
6390 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6391 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6392
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006393 with test_util.capture_sys_output() as (stdout, stderr):
6394 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6395 err = stderr.getvalue()
6396 self.assertRegex(
6397 err,
6398 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6399
Simon Glassad5cfe12023-01-07 14:07:14 -07006400 def testFitTeeOsOptionalFitBad(self):
6401 """Test an image with a FIT with an optional OP-TEE binary"""
6402 with self.assertRaises(ValueError) as exc:
6403 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6404 self.assertIn(
6405 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6406 str(exc.exception))
6407
6408 def testFitTeeOsBad(self):
6409 """Test an OP-TEE binary with wrong formats"""
6410 self.make_tee_bin('tee.bad1', 123)
6411 with self.assertRaises(ValueError) as exc:
6412 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6413 self.assertIn(
6414 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6415 str(exc.exception))
6416
6417 self.make_tee_bin('tee.bad2', 0, b'extra data')
6418 with self.assertRaises(ValueError) as exc:
6419 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6420 self.assertIn(
6421 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6422 str(exc.exception))
6423
Simon Glass63328f12023-01-07 14:07:15 -07006424 def testExtblobOptional(self):
6425 """Test an image with an external blob that is optional"""
6426 with test_util.capture_sys_output() as (stdout, stderr):
6427 data = self._DoReadFile('266_blob_ext_opt.dts')
6428 self.assertEqual(REFCODE_DATA, data)
6429 err = stderr.getvalue()
6430 self.assertRegex(
6431 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006432 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006433
Simon Glass7447a9d2023-01-11 16:10:12 -07006434 def testSectionInner(self):
6435 """Test an inner section with a size"""
6436 data = self._DoReadFile('267_section_inner.dts')
6437 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6438 self.assertEqual(expected, data)
6439
Simon Glassa4948b22023-01-11 16:10:14 -07006440 def testNull(self):
6441 """Test an image with a null entry"""
6442 data = self._DoReadFile('268_null.dts')
6443 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6444
Simon Glassf1ee03b2023-01-11 16:10:16 -07006445 def testOverlap(self):
6446 """Test an image with a overlapping entry"""
6447 data = self._DoReadFile('269_overlap.dts')
6448 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6449
6450 image = control.images['image']
6451 entries = image.GetEntries()
6452
6453 self.assertIn('inset', entries)
6454 inset = entries['inset']
6455 self.assertEqual(1, inset.offset);
6456 self.assertEqual(1, inset.image_pos);
6457 self.assertEqual(2, inset.size);
6458
6459 def testOverlapNull(self):
6460 """Test an image with a null overlap"""
6461 data = self._DoReadFile('270_overlap_null.dts')
6462 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6463
6464 # Check the FMAP
6465 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6466 self.assertEqual(4, fhdr.nareas)
6467 fiter = iter(fentries)
6468
6469 fentry = next(fiter)
6470 self.assertEqual(b'SECTION', fentry.name)
6471 self.assertEqual(0, fentry.offset)
6472 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6473 self.assertEqual(0, fentry.flags)
6474
6475 fentry = next(fiter)
6476 self.assertEqual(b'U_BOOT', fentry.name)
6477 self.assertEqual(0, fentry.offset)
6478 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6479 self.assertEqual(0, fentry.flags)
6480
6481 # Make sure that the NULL entry appears in the FMAP
6482 fentry = next(fiter)
6483 self.assertEqual(b'NULL', fentry.name)
6484 self.assertEqual(1, fentry.offset)
6485 self.assertEqual(2, fentry.size)
6486 self.assertEqual(0, fentry.flags)
6487
6488 fentry = next(fiter)
6489 self.assertEqual(b'FMAP', fentry.name)
6490 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6491
6492 def testOverlapBad(self):
6493 """Test an image with a bad overlapping entry"""
6494 with self.assertRaises(ValueError) as exc:
6495 self._DoReadFile('271_overlap_bad.dts')
6496 self.assertIn(
6497 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6498 str(exc.exception))
6499
6500 def testOverlapNoOffset(self):
6501 """Test an image with a bad overlapping entry"""
6502 with self.assertRaises(ValueError) as exc:
6503 self._DoReadFile('272_overlap_no_size.dts')
6504 self.assertIn(
6505 "Node '/binman/inset': 'fill' entry is missing properties: size",
6506 str(exc.exception))
6507
Simon Glasse0035c92023-01-11 16:10:17 -07006508 def testBlobSymbol(self):
6509 """Test a blob with symbols read from an ELF file"""
6510 elf_fname = self.ElfTestFile('blob_syms')
6511 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6512 TestFunctional._MakeInputFile('blob_syms.bin',
6513 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6514
6515 data = self._DoReadFile('273_blob_symbol.dts')
6516
6517 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6518 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6519 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6520 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6521 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6522
6523 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6524 expected = sym_values
6525 self.assertEqual(expected, data[:len(expected)])
6526
Simon Glass49e9c002023-01-11 16:10:19 -07006527 def testOffsetFromElf(self):
6528 """Test a blob with symbols read from an ELF file"""
6529 elf_fname = self.ElfTestFile('blob_syms')
6530 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6531 TestFunctional._MakeInputFile('blob_syms.bin',
6532 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6533
6534 data = self._DoReadFile('274_offset_from_elf.dts')
6535
6536 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6537 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6538
6539 image = control.images['image']
6540 entries = image.GetEntries()
6541
6542 self.assertIn('inset', entries)
6543 inset = entries['inset']
6544
6545 self.assertEqual(base + 4, inset.offset);
6546 self.assertEqual(base + 4, inset.image_pos);
6547 self.assertEqual(4, inset.size);
6548
6549 self.assertIn('inset2', entries)
6550 inset = entries['inset2']
6551 self.assertEqual(base + 8, inset.offset);
6552 self.assertEqual(base + 8, inset.image_pos);
6553 self.assertEqual(4, inset.size);
6554
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006555 def testFitAlign(self):
6556 """Test an image with an FIT with aligned external data"""
6557 data = self._DoReadFile('275_fit_align.dts')
6558 self.assertEqual(4096, len(data))
6559
6560 dtb = fdt.Fdt.FromData(data)
6561 dtb.Scan()
6562
6563 props = self._GetPropTree(dtb, ['data-position'])
6564 expected = {
6565 'u-boot:data-position': 1024,
6566 'fdt-1:data-position': 2048,
6567 'fdt-2:data-position': 3072,
6568 }
6569 self.assertEqual(expected, props)
6570
Jonas Karlman490f73c2023-01-21 19:02:12 +00006571 def testFitFirmwareLoadables(self):
6572 """Test an image with an FIT that use fit,firmware"""
6573 if not elf.ELF_TOOLS:
6574 self.skipTest('Python elftools not available')
6575 entry_args = {
6576 'of-list': 'test-fdt1',
6577 'default-dt': 'test-fdt1',
6578 'atf-bl31-path': 'bl31.elf',
6579 'tee-os-path': 'missing.bin',
6580 }
6581 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006582 with test_util.capture_sys_output() as (stdout, stderr):
6583 data = self._DoReadFileDtb(
6584 '276_fit_firmware_loadables.dts',
6585 entry_args=entry_args,
6586 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006587
6588 dtb = fdt.Fdt.FromData(data)
6589 dtb.Scan()
6590
6591 node = dtb.GetNode('/configurations/conf-uboot-1')
6592 self.assertEqual('u-boot', node.props['firmware'].value)
6593 self.assertEqual(['atf-1', 'atf-2'],
6594 fdt_util.GetStringList(node, 'loadables'))
6595
6596 node = dtb.GetNode('/configurations/conf-atf-1')
6597 self.assertEqual('atf-1', node.props['firmware'].value)
6598 self.assertEqual(['u-boot', 'atf-2'],
6599 fdt_util.GetStringList(node, 'loadables'))
6600
6601 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6602 self.assertEqual('u-boot', node.props['firmware'].value)
6603 self.assertEqual(['atf-1', 'atf-2'],
6604 fdt_util.GetStringList(node, 'loadables'))
6605
6606 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6607 self.assertEqual('atf-1', node.props['firmware'].value)
6608 self.assertEqual(['u-boot', 'atf-2'],
6609 fdt_util.GetStringList(node, 'loadables'))
6610
6611 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6612 self.assertEqual('atf-1', node.props['firmware'].value)
6613 self.assertEqual(['u-boot', 'atf-2'],
6614 fdt_util.GetStringList(node, 'loadables'))
6615
Simon Glass9a1c7262023-02-22 12:14:49 -07006616 def testTooldir(self):
6617 """Test that we can specify the tooldir"""
6618 with test_util.capture_sys_output() as (stdout, stderr):
6619 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6620 'tool', '-l'))
6621 self.assertEqual('fred', bintool.Bintool.tooldir)
6622
6623 # Check that the toolpath is updated correctly
6624 self.assertEqual(['fred'], tools.tool_search_paths)
6625
6626 # Try with a few toolpaths; the tooldir should be at the end
6627 with test_util.capture_sys_output() as (stdout, stderr):
6628 self.assertEqual(0, self._DoBinman(
6629 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6630 'tool', '-l'))
6631 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6632
Simon Glass49b77e82023-03-02 17:02:44 -07006633 def testReplaceSectionEntry(self):
6634 """Test replacing an entry in a section"""
6635 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6636 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6637 expect_data, dts='241_replace_section_simple.dts')
6638 self.assertEqual(expect_data, entry_data)
6639
6640 entries = image.GetEntries()
6641 self.assertIn('section', entries)
6642 section = entries['section']
6643
6644 sect_entries = section.GetEntries()
6645 self.assertIn('blob', sect_entries)
6646 entry = sect_entries['blob']
6647 self.assertEqual(len(expect_data), entry.size)
6648
6649 fname = tools.get_output_filename('image-updated.bin')
6650 data = tools.read_file(fname)
6651
6652 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6653 self.assertEqual(expect_data, new_blob_data)
6654
6655 self.assertEqual(U_BOOT_DATA,
6656 data[entry.image_pos + len(expect_data):]
6657 [:len(U_BOOT_DATA)])
6658
6659 def testReplaceSectionDeep(self):
6660 """Test replacing an entry in two levels of sections"""
6661 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6662 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6663 'section/section/blob', expect_data,
6664 dts='278_replace_section_deep.dts')
6665 self.assertEqual(expect_data, entry_data)
6666
6667 entries = image.GetEntries()
6668 self.assertIn('section', entries)
6669 section = entries['section']
6670
6671 subentries = section.GetEntries()
6672 self.assertIn('section', subentries)
6673 section = subentries['section']
6674
6675 sect_entries = section.GetEntries()
6676 self.assertIn('blob', sect_entries)
6677 entry = sect_entries['blob']
6678 self.assertEqual(len(expect_data), entry.size)
6679
6680 fname = tools.get_output_filename('image-updated.bin')
6681 data = tools.read_file(fname)
6682
6683 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6684 self.assertEqual(expect_data, new_blob_data)
6685
6686 self.assertEqual(U_BOOT_DATA,
6687 data[entry.image_pos + len(expect_data):]
6688 [:len(U_BOOT_DATA)])
6689
6690 def testReplaceFitSibling(self):
6691 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006692 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006693 fname = TestFunctional._MakeInputFile('once', b'available once')
6694 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6695 os.remove(fname)
6696
6697 try:
6698 tmpdir, updated_fname = self._SetupImageInTmpdir()
6699
6700 fname = os.path.join(tmpdir, 'update-blob')
6701 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6702 tools.write_file(fname, expected)
6703
6704 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6705 data = tools.read_file(updated_fname)
6706 start = len(U_BOOT_DTB_DATA)
6707 self.assertEqual(expected, data[start:start + len(expected)])
6708 map_fname = os.path.join(tmpdir, 'image-updated.map')
6709 self.assertFalse(os.path.exists(map_fname))
6710 finally:
6711 shutil.rmtree(tmpdir)
6712
Simon Glassc3fe97f2023-03-02 17:02:45 -07006713 def testX509Cert(self):
6714 """Test creating an X509 certificate"""
6715 keyfile = self.TestFile('key.key')
6716 entry_args = {
6717 'keyfile': keyfile,
6718 }
6719 data = self._DoReadFileDtb('279_x509_cert.dts',
6720 entry_args=entry_args)[0]
6721 cert = data[:-4]
6722 self.assertEqual(U_BOOT_DATA, data[-4:])
6723
6724 # TODO: verify the signature
6725
6726 def testX509CertMissing(self):
6727 """Test that binman still produces an image if openssl is missing"""
6728 keyfile = self.TestFile('key.key')
6729 entry_args = {
6730 'keyfile': 'keyfile',
6731 }
6732 with test_util.capture_sys_output() as (_, stderr):
6733 self._DoTestFile('279_x509_cert.dts',
6734 force_missing_bintools='openssl',
6735 entry_args=entry_args)
6736 err = stderr.getvalue()
6737 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6738
Jonas Karlman35305492023-02-25 19:01:33 +00006739 def testPackRockchipTpl(self):
6740 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006741 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006742 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6743
Jonas Karlman1016ec72023-02-25 19:01:35 +00006744 def testMkimageMissingBlobMultiple(self):
6745 """Test missing blob with mkimage entry and multiple-data-files"""
6746 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006747 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006748 err = stderr.getvalue()
6749 self.assertIn("is missing external blobs and is non-functional", err)
6750
6751 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006752 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006753 self.assertIn("not found in input path", str(e.exception))
6754
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006755 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6756 """Prepare sign environment
6757
6758 Create private and public keys, add pubkey into dtb.
6759
6760 Returns:
6761 Tuple:
6762 FIT container
6763 Image name
6764 Private key
6765 DTB
6766 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006767 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006768 data = self._DoReadFileRealDtb(dts)
6769 updated_fname = tools.get_output_filename('image-updated.bin')
6770 tools.write_file(updated_fname, data)
6771 dtb = tools.get_output_filename('source.dtb')
6772 private_key = tools.get_output_filename('test_key.key')
6773 public_key = tools.get_output_filename('test_key.crt')
6774 fit = tools.get_output_filename('fit.fit')
6775 key_dir = tools.get_output_dir()
6776
6777 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6778 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6779 private_key, '-out', public_key)
6780 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6781 '-n', 'test_key', '-r', 'conf', dtb)
6782
6783 return fit, updated_fname, private_key, dtb
6784
6785 def testSignSimple(self):
6786 """Test that a FIT container can be signed in image"""
6787 is_signed = False
6788 fit, fname, private_key, dtb = self._PrepareSignEnv()
6789
6790 # do sign with private key
6791 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6792 ['fit'])
6793 is_signed = self._CheckSign(fit, dtb)
6794
6795 self.assertEqual(is_signed, True)
6796
6797 def testSignExactFIT(self):
6798 """Test that a FIT container can be signed and replaced in image"""
6799 is_signed = False
6800 fit, fname, private_key, dtb = self._PrepareSignEnv()
6801
6802 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6803 args = []
6804 if self.toolpath:
6805 for path in self.toolpath:
6806 args += ['--toolpath', path]
6807
6808 # do sign with private key
6809 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6810 'sha256,rsa4096', '-f', fit, 'fit')
6811 is_signed = self._CheckSign(fit, dtb)
6812
6813 self.assertEqual(is_signed, True)
6814
6815 def testSignNonFit(self):
6816 """Test a non-FIT entry cannot be signed"""
6817 is_signed = False
6818 fit, fname, private_key, _ = self._PrepareSignEnv(
6819 '281_sign_non_fit.dts')
6820
6821 # do sign with private key
6822 with self.assertRaises(ValueError) as e:
6823 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6824 'sha256,rsa4096', '-f', fit, 'u-boot')
6825 self.assertIn(
6826 "Node '/u-boot': Updating signatures is not supported with this entry type",
6827 str(e.exception))
6828
6829 def testSignMissingMkimage(self):
6830 """Test that FIT signing handles a missing mkimage tool"""
6831 fit, fname, private_key, _ = self._PrepareSignEnv()
6832
6833 # try to sign with a missing mkimage tool
6834 bintool.Bintool.set_missing_list(['mkimage'])
6835 with self.assertRaises(ValueError) as e:
6836 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6837 ['fit'])
6838 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6839
Simon Glass4abf7842023-07-18 07:23:54 -06006840 def testSymbolNoWrite(self):
6841 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006842 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006843 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6844 no_write_symbols=True)
6845
6846 def testSymbolNoWriteExpanded(self):
6847 """Test disabling of symbol writing in expanded entries"""
6848 entry_args = {
6849 'spl-dtb': '1',
6850 }
6851 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6852 U_BOOT_SPL_DTB_DATA, 0x38,
6853 entry_args=entry_args, use_expanded=True,
6854 no_write_symbols=True)
6855
Marek Vasutf7413f02023-07-18 07:23:58 -06006856 def testMkimageSpecial(self):
6857 """Test mkimage ignores special hash-1 node"""
6858 data = self._DoReadFile('283_mkimage_special.dts')
6859
6860 # Just check that the data appears in the file somewhere
6861 self.assertIn(U_BOOT_DATA, data)
6862
Simon Glass2d94c422023-07-18 07:23:59 -06006863 def testFitFdtList(self):
6864 """Test an image with an FIT with the fit,fdt-list-val option"""
6865 entry_args = {
6866 'default-dt': 'test-fdt2',
6867 }
6868 data = self._DoReadFileDtb(
6869 '284_fit_fdt_list.dts',
6870 entry_args=entry_args,
6871 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6872 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6873 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6874
Simon Glass83b8bfe2023-07-18 07:24:01 -06006875 def testSplEmptyBss(self):
6876 """Test an expanded SPL with a zero-size BSS"""
6877 # ELF file with a '__bss_size' symbol
6878 self._SetupSplElf(src_fname='bss_data_zero')
6879
6880 entry_args = {
6881 'spl-bss-pad': 'y',
6882 'spl-dtb': 'y',
6883 }
6884 data = self._DoReadFileDtb('285_spl_expand.dts',
6885 use_expanded=True, entry_args=entry_args)[0]
6886
Simon Glassfc792842023-07-18 07:24:04 -06006887 def testTemplate(self):
6888 """Test using a template"""
6889 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6890 data = self._DoReadFile('286_template.dts')
6891 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6892 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6893 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6894
Simon Glass09490b02023-07-22 21:43:52 -06006895 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6896 self.assertTrue(os.path.exists(dtb_fname1))
6897 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6898 dtb.Scan()
6899 node1 = dtb.GetNode('/binman/template')
6900 self.assertTrue(node1)
6901 vga = dtb.GetNode('/binman/first/intel-vga')
6902 self.assertTrue(vga)
6903
Simon Glass54825e12023-07-22 21:43:56 -06006904 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6905 self.assertTrue(os.path.exists(dtb_fname2))
6906 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6907 dtb2.Scan()
6908 node2 = dtb2.GetNode('/binman/template')
6909 self.assertFalse(node2)
6910
Simon Glass9909c112023-07-18 07:24:05 -06006911 def testTemplateBlobMulti(self):
6912 """Test using a template with 'multiple-images' enabled"""
6913 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6914 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6915 retcode = self._DoTestFile('287_template_multi.dts')
6916
6917 self.assertEqual(0, retcode)
6918 image = control.images['image']
6919 image_fname = tools.get_output_filename('my-image.bin')
6920 data = tools.read_file(image_fname)
6921 self.assertEqual(b'blob@@@@other', data)
6922
Simon Glass5dc511b2023-07-18 07:24:06 -06006923 def testTemplateFit(self):
6924 """Test using a template in a FIT"""
6925 fit_data = self._DoReadFile('288_template_fit.dts')
6926 fname = os.path.join(self._indir, 'fit_data.fit')
6927 tools.write_file(fname, fit_data)
6928 out = tools.run('dumpimage', '-l', fname)
6929
Simon Glassaa6e0552023-07-18 07:24:07 -06006930 def testTemplateSection(self):
6931 """Test using a template in a section (not at top level)"""
6932 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6933 data = self._DoReadFile('289_template_section.dts')
6934 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6935 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6936 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6937
Simon Glassf53a7bc2023-07-18 07:24:08 -06006938 def testMkimageSymbols(self):
6939 """Test using mkimage to build an image with symbols in it"""
6940 self._SetupSplElf('u_boot_binman_syms')
6941 data = self._DoReadFile('290_mkimage_sym.dts')
6942
6943 image = control.images['image']
6944 entries = image.GetEntries()
6945 self.assertIn('u-boot', entries)
6946 u_boot = entries['u-boot']
6947
6948 mkim = entries['mkimage']
6949 mkim_entries = mkim.GetEntries()
6950 self.assertIn('u-boot-spl', mkim_entries)
6951 spl = mkim_entries['u-boot-spl']
6952 self.assertIn('u-boot-spl2', mkim_entries)
6953 spl2 = mkim_entries['u-boot-spl2']
6954
6955 # skip the mkimage header and the area sizes
6956 mk_data = data[mkim.offset + 0x40:]
6957 size, term = struct.unpack('>LL', mk_data[:8])
6958
6959 # There should be only one image, so check that the zero terminator is
6960 # present
6961 self.assertEqual(0, term)
6962
6963 content = mk_data[8:8 + size]
6964
6965 # The image should contain the symbols from u_boot_binman_syms.c
6966 # Note that image_pos is adjusted by the base address of the image,
6967 # which is 0x10 in our test image
6968 spl_data = content[:0x18]
6969 content = content[0x1b:]
6970
6971 # After the header is a table of offsets for each image. There should
6972 # only be one image, then a 0 terminator, so figure out the real start
6973 # of the image data
6974 base = 0x40 + 8
6975
6976 # Check symbols in both u-boot-spl and u-boot-spl2
6977 for i in range(2):
6978 vals = struct.unpack('<LLQLL', spl_data)
6979
6980 # The image should contain the symbols from u_boot_binman_syms.c
6981 # Note that image_pos is adjusted by the base address of the image,
6982 # which is 0x10 in our 'u_boot_binman_syms' test image
6983 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6984 self.assertEqual(base, vals[1])
6985 self.assertEqual(spl2.offset, vals[2])
6986 # figure out the internal positions of its components
6987 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6988
6989 # Check that spl and spl2 are actually at the indicated positions
6990 self.assertEqual(
6991 elf.BINMAN_SYM_MAGIC_VALUE,
6992 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6993 self.assertEqual(
6994 elf.BINMAN_SYM_MAGIC_VALUE,
6995 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6996
6997 self.assertEqual(len(U_BOOT_DATA), vals[4])
6998
6999 # Move to next
7000 spl_data = content[:0x18]
7001
Simon Glass86b3e472023-07-22 21:43:57 -06007002 def testTemplatePhandle(self):
7003 """Test using a template in a node containing a phandle"""
7004 entry_args = {
7005 'atf-bl31-path': 'bl31.elf',
7006 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06007007 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007008 entry_args=entry_args)
7009 fname = tools.get_output_filename('image.bin')
7010 out = tools.run('dumpimage', '-l', fname)
7011
7012 # We should see the FIT description and one for each of the two images
7013 lines = out.splitlines()
7014 descs = [line.split()[-1] for line in lines if 'escription' in line]
7015 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7016
7017 def testTemplatePhandleDup(self):
7018 """Test using a template in a node containing a phandle"""
7019 entry_args = {
7020 'atf-bl31-path': 'bl31.elf',
7021 }
7022 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007023 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007024 entry_args=entry_args)
7025 self.assertIn(
7026 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7027 str(e.exception))
7028
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307029 def testTIBoardConfig(self):
7030 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007031 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307032 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7033
Neha Malcom Francis8cd04512024-01-05 17:09:17 +05307034 def testTIBoardConfigLint(self):
7035 """Test that an incorrectly linted config file would generate error"""
7036 with self.assertRaises(ValueError) as e:
7037 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7038 self.assertIn("Yamllint error", str(e.exception))
7039
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307040 def testTIBoardConfigCombined(self):
7041 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007042 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307043 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7044 self.assertGreater(data, configlen_noheader)
7045
7046 def testTIBoardConfigNoDataType(self):
7047 """Test that error is thrown when data type is not supported"""
7048 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007049 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307050 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007051
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307052 def testPackTiSecure(self):
7053 """Test that an image with a TI secured binary can be created"""
7054 keyfile = self.TestFile('key.key')
7055 entry_args = {
7056 'keyfile': keyfile,
7057 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007058 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307059 entry_args=entry_args)[0]
7060 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7061
Manorit Chawdhry2e523b02023-12-29 16:16:27 +05307062 def testPackTiSecureFirewall(self):
7063 """Test that an image with a TI secured binary can be created"""
7064 keyfile = self.TestFile('key.key')
7065 entry_args = {
7066 'keyfile': keyfile,
7067 }
7068 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7069 entry_args=entry_args)[0]
7070 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7071 entry_args=entry_args)[0]
7072 self.assertGreater(len(data_firewall),len(data_no_firewall))
7073
7074 def testPackTiSecureFirewallMissingProperty(self):
7075 """Test that an image with a TI secured binary can be created"""
7076 keyfile = self.TestFile('key.key')
7077 entry_args = {
7078 'keyfile': keyfile,
7079 }
7080 with self.assertRaises(ValueError) as e:
7081 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7082 entry_args=entry_args)[0]
7083 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7084
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307085 def testPackTiSecureMissingTool(self):
7086 """Test that an image with a TI secured binary (non-functional) can be created
7087 when openssl is missing"""
7088 keyfile = self.TestFile('key.key')
7089 entry_args = {
7090 'keyfile': keyfile,
7091 }
7092 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007093 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307094 force_missing_bintools='openssl',
7095 entry_args=entry_args)
7096 err = stderr.getvalue()
7097 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7098
7099 def testPackTiSecureROM(self):
7100 """Test that a ROM image with a TI secured binary can be created"""
7101 keyfile = self.TestFile('key.key')
7102 entry_args = {
7103 'keyfile': keyfile,
7104 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007105 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307106 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007107 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307108 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007109 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307110 entry_args=entry_args)[0]
7111 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7112 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7113 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7114
7115 def testPackTiSecureROMCombined(self):
7116 """Test that a ROM image with a TI secured binary can be created"""
7117 keyfile = self.TestFile('key.key')
7118 entry_args = {
7119 'keyfile': keyfile,
7120 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007121 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307122 entry_args=entry_args)[0]
7123 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7124
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007125 def testEncryptedNoAlgo(self):
7126 """Test encrypted node with missing required properties"""
7127 with self.assertRaises(ValueError) as e:
7128 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7129 self.assertIn(
7130 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7131 str(e.exception))
7132
7133 def testEncryptedInvalidIvfile(self):
7134 """Test encrypted node with invalid iv file"""
7135 with self.assertRaises(ValueError) as e:
7136 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7137 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7138 str(e.exception))
7139
7140 def testEncryptedMissingKey(self):
7141 """Test encrypted node with missing key properties"""
7142 with self.assertRaises(ValueError) as e:
7143 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7144 self.assertIn(
7145 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7146 str(e.exception))
7147
7148 def testEncryptedKeySource(self):
7149 """Test encrypted node with key-source property"""
7150 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7151
7152 dtb = fdt.Fdt.FromData(data)
7153 dtb.Scan()
7154
7155 node = dtb.GetNode('/images/u-boot/cipher')
7156 self.assertEqual('algo-name', node.props['algo'].value)
7157 self.assertEqual('key-source-value', node.props['key-source'].value)
7158 self.assertEqual(ENCRYPTED_IV_DATA,
7159 tools.to_bytes(''.join(node.props['iv'].value)))
7160 self.assertNotIn('key', node.props)
7161
7162 def testEncryptedKeyFile(self):
7163 """Test encrypted node with key-filename property"""
7164 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7165
7166 dtb = fdt.Fdt.FromData(data)
7167 dtb.Scan()
7168
7169 node = dtb.GetNode('/images/u-boot/cipher')
7170 self.assertEqual('algo-name', node.props['algo'].value)
7171 self.assertEqual(ENCRYPTED_IV_DATA,
7172 tools.to_bytes(''.join(node.props['iv'].value)))
7173 self.assertEqual(ENCRYPTED_KEY_DATA,
7174 tools.to_bytes(''.join(node.props['key'].value)))
7175 self.assertNotIn('key-source', node.props)
7176
Lukas Funkee901faf2023-07-18 13:53:13 +02007177
7178 def testSplPubkeyDtb(self):
Simon Glass4b861272024-07-20 11:49:41 +01007179 """Test u_boot_spl_pubkey_dtb etype"""
7180 data = tools.read_file(self.TestFile("key.pem"))
7181 self._MakeInputFile("key.crt", data)
7182 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7183 image = control.images['image']
7184 entries = image.GetEntries()
7185 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7186 dtb_data = dtb_entry.GetData()
7187 dtb = fdt.Fdt.FromData(dtb_data)
7188 dtb.Scan()
Lukas Funkee901faf2023-07-18 13:53:13 +02007189
Simon Glass4b861272024-07-20 11:49:41 +01007190 signature_node = dtb.GetNode('/signature')
7191 self.assertIsNotNone(signature_node)
7192 key_node = signature_node.FindNode("key-key")
7193 self.assertIsNotNone(key_node)
7194 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7195 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7196 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007197
Lukas Funke712e1062023-08-03 17:22:14 +02007198 def testXilinxBootgenSigning(self):
7199 """Test xilinx-bootgen etype"""
7200 bootgen = bintool.Bintool.create('bootgen')
7201 self._CheckBintool(bootgen)
7202 data = tools.read_file(self.TestFile("key.key"))
7203 self._MakeInputFile("psk.pem", data)
7204 self._MakeInputFile("ssk.pem", data)
7205 self._SetupPmuFwlElf()
7206 self._SetupSplElf()
7207 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7208 image_fname = tools.get_output_filename('image.bin')
7209
7210 # Read partition header table and check if authentication is enabled
7211 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7212 "-read", image_fname, "pht").splitlines()
7213 attributes = {"authentication": None,
7214 "core": None,
7215 "encryption": None}
7216
7217 for l in bootgen_out:
7218 for a in attributes.keys():
7219 if a in l:
7220 m = re.match(fr".*{a} \[([^]]+)\]", l)
7221 attributes[a] = m.group(1)
7222
7223 self.assertTrue(attributes['authentication'] == "rsa")
7224 self.assertTrue(attributes['core'] == "a53-0")
7225 self.assertTrue(attributes['encryption'] == "no")
7226
7227 def testXilinxBootgenSigningEncryption(self):
7228 """Test xilinx-bootgen etype"""
7229 bootgen = bintool.Bintool.create('bootgen')
7230 self._CheckBintool(bootgen)
7231 data = tools.read_file(self.TestFile("key.key"))
7232 self._MakeInputFile("psk.pem", data)
7233 self._MakeInputFile("ssk.pem", data)
7234 self._SetupPmuFwlElf()
7235 self._SetupSplElf()
7236 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7237 image_fname = tools.get_output_filename('image.bin')
7238
7239 # Read boot header in order to verify encryption source and
7240 # encryption parameter
7241 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7242 "-read", image_fname, "bh").splitlines()
7243 attributes = {"auth_only":
7244 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7245 "encryption_keystore":
7246 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7247 "value": None},
7248 }
7249
7250 for l in bootgen_out:
7251 for a in attributes.keys():
7252 if a in l:
7253 m = re.match(attributes[a]['re'], l)
7254 attributes[a] = m.group(1)
7255
7256 # Check if fsbl-attribute is set correctly
7257 self.assertTrue(attributes['auth_only'] == "true")
7258 # Check if key is stored in efuse
7259 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7260
7261 def testXilinxBootgenMissing(self):
7262 """Test that binman still produces an image if bootgen is missing"""
7263 data = tools.read_file(self.TestFile("key.key"))
7264 self._MakeInputFile("psk.pem", data)
7265 self._MakeInputFile("ssk.pem", data)
7266 self._SetupPmuFwlElf()
7267 self._SetupSplElf()
7268 with test_util.capture_sys_output() as (_, stderr):
7269 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7270 force_missing_bintools='bootgen')
7271 err = stderr.getvalue()
7272 self.assertRegex(err,
7273 "Image 'image'.*missing bintools.*: bootgen")
7274
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307275 def _GetCapsuleHeaders(self, data):
7276 """Get the capsule header contents
7277
7278 Args:
7279 data: Capsule file contents
7280
7281 Returns:
7282 Dict:
7283 key: Capsule Header name (str)
7284 value: Header field value (str)
7285 """
7286 capsule_file = os.path.join(self._indir, 'test.capsule')
7287 tools.write_file(capsule_file, data)
7288
7289 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7290 lines = out.splitlines()
7291
7292 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7293 vals = {}
7294 for line in lines:
7295 mat = re_line.match(line)
7296 if mat:
7297 vals[mat.group(1)] = mat.group(2)
7298
7299 return vals
7300
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307301 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7302 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307303 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7304 fmp_size = "00000010"
7305 fmp_fw_version = "00000002"
7306 capsule_image_index = "00000001"
7307 oemflag = "00018000"
7308 auth_hdr_revision = "00000200"
7309 auth_hdr_cert_type = "00000EF1"
7310
7311 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307312
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307313 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307314
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307315 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307316
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307317 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7318 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7319 self.assertEqual(capsule_image_index,
7320 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307321
7322 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307323 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7324
7325 if signed_capsule:
7326 self.assertEqual(auth_hdr_revision,
7327 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7328 self.assertEqual(auth_hdr_cert_type,
7329 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7330 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7331 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7332
7333 if version_check:
7334 self.assertEqual(fmp_signature,
7335 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7336 self.assertEqual(fmp_size,
7337 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7338 self.assertEqual(fmp_fw_version,
7339 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7340
7341 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307342
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307343 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7344 if accept_capsule:
7345 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7346 else:
7347 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7348
7349 hdr = self._GetCapsuleHeaders(data)
7350
7351 self.assertEqual(capsule_hdr_guid.upper(),
7352 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7353
7354 if accept_capsule:
7355 capsule_size = "0000002C"
7356 else:
7357 capsule_size = "0000001C"
7358 self.assertEqual(capsule_size,
7359 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7360
7361 if accept_capsule:
7362 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7363
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307364 def testCapsuleGen(self):
7365 """Test generation of EFI capsule"""
7366 data = self._DoReadFile('311_capsule.dts')
7367
7368 self._CheckCapsule(data)
7369
7370 def testSignedCapsuleGen(self):
7371 """Test generation of EFI capsule"""
7372 data = tools.read_file(self.TestFile("key.key"))
7373 self._MakeInputFile("key.key", data)
7374 data = tools.read_file(self.TestFile("key.pem"))
7375 self._MakeInputFile("key.crt", data)
7376
7377 data = self._DoReadFile('312_capsule_signed.dts')
7378
7379 self._CheckCapsule(data, signed_capsule=True)
7380
7381 def testCapsuleGenVersionSupport(self):
7382 """Test generation of EFI capsule with version support"""
7383 data = self._DoReadFile('313_capsule_version.dts')
7384
7385 self._CheckCapsule(data, version_check=True)
7386
7387 def testCapsuleGenSignedVer(self):
7388 """Test generation of signed EFI capsule with version information"""
7389 data = tools.read_file(self.TestFile("key.key"))
7390 self._MakeInputFile("key.key", data)
7391 data = tools.read_file(self.TestFile("key.pem"))
7392 self._MakeInputFile("key.crt", data)
7393
7394 data = self._DoReadFile('314_capsule_signed_ver.dts')
7395
7396 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7397
7398 def testCapsuleGenCapOemFlags(self):
7399 """Test generation of EFI capsule with OEM Flags set"""
7400 data = self._DoReadFile('315_capsule_oemflags.dts')
7401
7402 self._CheckCapsule(data, capoemflags=True)
7403
7404 def testCapsuleGenKeyMissing(self):
7405 """Test that binman errors out on missing key"""
7406 with self.assertRaises(ValueError) as e:
7407 self._DoReadFile('316_capsule_missing_key.dts')
7408
7409 self.assertIn("Both private key and public key certificate need to be provided",
7410 str(e.exception))
7411
7412 def testCapsuleGenIndexMissing(self):
7413 """Test that binman errors out on missing image index"""
7414 with self.assertRaises(ValueError) as e:
7415 self._DoReadFile('317_capsule_missing_index.dts')
7416
7417 self.assertIn("entry is missing properties: image-index",
7418 str(e.exception))
7419
7420 def testCapsuleGenGuidMissing(self):
7421 """Test that binman errors out on missing image GUID"""
7422 with self.assertRaises(ValueError) as e:
7423 self._DoReadFile('318_capsule_missing_guid.dts')
7424
7425 self.assertIn("entry is missing properties: image-guid",
7426 str(e.exception))
7427
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307428 def testCapsuleGenAcceptCapsule(self):
7429 """Test generationg of accept EFI capsule"""
7430 data = self._DoReadFile('319_capsule_accept.dts')
7431
7432 self._CheckEmptyCapsule(data, accept_capsule=True)
7433
7434 def testCapsuleGenRevertCapsule(self):
7435 """Test generationg of revert EFI capsule"""
7436 data = self._DoReadFile('320_capsule_revert.dts')
7437
7438 self._CheckEmptyCapsule(data)
7439
7440 def testCapsuleGenAcceptGuidMissing(self):
7441 """Test that binman errors out on missing image GUID for accept capsule"""
7442 with self.assertRaises(ValueError) as e:
7443 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7444
7445 self.assertIn("Image GUID needed for generating accept capsule",
7446 str(e.exception))
7447
7448 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7449 """Test that capsule-type is specified"""
7450 with self.assertRaises(ValueError) as e:
7451 self._DoReadFile('322_empty_capsule_type_missing.dts')
7452
7453 self.assertIn("entry is missing properties: capsule-type",
7454 str(e.exception))
7455
7456 def testCapsuleGenAcceptOrRevertMissing(self):
7457 """Test that both accept and revert capsule are not specified"""
7458 with self.assertRaises(ValueError) as e:
7459 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7460
Simon Glassa360b8f2024-06-23 11:55:06 -06007461 def test_assume_size(self):
7462 """Test handling of the assume-size property for external blob"""
7463 with self.assertRaises(ValueError) as e:
7464 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7465 allow_fake_blobs=True)
7466 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7467 str(e.exception))
7468
7469 def test_assume_size_ok(self):
7470 """Test handling of the assume-size where it fits OK"""
7471 with test_util.capture_sys_output() as (stdout, stderr):
7472 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7473 allow_fake_blobs=True)
7474 err = stderr.getvalue()
7475 self.assertRegex(
7476 err,
7477 "Image '.*' has faked external blobs and is non-functional: .*")
7478
7479 def test_assume_size_no_fake(self):
7480 """Test handling of the assume-size where it fits OK"""
7481 with test_util.capture_sys_output() as (stdout, stderr):
7482 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7483 err = stderr.getvalue()
7484 self.assertRegex(
7485 err,
7486 "Image '.*' is missing external blobs and is non-functional: .*")
7487
Simon Glassf3598922024-07-20 11:49:45 +01007488 def CheckAlternates(self, dts, phase, xpl_data):
7489 """Run the test for the alterative-fdt etype
7490
7491 Args:
7492 dts (str): Devicetree file to process
7493 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7494 xpl_data (bytes): Expected data for the phase's binary
7495
7496 Returns:
7497 dict of .dtb files produced
7498 key: str filename
7499 value: Fdt object
7500 """
7501 testdir = TestFunctional._MakeInputDir('dtb')
7502 dtb_list = []
7503 for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
7504 tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
7505 base = os.path.splitext(os.path.basename(fname))[0]
7506 dtb_list.append(base + '.bin')
7507 shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
7508
7509 entry_args = {
7510 f'{phase}-dtb': '1',
7511 f'{phase}-bss-pad': 'y',
7512 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7513 }
7514 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7515 use_expanded=True, entry_args=entry_args)[0]
7516 self.assertEqual(xpl_data, data[:len(xpl_data)])
7517 rest = data[len(xpl_data):]
7518 pad_len = 10
7519 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7520
7521 # Check the dtb is using the test file
7522 dtb_data = rest[pad_len:]
7523 dtb = fdt.Fdt.FromData(dtb_data)
7524 dtb.Scan()
7525 fdt_size = dtb.GetFdtObj().totalsize()
7526 self.assertEqual('model-not-set',
7527 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7528
7529 pad_len = 10
7530
7531 # Check the other output files
7532 dtbs = {}
7533 for fname in dtb_list:
7534 pathname = tools.get_output_filename(fname)
7535 self.assertTrue(os.path.exists(pathname))
7536
7537 data = tools.read_file(pathname)
7538 self.assertEqual(xpl_data, data[:len(xpl_data)])
7539 rest = data[len(xpl_data):]
7540
7541 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7542 rest = rest[pad_len:]
7543
7544 dtb = fdt.Fdt.FromData(rest)
7545 dtb.Scan()
7546 dtbs[fname] = dtb
7547
7548 expected = 'one' if '1' in fname else 'two'
7549 self.assertEqual(f'u-boot,model-{expected}',
7550 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7551
7552 # Make sure the FDT is the same size as the 'main' one
7553 rest = rest[fdt_size:]
7554
7555 self.assertEqual(b'', rest)
7556 return dtbs
7557
7558 def testAlternatesFdt(self):
7559 """Test handling of alternates-fdt etype"""
7560 self._SetupTplElf()
7561 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7562 U_BOOT_TPL_NODTB_DATA)
7563 for dtb in dtbs.values():
7564 # Check for the node with the tag
7565 node = dtb.GetNode('/node')
7566 self.assertIsNotNone(node)
7567 self.assertEqual(5, len(node.props.keys()))
7568
7569 # Make sure the other node is still there
7570 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7571
7572 def testAlternatesFdtgrep(self):
7573 """Test handling of alternates-fdt etype using fdtgrep"""
7574 self._SetupTplElf()
7575 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7576 U_BOOT_TPL_NODTB_DATA)
7577 for dtb in dtbs.values():
7578 # Check for the node with the tag
7579 node = dtb.GetNode('/node')
7580 self.assertIsNotNone(node)
7581 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7582 node.props.keys())
7583
7584 # Make sure the other node is gone
7585 self.assertIsNone(dtb.GetNode('/node/other-node'))
7586
7587 def testAlternatesFdtgrepVpl(self):
7588 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7589 self._SetupVplElf()
7590 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7591 U_BOOT_VPL_NODTB_DATA)
7592
7593 def testAlternatesFdtgrepSpl(self):
7594 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7595 self._SetupSplElf()
7596 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7597 U_BOOT_SPL_NODTB_DATA)
7598
7599 def testAlternatesFdtgrepInval(self):
7600 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7601 self._SetupSplElf()
7602 with self.assertRaises(ValueError) as e:
7603 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7604 U_BOOT_SPL_NODTB_DATA)
7605 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7606 str(e.exception))
7607
Simon Glassa360b8f2024-06-23 11:55:06 -06007608
Simon Glassac599912017-11-12 21:52:22 -07007609if __name__ == "__main__":
7610 unittest.main()