blob: 2577c0016c0cbf7478f6c69cdd74a9bbb0974796 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass57454f42016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass57454f42016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glass45d556d2020-07-09 18:39:45 -06009import collections
Simon Glassf3598922024-07-20 11:49:45 +010010import glob
Simon Glassc585dd42020-04-17 18:09:03 -060011import gzip
Simon Glassae7cf032018-09-14 04:57:31 -060012import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070013from optparse import OptionParser
14import os
Simon Glass45d556d2020-07-09 18:39:45 -060015import re
Simon Glass57454f42016-11-25 20:15:52 -070016import shutil
17import struct
18import sys
19import tempfile
20import unittest
Simon Glass162017b2022-01-09 20:13:57 -070021import unittest.mock
22import urllib.error
Simon Glass57454f42016-11-25 20:15:52 -070023
Simon Glass4eae9252022-01-09 20:13:50 -070024from binman import bintool
Simon Glassc585dd42020-04-17 18:09:03 -060025from binman import cbfs_util
26from binman import cmdline
27from binman import control
28from binman import elf
29from binman import elf_test
Simon Glass3efb2972021-11-23 21:08:59 -070030from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060031from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060032from binman import state
33from dtoc import fdt
34from dtoc import fdt_util
35from binman.etype import fdtmap
36from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060037from binman.image import Image
Simon Glass131444f2023-02-23 18:18:04 -070038from u_boot_pylib import command
39from u_boot_pylib import test_util
40from u_boot_pylib import tools
41from u_boot_pylib import tout
Simon Glass57454f42016-11-25 20:15:52 -070042
43# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060044U_BOOT_DATA = b'1234'
45U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +030046U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass56d05412022-02-28 07:16:54 -070048U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glass303f62f2019-05-17 22:00:46 -060049BLOB_DATA = b'89'
50ME_DATA = b'0abcd'
51VGA_DATA = b'vga'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +053052EFI_CAPSULE_DATA = b'efi'
Simon Glass303f62f2019-05-17 22:00:46 -060053U_BOOT_DTB_DATA = b'udtb'
54U_BOOT_SPL_DTB_DATA = b'spldtb'
55U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass56d05412022-02-28 07:16:54 -070056U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glass303f62f2019-05-17 22:00:46 -060057X86_START16_DATA = b'start16'
58X86_START16_SPL_DATA = b'start16spl'
59X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060060X86_RESET16_DATA = b'reset16'
61X86_RESET16_SPL_DATA = b'reset16spl'
62X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060063PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
64U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
65U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
66U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass56d05412022-02-28 07:16:54 -070067U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +030068U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
69U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
70U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glass303f62f2019-05-17 22:00:46 -060071FSP_DATA = b'fsp'
72CMC_DATA = b'cmc'
73VBT_DATA = b'vbt'
74MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060075TEXT_DATA = 'text'
76TEXT_DATA2 = 'text2'
77TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060078CROS_EC_RW_DATA = b'ecrw'
79GBB_DATA = b'gbbd'
80BMPBLK_DATA = b'bmp'
81VBLOCK_DATA = b'vblk'
82FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
83 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060084COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060085COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060086REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060087FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060088FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060089FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060090ATF_BL31_DATA = b'bl31'
Roger Quadros5cdcea02022-02-19 20:50:04 +020091TEE_OS_DATA = b'this is some tee OS data'
Neha Malcom Francis59be2552023-12-05 15:12:18 +053092TI_DM_DATA = b'tidmtidm'
Simon Glass3efb2972021-11-23 21:08:59 -070093ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080094OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050095SCP_DATA = b'scp'
Jonas Karlman35305492023-02-25 19:01:33 +000096ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glassa435cd12020-09-01 05:13:59 -060097TEST_FDT1_DATA = b'fdt1'
98TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060099ENV_DATA = b'var1=1\nvar2="2"'
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200100ENCRYPTED_IV_DATA = b'123456'
101ENCRYPTED_KEY_DATA = b'abcde'
Philippe Reynesebe96cb2022-03-28 22:57:04 +0200102PRE_LOAD_MAGIC = b'UBSH'
103PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
104PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530105TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530106TI_UNSECURE_DATA = b'unsecuredata'
Simon Glassa435cd12020-09-01 05:13:59 -0600107
108# Subdirectory of the input dir to use to put test FDTs
109TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600110
Simon Glass2c6adba2019-07-20 12:23:47 -0600111# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600112EXTRACT_DTB_SIZE = 0x3c9
113
Simon Glass2c6adba2019-07-20 12:23:47 -0600114# Properties expected to be in the device tree when update_dtb is used
115BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
116
Simon Glassfb30e292019-07-20 12:23:51 -0600117# Extra properties expected to be in the device tree when allow-repack is used
118REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
119
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200120# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200121COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700122
Simon Glassad5cfe12023-01-07 14:07:14 -0700123TEE_ADDR = 0x5678
124
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530125# Firmware Management Protocol(FMP) GUID
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530126FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530127# Image GUID specified in the DTS
Caleb Connolly4bdc9602024-08-30 13:34:35 +0100128CAPSULE_IMAGE_GUID = '985F2937-7C2E-5E9A-8A5E-8E063312964B'
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530129# Windows cert GUID
130WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +0530131# Empty capsule GUIDs
132EMPTY_CAPSULE_ACCEPT_GUID = '0c996046-bcc0-4d04-85ec-e1fcedf1c6f8'
133EMPTY_CAPSULE_REVERT_GUID = 'acd58b4b-c0e8-475f-99b5-6b3f7e07aaf0'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530134
Simon Glass57454f42016-11-25 20:15:52 -0700135class TestFunctional(unittest.TestCase):
136 """Functional tests for binman
137
138 Most of these use a sample .dts file to build an image and then check
139 that it looks correct. The sample files are in the test/ subdirectory
140 and are numbered.
141
142 For each entry type a very small test file is created using fixed
143 string contents. This makes it easy to test that things look right, and
144 debug problems.
145
146 In some cases a 'real' file must be used - these are also supplied in
147 the test/ diurectory.
148 """
149 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600150 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700151 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600152 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700153
Simon Glass57454f42016-11-25 20:15:52 -0700154 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600155 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
156 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700157
158 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600159 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700160
161 # Create some test files
162 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
163 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
164 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600165 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700166 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700167 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700168 TestFunctional._MakeInputFile('me.bin', ME_DATA)
169 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600170 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600171
Jagdish Gediya311d4842018-09-03 21:35:08 +0530172 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600173
Simon Glassabab18c2019-08-24 07:22:49 -0600174 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
175 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700176 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600177 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600178 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600179
180 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
181 X86_RESET16_DATA)
182 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
183 X86_RESET16_SPL_DATA)
184 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
185 X86_RESET16_TPL_DATA)
186
Simon Glass57454f42016-11-25 20:15:52 -0700187 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700188 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
189 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600190 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
191 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700192 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
193 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700194 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
195 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700196 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700197 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600198 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600199 TestFunctional._MakeInputDir('devkeys')
200 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600201 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600202 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600203 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600204 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700205
Simon Glassf6290892019-08-24 07:22:53 -0600206 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
207 elf_test.BuildElfTestFiles(cls._elf_testdir)
208
Simon Glass72232452016-11-25 20:15:53 -0700209 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600210 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700211 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700212
213 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600214 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700215
Simon Glass862f8e22019-08-24 07:22:43 -0600216 shutil.copytree(cls.TestFile('files'),
217 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600218
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530219 shutil.copytree(cls.TestFile('yaml'),
220 os.path.join(cls._indir, 'yaml'))
221
Simon Glass7ba33592018-09-14 04:57:26 -0600222 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600223 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600224 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200225 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Neha Malcom Francis59be2552023-12-05 15:12:18 +0530226 TestFunctional._MakeInputFile('dm.bin', TI_DM_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700227 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800228 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500229 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman35305492023-02-25 19:01:33 +0000230 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530231 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530232 TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600233
Simon Glassa435cd12020-09-01 05:13:59 -0600234 # Add a few .dtb files for testing
235 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
236 TEST_FDT1_DATA)
237 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
238 TEST_FDT2_DATA)
239
Simon Glassa0729502020-09-06 10:35:33 -0600240 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
241
Simon Glass5f423422022-03-05 20:19:12 -0700242 # ELF file with two sections in different parts of memory, used for both
243 # ATF and OP_TEE
244 TestFunctional._MakeInputFile('bl31.elf',
245 tools.read_file(cls.ElfTestFile('elf_sections')))
246 TestFunctional._MakeInputFile('tee.elf',
247 tools.read_file(cls.ElfTestFile('elf_sections')))
248
Simon Glassad5cfe12023-01-07 14:07:14 -0700249 # Newer OP_TEE file in v1 binary format
250 cls.make_tee_bin('tee.bin')
251
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200252 # test files for encrypted tests
253 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
254 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
255
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200256 cls.comp_bintools = {}
257 for name in COMP_BINTOOLS:
258 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600259
Simon Glass57454f42016-11-25 20:15:52 -0700260 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600261 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700262 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600263 if cls.preserve_indir:
264 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600265 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600266 if cls._indir:
267 shutil.rmtree(cls._indir)
268 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700269
Simon Glass1c420c92019-07-08 13:18:49 -0600270 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600271 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600272 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600273 """Accept arguments controlling test execution
274
275 Args:
276 preserve_indir: Preserve the shared input directory used by all
277 tests in this class.
278 preserve_outdir: Preserve the output directories used by tests. Each
279 test has its own, so this is normally only useful when running a
280 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600281 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600282 """
283 cls.preserve_indir = preserve_indir
284 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600285 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600286 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600287
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200288 def _CheckBintool(self, bintool):
289 if not bintool.is_present():
290 self.skipTest('%s not available' % bintool.name)
291
Simon Glass1de34482019-07-08 13:18:53 -0600292 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200293 bintool = self.comp_bintools['lz4']
294 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600295
Simon Glassee9d10d2019-07-20 12:24:09 -0600296 def _CleanupOutputDir(self):
297 """Remove the temporary output directory"""
298 if self.preserve_outdirs:
299 print('Preserving output dir: %s' % tools.outdir)
300 else:
Simon Glass80025522022-01-29 14:14:04 -0700301 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600302
Simon Glass57454f42016-11-25 20:15:52 -0700303 def setUp(self):
304 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700305 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700306 command.test_result = None
307
308 def tearDown(self):
309 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600310 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700311
Simon Glassb3d6fc72019-07-20 12:24:10 -0600312 def _SetupImageInTmpdir(self):
313 """Set up the output image in a new temporary directory
314
315 This is used when an image has been generated in the output directory,
316 but we want to run binman again. This will create a new output
317 directory and fail to delete the original one.
318
319 This creates a new temporary directory, copies the image to it (with a
320 new name) and removes the old output directory.
321
322 Returns:
323 Tuple:
324 Temporary directory to use
325 New image filename
326 """
Simon Glass80025522022-01-29 14:14:04 -0700327 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600328 tmpdir = tempfile.mkdtemp(prefix='binman.')
329 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700330 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600331 self._CleanupOutputDir()
332 return tmpdir, updated_fname
333
Simon Glass8425a1f2018-07-17 13:25:48 -0600334 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600335 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600336 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
337 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
338 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700339 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600340
Simon Glass57454f42016-11-25 20:15:52 -0700341 def _RunBinman(self, *args, **kwargs):
342 """Run binman using the command line
343
344 Args:
345 Arguments to pass, as a list of strings
346 kwargs: Arguments to pass to Command.RunPipe()
347 """
Simon Glass840be732022-01-29 14:14:05 -0700348 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700349 capture=True, capture_stderr=True, raise_on_error=False)
350 if result.return_code and kwargs.get('raise_on_error', True):
351 raise Exception("Error running '%s': %s" % (' '.join(args),
352 result.stdout + result.stderr))
353 return result
354
Simon Glassf46732a2019-07-08 14:25:29 -0600355 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700356 """Run binman using directly (in the same process)
357
358 Args:
359 Arguments to pass, as a list of strings
360 Returns:
361 Return value (0 for success)
362 """
Simon Glassf46732a2019-07-08 14:25:29 -0600363 argv = list(argv)
364 args = cmdline.ParseArgs(argv)
365 args.pager = 'binman-invalid-pager'
366 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700367
368 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600369 # args.verbosity = tout.DEBUG
370 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700371
Simon Glass91710b32018-07-17 13:25:32 -0600372 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600373 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300374 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100375 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700376 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis6b463da2023-07-22 00:14:44 +0530377 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass57454f42016-11-25 20:15:52 -0700378 """Run binman with a given test file
379
380 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600381 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600382 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600383 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600384 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600385 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600386 entry_args: Dict of entry args to supply to binman
387 key: arg name
388 value: value of that arg
389 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600390 use_real_dtb: True to use the test file as the contents of
391 the u-boot-dtb entry. Normally this is not needed and the
392 test contents (the U_BOOT_DTB_DATA string) can be used.
393 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300394 use_expanded: True to use expanded entries where available, e.g.
395 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600396 verbosity: Verbosity level to use (0-3, None=don't set it)
397 allow_missing: Set the '--allow-missing' flag so that missing
398 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100399 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600400 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600401 threads: Number of threads to use (None for default, 0 for
402 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600403 test_section_timeout: True to force the first time to timeout, as
404 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600405 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon 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 Glasscd2783e2024-07-20 11:49:46 +01004184 def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True):
4185 """Check an image with an FIT with multiple FDT images"""
Simon Glassa435cd12020-09-01 05:13:59 -06004186 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 = {
Simon Glass1032acc2020-09-06 10:39:08 -06004224 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004225 }
Simon Glasscd2783e2024-07-20 11:49:46 +01004226 if use_fdt_list:
4227 entry_args['of-list'] = 'test-fdt1 test-fdt2'
Simon Glassa435cd12020-09-01 05:13:59 -06004228 data = self._DoReadFileDtb(
Simon Glasscd2783e2024-07-20 11:49:46 +01004229 dts,
Simon Glassa435cd12020-09-01 05:13:59 -06004230 entry_args=entry_args,
4231 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4232 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4233 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4234
4235 dtb = fdt.Fdt.FromData(fit_data)
4236 dtb.Scan()
4237 fnode = dtb.GetNode('/images/kernel')
4238 self.assertIn('data', fnode.props)
4239
4240 # Check all the properties in fdt-1 and fdt-2
4241 _CheckFdt(1, TEST_FDT1_DATA)
4242 _CheckFdt(2, TEST_FDT2_DATA)
4243
4244 # Check configurations
4245 _CheckConfig(1, TEST_FDT1_DATA)
4246 _CheckConfig(2, TEST_FDT2_DATA)
4247
Simon Glasscd2783e2024-07-20 11:49:46 +01004248 def testFitFdt(self):
4249 """Test an image with an FIT with multiple FDT images"""
4250 self.CheckFitFdt()
4251
Simon Glassa435cd12020-09-01 05:13:59 -06004252 def testFitFdtMissingList(self):
4253 """Test handling of a missing 'of-list' entry arg"""
4254 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004255 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004256 self.assertIn("Generator node requires 'of-list' entry argument",
4257 str(e.exception))
4258
4259 def testFitFdtEmptyList(self):
4260 """Test handling of an empty 'of-list' entry arg"""
4261 entry_args = {
4262 'of-list': '',
4263 }
4264 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4265
4266 def testFitFdtMissingProp(self):
4267 """Test handling of a missing 'fit,fdt-list' property"""
4268 with self.assertRaises(ValueError) as e:
4269 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4270 self.assertIn("Generator node requires 'fit,fdt-list' property",
4271 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004272
Simon Glass1032acc2020-09-06 10:39:08 -06004273 def testFitFdtMissing(self):
4274 """Test handling of a missing 'default-dt' entry arg"""
4275 entry_args = {
4276 'of-list': 'test-fdt1 test-fdt2',
4277 }
4278 with self.assertRaises(ValueError) as e:
4279 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004280 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004281 entry_args=entry_args,
4282 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4283 self.assertIn("Generated 'default' node requires default-dt entry argument",
4284 str(e.exception))
4285
4286 def testFitFdtNotInList(self):
4287 """Test handling of a default-dt that is not in the of-list"""
4288 entry_args = {
4289 'of-list': 'test-fdt1 test-fdt2',
4290 'default-dt': 'test-fdt3',
4291 }
4292 with self.assertRaises(ValueError) as e:
4293 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004294 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004295 entry_args=entry_args,
4296 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4297 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4298 str(e.exception))
4299
Simon Glassa820af72020-09-06 10:39:09 -06004300 def testFitExtblobMissingHelp(self):
4301 """Test display of help messages when an external blob is missing"""
4302 control.missing_blob_help = control._ReadMissingBlobHelp()
4303 control.missing_blob_help['wibble'] = 'Wibble test'
4304 control.missing_blob_help['another'] = 'Another test'
4305 with test_util.capture_sys_output() as (stdout, stderr):
4306 self._DoTestFile('168_fit_missing_blob.dts',
4307 allow_missing=True)
4308 err = stderr.getvalue()
4309
4310 # We can get the tag from the name, the type or the missing-msg
4311 # property. Check all three.
4312 self.assertIn('You may need to build ARM Trusted', err)
4313 self.assertIn('Wibble test', err)
4314 self.assertIn('Another test', err)
4315
Simon Glass6f1f4d42020-09-06 10:35:32 -06004316 def testMissingBlob(self):
4317 """Test handling of a blob containing a missing file"""
4318 with self.assertRaises(ValueError) as e:
4319 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4320 self.assertIn("Filename 'missing' not found in input path",
4321 str(e.exception))
4322
Simon Glassa0729502020-09-06 10:35:33 -06004323 def testEnvironment(self):
4324 """Test adding a U-Boot environment"""
4325 data = self._DoReadFile('174_env.dts')
4326 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4327 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4328 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4329 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4330 env)
4331
4332 def testEnvironmentNoSize(self):
4333 """Test that a missing 'size' property is detected"""
4334 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004335 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004336 self.assertIn("'u-boot-env' entry must have a size property",
4337 str(e.exception))
4338
4339 def testEnvironmentTooSmall(self):
4340 """Test handling of an environment that does not fit"""
4341 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004342 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004343
4344 # checksum, start byte, environment with \0 terminator, final \0
4345 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4346 short = need - 0x8
4347 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4348 str(e.exception))
4349
Simon Glassd1fdf752020-10-26 17:40:01 -06004350 def testSkipAtStart(self):
4351 """Test handling of skip-at-start section"""
4352 data = self._DoReadFile('177_skip_at_start.dts')
4353 self.assertEqual(U_BOOT_DATA, data)
4354
4355 image = control.images['image']
4356 entries = image.GetEntries()
4357 section = entries['section']
4358 self.assertEqual(0, section.offset)
4359 self.assertEqual(len(U_BOOT_DATA), section.size)
4360 self.assertEqual(U_BOOT_DATA, section.GetData())
4361
4362 entry = section.GetEntries()['u-boot']
4363 self.assertEqual(16, entry.offset)
4364 self.assertEqual(len(U_BOOT_DATA), entry.size)
4365 self.assertEqual(U_BOOT_DATA, entry.data)
4366
4367 def testSkipAtStartPad(self):
4368 """Test handling of skip-at-start section with padded entry"""
4369 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004370 before = tools.get_bytes(0, 8)
4371 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004372 all = before + U_BOOT_DATA + after
4373 self.assertEqual(all, data)
4374
4375 image = control.images['image']
4376 entries = image.GetEntries()
4377 section = entries['section']
4378 self.assertEqual(0, section.offset)
4379 self.assertEqual(len(all), section.size)
4380 self.assertEqual(all, section.GetData())
4381
4382 entry = section.GetEntries()['u-boot']
4383 self.assertEqual(16, entry.offset)
4384 self.assertEqual(len(all), entry.size)
4385 self.assertEqual(U_BOOT_DATA, entry.data)
4386
4387 def testSkipAtStartSectionPad(self):
4388 """Test handling of skip-at-start section with padding"""
4389 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004390 before = tools.get_bytes(0, 8)
4391 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004392 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004393 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004394
4395 image = control.images['image']
4396 entries = image.GetEntries()
4397 section = entries['section']
4398 self.assertEqual(0, section.offset)
4399 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004400 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004401 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004402
4403 entry = section.GetEntries()['u-boot']
4404 self.assertEqual(16, entry.offset)
4405 self.assertEqual(len(U_BOOT_DATA), entry.size)
4406 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004407
Simon Glassbb395742020-10-26 17:40:14 -06004408 def testSectionPad(self):
4409 """Testing padding with sections"""
4410 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004411 expected = (tools.get_bytes(ord('&'), 3) +
4412 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004413 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004414 tools.get_bytes(ord('!'), 1) +
4415 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004416 self.assertEqual(expected, data)
4417
4418 def testSectionAlign(self):
4419 """Testing alignment with sections"""
4420 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4421 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004422 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004423 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004424 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004425 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004426 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4427 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004428 self.assertEqual(expected, data)
4429
Simon Glassd92c8362020-10-26 17:40:25 -06004430 def testCompressImage(self):
4431 """Test compression of the entire image"""
4432 self._CheckLz4()
4433 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4434 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4435 dtb = fdt.Fdt(out_dtb_fname)
4436 dtb.Scan()
4437 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4438 'uncomp-size'])
4439 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004440 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004441
4442 # Do a sanity check on various fields
4443 image = control.images['image']
4444 entries = image.GetEntries()
4445 self.assertEqual(2, len(entries))
4446
4447 entry = entries['blob']
4448 self.assertEqual(COMPRESS_DATA, entry.data)
4449 self.assertEqual(len(COMPRESS_DATA), entry.size)
4450
4451 entry = entries['u-boot']
4452 self.assertEqual(U_BOOT_DATA, entry.data)
4453 self.assertEqual(len(U_BOOT_DATA), entry.size)
4454
4455 self.assertEqual(len(data), image.size)
4456 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4457 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4458 orig = self._decompress(image.data)
4459 self.assertEqual(orig, image.uncomp_data)
4460
4461 expected = {
4462 'blob:offset': 0,
4463 'blob:size': len(COMPRESS_DATA),
4464 'u-boot:offset': len(COMPRESS_DATA),
4465 'u-boot:size': len(U_BOOT_DATA),
4466 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4467 'offset': 0,
4468 'image-pos': 0,
4469 'size': len(data),
4470 }
4471 self.assertEqual(expected, props)
4472
4473 def testCompressImageLess(self):
4474 """Test compression where compression reduces the image size"""
4475 self._CheckLz4()
4476 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4477 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4478 dtb = fdt.Fdt(out_dtb_fname)
4479 dtb.Scan()
4480 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4481 'uncomp-size'])
4482 orig = self._decompress(data)
4483
Brandon Maiera657bc62024-06-04 16:16:05 +00004484 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004485
4486 # Do a sanity check on various fields
4487 image = control.images['image']
4488 entries = image.GetEntries()
4489 self.assertEqual(2, len(entries))
4490
4491 entry = entries['blob']
4492 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4493 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4494
4495 entry = entries['u-boot']
4496 self.assertEqual(U_BOOT_DATA, entry.data)
4497 self.assertEqual(len(U_BOOT_DATA), entry.size)
4498
4499 self.assertEqual(len(data), image.size)
4500 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4501 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4502 image.uncomp_size)
4503 orig = self._decompress(image.data)
4504 self.assertEqual(orig, image.uncomp_data)
4505
4506 expected = {
4507 'blob:offset': 0,
4508 'blob:size': len(COMPRESS_DATA_BIG),
4509 'u-boot:offset': len(COMPRESS_DATA_BIG),
4510 'u-boot:size': len(U_BOOT_DATA),
4511 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4512 'offset': 0,
4513 'image-pos': 0,
4514 'size': len(data),
4515 }
4516 self.assertEqual(expected, props)
4517
4518 def testCompressSectionSize(self):
4519 """Test compression of a section with a fixed size"""
4520 self._CheckLz4()
4521 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4522 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4523 dtb = fdt.Fdt(out_dtb_fname)
4524 dtb.Scan()
4525 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4526 'uncomp-size'])
4527 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004528 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004529 expected = {
4530 'section/blob:offset': 0,
4531 'section/blob:size': len(COMPRESS_DATA),
4532 'section/u-boot:offset': len(COMPRESS_DATA),
4533 'section/u-boot:size': len(U_BOOT_DATA),
4534 'section:offset': 0,
4535 'section:image-pos': 0,
4536 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4537 'section:size': 0x30,
4538 'offset': 0,
4539 'image-pos': 0,
4540 'size': 0x30,
4541 }
4542 self.assertEqual(expected, props)
4543
4544 def testCompressSection(self):
4545 """Test compression of a section with no fixed size"""
4546 self._CheckLz4()
4547 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4548 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4549 dtb = fdt.Fdt(out_dtb_fname)
4550 dtb.Scan()
4551 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4552 'uncomp-size'])
4553 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004554 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004555 expected = {
4556 'section/blob:offset': 0,
4557 'section/blob:size': len(COMPRESS_DATA),
4558 'section/u-boot:offset': len(COMPRESS_DATA),
4559 'section/u-boot:size': len(U_BOOT_DATA),
4560 'section:offset': 0,
4561 'section:image-pos': 0,
4562 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4563 'section:size': len(data),
4564 'offset': 0,
4565 'image-pos': 0,
4566 'size': len(data),
4567 }
4568 self.assertEqual(expected, props)
4569
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004570 def testLz4Missing(self):
4571 """Test that binman still produces an image if lz4 is missing"""
4572 with test_util.capture_sys_output() as (_, stderr):
4573 self._DoTestFile('185_compress_section.dts',
4574 force_missing_bintools='lz4')
4575 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004576 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004577
Simon Glassd92c8362020-10-26 17:40:25 -06004578 def testCompressExtra(self):
4579 """Test compression of a section with no fixed size"""
4580 self._CheckLz4()
4581 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4582 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4583 dtb = fdt.Fdt(out_dtb_fname)
4584 dtb.Scan()
4585 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4586 'uncomp-size'])
4587
4588 base = data[len(U_BOOT_DATA):]
Brandon Maiera657bc62024-06-04 16:16:05 +00004589 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glassd92c8362020-10-26 17:40:25 -06004590 rest = base[len(U_BOOT_DATA):]
4591
4592 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004593 bintool = self.comp_bintools['lz4']
4594 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004595 data1 = rest[:len(expect1)]
4596 section1 = self._decompress(data1)
Brandon Maiera657bc62024-06-04 16:16:05 +00004597 self.assertEqual(expect1, data1)
4598 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glassd92c8362020-10-26 17:40:25 -06004599 rest1 = rest[len(expect1):]
4600
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004601 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004602 data2 = rest1[:len(expect2)]
4603 section2 = self._decompress(data2)
Brandon Maiera657bc62024-06-04 16:16:05 +00004604 self.assertEqual(expect2, data2)
4605 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glassd92c8362020-10-26 17:40:25 -06004606 rest2 = rest1[len(expect2):]
4607
4608 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4609 len(expect2) + len(U_BOOT_DATA))
Brandon Maiera657bc62024-06-04 16:16:05 +00004610 #self.assertEqual(expect_size, len(data))
Simon Glassd92c8362020-10-26 17:40:25 -06004611
Brandon Maiera657bc62024-06-04 16:16:05 +00004612 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glassd92c8362020-10-26 17:40:25 -06004613
4614 self.maxDiff = None
4615 expected = {
4616 'u-boot:offset': 0,
4617 'u-boot:image-pos': 0,
4618 'u-boot:size': len(U_BOOT_DATA),
4619
4620 'base:offset': len(U_BOOT_DATA),
4621 'base:image-pos': len(U_BOOT_DATA),
4622 'base:size': len(data) - len(U_BOOT_DATA),
4623 'base/u-boot:offset': 0,
4624 'base/u-boot:image-pos': len(U_BOOT_DATA),
4625 'base/u-boot:size': len(U_BOOT_DATA),
4626 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4627 len(expect2),
4628 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4629 len(expect2),
4630 'base/u-boot2:size': len(U_BOOT_DATA),
4631
4632 'base/section:offset': len(U_BOOT_DATA),
4633 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4634 'base/section:size': len(expect1),
4635 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4636 'base/section/blob:offset': 0,
4637 'base/section/blob:size': len(COMPRESS_DATA),
4638 'base/section/u-boot:offset': len(COMPRESS_DATA),
4639 'base/section/u-boot:size': len(U_BOOT_DATA),
4640
4641 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4642 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4643 'base/section2:size': len(expect2),
4644 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4645 'base/section2/blob:offset': 0,
4646 'base/section2/blob:size': len(COMPRESS_DATA),
4647 'base/section2/blob2:offset': len(COMPRESS_DATA),
4648 'base/section2/blob2:size': len(COMPRESS_DATA),
4649
4650 'offset': 0,
4651 'image-pos': 0,
4652 'size': len(data),
4653 }
4654 self.assertEqual(expected, props)
4655
Simon Glassecbe4732021-01-06 21:35:15 -07004656 def testSymbolsSubsection(self):
4657 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004658 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004659
Simon Glass3fb25402021-01-06 21:35:16 -07004660 def testReadImageEntryArg(self):
4661 """Test reading an image that would need an entry arg to generate"""
4662 entry_args = {
4663 'cros-ec-rw-path': 'ecrw.bin',
4664 }
4665 data = self.data = self._DoReadFileDtb(
4666 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4667 entry_args=entry_args)
4668
Simon Glass80025522022-01-29 14:14:04 -07004669 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004670 orig_image = control.images['image']
4671
4672 # This should not generate an error about the missing 'cros-ec-rw-path'
4673 # since we are reading the image from a file. Compare with
4674 # testEntryArgsRequired()
4675 image = Image.FromFile(image_fname)
4676 self.assertEqual(orig_image.GetEntries().keys(),
4677 image.GetEntries().keys())
4678
Simon Glassa2af7302021-01-06 21:35:18 -07004679 def testFilesAlign(self):
4680 """Test alignment with files"""
4681 data = self._DoReadFile('190_files_align.dts')
4682
4683 # The first string is 15 bytes so will align to 16
4684 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4685 self.assertEqual(expect, data)
4686
Simon Glassdb84b562021-01-06 21:35:19 -07004687 def testReadImageSkip(self):
4688 """Test reading an image and accessing its FDT map"""
4689 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004690 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004691 orig_image = control.images['image']
4692 image = Image.FromFile(image_fname)
4693 self.assertEqual(orig_image.GetEntries().keys(),
4694 image.GetEntries().keys())
4695
4696 orig_entry = orig_image.GetEntries()['fdtmap']
4697 entry = image.GetEntries()['fdtmap']
4698 self.assertEqual(orig_entry.offset, entry.offset)
4699 self.assertEqual(orig_entry.size, entry.size)
4700 self.assertEqual(16, entry.image_pos)
4701
4702 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4703
Brandon Maiera657bc62024-06-04 16:16:05 +00004704 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glassdb84b562021-01-06 21:35:19 -07004705
Simon Glassc98de972021-03-18 20:24:57 +13004706 def testTplNoDtb(self):
4707 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004708 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004709 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4710 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4711 data[:len(U_BOOT_TPL_NODTB_DATA)])
4712
Simon Glass63f41d42021-03-18 20:24:58 +13004713 def testTplBssPad(self):
4714 """Test that we can pad TPL's BSS with zeros"""
4715 # ELF file with a '__bss_size' symbol
4716 self._SetupTplElf()
4717 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004718 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004719 data)
4720
4721 def testTplBssPadMissing(self):
4722 """Test that a missing symbol is detected"""
4723 self._SetupTplElf('u_boot_ucode_ptr')
4724 with self.assertRaises(ValueError) as e:
4725 self._DoReadFile('193_tpl_bss_pad.dts')
4726 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4727 str(e.exception))
4728
Simon Glass718b5292021-03-18 20:25:07 +13004729 def checkDtbSizes(self, data, pad_len, start):
4730 """Check the size arguments in a dtb embedded in an image
4731
4732 Args:
4733 data: The image data
4734 pad_len: Length of the pad section in the image, in bytes
4735 start: Start offset of the devicetree to examine, within the image
4736
4737 Returns:
4738 Size of the devicetree in bytes
4739 """
4740 dtb_data = data[start:]
4741 dtb = fdt.Fdt.FromData(dtb_data)
4742 fdt_size = dtb.GetFdtObj().totalsize()
4743 dtb.Scan()
4744 props = self._GetPropTree(dtb, 'size')
4745 self.assertEqual({
4746 'size': len(data),
4747 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4748 'u-boot-spl/u-boot-spl-dtb:size': 801,
4749 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4750 'u-boot-spl:size': 860,
4751 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4752 'u-boot/u-boot-dtb:size': 781,
4753 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4754 'u-boot:size': 827,
4755 }, props)
4756 return fdt_size
4757
4758 def testExpanded(self):
4759 """Test that an expanded entry type is selected when needed"""
4760 self._SetupSplElf()
4761 self._SetupTplElf()
4762
4763 # SPL has a devicetree, TPL does not
4764 entry_args = {
4765 'spl-dtb': '1',
4766 'spl-bss-pad': 'y',
4767 'tpl-dtb': '',
4768 }
4769 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4770 entry_args=entry_args)
4771 image = control.images['image']
4772 entries = image.GetEntries()
4773 self.assertEqual(3, len(entries))
4774
4775 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4776 self.assertIn('u-boot', entries)
4777 entry = entries['u-boot']
4778 self.assertEqual('u-boot-expanded', entry.etype)
4779 subent = entry.GetEntries()
4780 self.assertEqual(2, len(subent))
4781 self.assertIn('u-boot-nodtb', subent)
4782 self.assertIn('u-boot-dtb', subent)
4783
4784 # Second, u-boot-spl, which should be expanded into three parts
4785 self.assertIn('u-boot-spl', entries)
4786 entry = entries['u-boot-spl']
4787 self.assertEqual('u-boot-spl-expanded', entry.etype)
4788 subent = entry.GetEntries()
4789 self.assertEqual(3, len(subent))
4790 self.assertIn('u-boot-spl-nodtb', subent)
4791 self.assertIn('u-boot-spl-bss-pad', subent)
4792 self.assertIn('u-boot-spl-dtb', subent)
4793
4794 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4795 # devicetree
4796 self.assertIn('u-boot-tpl', entries)
4797 entry = entries['u-boot-tpl']
4798 self.assertEqual('u-boot-tpl', entry.etype)
4799 self.assertEqual(None, entry.GetEntries())
4800
4801 def testExpandedTpl(self):
4802 """Test that an expanded entry type is selected for TPL when needed"""
4803 self._SetupTplElf()
4804
4805 entry_args = {
4806 'tpl-bss-pad': 'y',
4807 'tpl-dtb': 'y',
4808 }
4809 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4810 entry_args=entry_args)
4811 image = control.images['image']
4812 entries = image.GetEntries()
4813 self.assertEqual(1, len(entries))
4814
4815 # We only have u-boot-tpl, which be expanded
4816 self.assertIn('u-boot-tpl', entries)
4817 entry = entries['u-boot-tpl']
4818 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4819 subent = entry.GetEntries()
4820 self.assertEqual(3, len(subent))
4821 self.assertIn('u-boot-tpl-nodtb', subent)
4822 self.assertIn('u-boot-tpl-bss-pad', subent)
4823 self.assertIn('u-boot-tpl-dtb', subent)
4824
4825 def testExpandedNoPad(self):
4826 """Test an expanded entry without BSS pad enabled"""
4827 self._SetupSplElf()
4828 self._SetupTplElf()
4829
4830 # SPL has a devicetree, TPL does not
4831 entry_args = {
4832 'spl-dtb': 'something',
4833 'spl-bss-pad': 'n',
4834 'tpl-dtb': '',
4835 }
4836 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4837 entry_args=entry_args)
4838 image = control.images['image']
4839 entries = image.GetEntries()
4840
4841 # Just check u-boot-spl, which should be expanded into two parts
4842 self.assertIn('u-boot-spl', entries)
4843 entry = entries['u-boot-spl']
4844 self.assertEqual('u-boot-spl-expanded', entry.etype)
4845 subent = entry.GetEntries()
4846 self.assertEqual(2, len(subent))
4847 self.assertIn('u-boot-spl-nodtb', subent)
4848 self.assertIn('u-boot-spl-dtb', subent)
4849
4850 def testExpandedTplNoPad(self):
4851 """Test that an expanded entry type with padding disabled in TPL"""
4852 self._SetupTplElf()
4853
4854 entry_args = {
4855 'tpl-bss-pad': '',
4856 'tpl-dtb': 'y',
4857 }
4858 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4859 entry_args=entry_args)
4860 image = control.images['image']
4861 entries = image.GetEntries()
4862 self.assertEqual(1, len(entries))
4863
4864 # We only have u-boot-tpl, which be expanded
4865 self.assertIn('u-boot-tpl', entries)
4866 entry = entries['u-boot-tpl']
4867 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4868 subent = entry.GetEntries()
4869 self.assertEqual(2, len(subent))
4870 self.assertIn('u-boot-tpl-nodtb', subent)
4871 self.assertIn('u-boot-tpl-dtb', subent)
4872
4873 def testFdtInclude(self):
4874 """Test that an Fdt is update within all binaries"""
4875 self._SetupSplElf()
4876 self._SetupTplElf()
4877
4878 # SPL has a devicetree, TPL does not
4879 self.maxDiff = None
4880 entry_args = {
4881 'spl-dtb': '1',
4882 'spl-bss-pad': 'y',
4883 'tpl-dtb': '',
4884 }
4885 # Build the image. It includes two separate devicetree binaries, each
4886 # with their own contents, but all contain the binman definition.
4887 data = self._DoReadFileDtb(
4888 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4889 update_dtb=True, entry_args=entry_args)[0]
4890 pad_len = 10
4891
4892 # Check the U-Boot dtb
4893 start = len(U_BOOT_NODTB_DATA)
4894 fdt_size = self.checkDtbSizes(data, pad_len, start)
4895
4896 # Now check SPL
4897 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4898 fdt_size = self.checkDtbSizes(data, pad_len, start)
4899
4900 # TPL has no devicetree
4901 start += fdt_size + len(U_BOOT_TPL_DATA)
4902 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004903
Simon Glass7098b7f2021-03-21 18:24:30 +13004904 def testSymbolsExpanded(self):
4905 """Test binman can assign symbols in expanded entries"""
4906 entry_args = {
4907 'spl-dtb': '1',
4908 }
4909 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4910 U_BOOT_SPL_DTB_DATA, 0x38,
4911 entry_args=entry_args, use_expanded=True)
4912
Simon Glasse1915782021-03-21 18:24:31 +13004913 def testCollection(self):
4914 """Test a collection"""
4915 data = self._DoReadFile('198_collection.dts')
4916 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004917 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4918 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004919 data)
4920
Simon Glass27a7f772021-03-21 18:24:32 +13004921 def testCollectionSection(self):
4922 """Test a collection where a section must be built first"""
4923 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004924 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004925 # building the contents, producing an error is anything is still
4926 # missing.
4927 data = self._DoReadFile('199_collection_section.dts')
4928 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004929 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4930 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004931 data)
4932
Simon Glassf427c5f2021-03-21 18:24:33 +13004933 def testAlignDefault(self):
4934 """Test that default alignment works on sections"""
4935 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004936 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004937 U_BOOT_DATA)
4938 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004939 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004940 # No alignment within the nested section
4941 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4942 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004943 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004944 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004945
Bin Mengc0b15742021-05-10 20:23:33 +08004946 def testPackOpenSBI(self):
4947 """Test that an image with an OpenSBI binary can be created"""
4948 data = self._DoReadFile('201_opensbi.dts')
4949 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4950
Simon Glass76f496d2021-07-06 10:36:37 -06004951 def testSectionsSingleThread(self):
4952 """Test sections without multithreading"""
4953 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004954 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4955 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4956 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004957 self.assertEqual(expected, data)
4958
4959 def testThreadTimeout(self):
4960 """Test handling a thread that takes too long"""
4961 with self.assertRaises(ValueError) as e:
4962 self._DoTestFile('202_section_timeout.dts',
4963 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004964 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004965
Simon Glass748a1d42021-07-06 10:36:41 -06004966 def testTiming(self):
4967 """Test output of timing information"""
4968 data = self._DoReadFile('055_sections.dts')
4969 with test_util.capture_sys_output() as (stdout, stderr):
4970 state.TimingShow()
4971 self.assertIn('read:', stdout.getvalue())
4972 self.assertIn('compress:', stdout.getvalue())
4973
Simon Glassadfb8492021-11-03 21:09:18 -06004974 def testUpdateFdtInElf(self):
4975 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004976 if not elf.ELF_TOOLS:
4977 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004978 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4979 outfile = os.path.join(self._indir, 'u-boot.out')
4980 begin_sym = 'dtb_embed_begin'
4981 end_sym = 'dtb_embed_end'
4982 retcode = self._DoTestFile(
4983 '060_fdt_update.dts', update_dtb=True,
4984 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4985 self.assertEqual(0, retcode)
4986
4987 # Check that the output file does in fact contact a dtb with the binman
4988 # definition in the correct place
4989 syms = elf.GetSymbolFileOffset(infile,
4990 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004991 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004992 dtb_data = data[syms['dtb_embed_begin'].offset:
4993 syms['dtb_embed_end'].offset]
4994
4995 dtb = fdt.Fdt.FromData(dtb_data)
4996 dtb.Scan()
4997 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4998 self.assertEqual({
4999 'image-pos': 0,
5000 'offset': 0,
5001 '_testing:offset': 32,
5002 '_testing:size': 2,
5003 '_testing:image-pos': 32,
5004 'section@0/u-boot:offset': 0,
5005 'section@0/u-boot:size': len(U_BOOT_DATA),
5006 'section@0/u-boot:image-pos': 0,
5007 'section@0:offset': 0,
5008 'section@0:size': 16,
5009 'section@0:image-pos': 0,
5010
5011 'section@1/u-boot:offset': 0,
5012 'section@1/u-boot:size': len(U_BOOT_DATA),
5013 'section@1/u-boot:image-pos': 16,
5014 'section@1:offset': 16,
5015 'section@1:size': 16,
5016 'section@1:image-pos': 16,
5017 'size': 40
5018 }, props)
5019
5020 def testUpdateFdtInElfInvalid(self):
5021 """Test that invalid args are detected with --update-fdt-in-elf"""
5022 with self.assertRaises(ValueError) as e:
5023 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5024 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5025 str(e.exception))
5026
5027 def testUpdateFdtInElfNoSyms(self):
5028 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005029 if not elf.ELF_TOOLS:
5030 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005031 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5032 outfile = ''
5033 begin_sym = 'wrong_begin'
5034 end_sym = 'wrong_end'
5035 with self.assertRaises(ValueError) as e:
5036 self._DoTestFile(
5037 '060_fdt_update.dts',
5038 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5039 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5040 str(e.exception))
5041
5042 def testUpdateFdtInElfTooSmall(self):
5043 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005044 if not elf.ELF_TOOLS:
5045 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005046 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5047 outfile = os.path.join(self._indir, 'u-boot.out')
5048 begin_sym = 'dtb_embed_begin'
5049 end_sym = 'dtb_embed_end'
5050 with self.assertRaises(ValueError) as e:
5051 self._DoTestFile(
5052 '060_fdt_update.dts', update_dtb=True,
5053 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5054 self.assertRegex(
5055 str(e.exception),
5056 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5057
Simon Glass88e04da2021-11-23 11:03:42 -07005058 def testVersion(self):
5059 """Test we can get the binman version"""
5060 version = '(unreleased)'
5061 self.assertEqual(version, state.GetVersion(self._indir))
5062
5063 with self.assertRaises(SystemExit):
5064 with test_util.capture_sys_output() as (_, stderr):
5065 self._DoBinman('-V')
5066 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5067
5068 # Try running the tool too, just to be safe
5069 result = self._RunBinman('-V')
5070 self.assertEqual('Binman %s\n' % version, result.stderr)
5071
5072 # Set up a version file to make sure that works
5073 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005074 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005075 binary=False)
5076 self.assertEqual(version, state.GetVersion(self._indir))
5077
Simon Glass637958f2021-11-23 21:09:50 -07005078 def testAltFormat(self):
5079 """Test that alternative formats can be used to extract"""
5080 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5081
5082 try:
5083 tmpdir, updated_fname = self._SetupImageInTmpdir()
5084 with test_util.capture_sys_output() as (stdout, _):
5085 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5086 self.assertEqual(
5087 '''Flag (-F) Entry type Description
5088fdt fdtmap Extract the devicetree blob from the fdtmap
5089''',
5090 stdout.getvalue())
5091
5092 dtb = os.path.join(tmpdir, 'fdt.dtb')
5093 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5094 dtb, 'fdtmap')
5095
5096 # Check that we can read it and it can be scanning, meaning it does
5097 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005098 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005099 dtb = fdt.Fdt.FromData(data)
5100 dtb.Scan()
5101
5102 # Now check u-boot which has no alt_format
5103 fname = os.path.join(tmpdir, 'fdt.dtb')
5104 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5105 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005106 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005107 self.assertEqual(U_BOOT_DATA, data)
5108
5109 finally:
5110 shutil.rmtree(tmpdir)
5111
Simon Glass0b00ae62021-11-23 21:09:52 -07005112 def testExtblobList(self):
5113 """Test an image with an external blob list"""
5114 data = self._DoReadFile('215_blob_ext_list.dts')
5115 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5116
5117 def testExtblobListMissing(self):
5118 """Test an image with a missing external blob"""
5119 with self.assertRaises(ValueError) as e:
5120 self._DoReadFile('216_blob_ext_list_missing.dts')
5121 self.assertIn("Filename 'missing-file' not found in input path",
5122 str(e.exception))
5123
5124 def testExtblobListMissingOk(self):
5125 """Test an image with an missing external blob that is allowed"""
5126 with test_util.capture_sys_output() as (stdout, stderr):
5127 self._DoTestFile('216_blob_ext_list_missing.dts',
5128 allow_missing=True)
5129 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005130 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005131
Simon Glass3efb2972021-11-23 21:08:59 -07005132 def testFip(self):
5133 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5134 data = self._DoReadFile('203_fip.dts')
5135 hdr, fents = fip_util.decode_fip(data)
5136 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5137 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5138 self.assertEqual(0x123, hdr.flags)
5139
5140 self.assertEqual(2, len(fents))
5141
5142 fent = fents[0]
5143 self.assertEqual(
5144 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5145 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5146 self.assertEqual('soc-fw', fent.fip_type)
5147 self.assertEqual(0x88, fent.offset)
5148 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5149 self.assertEqual(0x123456789abcdef, fent.flags)
5150 self.assertEqual(ATF_BL31_DATA, fent.data)
5151 self.assertEqual(True, fent.valid)
5152
5153 fent = fents[1]
5154 self.assertEqual(
5155 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5156 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5157 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5158 self.assertEqual(0x8c, fent.offset)
5159 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5160 self.assertEqual(0, fent.flags)
5161 self.assertEqual(ATF_BL2U_DATA, fent.data)
5162 self.assertEqual(True, fent.valid)
5163
5164 def testFipOther(self):
5165 """Basic FIP with something that isn't a external blob"""
5166 data = self._DoReadFile('204_fip_other.dts')
5167 hdr, fents = fip_util.decode_fip(data)
5168
5169 self.assertEqual(2, len(fents))
5170 fent = fents[1]
5171 self.assertEqual('rot-cert', fent.fip_type)
5172 self.assertEqual(b'aa', fent.data)
5173
Simon Glass3efb2972021-11-23 21:08:59 -07005174 def testFipNoType(self):
5175 """FIP with an entry of an unknown type"""
5176 with self.assertRaises(ValueError) as e:
5177 self._DoReadFile('205_fip_no_type.dts')
5178 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5179 str(e.exception))
5180
5181 def testFipUuid(self):
5182 """Basic FIP with a manual uuid"""
5183 data = self._DoReadFile('206_fip_uuid.dts')
5184 hdr, fents = fip_util.decode_fip(data)
5185
5186 self.assertEqual(2, len(fents))
5187 fent = fents[1]
5188 self.assertEqual(None, fent.fip_type)
5189 self.assertEqual(
5190 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5191 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5192 fent.uuid)
5193 self.assertEqual(U_BOOT_DATA, fent.data)
5194
5195 def testFipLs(self):
5196 """Test listing a FIP"""
5197 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5198 hdr, fents = fip_util.decode_fip(data)
5199
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005200 tmpdir = None
Simon Glass3efb2972021-11-23 21:08:59 -07005201 try:
5202 tmpdir, updated_fname = self._SetupImageInTmpdir()
5203 with test_util.capture_sys_output() as (stdout, stderr):
5204 self._DoBinman('ls', '-i', updated_fname)
5205 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005206 if tmpdir:
5207 shutil.rmtree(tmpdir)
Simon Glass3efb2972021-11-23 21:08:59 -07005208 lines = stdout.getvalue().splitlines()
5209 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005210'Name Image-pos Size Entry-type Offset Uncomp-size',
5211'--------------------------------------------------------------',
5212'image 0 2d3 section 0',
5213' atf-fip 0 90 atf-fip 0',
5214' soc-fw 88 4 blob-ext 88',
5215' u-boot 8c 4 u-boot 8c',
5216' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005217]
5218 self.assertEqual(expected, lines)
5219
5220 image = control.images['image']
5221 entries = image.GetEntries()
5222 fdtmap = entries['fdtmap']
5223
5224 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5225 magic = fdtmap_data[:8]
5226 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005227 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005228
5229 fdt_data = fdtmap_data[16:]
5230 dtb = fdt.Fdt.FromData(fdt_data)
5231 dtb.Scan()
5232 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5233 self.assertEqual({
5234 'atf-fip/soc-fw:image-pos': 136,
5235 'atf-fip/soc-fw:offset': 136,
5236 'atf-fip/soc-fw:size': 4,
5237 'atf-fip/u-boot:image-pos': 140,
5238 'atf-fip/u-boot:offset': 140,
5239 'atf-fip/u-boot:size': 4,
5240 'atf-fip:image-pos': 0,
5241 'atf-fip:offset': 0,
5242 'atf-fip:size': 144,
5243 'image-pos': 0,
5244 'offset': 0,
5245 'fdtmap:image-pos': fdtmap.image_pos,
5246 'fdtmap:offset': fdtmap.offset,
5247 'fdtmap:size': len(fdtmap_data),
5248 'size': len(data),
5249 }, props)
5250
5251 def testFipExtractOneEntry(self):
5252 """Test extracting a single entry fron an FIP"""
5253 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005254 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005255 fname = os.path.join(self._indir, 'output.extact')
5256 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005257 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005258 self.assertEqual(U_BOOT_DATA, data)
5259
5260 def testFipReplace(self):
5261 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005262 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005263 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005264 updated_fname = tools.get_output_filename('image-updated.bin')
5265 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005266 entry_name = 'atf-fip/u-boot'
5267 control.WriteEntry(updated_fname, entry_name, expected,
5268 allow_resize=True)
5269 actual = control.ReadEntry(updated_fname, entry_name)
5270 self.assertEqual(expected, actual)
5271
Simon Glass80025522022-01-29 14:14:04 -07005272 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005273 hdr, fents = fip_util.decode_fip(new_data)
5274
5275 self.assertEqual(2, len(fents))
5276
5277 # Check that the FIP entry is updated
5278 fent = fents[1]
5279 self.assertEqual(0x8c, fent.offset)
5280 self.assertEqual(len(expected), fent.size)
5281 self.assertEqual(0, fent.flags)
5282 self.assertEqual(expected, fent.data)
5283 self.assertEqual(True, fent.valid)
5284
5285 def testFipMissing(self):
5286 with test_util.capture_sys_output() as (stdout, stderr):
5287 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5288 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005289 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005290
5291 def testFipSize(self):
5292 """Test a FIP with a size property"""
5293 data = self._DoReadFile('210_fip_size.dts')
5294 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5295 hdr, fents = fip_util.decode_fip(data)
5296 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5297 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5298
5299 self.assertEqual(1, len(fents))
5300
5301 fent = fents[0]
5302 self.assertEqual('soc-fw', fent.fip_type)
5303 self.assertEqual(0x60, fent.offset)
5304 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5305 self.assertEqual(ATF_BL31_DATA, fent.data)
5306 self.assertEqual(True, fent.valid)
5307
5308 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005309 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005310
5311 def testFipBadAlign(self):
5312 """Test that an invalid alignment value in a FIP is detected"""
5313 with self.assertRaises(ValueError) as e:
5314 self._DoTestFile('211_fip_bad_align.dts')
5315 self.assertIn(
5316 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5317 str(e.exception))
5318
5319 def testFipCollection(self):
5320 """Test using a FIP in a collection"""
5321 data = self._DoReadFile('212_fip_collection.dts')
5322 entry1 = control.images['image'].GetEntries()['collection']
5323 data1 = data[:entry1.size]
5324 hdr1, fents2 = fip_util.decode_fip(data1)
5325
5326 entry2 = control.images['image'].GetEntries()['atf-fip']
5327 data2 = data[entry2.offset:entry2.offset + entry2.size]
5328 hdr1, fents2 = fip_util.decode_fip(data2)
5329
5330 # The 'collection' entry should have U-Boot included at the end
5331 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5332 self.assertEqual(data1, data2 + U_BOOT_DATA)
5333 self.assertEqual(U_BOOT_DATA, data1[-4:])
5334
5335 # There should be a U-Boot after the final FIP
5336 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005337
Simon Glassccae6862022-01-12 13:10:35 -07005338 def testFakeBlob(self):
5339 """Test handling of faking an external blob"""
5340 with test_util.capture_sys_output() as (stdout, stderr):
5341 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5342 allow_fake_blobs=True)
5343 err = stderr.getvalue()
5344 self.assertRegex(
5345 err,
5346 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005347
Simon Glassceb5f912022-01-09 20:13:46 -07005348 def testExtblobListFaked(self):
5349 """Test an extblob with missing external blob that are faked"""
5350 with test_util.capture_sys_output() as (stdout, stderr):
5351 self._DoTestFile('216_blob_ext_list_missing.dts',
5352 allow_fake_blobs=True)
5353 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005354 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005355
Simon Glass162017b2022-01-09 20:13:57 -07005356 def testListBintools(self):
5357 args = ['tool', '--list']
5358 with test_util.capture_sys_output() as (stdout, _):
5359 self._DoBinman(*args)
5360 out = stdout.getvalue().splitlines()
5361 self.assertTrue(len(out) >= 2)
5362
5363 def testFetchBintools(self):
5364 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005365 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005366 raise urllib.error.URLError('my error')
5367
5368 args = ['tool']
5369 with self.assertRaises(ValueError) as e:
5370 self._DoBinman(*args)
5371 self.assertIn("Invalid arguments to 'tool' subcommand",
5372 str(e.exception))
5373
5374 args = ['tool', '--fetch']
5375 with self.assertRaises(ValueError) as e:
5376 self._DoBinman(*args)
5377 self.assertIn('Please specify bintools to fetch', str(e.exception))
5378
5379 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005380 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005381 side_effect=fail_download):
5382 with test_util.capture_sys_output() as (stdout, _):
5383 self._DoBinman(*args)
5384 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5385
Simon Glass620c4462022-01-09 20:14:11 -07005386 def testBintoolDocs(self):
5387 """Test for creation of bintool documentation"""
5388 with test_util.capture_sys_output() as (stdout, stderr):
5389 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5390 self.assertTrue(len(stdout.getvalue()) > 0)
5391
5392 def testBintoolDocsMissing(self):
5393 """Test handling of missing bintool documentation"""
5394 with self.assertRaises(ValueError) as e:
5395 with test_util.capture_sys_output() as (stdout, stderr):
5396 control.write_bintool_docs(
5397 control.bintool.Bintool.get_tool_list(), 'mkimage')
5398 self.assertIn('Documentation is missing for modules: mkimage',
5399 str(e.exception))
5400
Jan Kiszka58c407f2022-01-28 20:37:53 +01005401 def testListWithGenNode(self):
5402 """Check handling of an FDT map when the section cannot be found"""
5403 entry_args = {
5404 'of-list': 'test-fdt1 test-fdt2',
5405 }
5406 data = self._DoReadFileDtb(
5407 '219_fit_gennode.dts',
5408 entry_args=entry_args,
5409 use_real_dtb=True,
5410 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5411
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005412 tmpdir = None
Jan Kiszka58c407f2022-01-28 20:37:53 +01005413 try:
5414 tmpdir, updated_fname = self._SetupImageInTmpdir()
5415 with test_util.capture_sys_output() as (stdout, stderr):
5416 self._RunBinman('ls', '-i', updated_fname)
5417 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005418 if tmpdir:
5419 shutil.rmtree(tmpdir)
Jan Kiszka58c407f2022-01-28 20:37:53 +01005420
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005421 def testFitSubentryUsesBintool(self):
5422 """Test that binman FIT subentries can use bintools"""
5423 command.test_result = self._HandleGbbCommand
5424 entry_args = {
5425 'keydir': 'devkeys',
5426 'bmpblk': 'bmpblk.bin',
5427 }
5428 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5429 entry_args=entry_args)
5430
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005431 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5432 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005433 self.assertIn(expected, data)
5434
5435 def testFitSubentryMissingBintool(self):
5436 """Test that binman reports missing bintools for FIT subentries"""
5437 entry_args = {
5438 'keydir': 'devkeys',
5439 }
5440 with test_util.capture_sys_output() as (_, stderr):
5441 self._DoTestFile('220_fit_subentry_bintool.dts',
5442 force_missing_bintools='futility', entry_args=entry_args)
5443 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005444 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005445
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005446 def testFitSubentryHashSubnode(self):
5447 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005448 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005449 data, _, _, out_dtb_name = self._DoReadFileDtb(
5450 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5451
5452 mkimage_dtb = fdt.Fdt.FromData(data)
5453 mkimage_dtb.Scan()
5454 binman_dtb = fdt.Fdt(out_dtb_name)
5455 binman_dtb.Scan()
5456
5457 # Check that binman didn't add hash values
5458 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5459 self.assertNotIn('value', fnode.props)
5460
5461 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5462 self.assertNotIn('value', fnode.props)
5463
5464 # Check that mkimage added hash values
5465 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5466 self.assertIn('value', fnode.props)
5467
5468 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5469 self.assertIn('value', fnode.props)
5470
Roger Quadros5cdcea02022-02-19 20:50:04 +02005471 def testPackTeeOs(self):
5472 """Test that an image with an TEE binary can be created"""
5473 data = self._DoReadFile('222_tee_os.dts')
5474 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5475
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305476 def testPackTiDm(self):
5477 """Test that an image with a TI DM binary can be created"""
5478 data = self._DoReadFile('225_ti_dm.dts')
5479 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5480
Simon Glass912339f2022-02-08 11:50:03 -07005481 def testFitFdtOper(self):
5482 """Check handling of a specified FIT operation"""
5483 entry_args = {
5484 'of-list': 'test-fdt1 test-fdt2',
5485 'default-dt': 'test-fdt2',
5486 }
5487 self._DoReadFileDtb(
5488 '223_fit_fdt_oper.dts',
5489 entry_args=entry_args,
5490 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5491
5492 def testFitFdtBadOper(self):
5493 """Check handling of an FDT map when the section cannot be found"""
5494 with self.assertRaises(ValueError) as exc:
5495 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005496 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005497 str(exc.exception))
5498
Simon Glassdd156a42022-03-05 20:18:59 -07005499 def test_uses_expand_size(self):
5500 """Test that the 'expand-size' property cannot be used anymore"""
5501 with self.assertRaises(ValueError) as e:
5502 data = self._DoReadFile('225_expand_size_bad.dts')
5503 self.assertIn(
5504 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5505 str(e.exception))
5506
Simon Glass5f423422022-03-05 20:19:12 -07005507 def testFitSplitElf(self):
5508 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005509 if not elf.ELF_TOOLS:
5510 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005511 entry_args = {
5512 'of-list': 'test-fdt1 test-fdt2',
5513 'default-dt': 'test-fdt2',
5514 'atf-bl31-path': 'bl31.elf',
5515 'tee-os-path': 'tee.elf',
5516 }
5517 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5518 data = self._DoReadFileDtb(
5519 '226_fit_split_elf.dts',
5520 entry_args=entry_args,
5521 extra_indirs=[test_subdir])[0]
5522
5523 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5524 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5525
5526 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5527 'data', 'load'}
5528 dtb = fdt.Fdt.FromData(fit_data)
5529 dtb.Scan()
5530
5531 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5532 segments, entry = elf.read_loadable_segments(elf_data)
5533
5534 # We assume there are two segments
Brandon Maiera657bc62024-06-04 16:16:05 +00005535 self.assertEqual(2, len(segments))
Simon Glass5f423422022-03-05 20:19:12 -07005536
5537 atf1 = dtb.GetNode('/images/atf-1')
5538 _, start, data = segments[0]
5539 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5540 self.assertEqual(entry,
5541 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5542 self.assertEqual(start,
5543 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5544 self.assertEqual(data, atf1.props['data'].bytes)
5545
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005546 hash_node = atf1.FindNode('hash')
5547 self.assertIsNotNone(hash_node)
5548 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5549
Simon Glass5f423422022-03-05 20:19:12 -07005550 atf2 = dtb.GetNode('/images/atf-2')
5551 self.assertEqual(base_keys, atf2.props.keys())
5552 _, start, data = segments[1]
5553 self.assertEqual(start,
5554 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5555 self.assertEqual(data, atf2.props['data'].bytes)
5556
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005557 hash_node = atf2.FindNode('hash')
5558 self.assertIsNotNone(hash_node)
5559 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5560
5561 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5562 self.assertIsNotNone(hash_node)
5563 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5564
Simon Glass5f423422022-03-05 20:19:12 -07005565 conf = dtb.GetNode('/configurations')
5566 self.assertEqual({'default'}, conf.props.keys())
5567
5568 for subnode in conf.subnodes:
5569 self.assertEqual({'description', 'fdt', 'loadables'},
5570 subnode.props.keys())
5571 self.assertEqual(
5572 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5573 fdt_util.GetStringList(subnode, 'loadables'))
5574
5575 def _check_bad_fit(self, dts):
5576 """Check a bad FIT
5577
5578 This runs with the given dts and returns the assertion raised
5579
5580 Args:
5581 dts (str): dts filename to use
5582
5583 Returns:
5584 str: Assertion string raised
5585 """
5586 entry_args = {
5587 'of-list': 'test-fdt1 test-fdt2',
5588 'default-dt': 'test-fdt2',
5589 'atf-bl31-path': 'bl31.elf',
5590 'tee-os-path': 'tee.elf',
5591 }
5592 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5593 with self.assertRaises(ValueError) as exc:
5594 self._DoReadFileDtb(dts, entry_args=entry_args,
5595 extra_indirs=[test_subdir])[0]
5596 return str(exc.exception)
5597
5598 def testFitSplitElfBadElf(self):
5599 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005600 if not elf.ELF_TOOLS:
5601 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005602 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5603 entry_args = {
5604 'of-list': 'test-fdt1 test-fdt2',
5605 'default-dt': 'test-fdt2',
5606 'atf-bl31-path': 'bad.elf',
5607 'tee-os-path': 'tee.elf',
5608 }
5609 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5610 with self.assertRaises(ValueError) as exc:
5611 self._DoReadFileDtb(
5612 '226_fit_split_elf.dts',
5613 entry_args=entry_args,
5614 extra_indirs=[test_subdir])[0]
5615 self.assertIn(
5616 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5617 str(exc.exception))
5618
Simon Glass5f423422022-03-05 20:19:12 -07005619 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005620 """Test an split-elf FIT with a missing ELF file
5621
5622 Args:
5623 kwargs (dict of str): Arguments to pass to _DoTestFile()
5624
5625 Returns:
5626 tuple:
5627 str: stdout result
5628 str: stderr result
5629 """
Simon Glass5f423422022-03-05 20:19:12 -07005630 entry_args = {
5631 'of-list': 'test-fdt1 test-fdt2',
5632 'default-dt': 'test-fdt2',
5633 'atf-bl31-path': 'bl31.elf',
5634 'tee-os-path': 'missing.elf',
5635 }
5636 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5637 with test_util.capture_sys_output() as (stdout, stderr):
5638 self._DoTestFile(
5639 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005640 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5641 out = stdout.getvalue()
5642 err = stderr.getvalue()
5643 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005644
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005645 def testFitSplitElfBadDirective(self):
5646 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5647 if not elf.ELF_TOOLS:
5648 self.skipTest('Python elftools not available')
5649 err = self._check_bad_fit('227_fit_bad_dir.dts')
5650 self.assertIn(
5651 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5652 err)
5653
5654 def testFitSplitElfBadDirectiveConfig(self):
5655 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5656 if not elf.ELF_TOOLS:
5657 self.skipTest('Python elftools not available')
5658 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5659 self.assertEqual(
5660 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5661 err)
5662
5663
Simon Glass5f423422022-03-05 20:19:12 -07005664 def testFitSplitElfMissing(self):
5665 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005666 if not elf.ELF_TOOLS:
5667 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005668 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005669 self.assertRegex(
5670 err,
5671 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005672 self.assertNotRegex(out, '.*Faked blob.*')
5673 fname = tools.get_output_filename('binman-fake/missing.elf')
5674 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005675
5676 def testFitSplitElfFaked(self):
5677 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005678 if not elf.ELF_TOOLS:
5679 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005680 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005681 self.assertRegex(
5682 err,
5683 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005684 self.assertRegex(
5685 out,
5686 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5687 fname = tools.get_output_filename('binman-fake/missing.elf')
5688 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005689
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005690 def testMkimageMissingBlob(self):
5691 """Test using mkimage to build an image"""
5692 with test_util.capture_sys_output() as (stdout, stderr):
5693 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5694 allow_fake_blobs=True)
5695 err = stderr.getvalue()
5696 self.assertRegex(
5697 err,
5698 "Image '.*' has faked external blobs and is non-functional: .*")
5699
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005700 def testPreLoad(self):
5701 """Test an image with a pre-load header"""
5702 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005703 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005704 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005705 data = self._DoReadFileDtb(
5706 '230_pre_load.dts', entry_args=entry_args,
5707 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005708 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5709 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5710 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Simon Glasse2dfb962023-07-24 09:19:57 -06005711
5712 def testPreLoadNoKey(self):
5713 """Test an image with a pre-load heade0r with missing key"""
5714 with self.assertRaises(FileNotFoundError) as exc:
5715 self._DoReadFile('230_pre_load.dts')
5716 self.assertIn("No such file or directory: 'dev.key'",
5717 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005718
5719 def testPreLoadPkcs(self):
5720 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005721 entry_args = {
5722 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5723 }
5724 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5725 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005726 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5727 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5728 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5729
5730 def testPreLoadPss(self):
5731 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005732 entry_args = {
5733 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5734 }
5735 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5736 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005737 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5738 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5739 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5740
5741 def testPreLoadInvalidPadding(self):
5742 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005743 entry_args = {
5744 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5745 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005746 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005747 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5748 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005749
5750 def testPreLoadInvalidSha(self):
5751 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005752 entry_args = {
5753 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5754 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005755 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005756 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5757 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005758
5759 def testPreLoadInvalidAlgo(self):
5760 """Test an image with a pre-load header with an invalid algo"""
5761 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005762 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005763
5764 def testPreLoadInvalidKey(self):
5765 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005766 entry_args = {
5767 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5768 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005769 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005770 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5771 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005772
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005773 def _CheckSafeUniqueNames(self, *images):
5774 """Check all entries of given images for unsafe unique names"""
5775 for image in images:
5776 entries = {}
5777 image._CollectEntries(entries, {}, image)
5778 for entry in entries.values():
5779 uniq = entry.GetUniqueName()
5780
5781 # Used as part of a filename, so must not be absolute paths.
5782 self.assertFalse(os.path.isabs(uniq))
5783
5784 def testSafeUniqueNames(self):
5785 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005786 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005787
5788 orig_image = control.images['image']
5789 image_fname = tools.get_output_filename('image.bin')
5790 image = Image.FromFile(image_fname)
5791
5792 self._CheckSafeUniqueNames(orig_image, image)
5793
5794 def testSafeUniqueNamesMulti(self):
5795 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005796 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005797
5798 orig_image = control.images['image']
5799 image_fname = tools.get_output_filename('image.bin')
5800 image = Image.FromFile(image_fname)
5801
5802 self._CheckSafeUniqueNames(orig_image, image)
5803
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005804 def testReplaceCmdWithBintool(self):
5805 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005806 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005807 expected = U_BOOT_DATA + b'aa'
5808 self.assertEqual(expected, data[:len(expected)])
5809
5810 try:
5811 tmpdir, updated_fname = self._SetupImageInTmpdir()
5812 fname = os.path.join(tmpdir, 'update-testing.bin')
5813 tools.write_file(fname, b'zz')
5814 self._DoBinman('replace', '-i', updated_fname,
5815 '_testing', '-f', fname)
5816
5817 data = tools.read_file(updated_fname)
5818 expected = U_BOOT_DATA + b'zz'
5819 self.assertEqual(expected, data[:len(expected)])
5820 finally:
5821 shutil.rmtree(tmpdir)
5822
5823 def testReplaceCmdOtherWithBintool(self):
5824 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005825 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005826 expected = U_BOOT_DATA + b'aa'
5827 self.assertEqual(expected, data[:len(expected)])
5828
5829 try:
5830 tmpdir, updated_fname = self._SetupImageInTmpdir()
5831 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5832 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5833 self._DoBinman('replace', '-i', updated_fname,
5834 'u-boot', '-f', fname)
5835
5836 data = tools.read_file(updated_fname)
5837 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5838 self.assertEqual(expected, data[:len(expected)])
5839 finally:
5840 shutil.rmtree(tmpdir)
5841
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005842 def testReplaceResizeNoRepackSameSize(self):
5843 """Test replacing entries with same-size data without repacking"""
5844 expected = b'x' * len(U_BOOT_DATA)
5845 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5846 self.assertEqual(expected, data)
5847
5848 path, fdtmap = state.GetFdtContents('fdtmap')
5849 self.assertIsNotNone(path)
5850 self.assertEqual(expected_fdtmap, fdtmap)
5851
5852 def testReplaceResizeNoRepackSmallerSize(self):
5853 """Test replacing entries with smaller-size data without repacking"""
5854 new_data = b'x'
5855 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5856 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5857 self.assertEqual(expected, data)
5858
5859 path, fdtmap = state.GetFdtContents('fdtmap')
5860 self.assertIsNotNone(path)
5861 self.assertEqual(expected_fdtmap, fdtmap)
5862
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005863 def testExtractFit(self):
5864 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005865 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005866 image_fname = tools.get_output_filename('image.bin')
5867
5868 fit_data = control.ReadEntry(image_fname, 'fit')
5869 fit = fdt.Fdt.FromData(fit_data)
5870 fit.Scan()
5871
5872 # Check subentry data inside the extracted fit
5873 for node_path, expected in [
5874 ('/images/kernel', U_BOOT_DATA),
5875 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5876 ('/images/scr-1', COMPRESS_DATA),
5877 ]:
5878 node = fit.GetNode(node_path)
5879 data = fit.GetProps(node)['data'].bytes
5880 self.assertEqual(expected, data)
5881
5882 def testExtractFitSubentries(self):
5883 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005884 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005885 image_fname = tools.get_output_filename('image.bin')
5886
5887 for entry_path, expected in [
5888 ('fit/kernel', U_BOOT_DATA),
5889 ('fit/kernel/u-boot', U_BOOT_DATA),
5890 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5891 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5892 ('fit/scr-1', COMPRESS_DATA),
5893 ('fit/scr-1/blob', COMPRESS_DATA),
5894 ]:
5895 data = control.ReadEntry(image_fname, entry_path)
5896 self.assertEqual(expected, data)
5897
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005898 def testReplaceFitSubentryLeafSameSize(self):
5899 """Test replacing a FIT leaf subentry with same-size data"""
5900 new_data = b'x' * len(U_BOOT_DATA)
5901 data, expected_fdtmap, _ = self._RunReplaceCmd(
5902 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005903 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005904 self.assertEqual(new_data, data)
5905
5906 path, fdtmap = state.GetFdtContents('fdtmap')
5907 self.assertIsNotNone(path)
5908 self.assertEqual(expected_fdtmap, fdtmap)
5909
5910 def testReplaceFitSubentryLeafBiggerSize(self):
5911 """Test replacing a FIT leaf subentry with bigger-size data"""
5912 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5913 data, expected_fdtmap, _ = self._RunReplaceCmd(
5914 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005915 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005916 self.assertEqual(new_data, data)
5917
5918 # Will be repacked, so fdtmap must change
5919 path, fdtmap = state.GetFdtContents('fdtmap')
5920 self.assertIsNotNone(path)
5921 self.assertNotEqual(expected_fdtmap, fdtmap)
5922
5923 def testReplaceFitSubentryLeafSmallerSize(self):
5924 """Test replacing a FIT leaf subentry with smaller-size data"""
5925 new_data = b'x'
5926 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5927 data, expected_fdtmap, _ = self._RunReplaceCmd(
5928 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005929 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005930 self.assertEqual(expected, data)
5931
5932 path, fdtmap = state.GetFdtContents('fdtmap')
5933 self.assertIsNotNone(path)
5934 self.assertEqual(expected_fdtmap, fdtmap)
5935
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005936 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005937 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005938 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005939 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5940 new_data, dts='241_replace_section_simple.dts')
5941 self.assertEqual(new_data, data)
5942
5943 entries = image.GetEntries()
5944 self.assertIn('section', entries)
5945 entry = entries['section']
5946 self.assertEqual(len(new_data), entry.size)
5947
5948 def testReplaceSectionLarger(self):
5949 """Test replacing a simple section with larger data"""
5950 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5951 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5952 new_data, dts='241_replace_section_simple.dts')
5953 self.assertEqual(new_data, data)
5954
5955 entries = image.GetEntries()
5956 self.assertIn('section', entries)
5957 entry = entries['section']
5958 self.assertEqual(len(new_data), entry.size)
5959 fentry = entries['fdtmap']
5960 self.assertEqual(entry.offset + entry.size, fentry.offset)
5961
5962 def testReplaceSectionSmaller(self):
5963 """Test replacing a simple section with smaller data"""
5964 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5965 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5966 new_data, dts='241_replace_section_simple.dts')
5967 self.assertEqual(new_data, data)
5968
5969 # The new size is the same as the old, just with a pad byte at the end
5970 entries = image.GetEntries()
5971 self.assertIn('section', entries)
5972 entry = entries['section']
5973 self.assertEqual(len(new_data), entry.size)
5974
5975 def testReplaceSectionSmallerAllow(self):
5976 """Test failing to replace a simple section with smaller data"""
5977 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5978 try:
5979 state.SetAllowEntryContraction(True)
5980 with self.assertRaises(ValueError) as exc:
5981 self._RunReplaceCmd('section', new_data,
5982 dts='241_replace_section_simple.dts')
5983 finally:
5984 state.SetAllowEntryContraction(False)
5985
5986 # Since we have no information about the position of things within the
5987 # section, we cannot adjust the position of /section-u-boot so it ends
5988 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06005989 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07005990 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5991 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06005992 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005993
Simon Glass8fbca772022-08-13 11:40:48 -06005994 def testMkimageImagename(self):
5995 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005996 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005997 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005998
5999 # Check that the data appears in the file somewhere
6000 self.assertIn(U_BOOT_SPL_DATA, data)
6001
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006002 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06006003 name = data[0x20:0x40]
6004
6005 # Build the filename that we expect to be placed in there, by virtue of
6006 # the -n paraameter
6007 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6008
6009 # Check that the image name is set to the temporary filename used
6010 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6011
Simon Glassb1669752022-08-13 11:40:49 -06006012 def testMkimageImage(self):
6013 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006014 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006015 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006016
6017 # Check that the data appears in the file somewhere
6018 self.assertIn(U_BOOT_SPL_DATA, data)
6019
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006020 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006021 name = data[0x20:0x40]
6022
6023 # Build the filename that we expect to be placed in there, by virtue of
6024 # the -n paraameter
6025 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6026
6027 # Check that the image name is set to the temporary filename used
6028 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6029
6030 # Check the corect data is in the imagename file
6031 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6032
6033 def testMkimageImageNoContent(self):
6034 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006035 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006036 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006037 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006038 self.assertIn('Could not complete processing of contents',
6039 str(exc.exception))
6040
6041 def testMkimageImageBad(self):
6042 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006043 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006044 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006045 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006046 self.assertIn('Cannot use both imagename node and data-to-imagename',
6047 str(exc.exception))
6048
Simon Glassbd5cd882022-08-13 11:40:50 -06006049 def testCollectionOther(self):
6050 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006051 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006052 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6053 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6054 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6055 data)
6056
6057 def testMkimageCollection(self):
6058 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006059 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006060 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006061 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6062 self.assertEqual(expect, data[:len(expect)])
6063
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006064 def testCompressDtbPrependInvalid(self):
6065 """Test that invalid header is detected"""
6066 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006067 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006068 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6069 "'u-boot-dtb': 'invalid'", str(e.exception))
6070
6071 def testCompressDtbPrependLength(self):
6072 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006073 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006074 image = control.images['image']
6075 entries = image.GetEntries()
6076 self.assertIn('u-boot-dtb', entries)
6077 u_boot_dtb = entries['u-boot-dtb']
6078 self.assertIn('fdtmap', entries)
6079 fdtmap = entries['fdtmap']
6080
6081 image_fname = tools.get_output_filename('image.bin')
6082 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6083 dtb = fdt.Fdt.FromData(orig)
6084 dtb.Scan()
6085 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6086 expected = {
6087 'u-boot:size': len(U_BOOT_DATA),
6088 'u-boot-dtb:uncomp-size': len(orig),
6089 'u-boot-dtb:size': u_boot_dtb.size,
6090 'fdtmap:size': fdtmap.size,
6091 'size': len(data),
6092 }
6093 self.assertEqual(expected, props)
6094
6095 # Check implementation
6096 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6097 rest = data[len(U_BOOT_DATA):]
6098 comp_data_len = struct.unpack('<I', rest[:4])[0]
6099 comp_data = rest[4:4 + comp_data_len]
6100 orig2 = self._decompress(comp_data)
6101 self.assertEqual(orig, orig2)
6102
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006103 def testInvalidCompress(self):
6104 """Test that invalid compress algorithm is detected"""
6105 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006106 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006107 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6108
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006109 def testCompUtilCompressions(self):
6110 """Test compression algorithms"""
6111 for bintool in self.comp_bintools.values():
6112 self._CheckBintool(bintool)
6113 data = bintool.compress(COMPRESS_DATA)
6114 self.assertNotEqual(COMPRESS_DATA, data)
6115 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006116 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006117
6118 def testCompUtilVersions(self):
6119 """Test tool version of compression algorithms"""
6120 for bintool in self.comp_bintools.values():
6121 self._CheckBintool(bintool)
6122 version = bintool.version()
6123 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6124
6125 def testCompUtilPadding(self):
6126 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006127 # Skip zstd because it doesn't support padding
6128 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006129 self._CheckBintool(bintool)
6130 data = bintool.compress(COMPRESS_DATA)
6131 self.assertNotEqual(COMPRESS_DATA, data)
6132 data += tools.get_bytes(0, 64)
6133 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006134 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006135
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006136 def testCompressDtbZstd(self):
6137 """Test that zstd compress of device-tree files failed"""
6138 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006139 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006140 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6141 "requires a length header", str(e.exception))
6142
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006143 def testMkimageMultipleDataFiles(self):
6144 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006145 self._SetupSplElf()
6146 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006147 data = self._DoReadFile('252_mkimage_mult_data.dts')
6148 # Size of files are packed in their 4B big-endian format
6149 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6150 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6151 # Size info is always followed by a 4B zero value.
6152 expect += tools.get_bytes(0, 4)
6153 expect += U_BOOT_TPL_DATA
6154 # All but last files are 4B-aligned
6155 align_pad = len(U_BOOT_TPL_DATA) % 4
6156 if align_pad:
6157 expect += tools.get_bytes(0, align_pad)
6158 expect += U_BOOT_SPL_DATA
6159 self.assertEqual(expect, data[-len(expect):])
6160
Marek Vasutf7413f02023-07-18 07:23:58 -06006161 def testMkimageMultipleExpanded(self):
6162 """Test passing multiple files to mkimage in a mkimage entry"""
6163 self._SetupSplElf()
6164 self._SetupTplElf()
6165 entry_args = {
6166 'spl-bss-pad': 'y',
6167 'spl-dtb': 'y',
6168 }
6169 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6170 use_expanded=True, entry_args=entry_args)[0]
6171 pad_len = 10
6172 tpl_expect = U_BOOT_TPL_DATA
6173 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6174 spl_expect += U_BOOT_SPL_DTB_DATA
6175
6176 content = data[0x40:]
6177 lens = struct.unpack('>III', content[:12])
6178
6179 # Size of files are packed in their 4B big-endian format
6180 # Size info is always followed by a 4B zero value.
6181 self.assertEqual(len(tpl_expect), lens[0])
6182 self.assertEqual(len(spl_expect), lens[1])
6183 self.assertEqual(0, lens[2])
6184
6185 rest = content[12:]
6186 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6187
6188 rest = rest[len(tpl_expect):]
6189 align_pad = len(tpl_expect) % 4
6190 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6191 rest = rest[align_pad:]
6192 self.assertEqual(spl_expect, rest)
6193
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006194 def testMkimageMultipleNoContent(self):
6195 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006196 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006197 with self.assertRaises(ValueError) as exc:
6198 self._DoReadFile('253_mkimage_mult_no_content.dts')
6199 self.assertIn('Could not complete processing of contents',
6200 str(exc.exception))
6201
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006202 def testMkimageFilename(self):
6203 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006204 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006205 retcode = self._DoTestFile('254_mkimage_filename.dts')
6206 self.assertEqual(0, retcode)
6207 fname = tools.get_output_filename('mkimage-test.bin')
6208 self.assertTrue(os.path.exists(fname))
6209
Simon Glass56d05412022-02-28 07:16:54 -07006210 def testVpl(self):
6211 """Test that an image with VPL and its device tree can be created"""
6212 # ELF file with a '__bss_size' symbol
6213 self._SetupVplElf()
6214 data = self._DoReadFile('255_u_boot_vpl.dts')
6215 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6216
6217 def testVplNoDtb(self):
6218 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6219 self._SetupVplElf()
6220 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6221 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6222 data[:len(U_BOOT_VPL_NODTB_DATA)])
6223
6224 def testExpandedVpl(self):
6225 """Test that an expanded entry type is selected for TPL when needed"""
6226 self._SetupVplElf()
6227
6228 entry_args = {
6229 'vpl-bss-pad': 'y',
6230 'vpl-dtb': 'y',
6231 }
6232 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6233 entry_args=entry_args)
6234 image = control.images['image']
6235 entries = image.GetEntries()
6236 self.assertEqual(1, len(entries))
6237
6238 # We only have u-boot-vpl, which be expanded
6239 self.assertIn('u-boot-vpl', entries)
6240 entry = entries['u-boot-vpl']
6241 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6242 subent = entry.GetEntries()
6243 self.assertEqual(3, len(subent))
6244 self.assertIn('u-boot-vpl-nodtb', subent)
6245 self.assertIn('u-boot-vpl-bss-pad', subent)
6246 self.assertIn('u-boot-vpl-dtb', subent)
6247
6248 def testVplBssPadMissing(self):
6249 """Test that a missing symbol is detected"""
6250 self._SetupVplElf('u_boot_ucode_ptr')
6251 with self.assertRaises(ValueError) as e:
6252 self._DoReadFile('258_vpl_bss_pad.dts')
6253 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6254 str(e.exception))
6255
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306256 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306257 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306258 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6259 self.assertEqual(0, retcode)
6260 image = control.images['test_image']
6261 fname = tools.get_output_filename('test_image.bin')
6262 sname = tools.get_output_filename('symlink_to_test.bin')
6263 self.assertTrue(os.path.islink(sname))
6264 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006265
Andrew Davis6b463da2023-07-22 00:14:44 +05306266 def testSymlinkOverwrite(self):
6267 """Test that symlinked images can be overwritten"""
6268 testdir = TestFunctional._MakeInputDir('symlinktest')
6269 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6270 # build the same image again in the same directory so that existing symlink is present
6271 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6272 fname = tools.get_output_filename('test_image.bin')
6273 sname = tools.get_output_filename('symlink_to_test.bin')
6274 self.assertTrue(os.path.islink(sname))
6275 self.assertEqual(os.readlink(sname), fname)
6276
Simon Glass37f85de2022-10-20 18:22:47 -06006277 def testSymbolsElf(self):
6278 """Test binman can assign symbols embedded in an ELF file"""
6279 if not elf.ELF_TOOLS:
6280 self.skipTest('Python elftools not available')
6281 self._SetupTplElf('u_boot_binman_syms')
6282 self._SetupVplElf('u_boot_binman_syms')
6283 self._SetupSplElf('u_boot_binman_syms')
6284 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6285 image_fname = tools.get_output_filename('image.bin')
6286
6287 image = control.images['image']
6288 entries = image.GetEntries()
6289
6290 for entry in entries.values():
6291 # No symbols in u-boot and it has faked contents anyway
6292 if entry.name == 'u-boot':
6293 continue
6294 edata = data[entry.image_pos:entry.image_pos + entry.size]
6295 efname = tools.get_output_filename(f'edata-{entry.name}')
6296 tools.write_file(efname, edata)
6297
6298 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6299 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6300 for name, sym in syms.items():
6301 msg = 'test'
6302 val = elf.GetSymbolValue(sym, edata, msg)
6303 entry_m = re_name.match(name)
6304 if entry_m:
6305 ename, prop = entry_m.group(1), entry_m.group(3)
6306 entry, entry_name, prop_name = image.LookupEntry(entries,
6307 name, msg)
6308 if prop_name == 'offset':
6309 expect_val = entry.offset
6310 elif prop_name == 'image_pos':
6311 expect_val = entry.image_pos
6312 elif prop_name == 'size':
6313 expect_val = entry.size
6314 self.assertEqual(expect_val, val)
6315
6316 def testSymbolsElfBad(self):
6317 """Check error when trying to write symbols without the elftools lib"""
6318 if not elf.ELF_TOOLS:
6319 self.skipTest('Python elftools not available')
6320 self._SetupTplElf('u_boot_binman_syms')
6321 self._SetupVplElf('u_boot_binman_syms')
6322 self._SetupSplElf('u_boot_binman_syms')
6323 try:
6324 elf.ELF_TOOLS = False
6325 with self.assertRaises(ValueError) as exc:
6326 self._DoReadFileDtb('260_symbols_elf.dts')
6327 finally:
6328 elf.ELF_TOOLS = True
6329 self.assertIn(
6330 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6331 'Cannot write symbols to an ELF file without Python elftools',
6332 str(exc.exception))
6333
Simon Glassde244162023-01-07 14:07:08 -07006334 def testSectionFilename(self):
6335 """Check writing of section contents to a file"""
6336 data = self._DoReadFile('261_section_fname.dts')
6337 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6338 tools.get_bytes(ord('!'), 7) +
6339 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6340 self.assertEqual(expected, data)
6341
6342 sect_fname = tools.get_output_filename('outfile.bin')
6343 self.assertTrue(os.path.exists(sect_fname))
6344 sect_data = tools.read_file(sect_fname)
6345 self.assertEqual(U_BOOT_DATA, sect_data)
6346
Simon Glass1e9e61c2023-01-07 14:07:12 -07006347 def testAbsent(self):
6348 """Check handling of absent entries"""
6349 data = self._DoReadFile('262_absent.dts')
6350 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6351
Simon Glassad5cfe12023-01-07 14:07:14 -07006352 def testPackTeeOsOptional(self):
6353 """Test that an image with an optional TEE binary can be created"""
6354 entry_args = {
6355 'tee-os-path': 'tee.elf',
6356 }
6357 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6358 entry_args=entry_args)[0]
6359 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6360
6361 def checkFitTee(self, dts, tee_fname):
6362 """Check that a tee-os entry works and returns data
6363
6364 Args:
6365 dts (str): Device tree filename to use
6366 tee_fname (str): filename containing tee-os
6367
6368 Returns:
6369 bytes: Image contents
6370 """
6371 if not elf.ELF_TOOLS:
6372 self.skipTest('Python elftools not available')
6373 entry_args = {
6374 'of-list': 'test-fdt1 test-fdt2',
6375 'default-dt': 'test-fdt2',
6376 'tee-os-path': tee_fname,
6377 }
6378 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6379 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6380 extra_indirs=[test_subdir])[0]
6381 return data
6382
6383 def testFitTeeOsOptionalFit(self):
6384 """Test an image with a FIT with an optional OP-TEE binary"""
6385 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6386
6387 # There should be only one node, holding the data set up in SetUpClass()
6388 # for tee.bin
6389 dtb = fdt.Fdt.FromData(data)
6390 dtb.Scan()
6391 node = dtb.GetNode('/images/tee-1')
6392 self.assertEqual(TEE_ADDR,
6393 fdt_util.fdt32_to_cpu(node.props['load'].value))
6394 self.assertEqual(TEE_ADDR,
6395 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6396 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6397
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006398 with test_util.capture_sys_output() as (stdout, stderr):
6399 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6400 err = stderr.getvalue()
6401 self.assertRegex(
6402 err,
6403 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6404
Simon Glassad5cfe12023-01-07 14:07:14 -07006405 def testFitTeeOsOptionalFitBad(self):
6406 """Test an image with a FIT with an optional OP-TEE binary"""
6407 with self.assertRaises(ValueError) as exc:
6408 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6409 self.assertIn(
6410 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6411 str(exc.exception))
6412
6413 def testFitTeeOsBad(self):
6414 """Test an OP-TEE binary with wrong formats"""
6415 self.make_tee_bin('tee.bad1', 123)
6416 with self.assertRaises(ValueError) as exc:
6417 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6418 self.assertIn(
6419 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6420 str(exc.exception))
6421
6422 self.make_tee_bin('tee.bad2', 0, b'extra data')
6423 with self.assertRaises(ValueError) as exc:
6424 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6425 self.assertIn(
6426 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6427 str(exc.exception))
6428
Simon Glass63328f12023-01-07 14:07:15 -07006429 def testExtblobOptional(self):
6430 """Test an image with an external blob that is optional"""
6431 with test_util.capture_sys_output() as (stdout, stderr):
6432 data = self._DoReadFile('266_blob_ext_opt.dts')
6433 self.assertEqual(REFCODE_DATA, data)
6434 err = stderr.getvalue()
6435 self.assertRegex(
6436 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006437 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006438
Simon Glass7447a9d2023-01-11 16:10:12 -07006439 def testSectionInner(self):
6440 """Test an inner section with a size"""
6441 data = self._DoReadFile('267_section_inner.dts')
6442 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6443 self.assertEqual(expected, data)
6444
Simon Glassa4948b22023-01-11 16:10:14 -07006445 def testNull(self):
6446 """Test an image with a null entry"""
6447 data = self._DoReadFile('268_null.dts')
6448 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6449
Simon Glassf1ee03b2023-01-11 16:10:16 -07006450 def testOverlap(self):
6451 """Test an image with a overlapping entry"""
6452 data = self._DoReadFile('269_overlap.dts')
6453 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6454
6455 image = control.images['image']
6456 entries = image.GetEntries()
6457
6458 self.assertIn('inset', entries)
6459 inset = entries['inset']
6460 self.assertEqual(1, inset.offset);
6461 self.assertEqual(1, inset.image_pos);
6462 self.assertEqual(2, inset.size);
6463
6464 def testOverlapNull(self):
6465 """Test an image with a null overlap"""
6466 data = self._DoReadFile('270_overlap_null.dts')
6467 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6468
6469 # Check the FMAP
6470 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6471 self.assertEqual(4, fhdr.nareas)
6472 fiter = iter(fentries)
6473
6474 fentry = next(fiter)
6475 self.assertEqual(b'SECTION', fentry.name)
6476 self.assertEqual(0, fentry.offset)
6477 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6478 self.assertEqual(0, fentry.flags)
6479
6480 fentry = next(fiter)
6481 self.assertEqual(b'U_BOOT', fentry.name)
6482 self.assertEqual(0, fentry.offset)
6483 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6484 self.assertEqual(0, fentry.flags)
6485
6486 # Make sure that the NULL entry appears in the FMAP
6487 fentry = next(fiter)
6488 self.assertEqual(b'NULL', fentry.name)
6489 self.assertEqual(1, fentry.offset)
6490 self.assertEqual(2, fentry.size)
6491 self.assertEqual(0, fentry.flags)
6492
6493 fentry = next(fiter)
6494 self.assertEqual(b'FMAP', fentry.name)
6495 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6496
6497 def testOverlapBad(self):
6498 """Test an image with a bad overlapping entry"""
6499 with self.assertRaises(ValueError) as exc:
6500 self._DoReadFile('271_overlap_bad.dts')
6501 self.assertIn(
6502 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6503 str(exc.exception))
6504
6505 def testOverlapNoOffset(self):
6506 """Test an image with a bad overlapping entry"""
6507 with self.assertRaises(ValueError) as exc:
6508 self._DoReadFile('272_overlap_no_size.dts')
6509 self.assertIn(
6510 "Node '/binman/inset': 'fill' entry is missing properties: size",
6511 str(exc.exception))
6512
Simon Glasse0035c92023-01-11 16:10:17 -07006513 def testBlobSymbol(self):
6514 """Test a blob with symbols read from an ELF file"""
6515 elf_fname = self.ElfTestFile('blob_syms')
6516 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6517 TestFunctional._MakeInputFile('blob_syms.bin',
6518 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6519
6520 data = self._DoReadFile('273_blob_symbol.dts')
6521
6522 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6523 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6524 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6525 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6526 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6527
6528 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6529 expected = sym_values
6530 self.assertEqual(expected, data[:len(expected)])
6531
Simon Glass49e9c002023-01-11 16:10:19 -07006532 def testOffsetFromElf(self):
6533 """Test a blob with symbols read from an ELF file"""
6534 elf_fname = self.ElfTestFile('blob_syms')
6535 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6536 TestFunctional._MakeInputFile('blob_syms.bin',
6537 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6538
6539 data = self._DoReadFile('274_offset_from_elf.dts')
6540
6541 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6542 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6543
6544 image = control.images['image']
6545 entries = image.GetEntries()
6546
6547 self.assertIn('inset', entries)
6548 inset = entries['inset']
6549
6550 self.assertEqual(base + 4, inset.offset);
6551 self.assertEqual(base + 4, inset.image_pos);
6552 self.assertEqual(4, inset.size);
6553
6554 self.assertIn('inset2', entries)
6555 inset = entries['inset2']
6556 self.assertEqual(base + 8, inset.offset);
6557 self.assertEqual(base + 8, inset.image_pos);
6558 self.assertEqual(4, inset.size);
6559
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006560 def testFitAlign(self):
6561 """Test an image with an FIT with aligned external data"""
6562 data = self._DoReadFile('275_fit_align.dts')
6563 self.assertEqual(4096, len(data))
6564
6565 dtb = fdt.Fdt.FromData(data)
6566 dtb.Scan()
6567
6568 props = self._GetPropTree(dtb, ['data-position'])
6569 expected = {
6570 'u-boot:data-position': 1024,
6571 'fdt-1:data-position': 2048,
6572 'fdt-2:data-position': 3072,
6573 }
6574 self.assertEqual(expected, props)
6575
Jonas Karlman490f73c2023-01-21 19:02:12 +00006576 def testFitFirmwareLoadables(self):
6577 """Test an image with an FIT that use fit,firmware"""
6578 if not elf.ELF_TOOLS:
6579 self.skipTest('Python elftools not available')
6580 entry_args = {
6581 'of-list': 'test-fdt1',
6582 'default-dt': 'test-fdt1',
6583 'atf-bl31-path': 'bl31.elf',
6584 'tee-os-path': 'missing.bin',
6585 }
6586 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006587 with test_util.capture_sys_output() as (stdout, stderr):
6588 data = self._DoReadFileDtb(
6589 '276_fit_firmware_loadables.dts',
6590 entry_args=entry_args,
6591 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006592
6593 dtb = fdt.Fdt.FromData(data)
6594 dtb.Scan()
6595
6596 node = dtb.GetNode('/configurations/conf-uboot-1')
6597 self.assertEqual('u-boot', node.props['firmware'].value)
6598 self.assertEqual(['atf-1', 'atf-2'],
6599 fdt_util.GetStringList(node, 'loadables'))
6600
6601 node = dtb.GetNode('/configurations/conf-atf-1')
6602 self.assertEqual('atf-1', node.props['firmware'].value)
6603 self.assertEqual(['u-boot', 'atf-2'],
6604 fdt_util.GetStringList(node, 'loadables'))
6605
6606 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6607 self.assertEqual('u-boot', node.props['firmware'].value)
6608 self.assertEqual(['atf-1', 'atf-2'],
6609 fdt_util.GetStringList(node, 'loadables'))
6610
6611 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6612 self.assertEqual('atf-1', node.props['firmware'].value)
6613 self.assertEqual(['u-boot', 'atf-2'],
6614 fdt_util.GetStringList(node, 'loadables'))
6615
6616 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6617 self.assertEqual('atf-1', node.props['firmware'].value)
6618 self.assertEqual(['u-boot', 'atf-2'],
6619 fdt_util.GetStringList(node, 'loadables'))
6620
Simon Glass9a1c7262023-02-22 12:14:49 -07006621 def testTooldir(self):
6622 """Test that we can specify the tooldir"""
6623 with test_util.capture_sys_output() as (stdout, stderr):
6624 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6625 'tool', '-l'))
6626 self.assertEqual('fred', bintool.Bintool.tooldir)
6627
6628 # Check that the toolpath is updated correctly
6629 self.assertEqual(['fred'], tools.tool_search_paths)
6630
6631 # Try with a few toolpaths; the tooldir should be at the end
6632 with test_util.capture_sys_output() as (stdout, stderr):
6633 self.assertEqual(0, self._DoBinman(
6634 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6635 'tool', '-l'))
6636 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6637
Simon Glass49b77e82023-03-02 17:02:44 -07006638 def testReplaceSectionEntry(self):
6639 """Test replacing an entry in a section"""
6640 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6641 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6642 expect_data, dts='241_replace_section_simple.dts')
6643 self.assertEqual(expect_data, entry_data)
6644
6645 entries = image.GetEntries()
6646 self.assertIn('section', entries)
6647 section = entries['section']
6648
6649 sect_entries = section.GetEntries()
6650 self.assertIn('blob', sect_entries)
6651 entry = sect_entries['blob']
6652 self.assertEqual(len(expect_data), entry.size)
6653
6654 fname = tools.get_output_filename('image-updated.bin')
6655 data = tools.read_file(fname)
6656
6657 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6658 self.assertEqual(expect_data, new_blob_data)
6659
6660 self.assertEqual(U_BOOT_DATA,
6661 data[entry.image_pos + len(expect_data):]
6662 [:len(U_BOOT_DATA)])
6663
6664 def testReplaceSectionDeep(self):
6665 """Test replacing an entry in two levels of sections"""
6666 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6667 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6668 'section/section/blob', expect_data,
6669 dts='278_replace_section_deep.dts')
6670 self.assertEqual(expect_data, entry_data)
6671
6672 entries = image.GetEntries()
6673 self.assertIn('section', entries)
6674 section = entries['section']
6675
6676 subentries = section.GetEntries()
6677 self.assertIn('section', subentries)
6678 section = subentries['section']
6679
6680 sect_entries = section.GetEntries()
6681 self.assertIn('blob', sect_entries)
6682 entry = sect_entries['blob']
6683 self.assertEqual(len(expect_data), entry.size)
6684
6685 fname = tools.get_output_filename('image-updated.bin')
6686 data = tools.read_file(fname)
6687
6688 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6689 self.assertEqual(expect_data, new_blob_data)
6690
6691 self.assertEqual(U_BOOT_DATA,
6692 data[entry.image_pos + len(expect_data):]
6693 [:len(U_BOOT_DATA)])
6694
6695 def testReplaceFitSibling(self):
6696 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006697 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006698 fname = TestFunctional._MakeInputFile('once', b'available once')
6699 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6700 os.remove(fname)
6701
6702 try:
6703 tmpdir, updated_fname = self._SetupImageInTmpdir()
6704
6705 fname = os.path.join(tmpdir, 'update-blob')
6706 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6707 tools.write_file(fname, expected)
6708
6709 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6710 data = tools.read_file(updated_fname)
6711 start = len(U_BOOT_DTB_DATA)
6712 self.assertEqual(expected, data[start:start + len(expected)])
6713 map_fname = os.path.join(tmpdir, 'image-updated.map')
6714 self.assertFalse(os.path.exists(map_fname))
6715 finally:
6716 shutil.rmtree(tmpdir)
6717
Simon Glassc3fe97f2023-03-02 17:02:45 -07006718 def testX509Cert(self):
6719 """Test creating an X509 certificate"""
6720 keyfile = self.TestFile('key.key')
6721 entry_args = {
6722 'keyfile': keyfile,
6723 }
6724 data = self._DoReadFileDtb('279_x509_cert.dts',
6725 entry_args=entry_args)[0]
6726 cert = data[:-4]
6727 self.assertEqual(U_BOOT_DATA, data[-4:])
6728
6729 # TODO: verify the signature
6730
6731 def testX509CertMissing(self):
6732 """Test that binman still produces an image if openssl is missing"""
6733 keyfile = self.TestFile('key.key')
6734 entry_args = {
6735 'keyfile': 'keyfile',
6736 }
6737 with test_util.capture_sys_output() as (_, stderr):
6738 self._DoTestFile('279_x509_cert.dts',
6739 force_missing_bintools='openssl',
6740 entry_args=entry_args)
6741 err = stderr.getvalue()
6742 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6743
Jonas Karlman35305492023-02-25 19:01:33 +00006744 def testPackRockchipTpl(self):
6745 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006746 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006747 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6748
Jonas Karlman1016ec72023-02-25 19:01:35 +00006749 def testMkimageMissingBlobMultiple(self):
6750 """Test missing blob with mkimage entry and multiple-data-files"""
6751 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006752 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006753 err = stderr.getvalue()
6754 self.assertIn("is missing external blobs and is non-functional", err)
6755
6756 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006757 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006758 self.assertIn("not found in input path", str(e.exception))
6759
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006760 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6761 """Prepare sign environment
6762
6763 Create private and public keys, add pubkey into dtb.
6764
6765 Returns:
6766 Tuple:
6767 FIT container
6768 Image name
6769 Private key
6770 DTB
6771 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006772 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006773 data = self._DoReadFileRealDtb(dts)
6774 updated_fname = tools.get_output_filename('image-updated.bin')
6775 tools.write_file(updated_fname, data)
6776 dtb = tools.get_output_filename('source.dtb')
6777 private_key = tools.get_output_filename('test_key.key')
6778 public_key = tools.get_output_filename('test_key.crt')
6779 fit = tools.get_output_filename('fit.fit')
6780 key_dir = tools.get_output_dir()
6781
6782 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6783 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6784 private_key, '-out', public_key)
6785 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6786 '-n', 'test_key', '-r', 'conf', dtb)
6787
6788 return fit, updated_fname, private_key, dtb
6789
6790 def testSignSimple(self):
6791 """Test that a FIT container can be signed in image"""
6792 is_signed = False
6793 fit, fname, private_key, dtb = self._PrepareSignEnv()
6794
6795 # do sign with private key
6796 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6797 ['fit'])
6798 is_signed = self._CheckSign(fit, dtb)
6799
6800 self.assertEqual(is_signed, True)
6801
6802 def testSignExactFIT(self):
6803 """Test that a FIT container can be signed and replaced in image"""
6804 is_signed = False
6805 fit, fname, private_key, dtb = self._PrepareSignEnv()
6806
6807 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6808 args = []
6809 if self.toolpath:
6810 for path in self.toolpath:
6811 args += ['--toolpath', path]
6812
6813 # do sign with private key
6814 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6815 'sha256,rsa4096', '-f', fit, 'fit')
6816 is_signed = self._CheckSign(fit, dtb)
6817
6818 self.assertEqual(is_signed, True)
6819
6820 def testSignNonFit(self):
6821 """Test a non-FIT entry cannot be signed"""
6822 is_signed = False
6823 fit, fname, private_key, _ = self._PrepareSignEnv(
6824 '281_sign_non_fit.dts')
6825
6826 # do sign with private key
6827 with self.assertRaises(ValueError) as e:
6828 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6829 'sha256,rsa4096', '-f', fit, 'u-boot')
6830 self.assertIn(
6831 "Node '/u-boot': Updating signatures is not supported with this entry type",
6832 str(e.exception))
6833
6834 def testSignMissingMkimage(self):
6835 """Test that FIT signing handles a missing mkimage tool"""
6836 fit, fname, private_key, _ = self._PrepareSignEnv()
6837
6838 # try to sign with a missing mkimage tool
6839 bintool.Bintool.set_missing_list(['mkimage'])
6840 with self.assertRaises(ValueError) as e:
6841 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6842 ['fit'])
6843 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6844
Simon Glass4abf7842023-07-18 07:23:54 -06006845 def testSymbolNoWrite(self):
6846 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006847 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006848 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6849 no_write_symbols=True)
6850
6851 def testSymbolNoWriteExpanded(self):
6852 """Test disabling of symbol writing in expanded entries"""
6853 entry_args = {
6854 'spl-dtb': '1',
6855 }
6856 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6857 U_BOOT_SPL_DTB_DATA, 0x38,
6858 entry_args=entry_args, use_expanded=True,
6859 no_write_symbols=True)
6860
Marek Vasutf7413f02023-07-18 07:23:58 -06006861 def testMkimageSpecial(self):
6862 """Test mkimage ignores special hash-1 node"""
6863 data = self._DoReadFile('283_mkimage_special.dts')
6864
6865 # Just check that the data appears in the file somewhere
6866 self.assertIn(U_BOOT_DATA, data)
6867
Simon Glass2d94c422023-07-18 07:23:59 -06006868 def testFitFdtList(self):
6869 """Test an image with an FIT with the fit,fdt-list-val option"""
6870 entry_args = {
6871 'default-dt': 'test-fdt2',
6872 }
6873 data = self._DoReadFileDtb(
6874 '284_fit_fdt_list.dts',
6875 entry_args=entry_args,
6876 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6877 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6878 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6879
Simon Glass83b8bfe2023-07-18 07:24:01 -06006880 def testSplEmptyBss(self):
6881 """Test an expanded SPL with a zero-size BSS"""
6882 # ELF file with a '__bss_size' symbol
6883 self._SetupSplElf(src_fname='bss_data_zero')
6884
6885 entry_args = {
6886 'spl-bss-pad': 'y',
6887 'spl-dtb': 'y',
6888 }
6889 data = self._DoReadFileDtb('285_spl_expand.dts',
6890 use_expanded=True, entry_args=entry_args)[0]
6891
Simon Glassfc792842023-07-18 07:24:04 -06006892 def testTemplate(self):
6893 """Test using a template"""
6894 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6895 data = self._DoReadFile('286_template.dts')
6896 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6897 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6898 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6899
Simon Glass09490b02023-07-22 21:43:52 -06006900 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6901 self.assertTrue(os.path.exists(dtb_fname1))
6902 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6903 dtb.Scan()
6904 node1 = dtb.GetNode('/binman/template')
6905 self.assertTrue(node1)
6906 vga = dtb.GetNode('/binman/first/intel-vga')
6907 self.assertTrue(vga)
6908
Simon Glass54825e12023-07-22 21:43:56 -06006909 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6910 self.assertTrue(os.path.exists(dtb_fname2))
6911 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6912 dtb2.Scan()
6913 node2 = dtb2.GetNode('/binman/template')
6914 self.assertFalse(node2)
6915
Simon Glass9909c112023-07-18 07:24:05 -06006916 def testTemplateBlobMulti(self):
6917 """Test using a template with 'multiple-images' enabled"""
6918 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6919 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6920 retcode = self._DoTestFile('287_template_multi.dts')
6921
6922 self.assertEqual(0, retcode)
6923 image = control.images['image']
6924 image_fname = tools.get_output_filename('my-image.bin')
6925 data = tools.read_file(image_fname)
6926 self.assertEqual(b'blob@@@@other', data)
6927
Simon Glass5dc511b2023-07-18 07:24:06 -06006928 def testTemplateFit(self):
6929 """Test using a template in a FIT"""
6930 fit_data = self._DoReadFile('288_template_fit.dts')
6931 fname = os.path.join(self._indir, 'fit_data.fit')
6932 tools.write_file(fname, fit_data)
6933 out = tools.run('dumpimage', '-l', fname)
6934
Simon Glassaa6e0552023-07-18 07:24:07 -06006935 def testTemplateSection(self):
6936 """Test using a template in a section (not at top level)"""
6937 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6938 data = self._DoReadFile('289_template_section.dts')
6939 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6940 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6941 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6942
Simon Glassf53a7bc2023-07-18 07:24:08 -06006943 def testMkimageSymbols(self):
6944 """Test using mkimage to build an image with symbols in it"""
6945 self._SetupSplElf('u_boot_binman_syms')
6946 data = self._DoReadFile('290_mkimage_sym.dts')
6947
6948 image = control.images['image']
6949 entries = image.GetEntries()
6950 self.assertIn('u-boot', entries)
6951 u_boot = entries['u-boot']
6952
6953 mkim = entries['mkimage']
6954 mkim_entries = mkim.GetEntries()
6955 self.assertIn('u-boot-spl', mkim_entries)
6956 spl = mkim_entries['u-boot-spl']
6957 self.assertIn('u-boot-spl2', mkim_entries)
6958 spl2 = mkim_entries['u-boot-spl2']
6959
6960 # skip the mkimage header and the area sizes
6961 mk_data = data[mkim.offset + 0x40:]
6962 size, term = struct.unpack('>LL', mk_data[:8])
6963
6964 # There should be only one image, so check that the zero terminator is
6965 # present
6966 self.assertEqual(0, term)
6967
6968 content = mk_data[8:8 + size]
6969
6970 # The image should contain the symbols from u_boot_binman_syms.c
6971 # Note that image_pos is adjusted by the base address of the image,
6972 # which is 0x10 in our test image
6973 spl_data = content[:0x18]
6974 content = content[0x1b:]
6975
6976 # After the header is a table of offsets for each image. There should
6977 # only be one image, then a 0 terminator, so figure out the real start
6978 # of the image data
6979 base = 0x40 + 8
6980
6981 # Check symbols in both u-boot-spl and u-boot-spl2
6982 for i in range(2):
6983 vals = struct.unpack('<LLQLL', spl_data)
6984
6985 # The image should contain the symbols from u_boot_binman_syms.c
6986 # Note that image_pos is adjusted by the base address of the image,
6987 # which is 0x10 in our 'u_boot_binman_syms' test image
6988 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6989 self.assertEqual(base, vals[1])
6990 self.assertEqual(spl2.offset, vals[2])
6991 # figure out the internal positions of its components
6992 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6993
6994 # Check that spl and spl2 are actually at the indicated positions
6995 self.assertEqual(
6996 elf.BINMAN_SYM_MAGIC_VALUE,
6997 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6998 self.assertEqual(
6999 elf.BINMAN_SYM_MAGIC_VALUE,
7000 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
7001
7002 self.assertEqual(len(U_BOOT_DATA), vals[4])
7003
7004 # Move to next
7005 spl_data = content[:0x18]
7006
Simon Glass86b3e472023-07-22 21:43:57 -06007007 def testTemplatePhandle(self):
7008 """Test using a template in a node containing a phandle"""
7009 entry_args = {
7010 'atf-bl31-path': 'bl31.elf',
7011 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06007012 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007013 entry_args=entry_args)
7014 fname = tools.get_output_filename('image.bin')
7015 out = tools.run('dumpimage', '-l', fname)
7016
7017 # We should see the FIT description and one for each of the two images
7018 lines = out.splitlines()
7019 descs = [line.split()[-1] for line in lines if 'escription' in line]
7020 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7021
7022 def testTemplatePhandleDup(self):
7023 """Test using a template in a node containing a phandle"""
7024 entry_args = {
7025 'atf-bl31-path': 'bl31.elf',
7026 }
7027 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007028 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007029 entry_args=entry_args)
7030 self.assertIn(
7031 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7032 str(e.exception))
7033
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307034 def testTIBoardConfig(self):
7035 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007036 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307037 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7038
Neha Malcom Francis8cd04512024-01-05 17:09:17 +05307039 def testTIBoardConfigLint(self):
7040 """Test that an incorrectly linted config file would generate error"""
7041 with self.assertRaises(ValueError) as e:
7042 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7043 self.assertIn("Yamllint error", str(e.exception))
7044
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307045 def testTIBoardConfigCombined(self):
7046 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007047 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307048 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7049 self.assertGreater(data, configlen_noheader)
7050
7051 def testTIBoardConfigNoDataType(self):
7052 """Test that error is thrown when data type is not supported"""
7053 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007054 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307055 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007056
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307057 def testPackTiSecure(self):
7058 """Test that an image with a TI secured binary can be created"""
7059 keyfile = self.TestFile('key.key')
7060 entry_args = {
7061 'keyfile': keyfile,
7062 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007063 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307064 entry_args=entry_args)[0]
7065 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7066
Manorit Chawdhry2e523b02023-12-29 16:16:27 +05307067 def testPackTiSecureFirewall(self):
7068 """Test that an image with a TI secured binary can be created"""
7069 keyfile = self.TestFile('key.key')
7070 entry_args = {
7071 'keyfile': keyfile,
7072 }
7073 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7074 entry_args=entry_args)[0]
7075 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7076 entry_args=entry_args)[0]
7077 self.assertGreater(len(data_firewall),len(data_no_firewall))
7078
7079 def testPackTiSecureFirewallMissingProperty(self):
7080 """Test that an image with a TI secured binary can be created"""
7081 keyfile = self.TestFile('key.key')
7082 entry_args = {
7083 'keyfile': keyfile,
7084 }
7085 with self.assertRaises(ValueError) as e:
7086 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7087 entry_args=entry_args)[0]
7088 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7089
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307090 def testPackTiSecureMissingTool(self):
7091 """Test that an image with a TI secured binary (non-functional) can be created
7092 when openssl is missing"""
7093 keyfile = self.TestFile('key.key')
7094 entry_args = {
7095 'keyfile': keyfile,
7096 }
7097 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007098 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307099 force_missing_bintools='openssl',
7100 entry_args=entry_args)
7101 err = stderr.getvalue()
7102 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7103
7104 def testPackTiSecureROM(self):
7105 """Test that a ROM image with a TI secured binary can be created"""
7106 keyfile = self.TestFile('key.key')
7107 entry_args = {
7108 'keyfile': keyfile,
7109 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007110 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307111 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007112 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307113 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007114 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307115 entry_args=entry_args)[0]
7116 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7117 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7118 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7119
7120 def testPackTiSecureROMCombined(self):
7121 """Test that a ROM image with a TI secured binary can be created"""
7122 keyfile = self.TestFile('key.key')
7123 entry_args = {
7124 'keyfile': keyfile,
7125 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007126 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307127 entry_args=entry_args)[0]
7128 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7129
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007130 def testEncryptedNoAlgo(self):
7131 """Test encrypted node with missing required properties"""
7132 with self.assertRaises(ValueError) as e:
7133 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7134 self.assertIn(
7135 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7136 str(e.exception))
7137
7138 def testEncryptedInvalidIvfile(self):
7139 """Test encrypted node with invalid iv file"""
7140 with self.assertRaises(ValueError) as e:
7141 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7142 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7143 str(e.exception))
7144
7145 def testEncryptedMissingKey(self):
7146 """Test encrypted node with missing key properties"""
7147 with self.assertRaises(ValueError) as e:
7148 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7149 self.assertIn(
7150 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7151 str(e.exception))
7152
7153 def testEncryptedKeySource(self):
7154 """Test encrypted node with key-source property"""
7155 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7156
7157 dtb = fdt.Fdt.FromData(data)
7158 dtb.Scan()
7159
7160 node = dtb.GetNode('/images/u-boot/cipher')
7161 self.assertEqual('algo-name', node.props['algo'].value)
7162 self.assertEqual('key-source-value', node.props['key-source'].value)
7163 self.assertEqual(ENCRYPTED_IV_DATA,
7164 tools.to_bytes(''.join(node.props['iv'].value)))
7165 self.assertNotIn('key', node.props)
7166
7167 def testEncryptedKeyFile(self):
7168 """Test encrypted node with key-filename property"""
7169 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7170
7171 dtb = fdt.Fdt.FromData(data)
7172 dtb.Scan()
7173
7174 node = dtb.GetNode('/images/u-boot/cipher')
7175 self.assertEqual('algo-name', node.props['algo'].value)
7176 self.assertEqual(ENCRYPTED_IV_DATA,
7177 tools.to_bytes(''.join(node.props['iv'].value)))
7178 self.assertEqual(ENCRYPTED_KEY_DATA,
7179 tools.to_bytes(''.join(node.props['key'].value)))
7180 self.assertNotIn('key-source', node.props)
7181
Lukas Funkee901faf2023-07-18 13:53:13 +02007182
7183 def testSplPubkeyDtb(self):
Simon Glass4b861272024-07-20 11:49:41 +01007184 """Test u_boot_spl_pubkey_dtb etype"""
7185 data = tools.read_file(self.TestFile("key.pem"))
7186 self._MakeInputFile("key.crt", data)
7187 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7188 image = control.images['image']
7189 entries = image.GetEntries()
7190 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7191 dtb_data = dtb_entry.GetData()
7192 dtb = fdt.Fdt.FromData(dtb_data)
7193 dtb.Scan()
Lukas Funkee901faf2023-07-18 13:53:13 +02007194
Simon Glass4b861272024-07-20 11:49:41 +01007195 signature_node = dtb.GetNode('/signature')
7196 self.assertIsNotNone(signature_node)
7197 key_node = signature_node.FindNode("key-key")
7198 self.assertIsNotNone(key_node)
7199 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7200 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7201 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007202
Lukas Funke712e1062023-08-03 17:22:14 +02007203 def testXilinxBootgenSigning(self):
7204 """Test xilinx-bootgen etype"""
7205 bootgen = bintool.Bintool.create('bootgen')
7206 self._CheckBintool(bootgen)
7207 data = tools.read_file(self.TestFile("key.key"))
7208 self._MakeInputFile("psk.pem", data)
7209 self._MakeInputFile("ssk.pem", data)
7210 self._SetupPmuFwlElf()
7211 self._SetupSplElf()
7212 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7213 image_fname = tools.get_output_filename('image.bin')
7214
7215 # Read partition header table and check if authentication is enabled
7216 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7217 "-read", image_fname, "pht").splitlines()
7218 attributes = {"authentication": None,
7219 "core": None,
7220 "encryption": None}
7221
7222 for l in bootgen_out:
7223 for a in attributes.keys():
7224 if a in l:
7225 m = re.match(fr".*{a} \[([^]]+)\]", l)
7226 attributes[a] = m.group(1)
7227
7228 self.assertTrue(attributes['authentication'] == "rsa")
7229 self.assertTrue(attributes['core'] == "a53-0")
7230 self.assertTrue(attributes['encryption'] == "no")
7231
7232 def testXilinxBootgenSigningEncryption(self):
7233 """Test xilinx-bootgen etype"""
7234 bootgen = bintool.Bintool.create('bootgen')
7235 self._CheckBintool(bootgen)
7236 data = tools.read_file(self.TestFile("key.key"))
7237 self._MakeInputFile("psk.pem", data)
7238 self._MakeInputFile("ssk.pem", data)
7239 self._SetupPmuFwlElf()
7240 self._SetupSplElf()
7241 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7242 image_fname = tools.get_output_filename('image.bin')
7243
7244 # Read boot header in order to verify encryption source and
7245 # encryption parameter
7246 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7247 "-read", image_fname, "bh").splitlines()
7248 attributes = {"auth_only":
7249 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7250 "encryption_keystore":
7251 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7252 "value": None},
7253 }
7254
7255 for l in bootgen_out:
7256 for a in attributes.keys():
7257 if a in l:
7258 m = re.match(attributes[a]['re'], l)
7259 attributes[a] = m.group(1)
7260
7261 # Check if fsbl-attribute is set correctly
7262 self.assertTrue(attributes['auth_only'] == "true")
7263 # Check if key is stored in efuse
7264 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7265
7266 def testXilinxBootgenMissing(self):
7267 """Test that binman still produces an image if bootgen is missing"""
7268 data = tools.read_file(self.TestFile("key.key"))
7269 self._MakeInputFile("psk.pem", data)
7270 self._MakeInputFile("ssk.pem", data)
7271 self._SetupPmuFwlElf()
7272 self._SetupSplElf()
7273 with test_util.capture_sys_output() as (_, stderr):
7274 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7275 force_missing_bintools='bootgen')
7276 err = stderr.getvalue()
7277 self.assertRegex(err,
7278 "Image 'image'.*missing bintools.*: bootgen")
7279
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307280 def _GetCapsuleHeaders(self, data):
7281 """Get the capsule header contents
7282
7283 Args:
7284 data: Capsule file contents
7285
7286 Returns:
7287 Dict:
7288 key: Capsule Header name (str)
7289 value: Header field value (str)
7290 """
7291 capsule_file = os.path.join(self._indir, 'test.capsule')
7292 tools.write_file(capsule_file, data)
7293
7294 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7295 lines = out.splitlines()
7296
7297 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7298 vals = {}
7299 for line in lines:
7300 mat = re_line.match(line)
7301 if mat:
7302 vals[mat.group(1)] = mat.group(2)
7303
7304 return vals
7305
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307306 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7307 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307308 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7309 fmp_size = "00000010"
7310 fmp_fw_version = "00000002"
7311 capsule_image_index = "00000001"
7312 oemflag = "00018000"
7313 auth_hdr_revision = "00000200"
7314 auth_hdr_cert_type = "00000EF1"
7315
7316 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307317
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307318 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307319
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307320 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307321
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307322 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7323 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7324 self.assertEqual(capsule_image_index,
7325 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307326
7327 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307328 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7329
7330 if signed_capsule:
7331 self.assertEqual(auth_hdr_revision,
7332 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7333 self.assertEqual(auth_hdr_cert_type,
7334 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7335 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7336 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7337
7338 if version_check:
7339 self.assertEqual(fmp_signature,
7340 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7341 self.assertEqual(fmp_size,
7342 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7343 self.assertEqual(fmp_fw_version,
7344 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7345
7346 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307347
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307348 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7349 if accept_capsule:
7350 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7351 else:
7352 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7353
7354 hdr = self._GetCapsuleHeaders(data)
7355
7356 self.assertEqual(capsule_hdr_guid.upper(),
7357 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7358
7359 if accept_capsule:
7360 capsule_size = "0000002C"
7361 else:
7362 capsule_size = "0000001C"
7363 self.assertEqual(capsule_size,
7364 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7365
7366 if accept_capsule:
7367 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7368
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307369 def testCapsuleGen(self):
7370 """Test generation of EFI capsule"""
7371 data = self._DoReadFile('311_capsule.dts')
7372
7373 self._CheckCapsule(data)
7374
7375 def testSignedCapsuleGen(self):
7376 """Test generation of EFI capsule"""
7377 data = tools.read_file(self.TestFile("key.key"))
7378 self._MakeInputFile("key.key", data)
7379 data = tools.read_file(self.TestFile("key.pem"))
7380 self._MakeInputFile("key.crt", data)
7381
7382 data = self._DoReadFile('312_capsule_signed.dts')
7383
7384 self._CheckCapsule(data, signed_capsule=True)
7385
7386 def testCapsuleGenVersionSupport(self):
7387 """Test generation of EFI capsule with version support"""
7388 data = self._DoReadFile('313_capsule_version.dts')
7389
7390 self._CheckCapsule(data, version_check=True)
7391
7392 def testCapsuleGenSignedVer(self):
7393 """Test generation of signed EFI capsule with version information"""
7394 data = tools.read_file(self.TestFile("key.key"))
7395 self._MakeInputFile("key.key", data)
7396 data = tools.read_file(self.TestFile("key.pem"))
7397 self._MakeInputFile("key.crt", data)
7398
7399 data = self._DoReadFile('314_capsule_signed_ver.dts')
7400
7401 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7402
7403 def testCapsuleGenCapOemFlags(self):
7404 """Test generation of EFI capsule with OEM Flags set"""
7405 data = self._DoReadFile('315_capsule_oemflags.dts')
7406
7407 self._CheckCapsule(data, capoemflags=True)
7408
7409 def testCapsuleGenKeyMissing(self):
7410 """Test that binman errors out on missing key"""
7411 with self.assertRaises(ValueError) as e:
7412 self._DoReadFile('316_capsule_missing_key.dts')
7413
7414 self.assertIn("Both private key and public key certificate need to be provided",
7415 str(e.exception))
7416
7417 def testCapsuleGenIndexMissing(self):
7418 """Test that binman errors out on missing image index"""
7419 with self.assertRaises(ValueError) as e:
7420 self._DoReadFile('317_capsule_missing_index.dts')
7421
7422 self.assertIn("entry is missing properties: image-index",
7423 str(e.exception))
7424
7425 def testCapsuleGenGuidMissing(self):
7426 """Test that binman errors out on missing image GUID"""
7427 with self.assertRaises(ValueError) as e:
7428 self._DoReadFile('318_capsule_missing_guid.dts')
7429
7430 self.assertIn("entry is missing properties: image-guid",
7431 str(e.exception))
7432
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307433 def testCapsuleGenAcceptCapsule(self):
7434 """Test generationg of accept EFI capsule"""
7435 data = self._DoReadFile('319_capsule_accept.dts')
7436
7437 self._CheckEmptyCapsule(data, accept_capsule=True)
7438
7439 def testCapsuleGenRevertCapsule(self):
7440 """Test generationg of revert EFI capsule"""
7441 data = self._DoReadFile('320_capsule_revert.dts')
7442
7443 self._CheckEmptyCapsule(data)
7444
7445 def testCapsuleGenAcceptGuidMissing(self):
7446 """Test that binman errors out on missing image GUID for accept capsule"""
7447 with self.assertRaises(ValueError) as e:
7448 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7449
7450 self.assertIn("Image GUID needed for generating accept capsule",
7451 str(e.exception))
7452
7453 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7454 """Test that capsule-type is specified"""
7455 with self.assertRaises(ValueError) as e:
7456 self._DoReadFile('322_empty_capsule_type_missing.dts')
7457
7458 self.assertIn("entry is missing properties: capsule-type",
7459 str(e.exception))
7460
7461 def testCapsuleGenAcceptOrRevertMissing(self):
7462 """Test that both accept and revert capsule are not specified"""
7463 with self.assertRaises(ValueError) as e:
7464 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7465
Simon Glassa360b8f2024-06-23 11:55:06 -06007466 def test_assume_size(self):
7467 """Test handling of the assume-size property for external blob"""
7468 with self.assertRaises(ValueError) as e:
7469 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7470 allow_fake_blobs=True)
7471 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7472 str(e.exception))
7473
7474 def test_assume_size_ok(self):
7475 """Test handling of the assume-size where it fits OK"""
7476 with test_util.capture_sys_output() as (stdout, stderr):
7477 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7478 allow_fake_blobs=True)
7479 err = stderr.getvalue()
7480 self.assertRegex(
7481 err,
7482 "Image '.*' has faked external blobs and is non-functional: .*")
7483
7484 def test_assume_size_no_fake(self):
7485 """Test handling of the assume-size where it fits OK"""
7486 with test_util.capture_sys_output() as (stdout, stderr):
7487 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7488 err = stderr.getvalue()
7489 self.assertRegex(
7490 err,
7491 "Image '.*' is missing external blobs and is non-functional: .*")
7492
Simon Glass5f7aadf2024-07-20 11:49:47 +01007493 def SetupAlternateDts(self):
7494 """Compile the .dts test files for alternative-fdt
7495
7496 Returns:
7497 tuple:
7498 str: Test directory created
7499 list of str: '.bin' files which we expect Binman to create
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 return testdir, dtb_list
7510
Simon Glassf3598922024-07-20 11:49:45 +01007511 def CheckAlternates(self, dts, phase, xpl_data):
7512 """Run the test for the alterative-fdt etype
7513
7514 Args:
7515 dts (str): Devicetree file to process
7516 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7517 xpl_data (bytes): Expected data for the phase's binary
7518
7519 Returns:
7520 dict of .dtb files produced
7521 key: str filename
7522 value: Fdt object
7523 """
Simon Glass5f7aadf2024-07-20 11:49:47 +01007524 dtb_list = self.SetupAlternateDts()[1]
Simon Glassf3598922024-07-20 11:49:45 +01007525
7526 entry_args = {
7527 f'{phase}-dtb': '1',
7528 f'{phase}-bss-pad': 'y',
7529 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7530 }
7531 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7532 use_expanded=True, entry_args=entry_args)[0]
7533 self.assertEqual(xpl_data, data[:len(xpl_data)])
7534 rest = data[len(xpl_data):]
7535 pad_len = 10
7536 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7537
7538 # Check the dtb is using the test file
7539 dtb_data = rest[pad_len:]
7540 dtb = fdt.Fdt.FromData(dtb_data)
7541 dtb.Scan()
7542 fdt_size = dtb.GetFdtObj().totalsize()
7543 self.assertEqual('model-not-set',
7544 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7545
7546 pad_len = 10
7547
7548 # Check the other output files
7549 dtbs = {}
7550 for fname in dtb_list:
7551 pathname = tools.get_output_filename(fname)
7552 self.assertTrue(os.path.exists(pathname))
7553
7554 data = tools.read_file(pathname)
7555 self.assertEqual(xpl_data, data[:len(xpl_data)])
7556 rest = data[len(xpl_data):]
7557
7558 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7559 rest = rest[pad_len:]
7560
7561 dtb = fdt.Fdt.FromData(rest)
7562 dtb.Scan()
7563 dtbs[fname] = dtb
7564
7565 expected = 'one' if '1' in fname else 'two'
7566 self.assertEqual(f'u-boot,model-{expected}',
7567 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7568
7569 # Make sure the FDT is the same size as the 'main' one
7570 rest = rest[fdt_size:]
7571
7572 self.assertEqual(b'', rest)
7573 return dtbs
7574
7575 def testAlternatesFdt(self):
7576 """Test handling of alternates-fdt etype"""
7577 self._SetupTplElf()
7578 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7579 U_BOOT_TPL_NODTB_DATA)
7580 for dtb in dtbs.values():
7581 # Check for the node with the tag
7582 node = dtb.GetNode('/node')
7583 self.assertIsNotNone(node)
7584 self.assertEqual(5, len(node.props.keys()))
7585
7586 # Make sure the other node is still there
7587 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7588
7589 def testAlternatesFdtgrep(self):
7590 """Test handling of alternates-fdt etype using fdtgrep"""
7591 self._SetupTplElf()
7592 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7593 U_BOOT_TPL_NODTB_DATA)
7594 for dtb in dtbs.values():
7595 # Check for the node with the tag
7596 node = dtb.GetNode('/node')
7597 self.assertIsNotNone(node)
7598 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7599 node.props.keys())
7600
7601 # Make sure the other node is gone
7602 self.assertIsNone(dtb.GetNode('/node/other-node'))
7603
7604 def testAlternatesFdtgrepVpl(self):
7605 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7606 self._SetupVplElf()
7607 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7608 U_BOOT_VPL_NODTB_DATA)
7609
7610 def testAlternatesFdtgrepSpl(self):
7611 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7612 self._SetupSplElf()
7613 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7614 U_BOOT_SPL_NODTB_DATA)
7615
7616 def testAlternatesFdtgrepInval(self):
7617 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7618 self._SetupSplElf()
7619 with self.assertRaises(ValueError) as e:
7620 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7621 U_BOOT_SPL_NODTB_DATA)
7622 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7623 str(e.exception))
7624
Simon Glasscd2783e2024-07-20 11:49:46 +01007625 def testFitFdtListDir(self):
7626 """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
7627 self.CheckFitFdt('333_fit_fdt_dir.dts', False)
7628
Simon Glass5f7aadf2024-07-20 11:49:47 +01007629 def testFitFdtCompat(self):
7630 """Test an image with an FIT with compatible in the config nodes"""
7631 entry_args = {
7632 'of-list': 'model1 model2',
7633 'default-dt': 'model2',
7634 }
7635 testdir, dtb_list = self.SetupAlternateDts()
7636 data = self._DoReadFileDtb(
7637 '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
7638 entry_args=entry_args, extra_indirs=[testdir])[0]
7639
7640 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7641
7642 fit = fdt.Fdt.FromData(fit_data)
7643 fit.Scan()
7644
7645 cnode = fit.GetNode('/configurations')
7646 self.assertIn('default', cnode.props)
7647 self.assertEqual('config-2', cnode.props['default'].value)
7648
7649 for seq in range(1, 2):
7650 name = f'config-{seq}'
7651 fnode = fit.GetNode('/configurations/%s' % name)
7652 self.assertIsNotNone(fnode)
7653 self.assertIn('compatible', fnode.props.keys())
7654 expected = 'one' if seq == 1 else 'two'
7655 self.assertEqual(f'u-boot,model-{expected}',
7656 fnode.props['compatible'].value)
7657
Simon Glassa04b9942024-07-20 11:49:48 +01007658 def testFitFdtPhase(self):
7659 """Test an image with an FIT with fdt-phase in the fdt nodes"""
7660 phase = 'tpl'
7661 entry_args = {
7662 f'{phase}-dtb': '1',
7663 f'{phase}-bss-pad': 'y',
7664 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7665 'of-list': 'model1 model2',
7666 'default-dt': 'model2',
7667 }
7668 testdir, dtb_list = self.SetupAlternateDts()
7669 data = self._DoReadFileDtb(
7670 '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
7671 entry_args=entry_args, extra_indirs=[testdir])[0]
7672 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7673 fit = fdt.Fdt.FromData(fit_data)
7674 fit.Scan()
7675
7676 # Check that each FDT has only the expected properties for the phase
7677 for seq in range(1, 2):
7678 fnode = fit.GetNode(f'/images/fdt-{seq}')
7679 self.assertIsNotNone(fnode)
7680 dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
7681 dtb.Scan()
7682
7683 # Make sure that the 'bootph-pre-sram' tag in /node protects it from
7684 # removal
7685 node = dtb.GetNode('/node')
7686 self.assertIsNotNone(node)
7687 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7688 node.props.keys())
7689
7690 # Make sure the other node is gone
7691 self.assertIsNone(dtb.GetNode('/node/other-node'))
7692
Simon Glassa360b8f2024-06-23 11:55:06 -06007693
Simon Glassac599912017-11-12 21:52:22 -07007694if __name__ == "__main__":
7695 unittest.main()