blob: 8cf867fd3fed56a5b0286f05c8712626faff0881 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass57454f42016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass57454f42016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glass45d556d2020-07-09 18:39:45 -06009import collections
Simon Glassf3598922024-07-20 11:49:45 +010010import glob
Simon Glassc585dd42020-04-17 18:09:03 -060011import gzip
Simon Glassae7cf032018-09-14 04:57:31 -060012import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070013from optparse import OptionParser
14import os
Simon Glass45d556d2020-07-09 18:39:45 -060015import re
Simon Glass57454f42016-11-25 20:15:52 -070016import shutil
17import struct
18import sys
19import tempfile
20import unittest
Simon Glass162017b2022-01-09 20:13:57 -070021import unittest.mock
22import urllib.error
Simon Glass57454f42016-11-25 20:15:52 -070023
Simon Glass4eae9252022-01-09 20:13:50 -070024from binman import bintool
Simon Glassc585dd42020-04-17 18:09:03 -060025from binman import cbfs_util
26from binman import cmdline
27from binman import control
28from binman import elf
29from binman import elf_test
Simon Glass3efb2972021-11-23 21:08:59 -070030from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060031from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060032from binman import state
33from dtoc import fdt
34from dtoc import fdt_util
35from binman.etype import fdtmap
36from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060037from binman.image import Image
Simon Glass131444f2023-02-23 18:18:04 -070038from u_boot_pylib import command
39from u_boot_pylib import test_util
40from u_boot_pylib import tools
41from u_boot_pylib import tout
Simon Glass57454f42016-11-25 20:15:52 -070042
43# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060044U_BOOT_DATA = b'1234'
45U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +030046U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass56d05412022-02-28 07:16:54 -070048U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glass303f62f2019-05-17 22:00:46 -060049BLOB_DATA = b'89'
50ME_DATA = b'0abcd'
51VGA_DATA = b'vga'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +053052EFI_CAPSULE_DATA = b'efi'
Simon Glass303f62f2019-05-17 22:00:46 -060053U_BOOT_DTB_DATA = b'udtb'
54U_BOOT_SPL_DTB_DATA = b'spldtb'
55U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass56d05412022-02-28 07:16:54 -070056U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glass303f62f2019-05-17 22:00:46 -060057X86_START16_DATA = b'start16'
58X86_START16_SPL_DATA = b'start16spl'
59X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060060X86_RESET16_DATA = b'reset16'
61X86_RESET16_SPL_DATA = b'reset16spl'
62X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060063PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
64U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
65U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
66U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass56d05412022-02-28 07:16:54 -070067U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +030068U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
69U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
70U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glass303f62f2019-05-17 22:00:46 -060071FSP_DATA = b'fsp'
72CMC_DATA = b'cmc'
73VBT_DATA = b'vbt'
74MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060075TEXT_DATA = 'text'
76TEXT_DATA2 = 'text2'
77TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060078CROS_EC_RW_DATA = b'ecrw'
79GBB_DATA = b'gbbd'
80BMPBLK_DATA = b'bmp'
81VBLOCK_DATA = b'vblk'
82FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
83 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060084COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060085COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060086REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060087FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060088FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060089FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060090ATF_BL31_DATA = b'bl31'
Roger Quadros5cdcea02022-02-19 20:50:04 +020091TEE_OS_DATA = b'this is some tee OS data'
Neha Malcom Francis59be2552023-12-05 15:12:18 +053092TI_DM_DATA = b'tidmtidm'
Simon Glass3efb2972021-11-23 21:08:59 -070093ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080094OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050095SCP_DATA = b'scp'
Jonas Karlman35305492023-02-25 19:01:33 +000096ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glassa435cd12020-09-01 05:13:59 -060097TEST_FDT1_DATA = b'fdt1'
98TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060099ENV_DATA = b'var1=1\nvar2="2"'
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200100ENCRYPTED_IV_DATA = b'123456'
101ENCRYPTED_KEY_DATA = b'abcde'
Philippe Reynesebe96cb2022-03-28 22:57:04 +0200102PRE_LOAD_MAGIC = b'UBSH'
103PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
104PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530105TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530106TI_UNSECURE_DATA = b'unsecuredata'
Simon Glassa435cd12020-09-01 05:13:59 -0600107
108# Subdirectory of the input dir to use to put test FDTs
109TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600110
Simon Glass2c6adba2019-07-20 12:23:47 -0600111# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600112EXTRACT_DTB_SIZE = 0x3c9
113
Simon Glass2c6adba2019-07-20 12:23:47 -0600114# Properties expected to be in the device tree when update_dtb is used
115BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
116
Simon Glassfb30e292019-07-20 12:23:51 -0600117# Extra properties expected to be in the device tree when allow-repack is used
118REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
119
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200120# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200121COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700122
Simon Glassad5cfe12023-01-07 14:07:14 -0700123TEE_ADDR = 0x5678
124
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530125# Firmware Management Protocol(FMP) GUID
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530126FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530127# Image GUID specified in the DTS
Caleb Connolly4bdc9602024-08-30 13:34:35 +0100128CAPSULE_IMAGE_GUID = '985F2937-7C2E-5E9A-8A5E-8E063312964B'
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530129# Windows cert GUID
130WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +0530131# Empty capsule GUIDs
132EMPTY_CAPSULE_ACCEPT_GUID = '0c996046-bcc0-4d04-85ec-e1fcedf1c6f8'
133EMPTY_CAPSULE_REVERT_GUID = 'acd58b4b-c0e8-475f-99b5-6b3f7e07aaf0'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530134
Simon Glass57454f42016-11-25 20:15:52 -0700135class TestFunctional(unittest.TestCase):
136 """Functional tests for binman
137
138 Most of these use a sample .dts file to build an image and then check
139 that it looks correct. The sample files are in the test/ subdirectory
140 and are numbered.
141
142 For each entry type a very small test file is created using fixed
143 string contents. This makes it easy to test that things look right, and
144 debug problems.
145
146 In some cases a 'real' file must be used - these are also supplied in
147 the test/ diurectory.
148 """
149 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600150 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700151 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600152 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700153
Simon Glass57454f42016-11-25 20:15:52 -0700154 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600155 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
156 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700157
158 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600159 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700160
161 # Create some test files
162 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
163 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
164 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600165 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700166 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700167 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700168 TestFunctional._MakeInputFile('me.bin', ME_DATA)
169 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600170 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600171
Jagdish Gediya311d4842018-09-03 21:35:08 +0530172 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600173
Simon Glassabab18c2019-08-24 07:22:49 -0600174 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
175 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700176 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600177 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600178 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600179
180 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
181 X86_RESET16_DATA)
182 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
183 X86_RESET16_SPL_DATA)
184 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
185 X86_RESET16_TPL_DATA)
186
Simon Glass57454f42016-11-25 20:15:52 -0700187 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700188 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
189 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600190 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
191 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700192 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
193 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700194 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
195 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700196 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700197 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600198 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600199 TestFunctional._MakeInputDir('devkeys')
200 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600201 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600202 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600203 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600204 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700205
Simon Glassf6290892019-08-24 07:22:53 -0600206 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
207 elf_test.BuildElfTestFiles(cls._elf_testdir)
208
Simon Glass72232452016-11-25 20:15:53 -0700209 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600210 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700211 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700212
213 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600214 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700215
Simon Glass862f8e22019-08-24 07:22:43 -0600216 shutil.copytree(cls.TestFile('files'),
217 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600218
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530219 shutil.copytree(cls.TestFile('yaml'),
220 os.path.join(cls._indir, 'yaml'))
221
Simon Glass7ba33592018-09-14 04:57:26 -0600222 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600223 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600224 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200225 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Neha Malcom Francis59be2552023-12-05 15:12:18 +0530226 TestFunctional._MakeInputFile('dm.bin', TI_DM_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700227 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800228 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500229 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman35305492023-02-25 19:01:33 +0000230 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530231 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530232 TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600233
Simon Glassa435cd12020-09-01 05:13:59 -0600234 # Add a few .dtb files for testing
235 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
236 TEST_FDT1_DATA)
237 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
238 TEST_FDT2_DATA)
239
Simon Glassa0729502020-09-06 10:35:33 -0600240 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
241
Simon Glass5f423422022-03-05 20:19:12 -0700242 # ELF file with two sections in different parts of memory, used for both
243 # ATF and OP_TEE
244 TestFunctional._MakeInputFile('bl31.elf',
245 tools.read_file(cls.ElfTestFile('elf_sections')))
246 TestFunctional._MakeInputFile('tee.elf',
247 tools.read_file(cls.ElfTestFile('elf_sections')))
248
Simon Glassad5cfe12023-01-07 14:07:14 -0700249 # Newer OP_TEE file in v1 binary format
250 cls.make_tee_bin('tee.bin')
251
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200252 # test files for encrypted tests
253 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
254 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
255
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200256 cls.comp_bintools = {}
257 for name in COMP_BINTOOLS:
258 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600259
Simon Glass57454f42016-11-25 20:15:52 -0700260 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600261 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700262 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600263 if cls.preserve_indir:
264 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600265 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600266 if cls._indir:
267 shutil.rmtree(cls._indir)
268 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700269
Simon Glass1c420c92019-07-08 13:18:49 -0600270 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600271 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600272 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600273 """Accept arguments controlling test execution
274
275 Args:
276 preserve_indir: Preserve the shared input directory used by all
277 tests in this class.
278 preserve_outdir: Preserve the output directories used by tests. Each
279 test has its own, so this is normally only useful when running a
280 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600281 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600282 """
283 cls.preserve_indir = preserve_indir
284 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600285 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600286 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600287
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200288 def _CheckBintool(self, bintool):
289 if not bintool.is_present():
290 self.skipTest('%s not available' % bintool.name)
291
Simon Glass1de34482019-07-08 13:18:53 -0600292 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200293 bintool = self.comp_bintools['lz4']
294 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600295
Simon Glassee9d10d2019-07-20 12:24:09 -0600296 def _CleanupOutputDir(self):
297 """Remove the temporary output directory"""
298 if self.preserve_outdirs:
299 print('Preserving output dir: %s' % tools.outdir)
300 else:
Simon Glass80025522022-01-29 14:14:04 -0700301 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600302
Simon Glass57454f42016-11-25 20:15:52 -0700303 def setUp(self):
304 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700305 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700306 command.test_result = None
307
308 def tearDown(self):
309 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600310 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700311
Simon Glassb3d6fc72019-07-20 12:24:10 -0600312 def _SetupImageInTmpdir(self):
313 """Set up the output image in a new temporary directory
314
315 This is used when an image has been generated in the output directory,
316 but we want to run binman again. This will create a new output
317 directory and fail to delete the original one.
318
319 This creates a new temporary directory, copies the image to it (with a
320 new name) and removes the old output directory.
321
322 Returns:
323 Tuple:
324 Temporary directory to use
325 New image filename
326 """
Simon Glass80025522022-01-29 14:14:04 -0700327 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600328 tmpdir = tempfile.mkdtemp(prefix='binman.')
329 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700330 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600331 self._CleanupOutputDir()
332 return tmpdir, updated_fname
333
Simon Glass8425a1f2018-07-17 13:25:48 -0600334 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600335 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600336 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
337 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
338 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700339 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600340
Simon Glass57454f42016-11-25 20:15:52 -0700341 def _RunBinman(self, *args, **kwargs):
342 """Run binman using the command line
343
344 Args:
345 Arguments to pass, as a list of strings
346 kwargs: Arguments to pass to Command.RunPipe()
347 """
Simon Glass840be732022-01-29 14:14:05 -0700348 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700349 capture=True, capture_stderr=True, raise_on_error=False)
350 if result.return_code and kwargs.get('raise_on_error', True):
351 raise Exception("Error running '%s': %s" % (' '.join(args),
352 result.stdout + result.stderr))
353 return result
354
Simon Glassf46732a2019-07-08 14:25:29 -0600355 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700356 """Run binman using directly (in the same process)
357
358 Args:
359 Arguments to pass, as a list of strings
360 Returns:
361 Return value (0 for success)
362 """
Simon Glassf46732a2019-07-08 14:25:29 -0600363 argv = list(argv)
364 args = cmdline.ParseArgs(argv)
365 args.pager = 'binman-invalid-pager'
366 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700367
368 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600369 # args.verbosity = tout.DEBUG
370 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700371
Simon Glass91710b32018-07-17 13:25:32 -0600372 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600373 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300374 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100375 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700376 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis6b463da2023-07-22 00:14:44 +0530377 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass57454f42016-11-25 20:15:52 -0700378 """Run binman with a given test file
379
380 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600381 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600382 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600383 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600384 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600385 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600386 entry_args: Dict of entry args to supply to binman
387 key: arg name
388 value: value of that arg
389 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600390 use_real_dtb: True to use the test file as the contents of
391 the u-boot-dtb entry. Normally this is not needed and the
392 test contents (the U_BOOT_DTB_DATA string) can be used.
393 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300394 use_expanded: True to use expanded entries where available, e.g.
395 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600396 verbosity: Verbosity level to use (0-3, None=don't set it)
397 allow_missing: Set the '--allow-missing' flag so that missing
398 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100399 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600400 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600401 threads: Number of threads to use (None for default, 0 for
402 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600403 test_section_timeout: True to force the first time to timeout, as
404 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600405 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glassb553e8a2024-08-26 13:11:29 -0600406 force_missing_bintools (str): comma-separated list of bintools to
Simon Glass66152ce2022-01-09 20:14:09 -0700407 regard as missing
Simon Glassb553e8a2024-08-26 13:11:29 -0600408 ignore_missing (bool): True to return success even if there are
409 missing blobs or bintools
Andrew Davis6b463da2023-07-22 00:14:44 +0530410 output_dir: Specific output directory to use for image using -O
Simon Glass9a798402021-11-03 21:09:17 -0600411
412 Returns:
413 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700414 """
Simon Glassf46732a2019-07-08 14:25:29 -0600415 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700416 if debug:
417 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600418 if verbosity is not None:
419 args.append('-v%d' % verbosity)
420 elif self.verbosity:
421 args.append('-v%d' % self.verbosity)
422 if self.toolpath:
423 for path in self.toolpath:
424 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600425 if threads is not None:
426 args.append('-T%d' % threads)
427 if test_section_timeout:
428 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600429 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600430 if map:
431 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600432 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600433 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600434 if not use_real_dtb:
435 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300436 if not use_expanded:
437 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600438 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600439 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600440 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600441 if allow_missing:
442 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700443 if ignore_missing:
444 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100445 if allow_fake_blobs:
446 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700447 if force_missing_bintools:
448 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600449 if update_fdt_in_elf:
450 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600451 if images:
452 for image in images:
453 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600454 if extra_indirs:
455 for indir in extra_indirs:
456 args += ['-I', indir]
Andrew Davis6b463da2023-07-22 00:14:44 +0530457 if output_dir:
458 args += ['-O', output_dir]
Simon Glass075a45c2017-11-13 18:55:00 -0700459 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700460
461 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700462 """Set up a new test device-tree file
463
464 The given file is compiled and set up as the device tree to be used
465 for ths test.
466
467 Args:
468 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600469 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700470
471 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600472 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700473 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600474 tmpdir = tempfile.mkdtemp(prefix='binmant.')
475 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600476 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700477 data = fd.read()
478 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600479 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600480 return data
Simon Glass57454f42016-11-25 20:15:52 -0700481
Simon Glass56d05412022-02-28 07:16:54 -0700482 def _GetDtbContentsForSpls(self, dtb_data, name):
483 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600484
485 For testing we don't actually have different versions of the DTB. With
486 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
487 we don't normally have any unwanted nodes.
488
489 We still want the DTBs for SPL and TPL to be different though, since
490 otherwise it is confusing to know which one we are looking at. So add
491 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600492
493 Args:
494 dtb_data: dtb data to modify (this should be a value devicetree)
495 name: Name of a new property to add
496
497 Returns:
498 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600499 """
500 dtb = fdt.Fdt.FromData(dtb_data)
501 dtb.Scan()
502 dtb.GetNode('/binman').AddZeroProp(name)
503 dtb.Sync(auto_resize=True)
504 dtb.Pack()
505 return dtb.GetContents()
506
Simon Glassed930672021-03-18 20:25:05 +1300507 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
Simon Glass3eb30a42024-08-26 13:11:42 -0600508 verbosity=None, map=False, update_dtb=False,
509 entry_args=None, reset_dtbs=True, extra_indirs=None,
510 threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700511 """Run binman and return the resulting image
512
513 This runs binman with a given test file and then reads the resulting
514 output file. It is a shortcut function since most tests need to do
515 these steps.
516
517 Raises an assertion failure if binman returns a non-zero exit code.
518
519 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600520 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700521 use_real_dtb: True to use the test file as the contents of
522 the u-boot-dtb entry. Normally this is not needed and the
523 test contents (the U_BOOT_DTB_DATA string) can be used.
524 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300525 use_expanded: True to use expanded entries where available, e.g.
526 'u-boot-expanded' instead of 'u-boot'
Simon Glass3eb30a42024-08-26 13:11:42 -0600527 verbosity: Verbosity level to use (0-3, None=don't set it)
Simon Glass30732662018-06-01 09:38:20 -0600528 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600529 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600530 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600531 entry_args: Dict of entry args to supply to binman
532 key: arg name
533 value: value of that arg
534 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
535 function. If reset_dtbs is True, then the original test dtb
536 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600537 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600538 threads: Number of threads to use (None for default, 0 for
539 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700540
541 Returns:
542 Tuple:
543 Resulting image contents
544 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600545 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600546 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700547 """
Simon Glass72232452016-11-25 20:15:53 -0700548 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700549 # Use the compiled test file as the u-boot-dtb input
550 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700551 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600552
553 # For testing purposes, make a copy of the DT for SPL and TPL. Add
Simon Glassd9e01d22024-07-20 11:49:40 +0100554 # a node indicating which it is, to aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700555 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600556 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
557 outfile = os.path.join(self._indir, dtb_fname)
558 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700559 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700560
561 try:
Simon Glass91710b32018-07-17 13:25:32 -0600562 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600563 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass3eb30a42024-08-26 13:11:42 -0600564 use_expanded=use_expanded, verbosity=verbosity,
565 extra_indirs=extra_indirs,
Simon Glass76f496d2021-07-06 10:36:37 -0600566 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700567 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700568 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700569
570 # Find the (only) image, read it and return its contents
571 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700572 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600573 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600574 if map:
Simon Glass80025522022-01-29 14:14:04 -0700575 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600576 with open(map_fname) as fd:
577 map_data = fd.read()
578 else:
579 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600580 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600581 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700582 finally:
583 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600584 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600585 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700586
Simon Glass5b4bce32019-07-08 14:25:26 -0600587 def _DoReadFileRealDtb(self, fname):
588 """Run binman with a real .dtb file and return the resulting data
589
590 Args:
591 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
592
593 Returns:
594 Resulting image contents
595 """
596 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
597
Simon Glass72232452016-11-25 20:15:53 -0700598 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600599 """Helper function which discards the device-tree binary
600
601 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600602 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600603 use_real_dtb: True to use the test file as the contents of
604 the u-boot-dtb entry. Normally this is not needed and the
605 test contents (the U_BOOT_DTB_DATA string) can be used.
606 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600607
608 Returns:
609 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600610 """
Simon Glass72232452016-11-25 20:15:53 -0700611 return self._DoReadFileDtb(fname, use_real_dtb)[0]
612
Simon Glass57454f42016-11-25 20:15:52 -0700613 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600614 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700615 """Create a new test input file, creating directories as needed
616
617 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600618 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700619 contents: File contents to write in to the file
620 Returns:
621 Full pathname of file created
622 """
Simon Glass862f8e22019-08-24 07:22:43 -0600623 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700624 dirname = os.path.dirname(pathname)
625 if dirname and not os.path.exists(dirname):
626 os.makedirs(dirname)
627 with open(pathname, 'wb') as fd:
628 fd.write(contents)
629 return pathname
630
631 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600632 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600633 """Create a new test input directory, creating directories as needed
634
635 Args:
636 dirname: Directory name to create
637
638 Returns:
639 Full pathname of directory created
640 """
Simon Glass862f8e22019-08-24 07:22:43 -0600641 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600642 if not os.path.exists(pathname):
643 os.makedirs(pathname)
644 return pathname
645
646 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600647 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600648 """Set up an ELF file with a '_dt_ucode_base_size' symbol
649
650 Args:
651 Filename of ELF file to use as SPL
652 """
Simon Glass93a806f2019-08-24 07:22:59 -0600653 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700654 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600655
656 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600657 def _SetupTplElf(cls, src_fname='bss_data'):
658 """Set up an ELF file with a '_dt_ucode_base_size' symbol
659
660 Args:
661 Filename of ELF file to use as TPL
662 """
663 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700664 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600665
666 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700667 def _SetupVplElf(cls, src_fname='bss_data'):
668 """Set up an ELF file with a '_dt_ucode_base_size' symbol
669
670 Args:
671 Filename of ELF file to use as VPL
672 """
673 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
674 tools.read_file(cls.ElfTestFile(src_fname)))
675
676 @classmethod
Lukas Funkee901faf2023-07-18 13:53:13 +0200677 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
678 """Set up an ELF file with a '_dt_ucode_base_size' symbol
679
680 Args:
681 Filename of ELF file to use as VPL
682 """
683 TestFunctional._MakeInputFile('pmu-firmware.elf',
684 tools.read_file(cls.ElfTestFile(src_fname)))
685
686 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600687 def _SetupDescriptor(cls):
688 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
689 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
690
691 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600692 def TestFile(cls, fname):
693 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700694
Simon Glassf6290892019-08-24 07:22:53 -0600695 @classmethod
696 def ElfTestFile(cls, fname):
697 return os.path.join(cls._elf_testdir, fname)
698
Simon Glassad5cfe12023-01-07 14:07:14 -0700699 @classmethod
700 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
701 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
702 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
703 dummy, paged_sz) + U_BOOT_DATA
704 data += extra_data
705 TestFunctional._MakeInputFile(fname, data)
706
Simon Glass57454f42016-11-25 20:15:52 -0700707 def AssertInList(self, grep_list, target):
708 """Assert that at least one of a list of things is in a target
709
710 Args:
711 grep_list: List of strings to check
712 target: Target string
713 """
714 for grep in grep_list:
715 if grep in target:
716 return
Simon Glass848cdb52019-05-17 22:00:50 -0600717 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700718
719 def CheckNoGaps(self, entries):
720 """Check that all entries fit together without gaps
721
722 Args:
723 entries: List of entries to check
724 """
Simon Glasse8561af2018-08-01 15:22:37 -0600725 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700726 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600727 self.assertEqual(offset, entry.offset)
728 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700729
Simon Glass72232452016-11-25 20:15:53 -0700730 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600731 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700732
733 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600734 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700735
736 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600737 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700738 """
739 return struct.unpack('>L', dtb[4:8])[0]
740
Simon Glass0f621332019-07-08 14:25:27 -0600741 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600742 def AddNode(node, path):
743 if node.name != '/':
744 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600745 for prop in node.props.values():
746 if prop.name in prop_names:
747 prop_path = path + ':' + prop.name
748 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
749 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600750 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600751 AddNode(subnode, path)
752
753 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600754 AddNode(dtb.GetRoot(), '')
755 return tree
756
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000757 def _CheckSign(self, fit, key):
758 try:
759 tools.run('fit_check_sign', '-k', key, '-f', fit)
760 except:
761 self.fail('Expected signed FIT container')
762 return False
763 return True
764
Paul HENRYS5cf82892025-02-24 22:20:55 +0100765 def _CheckPreload(self, image, key, algo="sha256,rsa2048",
766 padding="pkcs-1.5"):
767 try:
768 tools.run('preload_check_sign', '-k', key, '-a', algo, '-p',
769 padding, '-f', image)
770 except:
771 self.fail('Expected image signed with a pre-load')
772 return False
773 return True
774
Simon Glass57454f42016-11-25 20:15:52 -0700775 def testRun(self):
776 """Test a basic run with valid args"""
777 result = self._RunBinman('-h')
778
779 def testFullHelp(self):
780 """Test that the full help is displayed with -H"""
781 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300782 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500783 # Remove possible extraneous strings
784 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
785 gothelp = result.stdout.replace(extra, '')
786 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700787 self.assertEqual(0, len(result.stderr))
788 self.assertEqual(0, result.return_code)
789
790 def testFullHelpInternal(self):
791 """Test that the full help is displayed with -H"""
792 try:
793 command.test_result = command.CommandResult()
794 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300795 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700796 finally:
797 command.test_result = None
798
799 def testHelp(self):
800 """Test that the basic help is displayed with -h"""
801 result = self._RunBinman('-h')
802 self.assertTrue(len(result.stdout) > 200)
803 self.assertEqual(0, len(result.stderr))
804 self.assertEqual(0, result.return_code)
805
Simon Glass57454f42016-11-25 20:15:52 -0700806 def testBoard(self):
807 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600808 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700809 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300810 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700811 self.assertEqual(0, result)
812
813 def testNeedBoard(self):
814 """Test that we get an error when no board ius supplied"""
815 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600816 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700817 self.assertIn("Must provide a board to process (use -b <board>)",
818 str(e.exception))
819
820 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600821 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700822 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600823 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700824 # We get one error from libfdt, and a different one from fdtget.
825 self.AssertInList(["Couldn't open blob from 'missing_file'",
826 'No such file or directory'], str(e.exception))
827
828 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600829 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700830
831 Since this is a source file it should be compiled and the error
832 will come from the device-tree compiler (dtc).
833 """
834 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600835 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700836 self.assertIn("FATAL ERROR: Unable to parse input tree",
837 str(e.exception))
838
839 def testMissingNode(self):
840 """Test that a device tree without a 'binman' node generates an error"""
841 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600842 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700843 self.assertIn("does not have a 'binman' node", str(e.exception))
844
845 def testEmpty(self):
846 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600847 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700848 self.assertEqual(0, len(result.stderr))
849 self.assertEqual(0, result.return_code)
850
851 def testInvalidEntry(self):
852 """Test that an invalid entry is flagged"""
853 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600854 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600855 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700856 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
857 "'/binman/not-a-valid-type'", str(e.exception))
858
859 def testSimple(self):
860 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600861 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700862 self.assertEqual(U_BOOT_DATA, data)
863
Simon Glass075a45c2017-11-13 18:55:00 -0700864 def testSimpleDebug(self):
865 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600866 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700867
Simon Glass57454f42016-11-25 20:15:52 -0700868 def testDual(self):
869 """Test that we can handle creating two images
870
871 This also tests image padding.
872 """
Simon Glass511f6582018-10-01 12:22:30 -0600873 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700874 self.assertEqual(0, retcode)
875
876 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600877 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700878 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700879 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600880 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700881 data = fd.read()
882 self.assertEqual(U_BOOT_DATA, data)
883
884 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600885 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700886 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700887 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600888 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700889 data = fd.read()
890 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700891 self.assertEqual(tools.get_bytes(0, 3), data[:3])
892 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700893
894 def testBadAlign(self):
895 """Test that an invalid alignment value is detected"""
896 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600897 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700898 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
899 "of two", str(e.exception))
900
901 def testPackSimple(self):
902 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600903 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700904 self.assertEqual(0, retcode)
905 self.assertIn('image', control.images)
906 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600907 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700908 self.assertEqual(5, len(entries))
909
910 # First u-boot
911 self.assertIn('u-boot', entries)
912 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600913 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700914 self.assertEqual(len(U_BOOT_DATA), entry.size)
915
916 # Second u-boot, aligned to 16-byte boundary
917 self.assertIn('u-boot-align', entries)
918 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600919 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700920 self.assertEqual(len(U_BOOT_DATA), entry.size)
921
922 # Third u-boot, size 23 bytes
923 self.assertIn('u-boot-size', entries)
924 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600925 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700926 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
927 self.assertEqual(23, entry.size)
928
929 # Fourth u-boot, placed immediate after the above
930 self.assertIn('u-boot-next', entries)
931 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600932 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700933 self.assertEqual(len(U_BOOT_DATA), entry.size)
934
Simon Glasse8561af2018-08-01 15:22:37 -0600935 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700936 self.assertIn('u-boot-fixed', entries)
937 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600938 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700939 self.assertEqual(len(U_BOOT_DATA), entry.size)
940
Simon Glass39dd2152019-07-08 14:25:47 -0600941 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700942
943 def testPackExtra(self):
944 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600945 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
946 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700947
Simon Glass57454f42016-11-25 20:15:52 -0700948 self.assertIn('image', control.images)
949 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600950 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600951 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700952
Samuel Hollande2574022023-01-21 17:25:16 -0600953 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700954 self.assertIn('u-boot', entries)
955 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600956 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700957 self.assertEqual(3, entry.pad_before)
958 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600959 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700960 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
961 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600962 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700963
964 # Second u-boot has an aligned size, but it has no effect
965 self.assertIn('u-boot-align-size-nop', entries)
966 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600967 self.assertEqual(pos, entry.offset)
968 self.assertEqual(len(U_BOOT_DATA), entry.size)
969 self.assertEqual(U_BOOT_DATA, entry.data)
970 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
971 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700972
973 # Third u-boot has an aligned size too
974 self.assertIn('u-boot-align-size', entries)
975 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600976 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700977 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600978 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700979 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600980 data[pos:pos + entry.size])
981 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700982
983 # Fourth u-boot has an aligned end
984 self.assertIn('u-boot-align-end', entries)
985 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600986 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700987 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600988 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700989 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600990 data[pos:pos + entry.size])
991 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700992
993 # Fifth u-boot immediately afterwards
994 self.assertIn('u-boot-align-both', entries)
995 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600996 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700997 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600998 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700999 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -06001000 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -07001001
Samuel Hollande2574022023-01-21 17:25:16 -06001002 # Sixth u-boot with both minimum size and aligned size
1003 self.assertIn('u-boot-min-size', entries)
1004 entry = entries['u-boot-min-size']
1005 self.assertEqual(128, entry.offset)
1006 self.assertEqual(32, entry.size)
1007 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
1008 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
1009 data[pos:pos + entry.size])
1010
Simon Glass57454f42016-11-25 20:15:52 -07001011 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -06001012 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001013
Simon Glassafb9caa2020-10-26 17:40:10 -06001014 dtb = fdt.Fdt(out_dtb_fname)
1015 dtb.Scan()
1016 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
1017 expected = {
1018 'image-pos': 0,
1019 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -06001020 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -06001021
1022 'u-boot:image-pos': 0,
1023 'u-boot:offset': 0,
1024 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1025
1026 'u-boot-align-size-nop:image-pos': 12,
1027 'u-boot-align-size-nop:offset': 12,
1028 'u-boot-align-size-nop:size': 4,
1029
1030 'u-boot-align-size:image-pos': 16,
1031 'u-boot-align-size:offset': 16,
1032 'u-boot-align-size:size': 32,
1033
1034 'u-boot-align-end:image-pos': 48,
1035 'u-boot-align-end:offset': 48,
1036 'u-boot-align-end:size': 16,
1037
1038 'u-boot-align-both:image-pos': 64,
1039 'u-boot-align-both:offset': 64,
1040 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -06001041
1042 'u-boot-min-size:image-pos': 128,
1043 'u-boot-min-size:offset': 128,
1044 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -06001045 }
1046 self.assertEqual(expected, props)
1047
Simon Glass57454f42016-11-25 20:15:52 -07001048 def testPackAlignPowerOf2(self):
1049 """Test that invalid entry alignment is detected"""
1050 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001051 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001052 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1053 "of two", str(e.exception))
1054
1055 def testPackAlignSizePowerOf2(self):
1056 """Test that invalid entry size alignment is detected"""
1057 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001058 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001059 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1060 "power of two", str(e.exception))
1061
1062 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001063 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001064 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001065 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001066 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001067 "align 0x4 (4)", str(e.exception))
1068
1069 def testPackInvalidSizeAlign(self):
1070 """Test that invalid entry size alignment is detected"""
1071 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001072 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001073 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1074 "align-size 0x4 (4)", str(e.exception))
1075
1076 def testPackOverlap(self):
1077 """Test that overlapping regions are detected"""
1078 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001079 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001080 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001081 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1082 str(e.exception))
1083
1084 def testPackEntryOverflow(self):
1085 """Test that entries that overflow their size are detected"""
1086 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001087 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001088 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1089 "but entry size is 0x3 (3)", str(e.exception))
1090
1091 def testPackImageOverflow(self):
1092 """Test that entries which overflow the image size are detected"""
1093 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001094 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001095 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001096 "size 0x3 (3)", str(e.exception))
1097
1098 def testPackImageSize(self):
1099 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001100 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001101 self.assertEqual(0, retcode)
1102 self.assertIn('image', control.images)
1103 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001104 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001105
1106 def testPackImageSizeAlign(self):
1107 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001108 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001109 self.assertEqual(0, retcode)
1110 self.assertIn('image', control.images)
1111 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001112 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001113
1114 def testPackInvalidImageAlign(self):
1115 """Test that invalid image alignment is detected"""
1116 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001117 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001118 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001119 "align-size 0x8 (8)", str(e.exception))
1120
Simon Glass2a0fa982022-02-11 13:23:21 -07001121 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001122 """Test that invalid image alignment is detected"""
1123 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001124 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001125 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001126 "two", str(e.exception))
1127
1128 def testImagePadByte(self):
1129 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001130 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001131 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001132 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001133 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001134
1135 def testImageName(self):
1136 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001137 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001138 self.assertEqual(0, retcode)
1139 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001140 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001141 self.assertTrue(os.path.exists(fname))
1142
1143 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001144 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001145 self.assertTrue(os.path.exists(fname))
1146
1147 def testBlobFilename(self):
1148 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001149 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001150 self.assertEqual(BLOB_DATA, data)
1151
1152 def testPackSorted(self):
1153 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001154 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001155 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001156 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1157 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001158
Simon Glasse8561af2018-08-01 15:22:37 -06001159 def testPackZeroOffset(self):
1160 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001161 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001162 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001163 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001164 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001165 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1166 str(e.exception))
1167
1168 def testPackUbootDtb(self):
1169 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001170 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001171 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001172
1173 def testPackX86RomNoSize(self):
1174 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001175 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001176 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001177 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001178 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001179 "using end-at-4gb", str(e.exception))
1180
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301181 def test4gbAndSkipAtStartTogether(self):
1182 """Test that the end-at-4gb and skip-at-size property can't be used
1183 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001184 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301185 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001186 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001187 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301188 "'skip-at-start'", str(e.exception))
1189
Simon Glass72232452016-11-25 20:15:53 -07001190 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001191 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001192 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001193 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001194 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001195 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1196 "is outside the section '/binman' starting at "
1197 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001198 str(e.exception))
1199
1200 def testPackX86Rom(self):
1201 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001202 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001203 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001204 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1205 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001206
1207 def testPackX86RomMeNoDesc(self):
1208 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001209 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001210 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001211 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001212 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001213 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1214 str(e.exception))
1215 finally:
1216 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001217
1218 def testPackX86RomBadDesc(self):
1219 """Test that the Intel requires a descriptor entry"""
1220 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001221 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001222 self.assertIn("Node '/binman/intel-me': No offset set with "
1223 "offset-unset: should another entry provide this correct "
1224 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001225
1226 def testPackX86RomMe(self):
1227 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001228 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001229 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001230 if data[:0x1000] != expected_desc:
1231 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001232 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1233
1234 def testPackVga(self):
1235 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001236 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001237 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1238
1239 def testPackStart16(self):
1240 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001241 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001242 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1243
Jagdish Gediya311d4842018-09-03 21:35:08 +05301244 def testPackPowerpcMpc85xxBootpgResetvec(self):
1245 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1246 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001247 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301248 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1249
Simon Glass6ba679c2018-07-06 10:27:17 -06001250 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001251 """Handle running a test for insertion of microcode
1252
1253 Args:
1254 dts_fname: Name of test .dts file
1255 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001256 ucode_second: True if the microsecond entry is second instead of
1257 third
Simon Glass820af1d2018-07-06 10:27:16 -06001258
1259 Returns:
1260 Tuple:
1261 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001262 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001263 in the above (two 4-byte words)
1264 """
Simon Glass3d274232017-11-12 21:52:27 -07001265 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001266
1267 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001268 if ucode_second:
1269 ucode_content = data[len(nodtb_data):]
1270 ucode_pos = len(nodtb_data)
1271 dtb_with_ucode = ucode_content[16:]
1272 fdt_len = self.GetFdtLen(dtb_with_ucode)
1273 else:
1274 dtb_with_ucode = data[len(nodtb_data):]
1275 fdt_len = self.GetFdtLen(dtb_with_ucode)
1276 ucode_content = dtb_with_ucode[fdt_len:]
1277 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001278 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001279 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001280 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001281 dtb = fdt.FdtScan(fname)
1282 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001283 self.assertTrue(ucode)
1284 for node in ucode.subnodes:
1285 self.assertFalse(node.props.get('data'))
1286
Simon Glass72232452016-11-25 20:15:53 -07001287 # Check that the microcode appears immediately after the Fdt
1288 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001289 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001290 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1291 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001292 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001293
1294 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001295 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001296 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1297 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001298 u_boot = data[:len(nodtb_data)]
1299 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001300
1301 def testPackUbootMicrocode(self):
1302 """Test that x86 microcode can be handled correctly
1303
1304 We expect to see the following in the image, in order:
1305 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1306 place
1307 u-boot.dtb with the microcode removed
1308 the microcode
1309 """
Simon Glass511f6582018-10-01 12:22:30 -06001310 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001311 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001312 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1313 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001314
Simon Glassbac25c82017-05-27 07:38:26 -06001315 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001316 """Test that x86 microcode can be handled correctly
1317
1318 We expect to see the following in the image, in order:
1319 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1320 place
1321 u-boot.dtb with the microcode
1322 an empty microcode region
1323 """
1324 # We need the libfdt library to run this test since only that allows
1325 # finding the offset of a property. This is required by
1326 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001327 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001328
1329 second = data[len(U_BOOT_NODTB_DATA):]
1330
1331 fdt_len = self.GetFdtLen(second)
1332 third = second[fdt_len:]
1333 second = second[:fdt_len]
1334
Simon Glassbac25c82017-05-27 07:38:26 -06001335 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1336 self.assertIn(ucode_data, second)
1337 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001338
Simon Glassbac25c82017-05-27 07:38:26 -06001339 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001340 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001341 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1342 len(ucode_data))
1343 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001344 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1345 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001346
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001347 def testPackUbootSingleMicrocode(self):
1348 """Test that x86 microcode can be handled correctly with fdt_normal.
1349 """
Simon Glassbac25c82017-05-27 07:38:26 -06001350 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001351
Simon Glass996021e2016-11-25 20:15:54 -07001352 def testUBootImg(self):
1353 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001354 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001355 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001356
1357 def testNoMicrocode(self):
1358 """Test that a missing microcode region is detected"""
1359 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001360 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001361 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1362 "node found in ", str(e.exception))
1363
1364 def testMicrocodeWithoutNode(self):
1365 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1366 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001367 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001368 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1369 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1370
1371 def testMicrocodeWithoutNode2(self):
1372 """Test that a missing u-boot-ucode node is detected"""
1373 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001374 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001375 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1376 "microcode region u-boot-ucode", str(e.exception))
1377
1378 def testMicrocodeWithoutPtrInElf(self):
1379 """Test that a U-Boot binary without the microcode symbol is detected"""
1380 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001381 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001382 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001383 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001384
1385 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001386 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001387 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1388 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1389
1390 finally:
1391 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001392 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001393 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001394
1395 def testMicrocodeNotInImage(self):
1396 """Test that microcode must be placed within the image"""
1397 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001398 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001399 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1400 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001401 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001402
1403 def testWithoutMicrocode(self):
1404 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001405 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001406 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001407 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001408
1409 # Now check the device tree has no microcode
1410 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1411 second = data[len(U_BOOT_NODTB_DATA):]
1412
1413 fdt_len = self.GetFdtLen(second)
1414 self.assertEqual(dtb, second[:fdt_len])
1415
1416 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1417 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001418 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001419
1420 def testUnknownPosSize(self):
1421 """Test that microcode must be placed within the image"""
1422 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001423 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001424 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001425 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001426
1427 def testPackFsp(self):
1428 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001429 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001430 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1431
1432 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001433 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001434 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001435 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001436
1437 def testPackVbt(self):
1438 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001439 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001440 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001441
Simon Glass7f94e832017-11-12 21:52:25 -07001442 def testSplBssPad(self):
1443 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001444 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001445 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001446 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001447 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001448 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001449
Simon Glass04cda032018-10-01 21:12:42 -06001450 def testSplBssPadMissing(self):
1451 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001452 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001453 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001454 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001455 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1456 str(e.exception))
1457
Simon Glasse83679d2017-11-12 21:52:26 -07001458 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001459 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001460 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001461 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1462
Simon Glass6ba679c2018-07-06 10:27:17 -06001463 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1464 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001465
1466 We expect to see the following in the image, in order:
1467 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1468 correct place
1469 u-boot.dtb with the microcode removed
1470 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001471
1472 Args:
1473 dts: Device tree file to use for test
1474 ucode_second: True if the microsecond entry is second instead of
1475 third
Simon Glass3d274232017-11-12 21:52:27 -07001476 """
Simon Glass7057d022018-10-01 21:12:47 -06001477 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001478 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1479 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001480 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1481 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001482
Simon Glass6ba679c2018-07-06 10:27:17 -06001483 def testPackUbootSplMicrocode(self):
1484 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001485 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001486 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001487
1488 def testPackUbootSplMicrocodeReorder(self):
1489 """Test that order doesn't matter for microcode entries
1490
1491 This is the same as testPackUbootSplMicrocode but when we process the
1492 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1493 entry, so we reply on binman to try later.
1494 """
Simon Glass511f6582018-10-01 12:22:30 -06001495 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001496 ucode_second=True)
1497
Simon Glassa409c932017-11-12 21:52:28 -07001498 def testPackMrc(self):
1499 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001500 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001501 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1502
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001503 def testSplDtb(self):
1504 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001505 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001506 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001507 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1508
Simon Glass0a6da312017-11-13 18:54:56 -07001509 def testSplNoDtb(self):
1510 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001511 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001512 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001513 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1514
Simon Glass7098b7f2021-03-21 18:24:30 +13001515 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4b0f4142024-08-26 13:11:40 -06001516 use_expanded=False, no_write_symbols=False,
1517 symbols_base=None):
Simon Glass31e04cb2021-03-18 20:24:56 +13001518 """Check the image contains the expected symbol values
1519
1520 Args:
1521 dts: Device tree file to use for test
1522 base_data: Data before and after 'u-boot' section
Simon Glass3eb30a42024-08-26 13:11:42 -06001523 u_boot_offset (int): Offset of 'u-boot' section in image, or None if
1524 the offset not available due to it being in a compressed section
Simon Glass7098b7f2021-03-21 18:24:30 +13001525 entry_args: Dict of entry args to supply to binman
1526 key: arg name
1527 value: value of that arg
1528 use_expanded: True to use expanded entries where available, e.g.
1529 'u-boot-expanded' instead of 'u-boot'
Simon Glass4b0f4142024-08-26 13:11:40 -06001530 symbols_base (int): Value to expect for symbols-base in u-boot-spl,
1531 None if none
Simon Glass31e04cb2021-03-18 20:24:56 +13001532 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001533 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001534 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1535 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001536 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001537 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001538 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001539
Simon Glass7057d022018-10-01 21:12:47 -06001540 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001541 data = self._DoReadFileDtb(dts, entry_args=entry_args,
Simon Glass3eb30a42024-08-26 13:11:42 -06001542 use_expanded=use_expanded,
1543 verbosity=None if u_boot_offset else 3)[0]
1544
1545 # The lz4-compressed version of the U-Boot data is 19 bytes long
1546 comp_uboot_len = 19
1547
Simon Glass31e04cb2021-03-18 20:24:56 +13001548 # The image should contain the symbols from u_boot_binman_syms.c
1549 # Note that image_pos is adjusted by the base address of the image,
1550 # which is 0x10 in our test image
Simon Glass3eb30a42024-08-26 13:11:42 -06001551 # If u_boot_offset is None, Binman should write -1U into the image
Simon Glass4b0f4142024-08-26 13:11:40 -06001552 vals2 = (elf.BINMAN_SYM_MAGIC_VALUE, 0x00,
Simon Glass3eb30a42024-08-26 13:11:42 -06001553 u_boot_offset + len(U_BOOT_DATA) if u_boot_offset else
1554 len(U_BOOT_SPL_DATA) + 1 + comp_uboot_len,
1555 0x10 + u_boot_offset if u_boot_offset else 0xffffffff, 0x04)
Simon Glass4b0f4142024-08-26 13:11:40 -06001556
1557 # u-boot-spl has a symbols-base property, so take that into account if
1558 # required. The caller must supply the value
1559 vals = list(vals2)
1560 if symbols_base is not None:
1561 vals[3] = symbols_base + u_boot_offset
1562 vals = tuple(vals)
1563
Simon Glass4b4049e2024-08-26 13:11:39 -06001564 sym_values = struct.pack('<LLQLL', *vals)
Simon Glass4b0f4142024-08-26 13:11:40 -06001565 sym_values2 = struct.pack('<LLQLL', *vals2)
Simon Glass4abf7842023-07-18 07:23:54 -06001566 if no_write_symbols:
Simon Glass4b4049e2024-08-26 13:11:39 -06001567 self.assertEqual(
1568 base_data +
1569 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1570 U_BOOT_DATA + base_data, data)
Simon Glass4abf7842023-07-18 07:23:54 -06001571 else:
Simon Glass4b4049e2024-08-26 13:11:39 -06001572 got_vals = struct.unpack('<LLQLL', data[:24])
1573
1574 # For debugging:
1575 #print('expect:', list(f'{v:x}' for v in vals))
1576 #print(' got:', list(f'{v:x}' for v in got_vals))
1577
1578 self.assertEqual(vals, got_vals)
1579 self.assertEqual(sym_values, data[:24])
1580
1581 blen = len(base_data)
1582 self.assertEqual(base_data[24:], data[24:blen])
1583 self.assertEqual(0xff, data[blen])
1584
Simon Glass3eb30a42024-08-26 13:11:42 -06001585 if u_boot_offset:
1586 ofs = blen + 1 + len(U_BOOT_DATA)
1587 self.assertEqual(U_BOOT_DATA, data[blen + 1:ofs])
1588 else:
1589 ofs = blen + 1 + comp_uboot_len
Simon Glass4b4049e2024-08-26 13:11:39 -06001590
Simon Glass4b0f4142024-08-26 13:11:40 -06001591 self.assertEqual(sym_values2, data[ofs:ofs + 24])
Simon Glass4b4049e2024-08-26 13:11:39 -06001592 self.assertEqual(base_data[24:], data[ofs + 24:])
1593
1594 # Just repeating the above asserts all at once, for clarity
Simon Glass3eb30a42024-08-26 13:11:42 -06001595 if u_boot_offset:
1596 expected = (sym_values + base_data[24:] +
1597 tools.get_bytes(0xff, 1) + U_BOOT_DATA +
1598 sym_values2 + base_data[24:])
1599 self.assertEqual(expected, data)
Simon Glass4ca8e042017-11-13 18:55:01 -07001600
Simon Glass31e04cb2021-03-18 20:24:56 +13001601 def testSymbols(self):
1602 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001603 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001604
1605 def testSymbolsNoDtb(self):
1606 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001607 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001608 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1609 0x38)
1610
Simon Glasse76a3e62018-06-01 09:38:11 -06001611 def testPackUnitAddress(self):
1612 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001613 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001614 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1615
Simon Glassa91e1152018-06-01 09:38:16 -06001616 def testSections(self):
1617 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001618 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001619 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1620 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1621 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001622 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001623
Simon Glass30732662018-06-01 09:38:20 -06001624 def testMap(self):
1625 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001626 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001627 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700162800000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600162900000000 00000000 00000010 section@0
163000000000 00000000 00000004 u-boot
163100000010 00000010 00000010 section@1
163200000010 00000000 00000004 u-boot
163300000020 00000020 00000004 section@2
163400000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001635''', map_data)
1636
Simon Glass3b78d532018-06-01 09:38:21 -06001637 def testNamePrefix(self):
1638 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001639 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001640 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700164100000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600164200000000 00000000 00000010 section@0
164300000000 00000000 00000004 ro-u-boot
164400000010 00000010 00000010 section@1
164500000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001646''', map_data)
1647
Simon Glass6ba679c2018-07-06 10:27:17 -06001648 def testUnknownContents(self):
1649 """Test that obtaining the contents works as expected"""
1650 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001651 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001652 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001653 "processing of contents: remaining ["
1654 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001655
Simon Glass2e1169f2018-07-06 10:27:19 -06001656 def testBadChangeSize(self):
1657 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001658 try:
1659 state.SetAllowEntryExpansion(False)
1660 with self.assertRaises(ValueError) as e:
1661 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001662 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001663 str(e.exception))
1664 finally:
1665 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001666
Simon Glassa87014e2018-07-06 10:27:42 -06001667 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001668 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001669 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001670 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001671 dtb = fdt.Fdt(out_dtb_fname)
1672 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001673 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001674 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001675 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001676 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001677 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001678 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001679 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001680 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001681 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001682 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001683 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001684 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001685 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001686
Simon Glasse8561af2018-08-01 15:22:37 -06001687 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001688 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001689 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001690 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001691 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001692 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001693 'size': 40
1694 }, props)
1695
1696 def testUpdateFdtBad(self):
1697 """Test that we detect when ProcessFdt never completes"""
1698 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001699 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001700 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001701 '[<binman.etype._testing.Entry__testing',
1702 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001703
Simon Glass91710b32018-07-17 13:25:32 -06001704 def testEntryArgs(self):
1705 """Test passing arguments to entries from the command line"""
1706 entry_args = {
1707 'test-str-arg': 'test1',
1708 'test-int-arg': '456',
1709 }
Simon Glass511f6582018-10-01 12:22:30 -06001710 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001711 self.assertIn('image', control.images)
1712 entry = control.images['image'].GetEntries()['_testing']
1713 self.assertEqual('test0', entry.test_str_fdt)
1714 self.assertEqual('test1', entry.test_str_arg)
1715 self.assertEqual(123, entry.test_int_fdt)
1716 self.assertEqual(456, entry.test_int_arg)
1717
1718 def testEntryArgsMissing(self):
1719 """Test missing arguments and properties"""
1720 entry_args = {
1721 'test-int-arg': '456',
1722 }
Simon Glass511f6582018-10-01 12:22:30 -06001723 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001724 entry = control.images['image'].GetEntries()['_testing']
1725 self.assertEqual('test0', entry.test_str_fdt)
1726 self.assertEqual(None, entry.test_str_arg)
1727 self.assertEqual(None, entry.test_int_fdt)
1728 self.assertEqual(456, entry.test_int_arg)
1729
1730 def testEntryArgsRequired(self):
1731 """Test missing arguments and properties"""
1732 entry_args = {
1733 'test-int-arg': '456',
1734 }
1735 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001736 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001737 self.assertIn("Node '/binman/_testing': "
1738 'Missing required properties/entry args: test-str-arg, '
1739 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001740 str(e.exception))
1741
1742 def testEntryArgsInvalidFormat(self):
1743 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001744 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1745 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001746 with self.assertRaises(ValueError) as e:
1747 self._DoBinman(*args)
1748 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1749
1750 def testEntryArgsInvalidInteger(self):
1751 """Test that an invalid entry-argument integer is detected"""
1752 entry_args = {
1753 'test-int-arg': 'abc',
1754 }
1755 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001756 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001757 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1758 "'test-int-arg' (value 'abc') to integer",
1759 str(e.exception))
1760
1761 def testEntryArgsInvalidDatatype(self):
1762 """Test that an invalid entry-argument datatype is detected
1763
1764 This test could be written in entry_test.py except that it needs
1765 access to control.entry_args, which seems more than that module should
1766 be able to see.
1767 """
1768 entry_args = {
1769 'test-bad-datatype-arg': '12',
1770 }
1771 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001772 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001773 entry_args=entry_args)
1774 self.assertIn('GetArg() internal error: Unknown data type ',
1775 str(e.exception))
1776
Simon Glass2ca52032018-07-17 13:25:33 -06001777 def testText(self):
1778 """Test for a text entry type"""
1779 entry_args = {
1780 'test-id': TEXT_DATA,
1781 'test-id2': TEXT_DATA2,
1782 'test-id3': TEXT_DATA3,
1783 }
Simon Glass511f6582018-10-01 12:22:30 -06001784 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001785 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001786 expected = (tools.to_bytes(TEXT_DATA) +
1787 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1788 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001789 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001790 self.assertEqual(expected, data)
1791
Simon Glass969616c2018-07-17 13:25:36 -06001792 def testEntryDocs(self):
1793 """Test for creation of entry documentation"""
1794 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001795 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001796 self.assertTrue(len(stdout.getvalue()) > 0)
1797
1798 def testEntryDocsMissing(self):
1799 """Test handling of missing entry documentation"""
1800 with self.assertRaises(ValueError) as e:
1801 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001802 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001803 self.assertIn('Documentation is missing for modules: u_boot',
1804 str(e.exception))
1805
Simon Glass704784b2018-07-17 13:25:38 -06001806 def testFmap(self):
1807 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001808 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001809 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001810 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1811 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001812 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001813 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001814 self.assertEqual(1, fhdr.ver_major)
1815 self.assertEqual(0, fhdr.ver_minor)
1816 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001817 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001818 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001819 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001820 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001821 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001822
Simon Glass82059c22021-04-03 11:05:09 +13001823 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001824 self.assertEqual(b'SECTION0', fentry.name)
1825 self.assertEqual(0, fentry.offset)
1826 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001827 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001828
1829 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001830 self.assertEqual(b'RO_U_BOOT', fentry.name)
1831 self.assertEqual(0, fentry.offset)
1832 self.assertEqual(4, fentry.size)
1833 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001834
Simon Glass82059c22021-04-03 11:05:09 +13001835 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001836 self.assertEqual(b'SECTION1', fentry.name)
1837 self.assertEqual(16, fentry.offset)
1838 self.assertEqual(16, fentry.size)
1839 self.assertEqual(0, fentry.flags)
1840
1841 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001842 self.assertEqual(b'RW_U_BOOT', fentry.name)
1843 self.assertEqual(16, fentry.offset)
1844 self.assertEqual(4, fentry.size)
1845 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001846
Simon Glass82059c22021-04-03 11:05:09 +13001847 fentry = next(fiter)
1848 self.assertEqual(b'FMAP', fentry.name)
1849 self.assertEqual(32, fentry.offset)
1850 self.assertEqual(expect_size, fentry.size)
1851 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001852
Simon Glassdb168d42018-07-17 13:25:39 -06001853 def testBlobNamedByArg(self):
1854 """Test we can add a blob with the filename coming from an entry arg"""
1855 entry_args = {
1856 'cros-ec-rw-path': 'ecrw.bin',
1857 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001858 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001859
Simon Glass53f53992018-07-17 13:25:40 -06001860 def testFill(self):
1861 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001862 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001863 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001864 self.assertEqual(expected, data)
1865
1866 def testFillNoSize(self):
1867 """Test for an fill entry type with no size"""
1868 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001869 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001870 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001871 str(e.exception))
1872
Simon Glassc1ae83c2018-07-17 13:25:44 -06001873 def _HandleGbbCommand(self, pipe_list):
1874 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001875 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001876 fname = pipe_list[0][-1]
1877 # Append our GBB data to the file, which will happen every time the
1878 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001879 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001880 fd.write(GBB_DATA)
1881 return command.CommandResult()
1882
1883 def testGbb(self):
1884 """Test for the Chromium OS Google Binary Block"""
1885 command.test_result = self._HandleGbbCommand
1886 entry_args = {
1887 'keydir': 'devkeys',
1888 'bmpblk': 'bmpblk.bin',
1889 }
Simon Glass511f6582018-10-01 12:22:30 -06001890 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001891
1892 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001893 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1894 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001895 self.assertEqual(expected, data)
1896
1897 def testGbbTooSmall(self):
1898 """Test for the Chromium OS Google Binary Block being large enough"""
1899 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001900 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001901 self.assertIn("Node '/binman/gbb': GBB is too small",
1902 str(e.exception))
1903
1904 def testGbbNoSize(self):
1905 """Test for the Chromium OS Google Binary Block having a size"""
1906 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001907 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001908 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1909 str(e.exception))
1910
Simon Glass66152ce2022-01-09 20:14:09 -07001911 def testGbbMissing(self):
1912 """Test that binman still produces an image if futility is missing"""
1913 entry_args = {
1914 'keydir': 'devkeys',
1915 }
1916 with test_util.capture_sys_output() as (_, stderr):
1917 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1918 entry_args=entry_args)
1919 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001920 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001921
Simon Glass5c350162018-07-17 13:25:47 -06001922 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001923 """Fake calls to the futility utility
1924
1925 The expected pipe is:
1926
1927 [('futility', 'vbutil_firmware', '--vblock',
1928 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1929 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1930 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1931 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1932
1933 This writes to the output file (here, 'vblock.vblock'). If
1934 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1935 of the input data (here, 'input.vblock').
1936 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001937 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001938 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001939 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001940 if self._hash_data:
1941 infile = pipe_list[0][11]
1942 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001943 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001944 m.update(data)
1945 fd.write(m.digest())
1946 else:
1947 fd.write(VBLOCK_DATA)
1948
Simon Glass5c350162018-07-17 13:25:47 -06001949 return command.CommandResult()
1950
1951 def testVblock(self):
1952 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001953 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001954 command.test_result = self._HandleVblockCommand
1955 entry_args = {
1956 'keydir': 'devkeys',
1957 }
Simon Glass511f6582018-10-01 12:22:30 -06001958 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001959 entry_args=entry_args)
1960 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1961 self.assertEqual(expected, data)
1962
1963 def testVblockNoContent(self):
1964 """Test we detect a vblock which has no content to sign"""
1965 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001966 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001967 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001968 'property', str(e.exception))
1969
1970 def testVblockBadPhandle(self):
1971 """Test that we detect a vblock with an invalid phandle in contents"""
1972 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001973 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001974 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1975 '1000', str(e.exception))
1976
1977 def testVblockBadEntry(self):
1978 """Test that we detect an entry that points to a non-entry"""
1979 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001980 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001981 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1982 "'other'", str(e.exception))
1983
Simon Glass220c6222021-01-06 21:35:17 -07001984 def testVblockContent(self):
1985 """Test that the vblock signs the right data"""
1986 self._hash_data = True
1987 command.test_result = self._HandleVblockCommand
1988 entry_args = {
1989 'keydir': 'devkeys',
1990 }
1991 data = self._DoReadFileDtb(
1992 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1993 entry_args=entry_args)[0]
1994 hashlen = 32 # SHA256 hash is 32 bytes
1995 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1996 hashval = data[-hashlen:]
1997 dtb = data[len(U_BOOT_DATA):-hashlen]
1998
1999 expected_data = U_BOOT_DATA + dtb
2000
2001 # The hashval should be a hash of the dtb
2002 m = hashlib.sha256()
2003 m.update(expected_data)
2004 expected_hashval = m.digest()
2005 self.assertEqual(expected_hashval, hashval)
2006
Simon Glass66152ce2022-01-09 20:14:09 -07002007 def testVblockMissing(self):
2008 """Test that binman still produces an image if futility is missing"""
2009 entry_args = {
2010 'keydir': 'devkeys',
2011 }
2012 with test_util.capture_sys_output() as (_, stderr):
2013 self._DoTestFile('074_vblock.dts',
2014 force_missing_bintools='futility',
2015 entry_args=entry_args)
2016 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07002017 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07002018
Simon Glass8425a1f2018-07-17 13:25:48 -06002019 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06002020 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06002021 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06002022 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06002023 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06002024 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
2025
Simon Glass24b97442018-07-17 13:25:51 -06002026 def testUsesPos(self):
2027 """Test that the 'pos' property cannot be used anymore"""
2028 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002029 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06002030 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
2031 "'pos'", str(e.exception))
2032
Simon Glass274bf092018-09-14 04:57:08 -06002033 def testFillZero(self):
2034 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06002035 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07002036 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06002037
Simon Glass267de432018-09-14 04:57:09 -06002038 def testTextMissing(self):
2039 """Test for a text entry type where there is no text"""
2040 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002041 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06002042 self.assertIn("Node '/binman/text': No value provided for text label "
2043 "'test-id'", str(e.exception))
2044
Simon Glassed40e962018-09-14 04:57:10 -06002045 def testPackStart16Tpl(self):
2046 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06002047 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06002048 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
2049
Simon Glass3b376c32018-09-14 04:57:12 -06002050 def testSelectImage(self):
2051 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06002052 expected = 'Skipping images: image1'
2053
2054 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06002055 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06002056 with test_util.capture_sys_output() as (stdout, stderr):
2057 retcode = self._DoTestFile('006_dual_image.dts',
2058 verbosity=verbosity,
2059 images=['image2'])
2060 self.assertEqual(0, retcode)
2061 if verbosity:
2062 self.assertIn(expected, stdout.getvalue())
2063 else:
2064 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06002065
Simon Glass80025522022-01-29 14:14:04 -07002066 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2067 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06002068 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06002069
Simon Glasse219aa42018-09-14 04:57:24 -06002070 def testUpdateFdtAll(self):
2071 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06002072 self._SetupSplElf()
2073 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06002074 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06002075
2076 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06002077 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002078 'image-pos': 0,
2079 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06002080 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002081 'section:image-pos': 0,
2082 'section:size': 565,
2083 'section/u-boot-dtb:offset': 0,
2084 'section/u-boot-dtb:image-pos': 0,
2085 'section/u-boot-dtb:size': 565,
2086 'u-boot-spl-dtb:offset': 565,
2087 'u-boot-spl-dtb:image-pos': 565,
2088 'u-boot-spl-dtb:size': 585,
2089 'u-boot-tpl-dtb:offset': 1150,
2090 'u-boot-tpl-dtb:image-pos': 1150,
2091 'u-boot-tpl-dtb:size': 585,
2092 'u-boot-vpl-dtb:image-pos': 1735,
2093 'u-boot-vpl-dtb:offset': 1735,
2094 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002095 }
2096
2097 # We expect three device-tree files in the output, one after the other.
2098 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2099 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2100 # main U-Boot tree. All three should have the same postions and offset.
2101 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002102 self.maxDiff = None
2103 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002104 dtb = fdt.Fdt.FromData(data[start:])
2105 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002106 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002107 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002108 expected = dict(base_expected)
2109 if item:
2110 expected[item] = 0
2111 self.assertEqual(expected, props)
2112 start += dtb._fdt_obj.totalsize()
2113
2114 def testUpdateFdtOutput(self):
2115 """Test that output DTB files are updated"""
2116 try:
Simon Glass511f6582018-10-01 12:22:30 -06002117 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002118 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2119
2120 # Unfortunately, compiling a source file always results in a file
2121 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002122 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002123 # binman as a file called u-boot.dtb. To fix this, copy the file
2124 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002125 start = 0
2126 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002127 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002128 dtb = fdt.Fdt.FromData(data[start:])
2129 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002130 pathname = tools.get_output_filename(os.path.split(fname)[1])
2131 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002132 name = os.path.split(fname)[0]
2133
2134 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002135 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002136 else:
2137 orig_indata = dtb_data
2138 self.assertNotEqual(outdata, orig_indata,
2139 "Expected output file '%s' be updated" % pathname)
2140 self.assertEqual(outdata, data[start:start + size],
2141 "Expected output file '%s' to match output image" %
2142 pathname)
2143 start += size
2144 finally:
2145 self._ResetDtbs()
2146
Simon Glass7ba33592018-09-14 04:57:26 -06002147 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002148 bintool = self.comp_bintools['lz4']
2149 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002150
2151 def testCompress(self):
2152 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002153 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002154 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002155 use_real_dtb=True, update_dtb=True)
2156 dtb = fdt.Fdt(out_dtb_fname)
2157 dtb.Scan()
2158 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2159 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00002160 self.assertEqual(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002161
2162 # Do a sanity check on various fields
2163 image = control.images['image']
2164 entries = image.GetEntries()
2165 self.assertEqual(1, len(entries))
2166
2167 entry = entries['blob']
2168 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2169 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2170 orig = self._decompress(entry.data)
2171 self.assertEqual(orig, entry.uncomp_data)
2172
Simon Glass72eeff12020-10-26 17:40:16 -06002173 self.assertEqual(image.data, entry.data)
2174
Simon Glass7ba33592018-09-14 04:57:26 -06002175 expected = {
2176 'blob:uncomp-size': len(COMPRESS_DATA),
2177 'blob:size': len(data),
2178 'size': len(data),
2179 }
2180 self.assertEqual(expected, props)
2181
Simon Glassac6328c2018-09-14 04:57:28 -06002182 def testFiles(self):
2183 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002184 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002185 self.assertEqual(FILES_DATA, data)
2186
2187 def testFilesCompress(self):
2188 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002189 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002190 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002191
2192 image = control.images['image']
2193 entries = image.GetEntries()
2194 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002195 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002196
Simon Glass303f62f2019-05-17 22:00:46 -06002197 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002198 for i in range(1, 3):
2199 key = '%d.dat' % i
2200 start = entries[key].image_pos
2201 len = entries[key].size
2202 chunk = data[start:start + len]
2203 orig += self._decompress(chunk)
2204
2205 self.assertEqual(FILES_DATA, orig)
2206
2207 def testFilesMissing(self):
2208 """Test missing files"""
2209 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002210 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002211 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2212 'no files', str(e.exception))
2213
2214 def testFilesNoPattern(self):
2215 """Test missing files"""
2216 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002217 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002218 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2219 str(e.exception))
2220
Simon Glassdd156a42022-03-05 20:18:59 -07002221 def testExtendSize(self):
2222 """Test an extending entry"""
2223 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002224 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002225 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2226 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2227 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2228 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002229 self.assertEqual(expect, data)
2230 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700223100000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600223200000000 00000000 00000008 fill
223300000008 00000008 00000004 u-boot
22340000000c 0000000c 00000004 section
22350000000c 00000000 00000003 intel-mrc
223600000010 00000010 00000004 u-boot2
223700000014 00000014 0000000c section2
223800000014 00000000 00000008 fill
22390000001c 00000008 00000004 u-boot
224000000020 00000020 00000008 fill2
2241''', map_data)
2242
Simon Glassdd156a42022-03-05 20:18:59 -07002243 def testExtendSizeBad(self):
2244 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002245 with test_util.capture_sys_output() as (stdout, stderr):
2246 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002247 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002248 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2249 'expanding entry', str(e.exception))
2250
Simon Glassae7cf032018-09-14 04:57:31 -06002251 def testHash(self):
2252 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002253 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002254 use_real_dtb=True, update_dtb=True)
2255 dtb = fdt.Fdt(out_dtb_fname)
2256 dtb.Scan()
2257 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2258 m = hashlib.sha256()
2259 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002260 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002261
2262 def testHashNoAlgo(self):
2263 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002264 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002265 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2266 'hash node', str(e.exception))
2267
2268 def testHashBadAlgo(self):
2269 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002270 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002271 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002272 str(e.exception))
2273
2274 def testHashSection(self):
2275 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002276 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002277 use_real_dtb=True, update_dtb=True)
2278 dtb = fdt.Fdt(out_dtb_fname)
2279 dtb.Scan()
2280 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2281 m = hashlib.sha256()
2282 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002283 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002284 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002285
Simon Glass3fb4f422018-09-14 04:57:32 -06002286 def testPackUBootTplMicrocode(self):
2287 """Test that x86 microcode can be handled correctly in TPL
2288
2289 We expect to see the following in the image, in order:
2290 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2291 place
2292 u-boot-tpl.dtb with the microcode removed
2293 the microcode
2294 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002295 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002296 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002297 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002298 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2299 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002300
Simon Glassc64aea52018-09-14 04:57:34 -06002301 def testFmapX86(self):
2302 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002303 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002304 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002305 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002306 self.assertEqual(expected, data[:32])
2307 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2308
2309 self.assertEqual(0x100, fhdr.image_size)
2310
2311 self.assertEqual(0, fentries[0].offset)
2312 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002313 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002314
2315 self.assertEqual(4, fentries[1].offset)
2316 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002317 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002318
2319 self.assertEqual(32, fentries[2].offset)
2320 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2321 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002322 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002323
2324 def testFmapX86Section(self):
2325 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002326 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002327 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002328 self.assertEqual(expected, data[:32])
2329 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2330
Simon Glassb1d414c2021-04-03 11:05:10 +13002331 self.assertEqual(0x180, fhdr.image_size)
2332 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002333 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002334
Simon Glass82059c22021-04-03 11:05:09 +13002335 fentry = next(fiter)
2336 self.assertEqual(b'U_BOOT', fentry.name)
2337 self.assertEqual(0, fentry.offset)
2338 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002339
Simon Glass82059c22021-04-03 11:05:09 +13002340 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002341 self.assertEqual(b'SECTION', fentry.name)
2342 self.assertEqual(4, fentry.offset)
2343 self.assertEqual(0x20 + expect_size, fentry.size)
2344
2345 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002346 self.assertEqual(b'INTEL_MRC', fentry.name)
2347 self.assertEqual(4, fentry.offset)
2348 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002349
Simon Glass82059c22021-04-03 11:05:09 +13002350 fentry = next(fiter)
2351 self.assertEqual(b'FMAP', fentry.name)
2352 self.assertEqual(36, fentry.offset)
2353 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002354
Simon Glassb1714232018-09-14 04:57:35 -06002355 def testElf(self):
2356 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002357 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002358 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002359 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002360 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002361 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002362
Simon Glass0d673792019-07-08 13:18:25 -06002363 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002364 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002365 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002366 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002367 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002368 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002369
Simon Glasscd817d52018-09-14 04:57:36 -06002370 def testPackOverlapMap(self):
2371 """Test that overlapping regions are detected"""
2372 with test_util.capture_sys_output() as (stdout, stderr):
2373 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002374 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002375 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002376 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2377 stdout.getvalue())
2378
2379 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002380 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002381 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002382 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002383 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002384<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002385<none> 00000000 00000004 u-boot
2386<none> 00000003 00000004 u-boot-align
2387''', map_data)
2388
Simon Glass0d673792019-07-08 13:18:25 -06002389 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002390 """Test that an image with an Intel Reference code binary works"""
2391 data = self._DoReadFile('100_intel_refcode.dts')
2392 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2393
Simon Glasseb023b32019-04-25 21:58:39 -06002394 def testSectionOffset(self):
2395 """Tests use of a section with an offset"""
2396 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2397 map=True)
2398 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700239900000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600240000000004 00000004 00000010 section@0
240100000004 00000000 00000004 u-boot
240200000018 00000018 00000010 section@1
240300000018 00000000 00000004 u-boot
24040000002c 0000002c 00000004 section@2
24050000002c 00000000 00000004 u-boot
2406''', map_data)
2407 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002408 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2409 tools.get_bytes(0x21, 12) +
2410 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2411 tools.get_bytes(0x61, 12) +
2412 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2413 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002414
Simon Glass1de34482019-07-08 13:18:53 -06002415 def testCbfsRaw(self):
2416 """Test base handling of a Coreboot Filesystem (CBFS)
2417
2418 The exact contents of the CBFS is verified by similar tests in
2419 cbfs_util_test.py. The tests here merely check that the files added to
2420 the CBFS can be found in the final image.
2421 """
2422 data = self._DoReadFile('102_cbfs_raw.dts')
2423 size = 0xb0
2424
2425 cbfs = cbfs_util.CbfsReader(data)
2426 self.assertEqual(size, cbfs.rom_size)
2427
2428 self.assertIn('u-boot-dtb', cbfs.files)
2429 cfile = cbfs.files['u-boot-dtb']
2430 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2431
2432 def testCbfsArch(self):
2433 """Test on non-x86 architecture"""
2434 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2435 size = 0x100
2436
2437 cbfs = cbfs_util.CbfsReader(data)
2438 self.assertEqual(size, cbfs.rom_size)
2439
2440 self.assertIn('u-boot-dtb', cbfs.files)
2441 cfile = cbfs.files['u-boot-dtb']
2442 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2443
2444 def testCbfsStage(self):
2445 """Tests handling of a Coreboot Filesystem (CBFS)"""
2446 if not elf.ELF_TOOLS:
2447 self.skipTest('Python elftools not available')
2448 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2449 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2450 size = 0xb0
2451
2452 data = self._DoReadFile('104_cbfs_stage.dts')
2453 cbfs = cbfs_util.CbfsReader(data)
2454 self.assertEqual(size, cbfs.rom_size)
2455
2456 self.assertIn('u-boot', cbfs.files)
2457 cfile = cbfs.files['u-boot']
2458 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2459
2460 def testCbfsRawCompress(self):
2461 """Test handling of compressing raw files"""
2462 self._CheckLz4()
2463 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2464 size = 0x140
2465
2466 cbfs = cbfs_util.CbfsReader(data)
2467 self.assertIn('u-boot', cbfs.files)
2468 cfile = cbfs.files['u-boot']
2469 self.assertEqual(COMPRESS_DATA, cfile.data)
2470
2471 def testCbfsBadArch(self):
2472 """Test handling of a bad architecture"""
2473 with self.assertRaises(ValueError) as e:
2474 self._DoReadFile('106_cbfs_bad_arch.dts')
2475 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2476
2477 def testCbfsNoSize(self):
2478 """Test handling of a missing size property"""
2479 with self.assertRaises(ValueError) as e:
2480 self._DoReadFile('107_cbfs_no_size.dts')
2481 self.assertIn('entry must have a size property', str(e.exception))
2482
Simon Glass3e28f4f2021-11-23 11:03:54 -07002483 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002484 """Test handling of a CBFS entry which does not provide contentsy"""
2485 with self.assertRaises(ValueError) as e:
2486 self._DoReadFile('108_cbfs_no_contents.dts')
2487 self.assertIn('Could not complete processing of contents',
2488 str(e.exception))
2489
2490 def testCbfsBadCompress(self):
2491 """Test handling of a bad architecture"""
2492 with self.assertRaises(ValueError) as e:
2493 self._DoReadFile('109_cbfs_bad_compress.dts')
2494 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2495 str(e.exception))
2496
2497 def testCbfsNamedEntries(self):
2498 """Test handling of named entries"""
2499 data = self._DoReadFile('110_cbfs_name.dts')
2500
2501 cbfs = cbfs_util.CbfsReader(data)
2502 self.assertIn('FRED', cbfs.files)
2503 cfile1 = cbfs.files['FRED']
2504 self.assertEqual(U_BOOT_DATA, cfile1.data)
2505
2506 self.assertIn('hello', cbfs.files)
2507 cfile2 = cbfs.files['hello']
2508 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2509
Simon Glass759af872019-07-08 13:18:54 -06002510 def _SetupIfwi(self, fname):
2511 """Set up to run an IFWI test
2512
2513 Args:
2514 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2515 """
2516 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002517 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002518
2519 # Intel Integrated Firmware Image (IFWI) file
2520 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2521 data = fd.read()
2522 TestFunctional._MakeInputFile(fname,data)
2523
2524 def _CheckIfwi(self, data):
2525 """Check that an image with an IFWI contains the correct output
2526
2527 Args:
2528 data: Conents of output file
2529 """
Simon Glass80025522022-01-29 14:14:04 -07002530 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002531 if data[:0x1000] != expected_desc:
2532 self.fail('Expected descriptor binary at start of image')
2533
2534 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002535 image_fname = tools.get_output_filename('image.bin')
2536 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002537 ifwitool = bintool.Bintool.create('ifwitool')
2538 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002539
Simon Glass80025522022-01-29 14:14:04 -07002540 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002541 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002542
2543 def testPackX86RomIfwi(self):
2544 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2545 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002546 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002547 self._CheckIfwi(data)
2548
2549 def testPackX86RomIfwiNoDesc(self):
2550 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2551 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002552 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002553 self._CheckIfwi(data)
2554
2555 def testPackX86RomIfwiNoData(self):
2556 """Test that an x86 ROM with IFWI handles missing data"""
2557 self._SetupIfwi('ifwi.bin')
2558 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002559 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002560 self.assertIn('Could not complete processing of contents',
2561 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002562
Simon Glass66152ce2022-01-09 20:14:09 -07002563 def testIfwiMissing(self):
2564 """Test that binman still produces an image if ifwitool is missing"""
2565 self._SetupIfwi('fitimage.bin')
2566 with test_util.capture_sys_output() as (_, stderr):
2567 self._DoTestFile('111_x86_rom_ifwi.dts',
2568 force_missing_bintools='ifwitool')
2569 err = stderr.getvalue()
2570 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002571 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002572
Simon Glassc2f1aed2019-07-08 13:18:56 -06002573 def testCbfsOffset(self):
2574 """Test a CBFS with files at particular offsets
2575
2576 Like all CFBS tests, this is just checking the logic that calls
2577 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2578 """
2579 data = self._DoReadFile('114_cbfs_offset.dts')
2580 size = 0x200
2581
2582 cbfs = cbfs_util.CbfsReader(data)
2583 self.assertEqual(size, cbfs.rom_size)
2584
2585 self.assertIn('u-boot', cbfs.files)
2586 cfile = cbfs.files['u-boot']
2587 self.assertEqual(U_BOOT_DATA, cfile.data)
2588 self.assertEqual(0x40, cfile.cbfs_offset)
2589
2590 self.assertIn('u-boot-dtb', cbfs.files)
2591 cfile2 = cbfs.files['u-boot-dtb']
2592 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2593 self.assertEqual(0x140, cfile2.cbfs_offset)
2594
Simon Glass0f621332019-07-08 14:25:27 -06002595 def testFdtmap(self):
2596 """Test an FDT map can be inserted in the image"""
2597 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2598 fdtmap_data = data[len(U_BOOT_DATA):]
2599 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002600 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002601 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002602
2603 fdt_data = fdtmap_data[16:]
2604 dtb = fdt.Fdt.FromData(fdt_data)
2605 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002606 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002607 self.assertEqual({
2608 'image-pos': 0,
2609 'offset': 0,
2610 'u-boot:offset': 0,
2611 'u-boot:size': len(U_BOOT_DATA),
2612 'u-boot:image-pos': 0,
2613 'fdtmap:image-pos': 4,
2614 'fdtmap:offset': 4,
2615 'fdtmap:size': len(fdtmap_data),
2616 'size': len(data),
2617 }, props)
2618
2619 def testFdtmapNoMatch(self):
2620 """Check handling of an FDT map when the section cannot be found"""
2621 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2622
2623 # Mangle the section name, which should cause a mismatch between the
2624 # correct FDT path and the one expected by the section
2625 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002626 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002627 entries = image.GetEntries()
2628 fdtmap = entries['fdtmap']
2629 with self.assertRaises(ValueError) as e:
2630 fdtmap._GetFdtmap()
2631 self.assertIn("Cannot locate node for path '/binman-suffix'",
2632 str(e.exception))
2633
Simon Glasscec34ba2019-07-08 14:25:28 -06002634 def testFdtmapHeader(self):
2635 """Test an FDT map and image header can be inserted in the image"""
2636 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2637 fdtmap_pos = len(U_BOOT_DATA)
2638 fdtmap_data = data[fdtmap_pos:]
2639 fdt_data = fdtmap_data[16:]
2640 dtb = fdt.Fdt.FromData(fdt_data)
2641 fdt_size = dtb.GetFdtObj().totalsize()
2642 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002643 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002644 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2645 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2646
2647 def testFdtmapHeaderStart(self):
2648 """Test an image header can be inserted at the image start"""
2649 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2650 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2651 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002652 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002653 offset = struct.unpack('<I', hdr_data[4:])[0]
2654 self.assertEqual(fdtmap_pos, offset)
2655
2656 def testFdtmapHeaderPos(self):
2657 """Test an image header can be inserted at a chosen position"""
2658 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2659 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2660 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002661 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002662 offset = struct.unpack('<I', hdr_data[4:])[0]
2663 self.assertEqual(fdtmap_pos, offset)
2664
2665 def testHeaderMissingFdtmap(self):
2666 """Test an image header requires an fdtmap"""
2667 with self.assertRaises(ValueError) as e:
2668 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2669 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2670 str(e.exception))
2671
2672 def testHeaderNoLocation(self):
2673 """Test an image header with a no specified location is detected"""
2674 with self.assertRaises(ValueError) as e:
2675 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2676 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2677 str(e.exception))
2678
Simon Glasse61b6f62019-07-08 14:25:37 -06002679 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002680 """Test extending an entry after it is packed"""
2681 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002682 self.assertEqual(b'aaa', data[:3])
2683 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2684 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002685
Simon Glassdd156a42022-03-05 20:18:59 -07002686 def testEntryExtendBad(self):
2687 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002688 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002689 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002690 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002691 str(e.exception))
2692
Simon Glassdd156a42022-03-05 20:18:59 -07002693 def testEntryExtendSection(self):
2694 """Test extending an entry within a section after it is packed"""
2695 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002696 self.assertEqual(b'aaa', data[:3])
2697 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2698 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002699
Simon Glass90d29682019-07-08 14:25:38 -06002700 def testCompressDtb(self):
2701 """Test that compress of device-tree files is supported"""
2702 self._CheckLz4()
2703 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2704 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2705 comp_data = data[len(U_BOOT_DATA):]
2706 orig = self._decompress(comp_data)
2707 dtb = fdt.Fdt.FromData(orig)
2708 dtb.Scan()
2709 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2710 expected = {
2711 'u-boot:size': len(U_BOOT_DATA),
2712 'u-boot-dtb:uncomp-size': len(orig),
2713 'u-boot-dtb:size': len(comp_data),
2714 'size': len(data),
2715 }
2716 self.assertEqual(expected, props)
2717
Simon Glass151bbbf2019-07-08 14:25:41 -06002718 def testCbfsUpdateFdt(self):
2719 """Test that we can update the device tree with CBFS offset/size info"""
2720 self._CheckLz4()
2721 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2722 update_dtb=True)
2723 dtb = fdt.Fdt(out_dtb_fname)
2724 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002725 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002726 del props['cbfs/u-boot:size']
2727 self.assertEqual({
2728 'offset': 0,
2729 'size': len(data),
2730 'image-pos': 0,
2731 'cbfs:offset': 0,
2732 'cbfs:size': len(data),
2733 'cbfs:image-pos': 0,
Simon Glassfa144222023-10-14 14:40:28 -06002734 'cbfs/u-boot:offset': 0x30,
Simon Glass151bbbf2019-07-08 14:25:41 -06002735 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002736 'cbfs/u-boot:image-pos': 0x30,
2737 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002738 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002739 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002740 }, props)
2741
Simon Glass3c9b4f22019-07-08 14:25:42 -06002742 def testCbfsBadType(self):
2743 """Test an image header with a no specified location is detected"""
2744 with self.assertRaises(ValueError) as e:
2745 self._DoReadFile('126_cbfs_bad_type.dts')
2746 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2747
Simon Glass6b156f82019-07-08 14:25:43 -06002748 def testList(self):
2749 """Test listing the files in an image"""
2750 self._CheckLz4()
2751 data = self._DoReadFile('127_list.dts')
2752 image = control.images['image']
2753 entries = image.BuildEntryList()
2754 self.assertEqual(7, len(entries))
2755
2756 ent = entries[0]
2757 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002758 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002759 self.assertEqual('section', ent.etype)
2760 self.assertEqual(len(data), ent.size)
2761 self.assertEqual(0, ent.image_pos)
2762 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002763 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002764
2765 ent = entries[1]
2766 self.assertEqual(1, ent.indent)
2767 self.assertEqual('u-boot', ent.name)
2768 self.assertEqual('u-boot', ent.etype)
2769 self.assertEqual(len(U_BOOT_DATA), ent.size)
2770 self.assertEqual(0, ent.image_pos)
2771 self.assertEqual(None, ent.uncomp_size)
2772 self.assertEqual(0, ent.offset)
2773
2774 ent = entries[2]
2775 self.assertEqual(1, ent.indent)
2776 self.assertEqual('section', ent.name)
2777 self.assertEqual('section', ent.etype)
2778 section_size = ent.size
2779 self.assertEqual(0x100, ent.image_pos)
2780 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002781 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002782
2783 ent = entries[3]
2784 self.assertEqual(2, ent.indent)
2785 self.assertEqual('cbfs', ent.name)
2786 self.assertEqual('cbfs', ent.etype)
2787 self.assertEqual(0x400, ent.size)
2788 self.assertEqual(0x100, ent.image_pos)
2789 self.assertEqual(None, ent.uncomp_size)
2790 self.assertEqual(0, ent.offset)
2791
2792 ent = entries[4]
2793 self.assertEqual(3, ent.indent)
2794 self.assertEqual('u-boot', ent.name)
2795 self.assertEqual('u-boot', ent.etype)
2796 self.assertEqual(len(U_BOOT_DATA), ent.size)
2797 self.assertEqual(0x138, ent.image_pos)
2798 self.assertEqual(None, ent.uncomp_size)
2799 self.assertEqual(0x38, ent.offset)
2800
2801 ent = entries[5]
2802 self.assertEqual(3, ent.indent)
2803 self.assertEqual('u-boot-dtb', ent.name)
2804 self.assertEqual('text', ent.etype)
2805 self.assertGreater(len(COMPRESS_DATA), ent.size)
2806 self.assertEqual(0x178, ent.image_pos)
2807 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2808 self.assertEqual(0x78, ent.offset)
2809
2810 ent = entries[6]
2811 self.assertEqual(2, ent.indent)
2812 self.assertEqual('u-boot-dtb', ent.name)
2813 self.assertEqual('u-boot-dtb', ent.etype)
2814 self.assertEqual(0x500, ent.image_pos)
2815 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2816 dtb_size = ent.size
2817 # Compressing this data expands it since headers are added
2818 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2819 self.assertEqual(0x400, ent.offset)
2820
2821 self.assertEqual(len(data), 0x100 + section_size)
2822 self.assertEqual(section_size, 0x400 + dtb_size)
2823
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002824 def testFindFdtmap(self):
2825 """Test locating an FDT map in an image"""
2826 self._CheckLz4()
2827 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2828 image = control.images['image']
2829 entries = image.GetEntries()
2830 entry = entries['fdtmap']
2831 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2832
2833 def testFindFdtmapMissing(self):
2834 """Test failing to locate an FDP map"""
2835 data = self._DoReadFile('005_simple.dts')
2836 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2837
Simon Glassed39a3c2019-07-08 14:25:45 -06002838 def testFindImageHeader(self):
2839 """Test locating a image header"""
2840 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002841 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002842 image = control.images['image']
2843 entries = image.GetEntries()
2844 entry = entries['fdtmap']
2845 # The header should point to the FDT map
2846 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2847
2848 def testFindImageHeaderStart(self):
2849 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002850 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002851 image = control.images['image']
2852 entries = image.GetEntries()
2853 entry = entries['fdtmap']
2854 # The header should point to the FDT map
2855 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2856
2857 def testFindImageHeaderMissing(self):
2858 """Test failing to locate an image header"""
2859 data = self._DoReadFile('005_simple.dts')
2860 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2861
Simon Glassb8424fa2019-07-08 14:25:46 -06002862 def testReadImage(self):
2863 """Test reading an image and accessing its FDT map"""
2864 self._CheckLz4()
2865 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002866 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002867 orig_image = control.images['image']
2868 image = Image.FromFile(image_fname)
2869 self.assertEqual(orig_image.GetEntries().keys(),
2870 image.GetEntries().keys())
2871
2872 orig_entry = orig_image.GetEntries()['fdtmap']
2873 entry = image.GetEntries()['fdtmap']
Brandon Maiera657bc62024-06-04 16:16:05 +00002874 self.assertEqual(orig_entry.offset, entry.offset)
2875 self.assertEqual(orig_entry.size, entry.size)
2876 self.assertEqual(orig_entry.image_pos, entry.image_pos)
Simon Glassb8424fa2019-07-08 14:25:46 -06002877
2878 def testReadImageNoHeader(self):
2879 """Test accessing an image's FDT map without an image header"""
2880 self._CheckLz4()
2881 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002882 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002883 image = Image.FromFile(image_fname)
2884 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002885 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002886
2887 def testReadImageFail(self):
2888 """Test failing to read an image image's FDT map"""
2889 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002890 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002891 with self.assertRaises(ValueError) as e:
2892 image = Image.FromFile(image_fname)
2893 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002894
Simon Glassb2fd11d2019-07-08 14:25:48 -06002895 def testListCmd(self):
2896 """Test listing the files in an image using an Fdtmap"""
2897 self._CheckLz4()
2898 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2899
2900 # lz4 compression size differs depending on the version
2901 image = control.images['image']
2902 entries = image.GetEntries()
2903 section_size = entries['section'].size
2904 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2905 fdtmap_offset = entries['fdtmap'].offset
2906
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002907 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002908 try:
2909 tmpdir, updated_fname = self._SetupImageInTmpdir()
2910 with test_util.capture_sys_output() as (stdout, stderr):
2911 self._DoBinman('ls', '-i', updated_fname)
2912 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002913 if tmpdir:
2914 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002915 lines = stdout.getvalue().splitlines()
2916 expected = [
2917'Name Image-pos Size Entry-type Offset Uncomp-size',
2918'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002919'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002920' u-boot 0 4 u-boot 0',
2921' section 100 %x section 100' % section_size,
2922' cbfs 100 400 cbfs 0',
Simon Glassfa144222023-10-14 14:40:28 -06002923' u-boot 120 4 u-boot 20',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002924' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002925' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002926' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002927 (fdtmap_offset, fdtmap_offset),
2928' image-header bf8 8 image-header bf8',
2929 ]
2930 self.assertEqual(expected, lines)
2931
2932 def testListCmdFail(self):
2933 """Test failing to list an image"""
2934 self._DoReadFile('005_simple.dts')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002935 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002936 try:
2937 tmpdir, updated_fname = self._SetupImageInTmpdir()
2938 with self.assertRaises(ValueError) as e:
2939 self._DoBinman('ls', '-i', updated_fname)
2940 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002941 if tmpdir:
2942 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002943 self.assertIn("Cannot find FDT map in image", str(e.exception))
2944
2945 def _RunListCmd(self, paths, expected):
2946 """List out entries and check the result
2947
2948 Args:
2949 paths: List of paths to pass to the list command
2950 expected: Expected list of filenames to be returned, in order
2951 """
2952 self._CheckLz4()
2953 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002954 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002955 image = Image.FromFile(image_fname)
2956 lines = image.GetListEntries(paths)[1]
2957 files = [line[0].strip() for line in lines[1:]]
2958 self.assertEqual(expected, files)
2959
2960 def testListCmdSection(self):
2961 """Test listing the files in a section"""
2962 self._RunListCmd(['section'],
2963 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2964
2965 def testListCmdFile(self):
2966 """Test listing a particular file"""
2967 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2968
2969 def testListCmdWildcard(self):
2970 """Test listing a wildcarded file"""
2971 self._RunListCmd(['*boot*'],
2972 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2973
2974 def testListCmdWildcardMulti(self):
2975 """Test listing a wildcarded file"""
2976 self._RunListCmd(['*cb*', '*head*'],
2977 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2978
2979 def testListCmdEmpty(self):
2980 """Test listing a wildcarded file"""
2981 self._RunListCmd(['nothing'], [])
2982
2983 def testListCmdPath(self):
2984 """Test listing the files in a sub-entry of a section"""
2985 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2986
Simon Glass4c613bf2019-07-08 14:25:50 -06002987 def _RunExtractCmd(self, entry_name, decomp=True):
2988 """Extract an entry from an image
2989
2990 Args:
2991 entry_name: Entry name to extract
2992 decomp: True to decompress the data if compressed, False to leave
2993 it in its raw uncompressed format
2994
2995 Returns:
2996 data from entry
2997 """
2998 self._CheckLz4()
2999 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003000 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06003001 return control.ReadEntry(image_fname, entry_name, decomp)
3002
3003 def testExtractSimple(self):
3004 """Test extracting a single file"""
3005 data = self._RunExtractCmd('u-boot')
3006 self.assertEqual(U_BOOT_DATA, data)
3007
Simon Glass980a2842019-07-08 14:25:52 -06003008 def testExtractSection(self):
3009 """Test extracting the files in a section"""
3010 data = self._RunExtractCmd('section')
3011 cbfs_data = data[:0x400]
3012 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06003013 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06003014 dtb_data = data[0x400:]
3015 dtb = self._decompress(dtb_data)
3016 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3017
3018 def testExtractCompressed(self):
3019 """Test extracting compressed data"""
3020 data = self._RunExtractCmd('section/u-boot-dtb')
3021 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3022
3023 def testExtractRaw(self):
3024 """Test extracting compressed data without decompressing it"""
3025 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
3026 dtb = self._decompress(data)
3027 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3028
3029 def testExtractCbfs(self):
3030 """Test extracting CBFS data"""
3031 data = self._RunExtractCmd('section/cbfs/u-boot')
3032 self.assertEqual(U_BOOT_DATA, data)
3033
3034 def testExtractCbfsCompressed(self):
3035 """Test extracting CBFS compressed data"""
3036 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
3037 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
3038
3039 def testExtractCbfsRaw(self):
3040 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003041 bintool = self.comp_bintools['lzma_alone']
3042 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06003043 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02003044 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06003045 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
3046
Simon Glass4c613bf2019-07-08 14:25:50 -06003047 def testExtractBadEntry(self):
3048 """Test extracting a bad section path"""
3049 with self.assertRaises(ValueError) as e:
3050 self._RunExtractCmd('section/does-not-exist')
3051 self.assertIn("Entry 'does-not-exist' not found in '/section'",
3052 str(e.exception))
3053
3054 def testExtractMissingFile(self):
3055 """Test extracting file that does not exist"""
3056 with self.assertRaises(IOError) as e:
3057 control.ReadEntry('missing-file', 'name')
3058
3059 def testExtractBadFile(self):
3060 """Test extracting an invalid file"""
3061 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07003062 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06003063 with self.assertRaises(ValueError) as e:
3064 control.ReadEntry(fname, 'name')
3065
Simon Glass980a2842019-07-08 14:25:52 -06003066 def testExtractCmd(self):
3067 """Test extracting a file fron an image on the command line"""
3068 self._CheckLz4()
3069 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06003070 fname = os.path.join(self._indir, 'output.extact')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003071 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06003072 try:
3073 tmpdir, updated_fname = self._SetupImageInTmpdir()
3074 with test_util.capture_sys_output() as (stdout, stderr):
3075 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3076 '-f', fname)
3077 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003078 if tmpdir:
3079 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07003080 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003081 self.assertEqual(U_BOOT_DATA, data)
3082
3083 def testExtractOneEntry(self):
3084 """Test extracting a single entry fron an image """
3085 self._CheckLz4()
3086 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003087 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003088 fname = os.path.join(self._indir, 'output.extact')
3089 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003090 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003091 self.assertEqual(U_BOOT_DATA, data)
3092
3093 def _CheckExtractOutput(self, decomp):
3094 """Helper to test file output with and without decompression
3095
3096 Args:
3097 decomp: True to decompress entry data, False to output it raw
3098 """
3099 def _CheckPresent(entry_path, expect_data, expect_size=None):
3100 """Check and remove expected file
3101
3102 This checks the data/size of a file and removes the file both from
3103 the outfiles set and from the output directory. Once all files are
3104 processed, both the set and directory should be empty.
3105
3106 Args:
3107 entry_path: Entry path
3108 expect_data: Data to expect in file, or None to skip check
3109 expect_size: Size of data to expect in file, or None to skip
3110 """
3111 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003112 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003113 os.remove(path)
3114 if expect_data:
3115 self.assertEqual(expect_data, data)
3116 elif expect_size:
3117 self.assertEqual(expect_size, len(data))
3118 outfiles.remove(path)
3119
3120 def _CheckDirPresent(name):
3121 """Remove expected directory
3122
3123 This gives an error if the directory does not exist as expected
3124
3125 Args:
3126 name: Name of directory to remove
3127 """
3128 path = os.path.join(outdir, name)
3129 os.rmdir(path)
3130
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, [], decomp)
3135
3136 # Create a set of all file that were output (should be 9)
3137 outfiles = set()
3138 for root, dirs, files in os.walk(outdir):
3139 outfiles |= set([os.path.join(root, fname) for fname in files])
3140 self.assertEqual(9, len(outfiles))
3141 self.assertEqual(9, len(einfos))
3142
3143 image = control.images['image']
3144 entries = image.GetEntries()
3145
3146 # Check the 9 files in various ways
3147 section = entries['section']
3148 section_entries = section.GetEntries()
3149 cbfs_entries = section_entries['cbfs'].GetEntries()
3150 _CheckPresent('u-boot', U_BOOT_DATA)
3151 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3152 dtb_len = EXTRACT_DTB_SIZE
3153 if not decomp:
3154 dtb_len = cbfs_entries['u-boot-dtb'].size
3155 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3156 if not decomp:
3157 dtb_len = section_entries['u-boot-dtb'].size
3158 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3159
3160 fdtmap = entries['fdtmap']
3161 _CheckPresent('fdtmap', fdtmap.data)
3162 hdr = entries['image-header']
3163 _CheckPresent('image-header', hdr.data)
3164
3165 _CheckPresent('section/root', section.data)
3166 cbfs = section_entries['cbfs']
3167 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003168 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003169 _CheckPresent('root', data)
3170
3171 # There should be no files left. Remove all the directories to check.
3172 # If there are any files/dirs remaining, one of these checks will fail.
3173 self.assertEqual(0, len(outfiles))
3174 _CheckDirPresent('section/cbfs')
3175 _CheckDirPresent('section')
3176 _CheckDirPresent('')
3177 self.assertFalse(os.path.exists(outdir))
3178
3179 def testExtractAllEntries(self):
3180 """Test extracting all entries"""
3181 self._CheckLz4()
3182 self._CheckExtractOutput(decomp=True)
3183
3184 def testExtractAllEntriesRaw(self):
3185 """Test extracting all entries without decompressing them"""
3186 self._CheckLz4()
3187 self._CheckExtractOutput(decomp=False)
3188
3189 def testExtractSelectedEntries(self):
3190 """Test extracting some entries"""
3191 self._CheckLz4()
3192 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003193 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003194 outdir = os.path.join(self._indir, 'extract')
3195 einfos = control.ExtractEntries(image_fname, None, outdir,
3196 ['*cb*', '*head*'])
3197
3198 # File output is tested by testExtractAllEntries(), so just check that
3199 # the expected entries are selected
3200 names = [einfo.name for einfo in einfos]
3201 self.assertEqual(names,
3202 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3203
3204 def testExtractNoEntryPaths(self):
3205 """Test extracting some entries"""
3206 self._CheckLz4()
3207 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003208 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003209 with self.assertRaises(ValueError) as e:
3210 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003211 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003212 str(e.exception))
3213
3214 def testExtractTooManyEntryPaths(self):
3215 """Test extracting some entries"""
3216 self._CheckLz4()
3217 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003218 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003219 with self.assertRaises(ValueError) as e:
3220 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003221 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003222 str(e.exception))
3223
Simon Glass52d06212019-07-08 14:25:53 -06003224 def testPackAlignSection(self):
3225 """Test that sections can have alignment"""
3226 self._DoReadFile('131_pack_align_section.dts')
3227
3228 self.assertIn('image', control.images)
3229 image = control.images['image']
3230 entries = image.GetEntries()
3231 self.assertEqual(3, len(entries))
3232
3233 # First u-boot
3234 self.assertIn('u-boot', entries)
3235 entry = entries['u-boot']
3236 self.assertEqual(0, entry.offset)
3237 self.assertEqual(0, entry.image_pos)
3238 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3239 self.assertEqual(len(U_BOOT_DATA), entry.size)
3240
3241 # Section0
3242 self.assertIn('section0', entries)
3243 section0 = entries['section0']
3244 self.assertEqual(0x10, section0.offset)
3245 self.assertEqual(0x10, section0.image_pos)
3246 self.assertEqual(len(U_BOOT_DATA), section0.size)
3247
3248 # Second u-boot
3249 section_entries = section0.GetEntries()
3250 self.assertIn('u-boot', section_entries)
3251 entry = section_entries['u-boot']
3252 self.assertEqual(0, entry.offset)
3253 self.assertEqual(0x10, entry.image_pos)
3254 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3255 self.assertEqual(len(U_BOOT_DATA), entry.size)
3256
3257 # Section1
3258 self.assertIn('section1', entries)
3259 section1 = entries['section1']
3260 self.assertEqual(0x14, section1.offset)
3261 self.assertEqual(0x14, section1.image_pos)
3262 self.assertEqual(0x20, section1.size)
3263
3264 # Second u-boot
3265 section_entries = section1.GetEntries()
3266 self.assertIn('u-boot', section_entries)
3267 entry = section_entries['u-boot']
3268 self.assertEqual(0, entry.offset)
3269 self.assertEqual(0x14, entry.image_pos)
3270 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3271 self.assertEqual(len(U_BOOT_DATA), entry.size)
3272
3273 # Section2
3274 self.assertIn('section2', section_entries)
3275 section2 = section_entries['section2']
3276 self.assertEqual(0x4, section2.offset)
3277 self.assertEqual(0x18, section2.image_pos)
3278 self.assertEqual(4, section2.size)
3279
3280 # Third u-boot
3281 section_entries = section2.GetEntries()
3282 self.assertIn('u-boot', section_entries)
3283 entry = section_entries['u-boot']
3284 self.assertEqual(0, entry.offset)
3285 self.assertEqual(0x18, entry.image_pos)
3286 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3287 self.assertEqual(len(U_BOOT_DATA), entry.size)
3288
Simon Glassf8a54bc2019-07-20 12:23:56 -06003289 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3290 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003291 """Replace an entry in an image
3292
3293 This writes the entry data to update it, then opens the updated file and
3294 returns the value that it now finds there.
3295
3296 Args:
3297 entry_name: Entry name to replace
3298 data: Data to replace it with
3299 decomp: True to compress the data if needed, False if data is
3300 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003301 allow_resize: True to allow entries to change size, False to raise
3302 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003303
3304 Returns:
3305 Tuple:
3306 data from entry
3307 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003308 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003309 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003310 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003311 update_dtb=True)[1]
3312
3313 self.assertIn('image', control.images)
3314 image = control.images['image']
3315 entries = image.GetEntries()
3316 orig_dtb_data = entries['u-boot-dtb'].data
3317 orig_fdtmap_data = entries['fdtmap'].data
3318
Simon Glass80025522022-01-29 14:14:04 -07003319 image_fname = tools.get_output_filename('image.bin')
3320 updated_fname = tools.get_output_filename('image-updated.bin')
3321 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003322 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3323 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003324 data = control.ReadEntry(updated_fname, entry_name, decomp)
3325
Simon Glassf8a54bc2019-07-20 12:23:56 -06003326 # The DT data should not change unless resized:
3327 if not allow_resize:
3328 new_dtb_data = entries['u-boot-dtb'].data
3329 self.assertEqual(new_dtb_data, orig_dtb_data)
3330 new_fdtmap_data = entries['fdtmap'].data
3331 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003332
Simon Glassf8a54bc2019-07-20 12:23:56 -06003333 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003334
3335 def testReplaceSimple(self):
3336 """Test replacing a single file"""
3337 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003338 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3339 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003340 self.assertEqual(expected, data)
3341
3342 # Test that the state looks right. There should be an FDT for the fdtmap
3343 # that we jsut read back in, and it should match what we find in the
3344 # 'control' tables. Checking for an FDT that does not exist should
3345 # return None.
3346 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003347 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003348 self.assertEqual(expected_fdtmap, fdtmap)
3349
3350 dtb = state.GetFdtForEtype('fdtmap')
3351 self.assertEqual(dtb.GetContents(), fdtmap)
3352
3353 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3354 self.assertIsNone(missing_path)
3355 self.assertIsNone(missing_fdtmap)
3356
3357 missing_dtb = state.GetFdtForEtype('missing')
3358 self.assertIsNone(missing_dtb)
3359
3360 self.assertEqual('/binman', state.fdt_path_prefix)
3361
3362 def testReplaceResizeFail(self):
3363 """Test replacing a file by something larger"""
3364 expected = U_BOOT_DATA + b'x'
3365 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003366 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3367 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003368 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3369 str(e.exception))
3370
3371 def testReplaceMulti(self):
3372 """Test replacing entry data where multiple images are generated"""
3373 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3374 update_dtb=True)[0]
3375 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003376 updated_fname = tools.get_output_filename('image-updated.bin')
3377 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003378 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003379 control.WriteEntry(updated_fname, entry_name, expected,
3380 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003381 data = control.ReadEntry(updated_fname, entry_name)
3382 self.assertEqual(expected, data)
3383
3384 # Check the state looks right.
3385 self.assertEqual('/binman/image', state.fdt_path_prefix)
3386
3387 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003388 image_fname = tools.get_output_filename('first-image.bin')
3389 updated_fname = tools.get_output_filename('first-updated.bin')
3390 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003391 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003392 control.WriteEntry(updated_fname, entry_name, expected,
3393 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003394 data = control.ReadEntry(updated_fname, entry_name)
3395 self.assertEqual(expected, data)
3396
3397 # Check the state looks right.
3398 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003399
Simon Glassfb30e292019-07-20 12:23:51 -06003400 def testUpdateFdtAllRepack(self):
3401 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003402 self._SetupSplElf()
3403 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003404 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3405 SECTION_SIZE = 0x300
3406 DTB_SIZE = 602
3407 FDTMAP_SIZE = 608
3408 base_expected = {
3409 'offset': 0,
3410 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3411 'image-pos': 0,
3412 'section:offset': 0,
3413 'section:size': SECTION_SIZE,
3414 'section:image-pos': 0,
3415 'section/u-boot-dtb:offset': 4,
3416 'section/u-boot-dtb:size': 636,
3417 'section/u-boot-dtb:image-pos': 4,
3418 'u-boot-spl-dtb:offset': SECTION_SIZE,
3419 'u-boot-spl-dtb:size': DTB_SIZE,
3420 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3421 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3422 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3423 'u-boot-tpl-dtb:size': DTB_SIZE,
3424 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3425 'fdtmap:size': FDTMAP_SIZE,
3426 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3427 }
3428 main_expected = {
3429 'section:orig-size': SECTION_SIZE,
3430 'section/u-boot-dtb:orig-offset': 4,
3431 }
3432
3433 # We expect three device-tree files in the output, with the first one
3434 # within a fixed-size section.
3435 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3436 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3437 # main U-Boot tree. All three should have the same positions and offset
3438 # except that the main tree should include the main_expected properties
3439 start = 4
3440 for item in ['', 'spl', 'tpl', None]:
3441 if item is None:
3442 start += 16 # Move past fdtmap header
3443 dtb = fdt.Fdt.FromData(data[start:])
3444 dtb.Scan()
3445 props = self._GetPropTree(dtb,
3446 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3447 prefix='/' if item is None else '/binman/')
3448 expected = dict(base_expected)
3449 if item:
3450 expected[item] = 0
3451 else:
3452 # Main DTB and fdtdec should include the 'orig-' properties
3453 expected.update(main_expected)
3454 # Helpful for debugging:
3455 #for prop in sorted(props):
3456 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3457 self.assertEqual(expected, props)
3458 if item == '':
3459 start = SECTION_SIZE
3460 else:
3461 start += dtb._fdt_obj.totalsize()
3462
Simon Glass11453762019-07-20 12:23:55 -06003463 def testFdtmapHeaderMiddle(self):
3464 """Test an FDT map in the middle of an image when it should be at end"""
3465 with self.assertRaises(ValueError) as e:
3466 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3467 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3468 str(e.exception))
3469
3470 def testFdtmapHeaderStartBad(self):
3471 """Test an FDT map in middle of an image when it should be at start"""
3472 with self.assertRaises(ValueError) as e:
3473 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3474 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3475 str(e.exception))
3476
3477 def testFdtmapHeaderEndBad(self):
3478 """Test an FDT map at the start of an image when it should be at end"""
3479 with self.assertRaises(ValueError) as e:
3480 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3481 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3482 str(e.exception))
3483
3484 def testFdtmapHeaderNoSize(self):
3485 """Test an image header at the end of an image with undefined size"""
3486 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3487
Simon Glassf8a54bc2019-07-20 12:23:56 -06003488 def testReplaceResize(self):
3489 """Test replacing a single file in an entry with a larger file"""
3490 expected = U_BOOT_DATA + b'x'
3491 data, _, image = self._RunReplaceCmd('u-boot', expected,
3492 dts='139_replace_repack.dts')
3493 self.assertEqual(expected, data)
3494
3495 entries = image.GetEntries()
3496 dtb_data = entries['u-boot-dtb'].data
3497 dtb = fdt.Fdt.FromData(dtb_data)
3498 dtb.Scan()
3499
3500 # The u-boot section should now be larger in the dtb
3501 node = dtb.GetNode('/binman/u-boot')
3502 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3503
3504 # Same for the fdtmap
3505 fdata = entries['fdtmap'].data
3506 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3507 fdtb.Scan()
3508 fnode = fdtb.GetNode('/u-boot')
3509 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3510
3511 def testReplaceResizeNoRepack(self):
3512 """Test replacing an entry with a larger file when not allowed"""
3513 expected = U_BOOT_DATA + b'x'
3514 with self.assertRaises(ValueError) as e:
3515 self._RunReplaceCmd('u-boot', expected)
3516 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3517 str(e.exception))
3518
Simon Glass9d8ee322019-07-20 12:23:58 -06003519 def testEntryShrink(self):
3520 """Test contracting an entry after it is packed"""
3521 try:
3522 state.SetAllowEntryContraction(True)
3523 data = self._DoReadFileDtb('140_entry_shrink.dts',
3524 update_dtb=True)[0]
3525 finally:
3526 state.SetAllowEntryContraction(False)
3527 self.assertEqual(b'a', data[:1])
3528 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3529 self.assertEqual(b'a', data[-1:])
3530
3531 def testEntryShrinkFail(self):
3532 """Test not being allowed to contract an entry after it is packed"""
3533 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3534
3535 # In this case there is a spare byte at the end of the data. The size of
3536 # the contents is only 1 byte but we still have the size before it
3537 # shrunk.
3538 self.assertEqual(b'a\0', data[:2])
3539 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3540 self.assertEqual(b'a\0', data[-2:])
3541
Simon Glass70e32982019-07-20 12:24:01 -06003542 def testDescriptorOffset(self):
3543 """Test that the Intel descriptor is always placed at at the start"""
3544 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3545 image = control.images['image']
3546 entries = image.GetEntries()
3547 desc = entries['intel-descriptor']
3548 self.assertEqual(0xff800000, desc.offset);
3549 self.assertEqual(0xff800000, desc.image_pos);
3550
Simon Glass37fdd142019-07-20 12:24:06 -06003551 def testReplaceCbfs(self):
3552 """Test replacing a single file in CBFS without changing the size"""
3553 self._CheckLz4()
3554 expected = b'x' * len(U_BOOT_DATA)
3555 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003556 updated_fname = tools.get_output_filename('image-updated.bin')
3557 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003558 entry_name = 'section/cbfs/u-boot'
3559 control.WriteEntry(updated_fname, entry_name, expected,
3560 allow_resize=True)
3561 data = control.ReadEntry(updated_fname, entry_name)
3562 self.assertEqual(expected, data)
3563
3564 def testReplaceResizeCbfs(self):
3565 """Test replacing a single file in CBFS with one of a different size"""
3566 self._CheckLz4()
3567 expected = U_BOOT_DATA + b'x'
3568 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003569 updated_fname = tools.get_output_filename('image-updated.bin')
3570 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003571 entry_name = 'section/cbfs/u-boot'
3572 control.WriteEntry(updated_fname, entry_name, expected,
3573 allow_resize=True)
3574 data = control.ReadEntry(updated_fname, entry_name)
3575 self.assertEqual(expected, data)
3576
Simon Glass30033c22019-07-20 12:24:15 -06003577 def _SetupForReplace(self):
3578 """Set up some files to use to replace entries
3579
3580 This generates an image, copies it to a new file, extracts all the files
3581 in it and updates some of them
3582
3583 Returns:
3584 List
3585 Image filename
3586 Output directory
3587 Expected values for updated entries, each a string
3588 """
3589 data = self._DoReadFileRealDtb('143_replace_all.dts')
3590
Simon Glass80025522022-01-29 14:14:04 -07003591 updated_fname = tools.get_output_filename('image-updated.bin')
3592 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003593
3594 outdir = os.path.join(self._indir, 'extract')
3595 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3596
3597 expected1 = b'x' + U_BOOT_DATA + b'y'
3598 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003599 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003600
3601 expected2 = b'a' + U_BOOT_DATA + b'b'
3602 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003603 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003604
3605 expected_text = b'not the same text'
3606 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003607 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003608
3609 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3610 dtb = fdt.FdtScan(dtb_fname)
3611 node = dtb.GetNode('/binman/text')
3612 node.AddString('my-property', 'the value')
3613 dtb.Sync(auto_resize=True)
3614 dtb.Flush()
3615
3616 return updated_fname, outdir, expected1, expected2, expected_text
3617
3618 def _CheckReplaceMultiple(self, entry_paths):
3619 """Handle replacing the contents of multiple entries
3620
3621 Args:
3622 entry_paths: List of entry paths to replace
3623
3624 Returns:
3625 List
3626 Dict of entries in the image:
3627 key: Entry name
3628 Value: Entry object
3629 Expected values for updated entries, each a string
3630 """
3631 updated_fname, outdir, expected1, expected2, expected_text = (
3632 self._SetupForReplace())
3633 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3634
3635 image = Image.FromFile(updated_fname)
3636 image.LoadData()
3637 return image.GetEntries(), expected1, expected2, expected_text
3638
3639 def testReplaceAll(self):
3640 """Test replacing the contents of all entries"""
3641 entries, expected1, expected2, expected_text = (
3642 self._CheckReplaceMultiple([]))
3643 data = entries['u-boot'].data
3644 self.assertEqual(expected1, data)
3645
3646 data = entries['u-boot2'].data
3647 self.assertEqual(expected2, data)
3648
3649 data = entries['text'].data
3650 self.assertEqual(expected_text, data)
3651
3652 # Check that the device tree is updated
3653 data = entries['u-boot-dtb'].data
3654 dtb = fdt.Fdt.FromData(data)
3655 dtb.Scan()
3656 node = dtb.GetNode('/binman/text')
3657 self.assertEqual('the value', node.props['my-property'].value)
3658
3659 def testReplaceSome(self):
3660 """Test replacing the contents of a few entries"""
3661 entries, expected1, expected2, expected_text = (
3662 self._CheckReplaceMultiple(['u-boot2', 'text']))
3663
3664 # This one should not change
3665 data = entries['u-boot'].data
3666 self.assertEqual(U_BOOT_DATA, data)
3667
3668 data = entries['u-boot2'].data
3669 self.assertEqual(expected2, data)
3670
3671 data = entries['text'].data
3672 self.assertEqual(expected_text, data)
3673
3674 def testReplaceCmd(self):
3675 """Test replacing a file fron an image on the command line"""
3676 self._DoReadFileRealDtb('143_replace_all.dts')
3677
3678 try:
3679 tmpdir, updated_fname = self._SetupImageInTmpdir()
3680
3681 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3682 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003683 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003684
3685 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003686 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003687 self.assertEqual(expected, data[:len(expected)])
3688 map_fname = os.path.join(tmpdir, 'image-updated.map')
3689 self.assertFalse(os.path.exists(map_fname))
3690 finally:
3691 shutil.rmtree(tmpdir)
3692
3693 def testReplaceCmdSome(self):
3694 """Test replacing some files fron an image on the command line"""
3695 updated_fname, outdir, expected1, expected2, expected_text = (
3696 self._SetupForReplace())
3697
3698 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3699 'u-boot2', 'text')
3700
Simon Glass80025522022-01-29 14:14:04 -07003701 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003702 image = Image.FromFile(updated_fname)
3703 image.LoadData()
3704 entries = image.GetEntries()
3705
3706 # This one should not change
3707 data = entries['u-boot'].data
3708 self.assertEqual(U_BOOT_DATA, data)
3709
3710 data = entries['u-boot2'].data
3711 self.assertEqual(expected2, data)
3712
3713 data = entries['text'].data
3714 self.assertEqual(expected_text, data)
3715
3716 def testReplaceMissing(self):
3717 """Test replacing entries where the file is missing"""
3718 updated_fname, outdir, expected1, expected2, expected_text = (
3719 self._SetupForReplace())
3720
3721 # Remove one of the files, to generate a warning
3722 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3723 os.remove(u_boot_fname1)
3724
3725 with test_util.capture_sys_output() as (stdout, stderr):
3726 control.ReplaceEntries(updated_fname, None, outdir, [])
3727 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003728 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003729
3730 def testReplaceCmdMap(self):
3731 """Test replacing a file fron an image on the command line"""
3732 self._DoReadFileRealDtb('143_replace_all.dts')
3733
3734 try:
3735 tmpdir, updated_fname = self._SetupImageInTmpdir()
3736
3737 fname = os.path.join(self._indir, 'update-u-boot.bin')
3738 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003739 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003740
3741 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3742 '-f', fname, '-m')
3743 map_fname = os.path.join(tmpdir, 'image-updated.map')
3744 self.assertTrue(os.path.exists(map_fname))
3745 finally:
3746 shutil.rmtree(tmpdir)
3747
3748 def testReplaceNoEntryPaths(self):
3749 """Test replacing an entry without an entry path"""
3750 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003751 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003752 with self.assertRaises(ValueError) as e:
3753 control.ReplaceEntries(image_fname, 'fname', None, [])
3754 self.assertIn('Must specify an entry path to read with -f',
3755 str(e.exception))
3756
3757 def testReplaceTooManyEntryPaths(self):
3758 """Test extracting some entries"""
3759 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003760 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003761 with self.assertRaises(ValueError) as e:
3762 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3763 self.assertIn('Must specify exactly one entry path to write with -f',
3764 str(e.exception))
3765
Simon Glass0b074d62019-08-24 07:22:48 -06003766 def testPackReset16(self):
3767 """Test that an image with an x86 reset16 region can be created"""
3768 data = self._DoReadFile('144_x86_reset16.dts')
3769 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3770
3771 def testPackReset16Spl(self):
3772 """Test that an image with an x86 reset16-spl region can be created"""
3773 data = self._DoReadFile('145_x86_reset16_spl.dts')
3774 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3775
3776 def testPackReset16Tpl(self):
3777 """Test that an image with an x86 reset16-tpl region can be created"""
3778 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3779 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3780
Simon Glass232f90c2019-08-24 07:22:50 -06003781 def testPackIntelFit(self):
3782 """Test that an image with an Intel FIT and pointer can be created"""
3783 data = self._DoReadFile('147_intel_fit.dts')
3784 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3785 fit = data[16:32];
3786 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3787 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3788
3789 image = control.images['image']
3790 entries = image.GetEntries()
3791 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3792 self.assertEqual(expected_ptr, ptr)
3793
3794 def testPackIntelFitMissing(self):
3795 """Test detection of a FIT pointer with not FIT region"""
3796 with self.assertRaises(ValueError) as e:
3797 self._DoReadFile('148_intel_fit_missing.dts')
3798 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3799 str(e.exception))
3800
Simon Glass72555fa2019-11-06 17:22:44 -07003801 def _CheckSymbolsTplSection(self, dts, expected_vals):
3802 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003803 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003804 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003805 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003806 self.assertEqual(expected1, data[:upto1])
3807
3808 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003809 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003810 self.assertEqual(expected2, data[upto1:upto2])
3811
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003812 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003813 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003814 self.assertEqual(expected3, data[upto2:upto3])
3815
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003816 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003817 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3818
3819 def testSymbolsTplSection(self):
3820 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3821 self._SetupSplElf('u_boot_binman_syms')
3822 self._SetupTplElf('u_boot_binman_syms')
3823 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003824 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003825
3826 def testSymbolsTplSectionX86(self):
3827 """Test binman can assign symbols in a section with end-at-4gb"""
3828 self._SetupSplElf('u_boot_binman_syms_x86')
3829 self._SetupTplElf('u_boot_binman_syms_x86')
3830 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003831 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003832 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003833
Simon Glass98c59572019-08-24 07:23:03 -06003834 def testPackX86RomIfwiSectiom(self):
3835 """Test that a section can be placed in an IFWI region"""
3836 self._SetupIfwi('fitimage.bin')
3837 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3838 self._CheckIfwi(data)
3839
Simon Glassba7985d2019-08-24 07:23:07 -06003840 def testPackFspM(self):
3841 """Test that an image with a FSP memory-init binary can be created"""
3842 data = self._DoReadFile('152_intel_fsp_m.dts')
3843 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3844
Simon Glass4d9086d2019-10-20 21:31:35 -06003845 def testPackFspS(self):
3846 """Test that an image with a FSP silicon-init binary can be created"""
3847 data = self._DoReadFile('153_intel_fsp_s.dts')
3848 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003849
Simon Glass9ea87b22019-10-20 21:31:36 -06003850 def testPackFspT(self):
3851 """Test that an image with a FSP temp-ram-init binary can be created"""
3852 data = self._DoReadFile('154_intel_fsp_t.dts')
3853 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3854
Simon Glass48f3aad2020-07-09 18:39:31 -06003855 def testMkimage(self):
3856 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003857 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003858 data = self._DoReadFile('156_mkimage.dts')
3859
3860 # Just check that the data appears in the file somewhere
3861 self.assertIn(U_BOOT_SPL_DATA, data)
3862
Simon Glass66152ce2022-01-09 20:14:09 -07003863 def testMkimageMissing(self):
3864 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003865 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003866 with test_util.capture_sys_output() as (_, stderr):
3867 self._DoTestFile('156_mkimage.dts',
3868 force_missing_bintools='mkimage')
3869 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003870 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003871
Simon Glass5e560182020-07-09 18:39:36 -06003872 def testExtblob(self):
3873 """Test an image with an external blob"""
3874 data = self._DoReadFile('157_blob_ext.dts')
3875 self.assertEqual(REFCODE_DATA, data)
3876
3877 def testExtblobMissing(self):
3878 """Test an image with a missing external blob"""
3879 with self.assertRaises(ValueError) as e:
3880 self._DoReadFile('158_blob_ext_missing.dts')
3881 self.assertIn("Filename 'missing-file' not found in input path",
3882 str(e.exception))
3883
Simon Glass5d94cc62020-07-09 18:39:38 -06003884 def testExtblobMissingOk(self):
3885 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003886 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003887 ret = self._DoTestFile('158_blob_ext_missing.dts',
3888 allow_missing=True)
3889 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003890 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003891 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003892 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003893 self.assertIn('Some images are invalid', err)
3894
3895 def testExtblobMissingOkFlag(self):
3896 """Test an image with an missing external blob allowed with -W"""
3897 with test_util.capture_sys_output() as (stdout, stderr):
3898 ret = self._DoTestFile('158_blob_ext_missing.dts',
3899 allow_missing=True, ignore_missing=True)
3900 self.assertEqual(0, ret)
3901 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003902 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003903 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003904 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003905
3906 def testExtblobMissingOkSect(self):
3907 """Test an image with an missing external blob that is allowed"""
3908 with test_util.capture_sys_output() as (stdout, stderr):
3909 self._DoTestFile('159_blob_ext_missing_sect.dts',
3910 allow_missing=True)
3911 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003912 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003913
Simon Glasse88cef92020-07-09 18:39:41 -06003914 def testPackX86RomMeMissingDesc(self):
3915 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003916 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003917 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003918 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003919 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003920
3921 def testPackX86RomMissingIfwi(self):
3922 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3923 self._SetupIfwi('fitimage.bin')
3924 pathname = os.path.join(self._indir, 'fitimage.bin')
3925 os.remove(pathname)
3926 with test_util.capture_sys_output() as (stdout, stderr):
3927 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3928 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003929 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003930
Simon Glass2a0fa982022-02-11 13:23:21 -07003931 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003932 """Test that zero-size overlapping regions are ignored"""
3933 self._DoTestFile('160_pack_overlap_zero.dts')
3934
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003935 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003936 # The data should be inside the FIT
3937 dtb = fdt.Fdt.FromData(fit_data)
3938 dtb.Scan()
3939 fnode = dtb.GetNode('/images/kernel')
3940 self.assertIn('data', fnode.props)
3941
3942 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003943 tools.write_file(fname, fit_data)
3944 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003945
3946 # Check a few features to make sure the plumbing works. We don't need
3947 # to test the operation of mkimage or dumpimage here. First convert the
3948 # output into a dict where the keys are the fields printed by dumpimage
3949 # and the values are a list of values for each field
3950 lines = out.splitlines()
3951
3952 # Converts "Compression: gzip compressed" into two groups:
3953 # 'Compression' and 'gzip compressed'
3954 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3955 vals = collections.defaultdict(list)
3956 for line in lines:
3957 mat = re_line.match(line)
3958 vals[mat.group(1)].append(mat.group(2))
3959
Brandon Maiera657bc62024-06-04 16:16:05 +00003960 self.assertEqual('FIT description: test-desc', lines[0])
Simon Glass45d556d2020-07-09 18:39:45 -06003961 self.assertIn('Created:', lines[1])
3962 self.assertIn('Image 0 (kernel)', vals)
3963 self.assertIn('Hash value', vals)
3964 data_sizes = vals.get('Data Size')
3965 self.assertIsNotNone(data_sizes)
3966 self.assertEqual(2, len(data_sizes))
3967 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003968 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3969 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3970
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003971 # Check if entry listing correctly omits /images/
3972 image = control.images['image']
3973 fit_entry = image.GetEntries()['fit']
3974 subentries = list(fit_entry.GetEntries().keys())
3975 expected = ['kernel', 'fdt-1']
3976 self.assertEqual(expected, subentries)
3977
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003978 def testSimpleFit(self):
3979 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003980 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003981 data = self._DoReadFile('161_fit.dts')
3982 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3983 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3984 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3985
3986 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3987
3988 def testSimpleFitExpandsSubentries(self):
3989 """Test that FIT images expand their subentries"""
3990 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3991 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3992 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3993 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3994
3995 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003996
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003997 def testSimpleFitImagePos(self):
3998 """Test that we have correct image-pos for FIT subentries"""
3999 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
4000 update_dtb=True)
4001 dtb = fdt.Fdt(out_dtb_fname)
4002 dtb.Scan()
4003 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4004
Simon Glassb7bad182022-03-05 20:19:01 -07004005 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004006 self.assertEqual({
4007 'image-pos': 0,
4008 'offset': 0,
4009 'size': 1890,
4010
4011 'u-boot:image-pos': 0,
4012 'u-boot:offset': 0,
4013 'u-boot:size': 4,
4014
4015 'fit:image-pos': 4,
4016 'fit:offset': 4,
4017 'fit:size': 1840,
4018
Simon Glassb7bad182022-03-05 20:19:01 -07004019 'fit/images/kernel:image-pos': 304,
4020 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004021 'fit/images/kernel:size': 4,
4022
Simon Glassb7bad182022-03-05 20:19:01 -07004023 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004024 'fit/images/kernel/u-boot:offset': 0,
4025 'fit/images/kernel/u-boot:size': 4,
4026
Simon Glassb7bad182022-03-05 20:19:01 -07004027 'fit/images/fdt-1:image-pos': 552,
4028 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004029 'fit/images/fdt-1:size': 6,
4030
Simon Glassb7bad182022-03-05 20:19:01 -07004031 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004032 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
4033 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
4034
4035 'u-boot-nodtb:image-pos': 1844,
4036 'u-boot-nodtb:offset': 1844,
4037 'u-boot-nodtb:size': 46,
4038 }, props)
4039
4040 # Actually check the data is where we think it is
4041 for node, expected in [
4042 ("u-boot", U_BOOT_DATA),
4043 ("fit/images/kernel", U_BOOT_DATA),
4044 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4045 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
4046 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
4047 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4048 ]:
4049 image_pos = props[f"{node}:image-pos"]
4050 size = props[f"{node}:size"]
4051 self.assertEqual(len(expected), size)
4052 self.assertEqual(expected, data[image_pos:image_pos+size])
4053
Simon Glass45d556d2020-07-09 18:39:45 -06004054 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06004055 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06004056 data = self._DoReadFile('162_fit_external.dts')
4057 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
4058
Simon Glass7932c882022-01-09 20:13:39 -07004059 # Size of the external-data region as set up by mkimage
4060 external_data_size = len(U_BOOT_DATA) + 2
4061 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07004062 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07004063 len(U_BOOT_NODTB_DATA))
4064
Simon Glass45d556d2020-07-09 18:39:45 -06004065 # The data should be outside the FIT
4066 dtb = fdt.Fdt.FromData(fit_data)
4067 dtb.Scan()
4068 fnode = dtb.GetNode('/images/kernel')
4069 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07004070 self.assertEqual(len(U_BOOT_DATA),
4071 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4072 fit_pos = 0x400;
4073 self.assertEqual(
4074 fit_pos,
4075 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4076
Brandon Maiera657bc62024-06-04 16:16:05 +00004077 self.assertEqual(expected_size, len(data))
Simon Glass7932c882022-01-09 20:13:39 -07004078 actual_pos = len(U_BOOT_DATA) + fit_pos
4079 self.assertEqual(U_BOOT_DATA + b'aa',
4080 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004081
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004082 def testFitExternalImagePos(self):
4083 """Test that we have correct image-pos for external FIT subentries"""
4084 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4085 update_dtb=True)
4086 dtb = fdt.Fdt(out_dtb_fname)
4087 dtb.Scan()
4088 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4089
4090 self.assertEqual({
4091 'image-pos': 0,
4092 'offset': 0,
4093 'size': 1082,
4094
4095 'u-boot:image-pos': 0,
4096 'u-boot:offset': 0,
4097 'u-boot:size': 4,
4098
4099 'fit:size': 1032,
4100 'fit:offset': 4,
4101 'fit:image-pos': 4,
4102
4103 'fit/images/kernel:size': 4,
4104 'fit/images/kernel:offset': 1024,
4105 'fit/images/kernel:image-pos': 1028,
4106
4107 'fit/images/kernel/u-boot:size': 4,
4108 'fit/images/kernel/u-boot:offset': 0,
4109 'fit/images/kernel/u-boot:image-pos': 1028,
4110
4111 'fit/images/fdt-1:size': 2,
4112 'fit/images/fdt-1:offset': 1028,
4113 'fit/images/fdt-1:image-pos': 1032,
4114
4115 'fit/images/fdt-1/_testing:size': 2,
4116 'fit/images/fdt-1/_testing:offset': 0,
4117 'fit/images/fdt-1/_testing:image-pos': 1032,
4118
4119 'u-boot-nodtb:image-pos': 1036,
4120 'u-boot-nodtb:offset': 1036,
4121 'u-boot-nodtb:size': 46,
4122 }, props)
4123
4124 # Actually check the data is where we think it is
4125 for node, expected in [
4126 ("u-boot", U_BOOT_DATA),
4127 ("fit/images/kernel", U_BOOT_DATA),
4128 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4129 ("fit/images/fdt-1", b'aa'),
4130 ("fit/images/fdt-1/_testing", b'aa'),
4131 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4132 ]:
4133 image_pos = props[f"{node}:image-pos"]
4134 size = props[f"{node}:size"]
4135 self.assertEqual(len(expected), size)
4136 self.assertEqual(expected, data[image_pos:image_pos+size])
4137
Simon Glass66152ce2022-01-09 20:14:09 -07004138 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004139 """Test that binman complains if mkimage is missing"""
4140 with self.assertRaises(ValueError) as e:
4141 self._DoTestFile('162_fit_external.dts',
4142 force_missing_bintools='mkimage')
4143 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4144 str(e.exception))
4145
4146 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004147 """Test that binman still produces a FIT image if mkimage is missing"""
4148 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004149 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004150 force_missing_bintools='mkimage')
4151 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004152 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004153
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004154 def testSectionIgnoreHashSignature(self):
4155 """Test that sections ignore hash, signature nodes for its data"""
4156 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4157 expected = (U_BOOT_DATA + U_BOOT_DATA)
4158 self.assertEqual(expected, data)
4159
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004160 def testPadInSections(self):
4161 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004162 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4163 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004164 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4165 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004166 U_BOOT_DATA)
4167 self.assertEqual(expected, data)
4168
Simon Glassd12599d2020-10-26 17:40:09 -06004169 dtb = fdt.Fdt(out_dtb_fname)
4170 dtb.Scan()
4171 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4172 expected = {
4173 'image-pos': 0,
4174 'offset': 0,
4175 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4176
4177 'section:image-pos': 0,
4178 'section:offset': 0,
4179 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4180
4181 'section/before:image-pos': 0,
4182 'section/before:offset': 0,
4183 'section/before:size': len(U_BOOT_DATA),
4184
4185 'section/u-boot:image-pos': 4,
4186 'section/u-boot:offset': 4,
4187 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4188
4189 'section/after:image-pos': 26,
4190 'section/after:offset': 26,
4191 'section/after:size': len(U_BOOT_DATA),
4192 }
4193 self.assertEqual(expected, props)
4194
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004195 def testFitImageSubentryAlignment(self):
4196 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004197 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004198 entry_args = {
4199 'test-id': TEXT_DATA,
4200 }
4201 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4202 entry_args=entry_args)
4203 dtb = fdt.Fdt.FromData(data)
4204 dtb.Scan()
4205
4206 node = dtb.GetNode('/images/kernel')
4207 data = dtb.GetProps(node)["data"].bytes
4208 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004209 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4210 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004211 self.assertEqual(expected, data)
4212
4213 node = dtb.GetNode('/images/fdt-1')
4214 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004215 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4216 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004217 U_BOOT_DTB_DATA)
4218 self.assertEqual(expected, data)
4219
4220 def testFitExtblobMissingOk(self):
4221 """Test a FIT with a missing external blob that is allowed"""
4222 with test_util.capture_sys_output() as (stdout, stderr):
4223 self._DoTestFile('168_fit_missing_blob.dts',
4224 allow_missing=True)
4225 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004226 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004227
Simon Glass21db0ff2020-09-01 05:13:54 -06004228 def testBlobNamedByArgMissing(self):
4229 """Test handling of a missing entry arg"""
4230 with self.assertRaises(ValueError) as e:
4231 self._DoReadFile('068_blob_named_by_arg.dts')
4232 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4233 str(e.exception))
4234
Simon Glass559c4de2020-09-01 05:13:58 -06004235 def testPackBl31(self):
4236 """Test that an image with an ATF BL31 binary can be created"""
4237 data = self._DoReadFile('169_atf_bl31.dts')
4238 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4239
Samuel Holland9d8cc632020-10-21 21:12:15 -05004240 def testPackScp(self):
4241 """Test that an image with an SCP binary can be created"""
4242 data = self._DoReadFile('172_scp.dts')
4243 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4244
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004245 def CheckFitFdt(self, dts='170_fit_fdt.dts', use_fdt_list=True,
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004246 default_dt=None, use_seq_num=True):
Simon Glasscd2783e2024-07-20 11:49:46 +01004247 """Check an image with an FIT with multiple FDT images"""
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004248 def _CheckFdt(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004249 """Check the FDT nodes
4250
4251 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004252 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004253 expected_data: Expected contents of 'data' property
4254 """
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004255 name = 'fdt-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004256 fnode = dtb.GetNode('/images/%s' % name)
4257 self.assertIsNotNone(fnode)
4258 self.assertEqual({'description','type', 'compression', 'data'},
4259 set(fnode.props.keys()))
4260 self.assertEqual(expected_data, fnode.props['data'].bytes)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004261 description = (
4262 'fdt-test-fdt%s.dtb' % val if len(val) == 1 else
4263 'fdt-%s.dtb' % val
4264 )
4265 self.assertEqual(description, fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004266 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004267
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004268 def _CheckConfig(val, expected_data):
Simon Glassa435cd12020-09-01 05:13:59 -06004269 """Check the configuration nodes
4270
4271 Args:
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004272 val: Sequence number to check (0 or 1) or fdt name
Simon Glassa435cd12020-09-01 05:13:59 -06004273 expected_data: Expected contents of 'data' property
4274 """
4275 cnode = dtb.GetNode('/configurations')
4276 self.assertIn('default', cnode.props)
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004277 default = (
4278 'config-2' if len(val) == 1 else
4279 'config-test-fdt2'
4280 )
4281 self.assertEqual(default, cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004282
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004283 name = 'config-%s' % val
Simon Glassa435cd12020-09-01 05:13:59 -06004284 fnode = dtb.GetNode('/configurations/%s' % name)
4285 self.assertIsNotNone(fnode)
4286 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4287 set(fnode.props.keys()))
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004288 description = (
4289 'conf-test-fdt%s.dtb' % val if len(val) == 1 else
4290 'conf-%s.dtb' % val
4291 )
4292 self.assertEqual(description, fnode.props['description'].value)
4293 self.assertEqual('fdt-%s' % val, fnode.props['fdt'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004294
4295 entry_args = {
Simon Glass1032acc2020-09-06 10:39:08 -06004296 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004297 }
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004298 extra_indirs = None
Simon Glasscd2783e2024-07-20 11:49:46 +01004299 if use_fdt_list:
4300 entry_args['of-list'] = 'test-fdt1 test-fdt2'
Simon Glassd2a9d6e2024-08-26 13:11:37 -06004301 if default_dt:
4302 entry_args['default-dt'] = default_dt
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004303 if use_fdt_list:
4304 extra_indirs = [os.path.join(self._indir, TEST_FDT_SUBDIR)]
Simon Glassa435cd12020-09-01 05:13:59 -06004305 data = self._DoReadFileDtb(
Simon Glasscd2783e2024-07-20 11:49:46 +01004306 dts,
Simon Glassa435cd12020-09-01 05:13:59 -06004307 entry_args=entry_args,
Paul HENRYS87a8e7c2024-11-25 19:16:54 +01004308 extra_indirs=extra_indirs)[0]
Simon Glassa435cd12020-09-01 05:13:59 -06004309 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4310 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4311
4312 dtb = fdt.Fdt.FromData(fit_data)
4313 dtb.Scan()
4314 fnode = dtb.GetNode('/images/kernel')
4315 self.assertIn('data', fnode.props)
4316
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004317 if use_seq_num == True:
4318 # Check all the properties in fdt-1 and fdt-2
4319 _CheckFdt('1', TEST_FDT1_DATA)
4320 _CheckFdt('2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004321
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01004322 # Check configurations
4323 _CheckConfig('1', TEST_FDT1_DATA)
4324 _CheckConfig('2', TEST_FDT2_DATA)
4325 else:
4326 # Check all the properties in fdt-1 and fdt-2
4327 _CheckFdt('test-fdt1', TEST_FDT1_DATA)
4328 _CheckFdt('test-fdt2', TEST_FDT2_DATA)
4329
4330 # Check configurations
4331 _CheckConfig('test-fdt1', TEST_FDT1_DATA)
4332 _CheckConfig('test-fdt2', TEST_FDT2_DATA)
Simon Glassa435cd12020-09-01 05:13:59 -06004333
Simon Glasscd2783e2024-07-20 11:49:46 +01004334 def testFitFdt(self):
4335 """Test an image with an FIT with multiple FDT images"""
4336 self.CheckFitFdt()
4337
Simon Glassa435cd12020-09-01 05:13:59 -06004338 def testFitFdtMissingList(self):
4339 """Test handling of a missing 'of-list' entry arg"""
4340 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004341 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004342 self.assertIn("Generator node requires 'of-list' entry argument",
4343 str(e.exception))
4344
4345 def testFitFdtEmptyList(self):
4346 """Test handling of an empty 'of-list' entry arg"""
4347 entry_args = {
4348 'of-list': '',
4349 }
4350 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4351
4352 def testFitFdtMissingProp(self):
4353 """Test handling of a missing 'fit,fdt-list' property"""
4354 with self.assertRaises(ValueError) as e:
4355 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4356 self.assertIn("Generator node requires 'fit,fdt-list' property",
4357 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004358
Simon Glass1032acc2020-09-06 10:39:08 -06004359 def testFitFdtMissing(self):
4360 """Test handling of a missing 'default-dt' entry arg"""
4361 entry_args = {
4362 'of-list': 'test-fdt1 test-fdt2',
4363 }
4364 with self.assertRaises(ValueError) as e:
4365 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004366 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004367 entry_args=entry_args,
4368 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4369 self.assertIn("Generated 'default' node requires default-dt entry argument",
4370 str(e.exception))
4371
4372 def testFitFdtNotInList(self):
4373 """Test handling of a default-dt that is not in the of-list"""
4374 entry_args = {
4375 'of-list': 'test-fdt1 test-fdt2',
4376 'default-dt': 'test-fdt3',
4377 }
4378 with self.assertRaises(ValueError) as e:
4379 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004380 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004381 entry_args=entry_args,
4382 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4383 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4384 str(e.exception))
4385
Simon Glassa820af72020-09-06 10:39:09 -06004386 def testFitExtblobMissingHelp(self):
4387 """Test display of help messages when an external blob is missing"""
4388 control.missing_blob_help = control._ReadMissingBlobHelp()
4389 control.missing_blob_help['wibble'] = 'Wibble test'
4390 control.missing_blob_help['another'] = 'Another test'
4391 with test_util.capture_sys_output() as (stdout, stderr):
4392 self._DoTestFile('168_fit_missing_blob.dts',
4393 allow_missing=True)
4394 err = stderr.getvalue()
4395
4396 # We can get the tag from the name, the type or the missing-msg
4397 # property. Check all three.
4398 self.assertIn('You may need to build ARM Trusted', err)
4399 self.assertIn('Wibble test', err)
4400 self.assertIn('Another test', err)
4401
Simon Glass6f1f4d42020-09-06 10:35:32 -06004402 def testMissingBlob(self):
4403 """Test handling of a blob containing a missing file"""
4404 with self.assertRaises(ValueError) as e:
4405 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4406 self.assertIn("Filename 'missing' not found in input path",
4407 str(e.exception))
4408
Simon Glassa0729502020-09-06 10:35:33 -06004409 def testEnvironment(self):
4410 """Test adding a U-Boot environment"""
4411 data = self._DoReadFile('174_env.dts')
4412 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4413 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4414 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4415 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4416 env)
4417
4418 def testEnvironmentNoSize(self):
4419 """Test that a missing 'size' property is detected"""
4420 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004421 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004422 self.assertIn("'u-boot-env' entry must have a size property",
4423 str(e.exception))
4424
4425 def testEnvironmentTooSmall(self):
4426 """Test handling of an environment that does not fit"""
4427 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004428 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004429
4430 # checksum, start byte, environment with \0 terminator, final \0
4431 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4432 short = need - 0x8
4433 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4434 str(e.exception))
4435
Simon Glassd1fdf752020-10-26 17:40:01 -06004436 def testSkipAtStart(self):
4437 """Test handling of skip-at-start section"""
4438 data = self._DoReadFile('177_skip_at_start.dts')
4439 self.assertEqual(U_BOOT_DATA, data)
4440
4441 image = control.images['image']
4442 entries = image.GetEntries()
4443 section = entries['section']
4444 self.assertEqual(0, section.offset)
4445 self.assertEqual(len(U_BOOT_DATA), section.size)
4446 self.assertEqual(U_BOOT_DATA, section.GetData())
4447
4448 entry = section.GetEntries()['u-boot']
4449 self.assertEqual(16, entry.offset)
4450 self.assertEqual(len(U_BOOT_DATA), entry.size)
4451 self.assertEqual(U_BOOT_DATA, entry.data)
4452
4453 def testSkipAtStartPad(self):
4454 """Test handling of skip-at-start section with padded entry"""
4455 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004456 before = tools.get_bytes(0, 8)
4457 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004458 all = before + U_BOOT_DATA + after
4459 self.assertEqual(all, data)
4460
4461 image = control.images['image']
4462 entries = image.GetEntries()
4463 section = entries['section']
4464 self.assertEqual(0, section.offset)
4465 self.assertEqual(len(all), section.size)
4466 self.assertEqual(all, section.GetData())
4467
4468 entry = section.GetEntries()['u-boot']
4469 self.assertEqual(16, entry.offset)
4470 self.assertEqual(len(all), entry.size)
4471 self.assertEqual(U_BOOT_DATA, entry.data)
4472
4473 def testSkipAtStartSectionPad(self):
4474 """Test handling of skip-at-start section with padding"""
4475 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004476 before = tools.get_bytes(0, 8)
4477 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004478 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004479 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004480
4481 image = control.images['image']
4482 entries = image.GetEntries()
4483 section = entries['section']
4484 self.assertEqual(0, section.offset)
4485 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004486 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004487 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004488
4489 entry = section.GetEntries()['u-boot']
4490 self.assertEqual(16, entry.offset)
4491 self.assertEqual(len(U_BOOT_DATA), entry.size)
4492 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004493
Simon Glassbb395742020-10-26 17:40:14 -06004494 def testSectionPad(self):
4495 """Testing padding with sections"""
4496 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004497 expected = (tools.get_bytes(ord('&'), 3) +
4498 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004499 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004500 tools.get_bytes(ord('!'), 1) +
4501 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004502 self.assertEqual(expected, data)
4503
4504 def testSectionAlign(self):
4505 """Testing alignment with sections"""
4506 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4507 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004508 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004509 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004510 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004511 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004512 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4513 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004514 self.assertEqual(expected, data)
4515
Simon Glassd92c8362020-10-26 17:40:25 -06004516 def testCompressImage(self):
4517 """Test compression of the entire image"""
4518 self._CheckLz4()
4519 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4520 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4521 dtb = fdt.Fdt(out_dtb_fname)
4522 dtb.Scan()
4523 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4524 'uncomp-size'])
4525 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004526 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004527
4528 # Do a sanity check on various fields
4529 image = control.images['image']
4530 entries = image.GetEntries()
4531 self.assertEqual(2, len(entries))
4532
4533 entry = entries['blob']
4534 self.assertEqual(COMPRESS_DATA, entry.data)
4535 self.assertEqual(len(COMPRESS_DATA), entry.size)
4536
4537 entry = entries['u-boot']
4538 self.assertEqual(U_BOOT_DATA, entry.data)
4539 self.assertEqual(len(U_BOOT_DATA), entry.size)
4540
4541 self.assertEqual(len(data), image.size)
4542 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4543 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4544 orig = self._decompress(image.data)
4545 self.assertEqual(orig, image.uncomp_data)
4546
4547 expected = {
4548 'blob:offset': 0,
4549 'blob:size': len(COMPRESS_DATA),
4550 'u-boot:offset': len(COMPRESS_DATA),
4551 'u-boot:size': len(U_BOOT_DATA),
4552 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4553 'offset': 0,
4554 'image-pos': 0,
4555 'size': len(data),
4556 }
4557 self.assertEqual(expected, props)
4558
4559 def testCompressImageLess(self):
4560 """Test compression where compression reduces the image size"""
4561 self._CheckLz4()
4562 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4563 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4564 dtb = fdt.Fdt(out_dtb_fname)
4565 dtb.Scan()
4566 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4567 'uncomp-size'])
4568 orig = self._decompress(data)
4569
Brandon Maiera657bc62024-06-04 16:16:05 +00004570 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004571
4572 # Do a sanity check on various fields
4573 image = control.images['image']
4574 entries = image.GetEntries()
4575 self.assertEqual(2, len(entries))
4576
4577 entry = entries['blob']
4578 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4579 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4580
4581 entry = entries['u-boot']
4582 self.assertEqual(U_BOOT_DATA, entry.data)
4583 self.assertEqual(len(U_BOOT_DATA), entry.size)
4584
4585 self.assertEqual(len(data), image.size)
4586 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4587 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4588 image.uncomp_size)
4589 orig = self._decompress(image.data)
4590 self.assertEqual(orig, image.uncomp_data)
4591
4592 expected = {
4593 'blob:offset': 0,
4594 'blob:size': len(COMPRESS_DATA_BIG),
4595 'u-boot:offset': len(COMPRESS_DATA_BIG),
4596 'u-boot:size': len(U_BOOT_DATA),
4597 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4598 'offset': 0,
4599 'image-pos': 0,
4600 'size': len(data),
4601 }
4602 self.assertEqual(expected, props)
4603
4604 def testCompressSectionSize(self):
4605 """Test compression of a section with a fixed size"""
4606 self._CheckLz4()
4607 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4608 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4609 dtb = fdt.Fdt(out_dtb_fname)
4610 dtb.Scan()
4611 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4612 'uncomp-size'])
4613 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004614 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004615 expected = {
4616 'section/blob:offset': 0,
4617 'section/blob:size': len(COMPRESS_DATA),
4618 'section/u-boot:offset': len(COMPRESS_DATA),
4619 'section/u-boot:size': len(U_BOOT_DATA),
4620 'section:offset': 0,
4621 'section:image-pos': 0,
4622 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4623 'section:size': 0x30,
4624 'offset': 0,
4625 'image-pos': 0,
4626 'size': 0x30,
4627 }
4628 self.assertEqual(expected, props)
4629
4630 def testCompressSection(self):
4631 """Test compression of a section with no fixed size"""
4632 self._CheckLz4()
4633 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4634 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4635 dtb = fdt.Fdt(out_dtb_fname)
4636 dtb.Scan()
4637 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4638 'uncomp-size'])
4639 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004640 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004641 expected = {
4642 'section/blob:offset': 0,
4643 'section/blob:size': len(COMPRESS_DATA),
4644 'section/u-boot:offset': len(COMPRESS_DATA),
4645 'section/u-boot:size': len(U_BOOT_DATA),
4646 'section:offset': 0,
4647 'section:image-pos': 0,
4648 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4649 'section:size': len(data),
4650 'offset': 0,
4651 'image-pos': 0,
4652 'size': len(data),
4653 }
4654 self.assertEqual(expected, props)
4655
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004656 def testLz4Missing(self):
4657 """Test that binman still produces an image if lz4 is missing"""
4658 with test_util.capture_sys_output() as (_, stderr):
4659 self._DoTestFile('185_compress_section.dts',
4660 force_missing_bintools='lz4')
4661 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004662 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004663
Simon Glassd92c8362020-10-26 17:40:25 -06004664 def testCompressExtra(self):
4665 """Test compression of a section with no fixed size"""
4666 self._CheckLz4()
4667 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4668 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4669 dtb = fdt.Fdt(out_dtb_fname)
4670 dtb.Scan()
4671 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4672 'uncomp-size'])
4673
4674 base = data[len(U_BOOT_DATA):]
Brandon Maiera657bc62024-06-04 16:16:05 +00004675 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glassd92c8362020-10-26 17:40:25 -06004676 rest = base[len(U_BOOT_DATA):]
4677
4678 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004679 bintool = self.comp_bintools['lz4']
4680 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004681 data1 = rest[:len(expect1)]
4682 section1 = self._decompress(data1)
Brandon Maiera657bc62024-06-04 16:16:05 +00004683 self.assertEqual(expect1, data1)
4684 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glassd92c8362020-10-26 17:40:25 -06004685 rest1 = rest[len(expect1):]
4686
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004687 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004688 data2 = rest1[:len(expect2)]
4689 section2 = self._decompress(data2)
Brandon Maiera657bc62024-06-04 16:16:05 +00004690 self.assertEqual(expect2, data2)
4691 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glassd92c8362020-10-26 17:40:25 -06004692 rest2 = rest1[len(expect2):]
4693
4694 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4695 len(expect2) + len(U_BOOT_DATA))
Brandon Maiera657bc62024-06-04 16:16:05 +00004696 #self.assertEqual(expect_size, len(data))
Simon Glassd92c8362020-10-26 17:40:25 -06004697
Brandon Maiera657bc62024-06-04 16:16:05 +00004698 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glassd92c8362020-10-26 17:40:25 -06004699
4700 self.maxDiff = None
4701 expected = {
4702 'u-boot:offset': 0,
4703 'u-boot:image-pos': 0,
4704 'u-boot:size': len(U_BOOT_DATA),
4705
4706 'base:offset': len(U_BOOT_DATA),
4707 'base:image-pos': len(U_BOOT_DATA),
4708 'base:size': len(data) - len(U_BOOT_DATA),
4709 'base/u-boot:offset': 0,
4710 'base/u-boot:image-pos': len(U_BOOT_DATA),
4711 'base/u-boot:size': len(U_BOOT_DATA),
4712 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4713 len(expect2),
4714 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4715 len(expect2),
4716 'base/u-boot2:size': len(U_BOOT_DATA),
4717
4718 'base/section:offset': len(U_BOOT_DATA),
4719 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4720 'base/section:size': len(expect1),
4721 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4722 'base/section/blob:offset': 0,
4723 'base/section/blob:size': len(COMPRESS_DATA),
4724 'base/section/u-boot:offset': len(COMPRESS_DATA),
4725 'base/section/u-boot:size': len(U_BOOT_DATA),
4726
4727 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4728 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4729 'base/section2:size': len(expect2),
4730 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4731 'base/section2/blob:offset': 0,
4732 'base/section2/blob:size': len(COMPRESS_DATA),
4733 'base/section2/blob2:offset': len(COMPRESS_DATA),
4734 'base/section2/blob2:size': len(COMPRESS_DATA),
4735
4736 'offset': 0,
4737 'image-pos': 0,
4738 'size': len(data),
4739 }
4740 self.assertEqual(expected, props)
4741
Simon Glassecbe4732021-01-06 21:35:15 -07004742 def testSymbolsSubsection(self):
4743 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004744 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004745
Simon Glass3fb25402021-01-06 21:35:16 -07004746 def testReadImageEntryArg(self):
4747 """Test reading an image that would need an entry arg to generate"""
4748 entry_args = {
4749 'cros-ec-rw-path': 'ecrw.bin',
4750 }
4751 data = self.data = self._DoReadFileDtb(
4752 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4753 entry_args=entry_args)
4754
Simon Glass80025522022-01-29 14:14:04 -07004755 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004756 orig_image = control.images['image']
4757
4758 # This should not generate an error about the missing 'cros-ec-rw-path'
4759 # since we are reading the image from a file. Compare with
4760 # testEntryArgsRequired()
4761 image = Image.FromFile(image_fname)
4762 self.assertEqual(orig_image.GetEntries().keys(),
4763 image.GetEntries().keys())
4764
Simon Glassa2af7302021-01-06 21:35:18 -07004765 def testFilesAlign(self):
4766 """Test alignment with files"""
4767 data = self._DoReadFile('190_files_align.dts')
4768
4769 # The first string is 15 bytes so will align to 16
4770 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4771 self.assertEqual(expect, data)
4772
Simon Glassdb84b562021-01-06 21:35:19 -07004773 def testReadImageSkip(self):
4774 """Test reading an image and accessing its FDT map"""
4775 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004776 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004777 orig_image = control.images['image']
4778 image = Image.FromFile(image_fname)
4779 self.assertEqual(orig_image.GetEntries().keys(),
4780 image.GetEntries().keys())
4781
4782 orig_entry = orig_image.GetEntries()['fdtmap']
4783 entry = image.GetEntries()['fdtmap']
4784 self.assertEqual(orig_entry.offset, entry.offset)
4785 self.assertEqual(orig_entry.size, entry.size)
4786 self.assertEqual(16, entry.image_pos)
4787
4788 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4789
Brandon Maiera657bc62024-06-04 16:16:05 +00004790 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glassdb84b562021-01-06 21:35:19 -07004791
Simon Glassc98de972021-03-18 20:24:57 +13004792 def testTplNoDtb(self):
4793 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004794 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004795 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4796 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4797 data[:len(U_BOOT_TPL_NODTB_DATA)])
4798
Simon Glass63f41d42021-03-18 20:24:58 +13004799 def testTplBssPad(self):
4800 """Test that we can pad TPL's BSS with zeros"""
4801 # ELF file with a '__bss_size' symbol
4802 self._SetupTplElf()
4803 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004804 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004805 data)
4806
4807 def testTplBssPadMissing(self):
4808 """Test that a missing symbol is detected"""
4809 self._SetupTplElf('u_boot_ucode_ptr')
4810 with self.assertRaises(ValueError) as e:
4811 self._DoReadFile('193_tpl_bss_pad.dts')
4812 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4813 str(e.exception))
4814
Simon Glass718b5292021-03-18 20:25:07 +13004815 def checkDtbSizes(self, data, pad_len, start):
4816 """Check the size arguments in a dtb embedded in an image
4817
4818 Args:
4819 data: The image data
4820 pad_len: Length of the pad section in the image, in bytes
4821 start: Start offset of the devicetree to examine, within the image
4822
4823 Returns:
4824 Size of the devicetree in bytes
4825 """
4826 dtb_data = data[start:]
4827 dtb = fdt.Fdt.FromData(dtb_data)
4828 fdt_size = dtb.GetFdtObj().totalsize()
4829 dtb.Scan()
4830 props = self._GetPropTree(dtb, 'size')
4831 self.assertEqual({
4832 'size': len(data),
4833 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4834 'u-boot-spl/u-boot-spl-dtb:size': 801,
4835 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4836 'u-boot-spl:size': 860,
4837 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4838 'u-boot/u-boot-dtb:size': 781,
4839 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4840 'u-boot:size': 827,
4841 }, props)
4842 return fdt_size
4843
4844 def testExpanded(self):
4845 """Test that an expanded entry type is selected when needed"""
4846 self._SetupSplElf()
4847 self._SetupTplElf()
4848
4849 # SPL has a devicetree, TPL does not
4850 entry_args = {
4851 'spl-dtb': '1',
4852 'spl-bss-pad': 'y',
4853 'tpl-dtb': '',
4854 }
4855 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4856 entry_args=entry_args)
4857 image = control.images['image']
4858 entries = image.GetEntries()
4859 self.assertEqual(3, len(entries))
4860
4861 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4862 self.assertIn('u-boot', entries)
4863 entry = entries['u-boot']
4864 self.assertEqual('u-boot-expanded', entry.etype)
4865 subent = entry.GetEntries()
4866 self.assertEqual(2, len(subent))
4867 self.assertIn('u-boot-nodtb', subent)
4868 self.assertIn('u-boot-dtb', subent)
4869
4870 # Second, u-boot-spl, which should be expanded into three parts
4871 self.assertIn('u-boot-spl', entries)
4872 entry = entries['u-boot-spl']
4873 self.assertEqual('u-boot-spl-expanded', entry.etype)
4874 subent = entry.GetEntries()
4875 self.assertEqual(3, len(subent))
4876 self.assertIn('u-boot-spl-nodtb', subent)
4877 self.assertIn('u-boot-spl-bss-pad', subent)
4878 self.assertIn('u-boot-spl-dtb', subent)
4879
4880 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4881 # devicetree
4882 self.assertIn('u-boot-tpl', entries)
4883 entry = entries['u-boot-tpl']
4884 self.assertEqual('u-boot-tpl', entry.etype)
4885 self.assertEqual(None, entry.GetEntries())
4886
4887 def testExpandedTpl(self):
4888 """Test that an expanded entry type is selected for TPL when needed"""
4889 self._SetupTplElf()
4890
4891 entry_args = {
4892 'tpl-bss-pad': 'y',
4893 'tpl-dtb': 'y',
4894 }
4895 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4896 entry_args=entry_args)
4897 image = control.images['image']
4898 entries = image.GetEntries()
4899 self.assertEqual(1, len(entries))
4900
4901 # We only have u-boot-tpl, which be expanded
4902 self.assertIn('u-boot-tpl', entries)
4903 entry = entries['u-boot-tpl']
4904 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4905 subent = entry.GetEntries()
4906 self.assertEqual(3, len(subent))
4907 self.assertIn('u-boot-tpl-nodtb', subent)
4908 self.assertIn('u-boot-tpl-bss-pad', subent)
4909 self.assertIn('u-boot-tpl-dtb', subent)
4910
4911 def testExpandedNoPad(self):
4912 """Test an expanded entry without BSS pad enabled"""
4913 self._SetupSplElf()
4914 self._SetupTplElf()
4915
4916 # SPL has a devicetree, TPL does not
4917 entry_args = {
4918 'spl-dtb': 'something',
4919 'spl-bss-pad': 'n',
4920 'tpl-dtb': '',
4921 }
4922 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4923 entry_args=entry_args)
4924 image = control.images['image']
4925 entries = image.GetEntries()
4926
4927 # Just check u-boot-spl, which should be expanded into two parts
4928 self.assertIn('u-boot-spl', entries)
4929 entry = entries['u-boot-spl']
4930 self.assertEqual('u-boot-spl-expanded', entry.etype)
4931 subent = entry.GetEntries()
4932 self.assertEqual(2, len(subent))
4933 self.assertIn('u-boot-spl-nodtb', subent)
4934 self.assertIn('u-boot-spl-dtb', subent)
4935
4936 def testExpandedTplNoPad(self):
4937 """Test that an expanded entry type with padding disabled in TPL"""
4938 self._SetupTplElf()
4939
4940 entry_args = {
4941 'tpl-bss-pad': '',
4942 'tpl-dtb': 'y',
4943 }
4944 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4945 entry_args=entry_args)
4946 image = control.images['image']
4947 entries = image.GetEntries()
4948 self.assertEqual(1, len(entries))
4949
4950 # We only have u-boot-tpl, which be expanded
4951 self.assertIn('u-boot-tpl', entries)
4952 entry = entries['u-boot-tpl']
4953 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4954 subent = entry.GetEntries()
4955 self.assertEqual(2, len(subent))
4956 self.assertIn('u-boot-tpl-nodtb', subent)
4957 self.assertIn('u-boot-tpl-dtb', subent)
4958
4959 def testFdtInclude(self):
4960 """Test that an Fdt is update within all binaries"""
4961 self._SetupSplElf()
4962 self._SetupTplElf()
4963
4964 # SPL has a devicetree, TPL does not
4965 self.maxDiff = None
4966 entry_args = {
4967 'spl-dtb': '1',
4968 'spl-bss-pad': 'y',
4969 'tpl-dtb': '',
4970 }
4971 # Build the image. It includes two separate devicetree binaries, each
4972 # with their own contents, but all contain the binman definition.
4973 data = self._DoReadFileDtb(
4974 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4975 update_dtb=True, entry_args=entry_args)[0]
4976 pad_len = 10
4977
4978 # Check the U-Boot dtb
4979 start = len(U_BOOT_NODTB_DATA)
4980 fdt_size = self.checkDtbSizes(data, pad_len, start)
4981
4982 # Now check SPL
4983 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4984 fdt_size = self.checkDtbSizes(data, pad_len, start)
4985
4986 # TPL has no devicetree
4987 start += fdt_size + len(U_BOOT_TPL_DATA)
4988 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004989
Simon Glass7098b7f2021-03-21 18:24:30 +13004990 def testSymbolsExpanded(self):
4991 """Test binman can assign symbols in expanded entries"""
4992 entry_args = {
4993 'spl-dtb': '1',
4994 }
4995 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4996 U_BOOT_SPL_DTB_DATA, 0x38,
4997 entry_args=entry_args, use_expanded=True)
4998
Simon Glasse1915782021-03-21 18:24:31 +13004999 def testCollection(self):
5000 """Test a collection"""
5001 data = self._DoReadFile('198_collection.dts')
5002 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07005003 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5004 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13005005 data)
5006
Simon Glass27a7f772021-03-21 18:24:32 +13005007 def testCollectionSection(self):
5008 """Test a collection where a section must be built first"""
5009 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07005010 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13005011 # building the contents, producing an error is anything is still
5012 # missing.
5013 data = self._DoReadFile('199_collection_section.dts')
5014 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07005015 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
5016 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13005017 data)
5018
Simon Glassf427c5f2021-03-21 18:24:33 +13005019 def testAlignDefault(self):
5020 """Test that default alignment works on sections"""
5021 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07005022 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13005023 U_BOOT_DATA)
5024 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07005025 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13005026 # No alignment within the nested section
5027 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
5028 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07005029 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13005030 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13005031
Bin Mengc0b15742021-05-10 20:23:33 +08005032 def testPackOpenSBI(self):
5033 """Test that an image with an OpenSBI binary can be created"""
5034 data = self._DoReadFile('201_opensbi.dts')
5035 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
5036
Simon Glass76f496d2021-07-06 10:36:37 -06005037 def testSectionsSingleThread(self):
5038 """Test sections without multithreading"""
5039 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07005040 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
5041 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
5042 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06005043 self.assertEqual(expected, data)
5044
5045 def testThreadTimeout(self):
5046 """Test handling a thread that takes too long"""
5047 with self.assertRaises(ValueError) as e:
5048 self._DoTestFile('202_section_timeout.dts',
5049 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06005050 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06005051
Simon Glass748a1d42021-07-06 10:36:41 -06005052 def testTiming(self):
5053 """Test output of timing information"""
5054 data = self._DoReadFile('055_sections.dts')
5055 with test_util.capture_sys_output() as (stdout, stderr):
5056 state.TimingShow()
5057 self.assertIn('read:', stdout.getvalue())
5058 self.assertIn('compress:', stdout.getvalue())
5059
Simon Glassadfb8492021-11-03 21:09:18 -06005060 def testUpdateFdtInElf(self):
5061 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005062 if not elf.ELF_TOOLS:
5063 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005064 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5065 outfile = os.path.join(self._indir, 'u-boot.out')
5066 begin_sym = 'dtb_embed_begin'
5067 end_sym = 'dtb_embed_end'
5068 retcode = self._DoTestFile(
5069 '060_fdt_update.dts', update_dtb=True,
5070 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5071 self.assertEqual(0, retcode)
5072
5073 # Check that the output file does in fact contact a dtb with the binman
5074 # definition in the correct place
5075 syms = elf.GetSymbolFileOffset(infile,
5076 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07005077 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06005078 dtb_data = data[syms['dtb_embed_begin'].offset:
5079 syms['dtb_embed_end'].offset]
5080
5081 dtb = fdt.Fdt.FromData(dtb_data)
5082 dtb.Scan()
5083 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
5084 self.assertEqual({
5085 'image-pos': 0,
5086 'offset': 0,
5087 '_testing:offset': 32,
5088 '_testing:size': 2,
5089 '_testing:image-pos': 32,
5090 'section@0/u-boot:offset': 0,
5091 'section@0/u-boot:size': len(U_BOOT_DATA),
5092 'section@0/u-boot:image-pos': 0,
5093 'section@0:offset': 0,
5094 'section@0:size': 16,
5095 'section@0:image-pos': 0,
5096
5097 'section@1/u-boot:offset': 0,
5098 'section@1/u-boot:size': len(U_BOOT_DATA),
5099 'section@1/u-boot:image-pos': 16,
5100 'section@1:offset': 16,
5101 'section@1:size': 16,
5102 'section@1:image-pos': 16,
5103 'size': 40
5104 }, props)
5105
5106 def testUpdateFdtInElfInvalid(self):
5107 """Test that invalid args are detected with --update-fdt-in-elf"""
5108 with self.assertRaises(ValueError) as e:
5109 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5110 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5111 str(e.exception))
5112
5113 def testUpdateFdtInElfNoSyms(self):
5114 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005115 if not elf.ELF_TOOLS:
5116 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005117 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5118 outfile = ''
5119 begin_sym = 'wrong_begin'
5120 end_sym = 'wrong_end'
5121 with self.assertRaises(ValueError) as e:
5122 self._DoTestFile(
5123 '060_fdt_update.dts',
5124 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5125 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5126 str(e.exception))
5127
5128 def testUpdateFdtInElfTooSmall(self):
5129 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005130 if not elf.ELF_TOOLS:
5131 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005132 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5133 outfile = os.path.join(self._indir, 'u-boot.out')
5134 begin_sym = 'dtb_embed_begin'
5135 end_sym = 'dtb_embed_end'
5136 with self.assertRaises(ValueError) as e:
5137 self._DoTestFile(
5138 '060_fdt_update.dts', update_dtb=True,
5139 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5140 self.assertRegex(
5141 str(e.exception),
5142 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5143
Simon Glass88e04da2021-11-23 11:03:42 -07005144 def testVersion(self):
5145 """Test we can get the binman version"""
5146 version = '(unreleased)'
5147 self.assertEqual(version, state.GetVersion(self._indir))
5148
5149 with self.assertRaises(SystemExit):
5150 with test_util.capture_sys_output() as (_, stderr):
5151 self._DoBinman('-V')
5152 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5153
5154 # Try running the tool too, just to be safe
5155 result = self._RunBinman('-V')
5156 self.assertEqual('Binman %s\n' % version, result.stderr)
5157
5158 # Set up a version file to make sure that works
5159 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005160 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005161 binary=False)
5162 self.assertEqual(version, state.GetVersion(self._indir))
5163
Simon Glass637958f2021-11-23 21:09:50 -07005164 def testAltFormat(self):
5165 """Test that alternative formats can be used to extract"""
5166 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5167
5168 try:
5169 tmpdir, updated_fname = self._SetupImageInTmpdir()
5170 with test_util.capture_sys_output() as (stdout, _):
5171 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5172 self.assertEqual(
5173 '''Flag (-F) Entry type Description
5174fdt fdtmap Extract the devicetree blob from the fdtmap
5175''',
5176 stdout.getvalue())
5177
5178 dtb = os.path.join(tmpdir, 'fdt.dtb')
5179 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5180 dtb, 'fdtmap')
5181
5182 # Check that we can read it and it can be scanning, meaning it does
5183 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005184 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005185 dtb = fdt.Fdt.FromData(data)
5186 dtb.Scan()
5187
5188 # Now check u-boot which has no alt_format
5189 fname = os.path.join(tmpdir, 'fdt.dtb')
5190 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5191 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005192 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005193 self.assertEqual(U_BOOT_DATA, data)
5194
5195 finally:
5196 shutil.rmtree(tmpdir)
5197
Simon Glass0b00ae62021-11-23 21:09:52 -07005198 def testExtblobList(self):
5199 """Test an image with an external blob list"""
5200 data = self._DoReadFile('215_blob_ext_list.dts')
5201 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5202
5203 def testExtblobListMissing(self):
5204 """Test an image with a missing external blob"""
5205 with self.assertRaises(ValueError) as e:
5206 self._DoReadFile('216_blob_ext_list_missing.dts')
5207 self.assertIn("Filename 'missing-file' not found in input path",
5208 str(e.exception))
5209
5210 def testExtblobListMissingOk(self):
5211 """Test an image with an missing external blob that is allowed"""
5212 with test_util.capture_sys_output() as (stdout, stderr):
5213 self._DoTestFile('216_blob_ext_list_missing.dts',
5214 allow_missing=True)
5215 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005216 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005217
Simon Glass3efb2972021-11-23 21:08:59 -07005218 def testFip(self):
5219 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5220 data = self._DoReadFile('203_fip.dts')
5221 hdr, fents = fip_util.decode_fip(data)
5222 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5223 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5224 self.assertEqual(0x123, hdr.flags)
5225
5226 self.assertEqual(2, len(fents))
5227
5228 fent = fents[0]
5229 self.assertEqual(
5230 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5231 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5232 self.assertEqual('soc-fw', fent.fip_type)
5233 self.assertEqual(0x88, fent.offset)
5234 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5235 self.assertEqual(0x123456789abcdef, fent.flags)
5236 self.assertEqual(ATF_BL31_DATA, fent.data)
5237 self.assertEqual(True, fent.valid)
5238
5239 fent = fents[1]
5240 self.assertEqual(
5241 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5242 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5243 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5244 self.assertEqual(0x8c, fent.offset)
5245 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5246 self.assertEqual(0, fent.flags)
5247 self.assertEqual(ATF_BL2U_DATA, fent.data)
5248 self.assertEqual(True, fent.valid)
5249
5250 def testFipOther(self):
5251 """Basic FIP with something that isn't a external blob"""
5252 data = self._DoReadFile('204_fip_other.dts')
5253 hdr, fents = fip_util.decode_fip(data)
5254
5255 self.assertEqual(2, len(fents))
5256 fent = fents[1]
5257 self.assertEqual('rot-cert', fent.fip_type)
5258 self.assertEqual(b'aa', fent.data)
5259
Simon Glass3efb2972021-11-23 21:08:59 -07005260 def testFipNoType(self):
5261 """FIP with an entry of an unknown type"""
5262 with self.assertRaises(ValueError) as e:
5263 self._DoReadFile('205_fip_no_type.dts')
5264 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5265 str(e.exception))
5266
5267 def testFipUuid(self):
5268 """Basic FIP with a manual uuid"""
5269 data = self._DoReadFile('206_fip_uuid.dts')
5270 hdr, fents = fip_util.decode_fip(data)
5271
5272 self.assertEqual(2, len(fents))
5273 fent = fents[1]
5274 self.assertEqual(None, fent.fip_type)
5275 self.assertEqual(
5276 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5277 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5278 fent.uuid)
5279 self.assertEqual(U_BOOT_DATA, fent.data)
5280
5281 def testFipLs(self):
5282 """Test listing a FIP"""
5283 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5284 hdr, fents = fip_util.decode_fip(data)
5285
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005286 tmpdir = None
Simon Glass3efb2972021-11-23 21:08:59 -07005287 try:
5288 tmpdir, updated_fname = self._SetupImageInTmpdir()
5289 with test_util.capture_sys_output() as (stdout, stderr):
5290 self._DoBinman('ls', '-i', updated_fname)
5291 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005292 if tmpdir:
5293 shutil.rmtree(tmpdir)
Simon Glass3efb2972021-11-23 21:08:59 -07005294 lines = stdout.getvalue().splitlines()
5295 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005296'Name Image-pos Size Entry-type Offset Uncomp-size',
5297'--------------------------------------------------------------',
5298'image 0 2d3 section 0',
5299' atf-fip 0 90 atf-fip 0',
5300' soc-fw 88 4 blob-ext 88',
5301' u-boot 8c 4 u-boot 8c',
5302' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005303]
5304 self.assertEqual(expected, lines)
5305
5306 image = control.images['image']
5307 entries = image.GetEntries()
5308 fdtmap = entries['fdtmap']
5309
5310 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5311 magic = fdtmap_data[:8]
5312 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005313 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005314
5315 fdt_data = fdtmap_data[16:]
5316 dtb = fdt.Fdt.FromData(fdt_data)
5317 dtb.Scan()
5318 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5319 self.assertEqual({
5320 'atf-fip/soc-fw:image-pos': 136,
5321 'atf-fip/soc-fw:offset': 136,
5322 'atf-fip/soc-fw:size': 4,
5323 'atf-fip/u-boot:image-pos': 140,
5324 'atf-fip/u-boot:offset': 140,
5325 'atf-fip/u-boot:size': 4,
5326 'atf-fip:image-pos': 0,
5327 'atf-fip:offset': 0,
5328 'atf-fip:size': 144,
5329 'image-pos': 0,
5330 'offset': 0,
5331 'fdtmap:image-pos': fdtmap.image_pos,
5332 'fdtmap:offset': fdtmap.offset,
5333 'fdtmap:size': len(fdtmap_data),
5334 'size': len(data),
5335 }, props)
5336
5337 def testFipExtractOneEntry(self):
5338 """Test extracting a single entry fron an FIP"""
5339 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005340 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005341 fname = os.path.join(self._indir, 'output.extact')
5342 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005343 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005344 self.assertEqual(U_BOOT_DATA, data)
5345
5346 def testFipReplace(self):
5347 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005348 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005349 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005350 updated_fname = tools.get_output_filename('image-updated.bin')
5351 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005352 entry_name = 'atf-fip/u-boot'
5353 control.WriteEntry(updated_fname, entry_name, expected,
5354 allow_resize=True)
5355 actual = control.ReadEntry(updated_fname, entry_name)
5356 self.assertEqual(expected, actual)
5357
Simon Glass80025522022-01-29 14:14:04 -07005358 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005359 hdr, fents = fip_util.decode_fip(new_data)
5360
5361 self.assertEqual(2, len(fents))
5362
5363 # Check that the FIP entry is updated
5364 fent = fents[1]
5365 self.assertEqual(0x8c, fent.offset)
5366 self.assertEqual(len(expected), fent.size)
5367 self.assertEqual(0, fent.flags)
5368 self.assertEqual(expected, fent.data)
5369 self.assertEqual(True, fent.valid)
5370
5371 def testFipMissing(self):
5372 with test_util.capture_sys_output() as (stdout, stderr):
5373 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5374 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005375 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005376
5377 def testFipSize(self):
5378 """Test a FIP with a size property"""
5379 data = self._DoReadFile('210_fip_size.dts')
5380 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5381 hdr, fents = fip_util.decode_fip(data)
5382 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5383 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5384
5385 self.assertEqual(1, len(fents))
5386
5387 fent = fents[0]
5388 self.assertEqual('soc-fw', fent.fip_type)
5389 self.assertEqual(0x60, fent.offset)
5390 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5391 self.assertEqual(ATF_BL31_DATA, fent.data)
5392 self.assertEqual(True, fent.valid)
5393
5394 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005395 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005396
5397 def testFipBadAlign(self):
5398 """Test that an invalid alignment value in a FIP is detected"""
5399 with self.assertRaises(ValueError) as e:
5400 self._DoTestFile('211_fip_bad_align.dts')
5401 self.assertIn(
5402 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5403 str(e.exception))
5404
5405 def testFipCollection(self):
5406 """Test using a FIP in a collection"""
5407 data = self._DoReadFile('212_fip_collection.dts')
5408 entry1 = control.images['image'].GetEntries()['collection']
5409 data1 = data[:entry1.size]
5410 hdr1, fents2 = fip_util.decode_fip(data1)
5411
5412 entry2 = control.images['image'].GetEntries()['atf-fip']
5413 data2 = data[entry2.offset:entry2.offset + entry2.size]
5414 hdr1, fents2 = fip_util.decode_fip(data2)
5415
5416 # The 'collection' entry should have U-Boot included at the end
5417 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5418 self.assertEqual(data1, data2 + U_BOOT_DATA)
5419 self.assertEqual(U_BOOT_DATA, data1[-4:])
5420
5421 # There should be a U-Boot after the final FIP
5422 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005423
Simon Glassccae6862022-01-12 13:10:35 -07005424 def testFakeBlob(self):
5425 """Test handling of faking an external blob"""
5426 with test_util.capture_sys_output() as (stdout, stderr):
5427 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5428 allow_fake_blobs=True)
5429 err = stderr.getvalue()
5430 self.assertRegex(
5431 err,
5432 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005433
Simon Glassceb5f912022-01-09 20:13:46 -07005434 def testExtblobListFaked(self):
5435 """Test an extblob with missing external blob that are faked"""
5436 with test_util.capture_sys_output() as (stdout, stderr):
5437 self._DoTestFile('216_blob_ext_list_missing.dts',
5438 allow_fake_blobs=True)
5439 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005440 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005441
Simon Glass162017b2022-01-09 20:13:57 -07005442 def testListBintools(self):
5443 args = ['tool', '--list']
5444 with test_util.capture_sys_output() as (stdout, _):
5445 self._DoBinman(*args)
5446 out = stdout.getvalue().splitlines()
5447 self.assertTrue(len(out) >= 2)
5448
5449 def testFetchBintools(self):
5450 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005451 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005452 raise urllib.error.URLError('my error')
5453
5454 args = ['tool']
5455 with self.assertRaises(ValueError) as e:
5456 self._DoBinman(*args)
5457 self.assertIn("Invalid arguments to 'tool' subcommand",
5458 str(e.exception))
5459
5460 args = ['tool', '--fetch']
5461 with self.assertRaises(ValueError) as e:
5462 self._DoBinman(*args)
5463 self.assertIn('Please specify bintools to fetch', str(e.exception))
5464
5465 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005466 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005467 side_effect=fail_download):
5468 with test_util.capture_sys_output() as (stdout, _):
5469 self._DoBinman(*args)
5470 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5471
Simon Glass620c4462022-01-09 20:14:11 -07005472 def testBintoolDocs(self):
5473 """Test for creation of bintool documentation"""
5474 with test_util.capture_sys_output() as (stdout, stderr):
5475 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5476 self.assertTrue(len(stdout.getvalue()) > 0)
5477
5478 def testBintoolDocsMissing(self):
5479 """Test handling of missing bintool documentation"""
5480 with self.assertRaises(ValueError) as e:
5481 with test_util.capture_sys_output() as (stdout, stderr):
5482 control.write_bintool_docs(
5483 control.bintool.Bintool.get_tool_list(), 'mkimage')
5484 self.assertIn('Documentation is missing for modules: mkimage',
5485 str(e.exception))
5486
Jan Kiszka58c407f2022-01-28 20:37:53 +01005487 def testListWithGenNode(self):
5488 """Check handling of an FDT map when the section cannot be found"""
5489 entry_args = {
5490 'of-list': 'test-fdt1 test-fdt2',
5491 }
5492 data = self._DoReadFileDtb(
5493 '219_fit_gennode.dts',
5494 entry_args=entry_args,
5495 use_real_dtb=True,
5496 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5497
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005498 tmpdir = None
Jan Kiszka58c407f2022-01-28 20:37:53 +01005499 try:
5500 tmpdir, updated_fname = self._SetupImageInTmpdir()
5501 with test_util.capture_sys_output() as (stdout, stderr):
5502 self._RunBinman('ls', '-i', updated_fname)
5503 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005504 if tmpdir:
5505 shutil.rmtree(tmpdir)
Jan Kiszka58c407f2022-01-28 20:37:53 +01005506
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005507 def testFitSubentryUsesBintool(self):
5508 """Test that binman FIT subentries can use bintools"""
5509 command.test_result = self._HandleGbbCommand
5510 entry_args = {
5511 'keydir': 'devkeys',
5512 'bmpblk': 'bmpblk.bin',
5513 }
5514 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5515 entry_args=entry_args)
5516
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005517 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5518 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005519 self.assertIn(expected, data)
5520
5521 def testFitSubentryMissingBintool(self):
5522 """Test that binman reports missing bintools for FIT subentries"""
5523 entry_args = {
5524 'keydir': 'devkeys',
5525 }
5526 with test_util.capture_sys_output() as (_, stderr):
5527 self._DoTestFile('220_fit_subentry_bintool.dts',
5528 force_missing_bintools='futility', entry_args=entry_args)
5529 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005530 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005531
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005532 def testFitSubentryHashSubnode(self):
5533 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005534 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005535 data, _, _, out_dtb_name = self._DoReadFileDtb(
5536 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5537
5538 mkimage_dtb = fdt.Fdt.FromData(data)
5539 mkimage_dtb.Scan()
5540 binman_dtb = fdt.Fdt(out_dtb_name)
5541 binman_dtb.Scan()
5542
5543 # Check that binman didn't add hash values
5544 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5545 self.assertNotIn('value', fnode.props)
5546
5547 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5548 self.assertNotIn('value', fnode.props)
5549
5550 # Check that mkimage added hash values
5551 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5552 self.assertIn('value', fnode.props)
5553
5554 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5555 self.assertIn('value', fnode.props)
5556
Roger Quadros5cdcea02022-02-19 20:50:04 +02005557 def testPackTeeOs(self):
5558 """Test that an image with an TEE binary can be created"""
5559 data = self._DoReadFile('222_tee_os.dts')
5560 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5561
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305562 def testPackTiDm(self):
5563 """Test that an image with a TI DM binary can be created"""
5564 data = self._DoReadFile('225_ti_dm.dts')
5565 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5566
Simon Glass912339f2022-02-08 11:50:03 -07005567 def testFitFdtOper(self):
5568 """Check handling of a specified FIT operation"""
5569 entry_args = {
5570 'of-list': 'test-fdt1 test-fdt2',
5571 'default-dt': 'test-fdt2',
5572 }
5573 self._DoReadFileDtb(
5574 '223_fit_fdt_oper.dts',
5575 entry_args=entry_args,
5576 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5577
5578 def testFitFdtBadOper(self):
5579 """Check handling of an FDT map when the section cannot be found"""
5580 with self.assertRaises(ValueError) as exc:
5581 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005582 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005583 str(exc.exception))
5584
Simon Glassdd156a42022-03-05 20:18:59 -07005585 def test_uses_expand_size(self):
5586 """Test that the 'expand-size' property cannot be used anymore"""
5587 with self.assertRaises(ValueError) as e:
5588 data = self._DoReadFile('225_expand_size_bad.dts')
5589 self.assertIn(
5590 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5591 str(e.exception))
5592
Simon Glass5f423422022-03-05 20:19:12 -07005593 def testFitSplitElf(self):
5594 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005595 if not elf.ELF_TOOLS:
5596 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005597 entry_args = {
5598 'of-list': 'test-fdt1 test-fdt2',
5599 'default-dt': 'test-fdt2',
5600 'atf-bl31-path': 'bl31.elf',
5601 'tee-os-path': 'tee.elf',
5602 }
5603 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5604 data = self._DoReadFileDtb(
5605 '226_fit_split_elf.dts',
5606 entry_args=entry_args,
5607 extra_indirs=[test_subdir])[0]
5608
5609 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5610 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5611
5612 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5613 'data', 'load'}
5614 dtb = fdt.Fdt.FromData(fit_data)
5615 dtb.Scan()
5616
5617 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5618 segments, entry = elf.read_loadable_segments(elf_data)
5619
5620 # We assume there are two segments
Brandon Maiera657bc62024-06-04 16:16:05 +00005621 self.assertEqual(2, len(segments))
Simon Glass5f423422022-03-05 20:19:12 -07005622
5623 atf1 = dtb.GetNode('/images/atf-1')
5624 _, start, data = segments[0]
5625 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5626 self.assertEqual(entry,
5627 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5628 self.assertEqual(start,
5629 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5630 self.assertEqual(data, atf1.props['data'].bytes)
5631
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005632 hash_node = atf1.FindNode('hash')
5633 self.assertIsNotNone(hash_node)
5634 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5635
Simon Glass5f423422022-03-05 20:19:12 -07005636 atf2 = dtb.GetNode('/images/atf-2')
5637 self.assertEqual(base_keys, atf2.props.keys())
5638 _, start, data = segments[1]
5639 self.assertEqual(start,
5640 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5641 self.assertEqual(data, atf2.props['data'].bytes)
5642
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005643 hash_node = atf2.FindNode('hash')
5644 self.assertIsNotNone(hash_node)
5645 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5646
5647 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5648 self.assertIsNotNone(hash_node)
5649 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5650
Simon Glass5f423422022-03-05 20:19:12 -07005651 conf = dtb.GetNode('/configurations')
5652 self.assertEqual({'default'}, conf.props.keys())
5653
5654 for subnode in conf.subnodes:
5655 self.assertEqual({'description', 'fdt', 'loadables'},
5656 subnode.props.keys())
5657 self.assertEqual(
5658 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5659 fdt_util.GetStringList(subnode, 'loadables'))
5660
5661 def _check_bad_fit(self, dts):
5662 """Check a bad FIT
5663
5664 This runs with the given dts and returns the assertion raised
5665
5666 Args:
5667 dts (str): dts filename to use
5668
5669 Returns:
5670 str: Assertion string raised
5671 """
5672 entry_args = {
5673 'of-list': 'test-fdt1 test-fdt2',
5674 'default-dt': 'test-fdt2',
5675 'atf-bl31-path': 'bl31.elf',
5676 'tee-os-path': 'tee.elf',
5677 }
5678 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5679 with self.assertRaises(ValueError) as exc:
5680 self._DoReadFileDtb(dts, entry_args=entry_args,
5681 extra_indirs=[test_subdir])[0]
5682 return str(exc.exception)
5683
5684 def testFitSplitElfBadElf(self):
5685 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005686 if not elf.ELF_TOOLS:
5687 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005688 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5689 entry_args = {
5690 'of-list': 'test-fdt1 test-fdt2',
5691 'default-dt': 'test-fdt2',
5692 'atf-bl31-path': 'bad.elf',
5693 'tee-os-path': 'tee.elf',
5694 }
5695 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5696 with self.assertRaises(ValueError) as exc:
5697 self._DoReadFileDtb(
5698 '226_fit_split_elf.dts',
5699 entry_args=entry_args,
5700 extra_indirs=[test_subdir])[0]
5701 self.assertIn(
5702 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5703 str(exc.exception))
5704
Simon Glass5f423422022-03-05 20:19:12 -07005705 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005706 """Test an split-elf FIT with a missing ELF file
5707
5708 Args:
5709 kwargs (dict of str): Arguments to pass to _DoTestFile()
5710
5711 Returns:
5712 tuple:
5713 str: stdout result
5714 str: stderr result
5715 """
Simon Glass5f423422022-03-05 20:19:12 -07005716 entry_args = {
5717 'of-list': 'test-fdt1 test-fdt2',
5718 'default-dt': 'test-fdt2',
5719 'atf-bl31-path': 'bl31.elf',
5720 'tee-os-path': 'missing.elf',
5721 }
5722 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5723 with test_util.capture_sys_output() as (stdout, stderr):
5724 self._DoTestFile(
5725 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005726 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5727 out = stdout.getvalue()
5728 err = stderr.getvalue()
5729 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005730
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005731 def testFitSplitElfBadDirective(self):
5732 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5733 if not elf.ELF_TOOLS:
5734 self.skipTest('Python elftools not available')
5735 err = self._check_bad_fit('227_fit_bad_dir.dts')
5736 self.assertIn(
5737 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5738 err)
5739
5740 def testFitSplitElfBadDirectiveConfig(self):
5741 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5742 if not elf.ELF_TOOLS:
5743 self.skipTest('Python elftools not available')
5744 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5745 self.assertEqual(
5746 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5747 err)
5748
5749
Simon Glass5f423422022-03-05 20:19:12 -07005750 def testFitSplitElfMissing(self):
5751 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005752 if not elf.ELF_TOOLS:
5753 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005754 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005755 self.assertRegex(
5756 err,
5757 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005758 self.assertNotRegex(out, '.*Faked blob.*')
5759 fname = tools.get_output_filename('binman-fake/missing.elf')
5760 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005761
5762 def testFitSplitElfFaked(self):
5763 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005764 if not elf.ELF_TOOLS:
5765 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005766 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005767 self.assertRegex(
5768 err,
5769 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005770 self.assertRegex(
5771 out,
5772 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5773 fname = tools.get_output_filename('binman-fake/missing.elf')
5774 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005775
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005776 def testMkimageMissingBlob(self):
5777 """Test using mkimage to build an image"""
5778 with test_util.capture_sys_output() as (stdout, stderr):
5779 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5780 allow_fake_blobs=True)
5781 err = stderr.getvalue()
5782 self.assertRegex(
5783 err,
5784 "Image '.*' has faked external blobs and is non-functional: .*")
5785
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005786 def testPreLoad(self):
5787 """Test an image with a pre-load header"""
5788 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005789 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005790 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005791 data = self._DoReadFileDtb(
5792 '230_pre_load.dts', entry_args=entry_args,
5793 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Paul HENRYS5cf82892025-02-24 22:20:55 +01005794
5795 image_fname = tools.get_output_filename('image.bin')
5796 is_signed = self._CheckPreload(image_fname, self.TestFile("dev.key"))
5797
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005798 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5799 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5800 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Paul HENRYS5cf82892025-02-24 22:20:55 +01005801 self.assertEqual(is_signed, True)
Simon Glasse2dfb962023-07-24 09:19:57 -06005802
5803 def testPreLoadNoKey(self):
5804 """Test an image with a pre-load heade0r with missing key"""
5805 with self.assertRaises(FileNotFoundError) as exc:
5806 self._DoReadFile('230_pre_load.dts')
5807 self.assertIn("No such file or directory: 'dev.key'",
5808 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005809
5810 def testPreLoadPkcs(self):
5811 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005812 entry_args = {
5813 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5814 }
5815 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5816 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005817 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5818 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5819 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5820
5821 def testPreLoadPss(self):
5822 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005823 entry_args = {
5824 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5825 }
5826 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5827 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005828 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5829 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5830 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5831
5832 def testPreLoadInvalidPadding(self):
5833 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005834 entry_args = {
5835 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5836 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005837 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005838 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5839 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005840
5841 def testPreLoadInvalidSha(self):
5842 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005843 entry_args = {
5844 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5845 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005846 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005847 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5848 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005849
5850 def testPreLoadInvalidAlgo(self):
5851 """Test an image with a pre-load header with an invalid algo"""
5852 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005853 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005854
5855 def testPreLoadInvalidKey(self):
5856 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005857 entry_args = {
5858 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5859 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005860 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005861 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5862 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005863
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005864 def _CheckSafeUniqueNames(self, *images):
5865 """Check all entries of given images for unsafe unique names"""
5866 for image in images:
5867 entries = {}
5868 image._CollectEntries(entries, {}, image)
5869 for entry in entries.values():
5870 uniq = entry.GetUniqueName()
5871
5872 # Used as part of a filename, so must not be absolute paths.
5873 self.assertFalse(os.path.isabs(uniq))
5874
5875 def testSafeUniqueNames(self):
5876 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005877 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005878
5879 orig_image = control.images['image']
5880 image_fname = tools.get_output_filename('image.bin')
5881 image = Image.FromFile(image_fname)
5882
5883 self._CheckSafeUniqueNames(orig_image, image)
5884
5885 def testSafeUniqueNamesMulti(self):
5886 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005887 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005888
5889 orig_image = control.images['image']
5890 image_fname = tools.get_output_filename('image.bin')
5891 image = Image.FromFile(image_fname)
5892
5893 self._CheckSafeUniqueNames(orig_image, image)
5894
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005895 def testReplaceCmdWithBintool(self):
5896 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005897 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005898 expected = U_BOOT_DATA + b'aa'
5899 self.assertEqual(expected, data[:len(expected)])
5900
5901 try:
5902 tmpdir, updated_fname = self._SetupImageInTmpdir()
5903 fname = os.path.join(tmpdir, 'update-testing.bin')
5904 tools.write_file(fname, b'zz')
5905 self._DoBinman('replace', '-i', updated_fname,
5906 '_testing', '-f', fname)
5907
5908 data = tools.read_file(updated_fname)
5909 expected = U_BOOT_DATA + b'zz'
5910 self.assertEqual(expected, data[:len(expected)])
5911 finally:
5912 shutil.rmtree(tmpdir)
5913
5914 def testReplaceCmdOtherWithBintool(self):
5915 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005916 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005917 expected = U_BOOT_DATA + b'aa'
5918 self.assertEqual(expected, data[:len(expected)])
5919
5920 try:
5921 tmpdir, updated_fname = self._SetupImageInTmpdir()
5922 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5923 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5924 self._DoBinman('replace', '-i', updated_fname,
5925 'u-boot', '-f', fname)
5926
5927 data = tools.read_file(updated_fname)
5928 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5929 self.assertEqual(expected, data[:len(expected)])
5930 finally:
5931 shutil.rmtree(tmpdir)
5932
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005933 def testReplaceResizeNoRepackSameSize(self):
5934 """Test replacing entries with same-size data without repacking"""
5935 expected = b'x' * len(U_BOOT_DATA)
5936 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5937 self.assertEqual(expected, data)
5938
5939 path, fdtmap = state.GetFdtContents('fdtmap')
5940 self.assertIsNotNone(path)
5941 self.assertEqual(expected_fdtmap, fdtmap)
5942
5943 def testReplaceResizeNoRepackSmallerSize(self):
5944 """Test replacing entries with smaller-size data without repacking"""
5945 new_data = b'x'
5946 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5947 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5948 self.assertEqual(expected, data)
5949
5950 path, fdtmap = state.GetFdtContents('fdtmap')
5951 self.assertIsNotNone(path)
5952 self.assertEqual(expected_fdtmap, fdtmap)
5953
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005954 def testExtractFit(self):
5955 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005956 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005957 image_fname = tools.get_output_filename('image.bin')
5958
5959 fit_data = control.ReadEntry(image_fname, 'fit')
5960 fit = fdt.Fdt.FromData(fit_data)
5961 fit.Scan()
5962
5963 # Check subentry data inside the extracted fit
5964 for node_path, expected in [
5965 ('/images/kernel', U_BOOT_DATA),
5966 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5967 ('/images/scr-1', COMPRESS_DATA),
5968 ]:
5969 node = fit.GetNode(node_path)
5970 data = fit.GetProps(node)['data'].bytes
5971 self.assertEqual(expected, data)
5972
5973 def testExtractFitSubentries(self):
5974 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005975 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005976 image_fname = tools.get_output_filename('image.bin')
5977
5978 for entry_path, expected in [
5979 ('fit/kernel', U_BOOT_DATA),
5980 ('fit/kernel/u-boot', U_BOOT_DATA),
5981 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5982 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5983 ('fit/scr-1', COMPRESS_DATA),
5984 ('fit/scr-1/blob', COMPRESS_DATA),
5985 ]:
5986 data = control.ReadEntry(image_fname, entry_path)
5987 self.assertEqual(expected, data)
5988
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005989 def testReplaceFitSubentryLeafSameSize(self):
5990 """Test replacing a FIT leaf subentry with same-size data"""
5991 new_data = b'x' * len(U_BOOT_DATA)
5992 data, expected_fdtmap, _ = self._RunReplaceCmd(
5993 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005994 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005995 self.assertEqual(new_data, data)
5996
5997 path, fdtmap = state.GetFdtContents('fdtmap')
5998 self.assertIsNotNone(path)
5999 self.assertEqual(expected_fdtmap, fdtmap)
6000
6001 def testReplaceFitSubentryLeafBiggerSize(self):
6002 """Test replacing a FIT leaf subentry with bigger-size data"""
6003 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
6004 data, expected_fdtmap, _ = self._RunReplaceCmd(
6005 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006006 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006007 self.assertEqual(new_data, data)
6008
6009 # Will be repacked, so fdtmap must change
6010 path, fdtmap = state.GetFdtContents('fdtmap')
6011 self.assertIsNotNone(path)
6012 self.assertNotEqual(expected_fdtmap, fdtmap)
6013
6014 def testReplaceFitSubentryLeafSmallerSize(self):
6015 """Test replacing a FIT leaf subentry with smaller-size data"""
6016 new_data = b'x'
6017 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
6018 data, expected_fdtmap, _ = self._RunReplaceCmd(
6019 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006020 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03006021 self.assertEqual(expected, data)
6022
6023 path, fdtmap = state.GetFdtContents('fdtmap')
6024 self.assertIsNotNone(path)
6025 self.assertEqual(expected_fdtmap, fdtmap)
6026
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006027 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07006028 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006029 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07006030 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6031 new_data, dts='241_replace_section_simple.dts')
6032 self.assertEqual(new_data, data)
6033
6034 entries = image.GetEntries()
6035 self.assertIn('section', entries)
6036 entry = entries['section']
6037 self.assertEqual(len(new_data), entry.size)
6038
6039 def testReplaceSectionLarger(self):
6040 """Test replacing a simple section with larger data"""
6041 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6042 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6043 new_data, dts='241_replace_section_simple.dts')
6044 self.assertEqual(new_data, data)
6045
6046 entries = image.GetEntries()
6047 self.assertIn('section', entries)
6048 entry = entries['section']
6049 self.assertEqual(len(new_data), entry.size)
6050 fentry = entries['fdtmap']
6051 self.assertEqual(entry.offset + entry.size, fentry.offset)
6052
6053 def testReplaceSectionSmaller(self):
6054 """Test replacing a simple section with smaller data"""
6055 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
6056 data, expected_fdtmap, image = self._RunReplaceCmd('section',
6057 new_data, dts='241_replace_section_simple.dts')
6058 self.assertEqual(new_data, data)
6059
6060 # The new size is the same as the old, just with a pad byte at the end
6061 entries = image.GetEntries()
6062 self.assertIn('section', entries)
6063 entry = entries['section']
6064 self.assertEqual(len(new_data), entry.size)
6065
6066 def testReplaceSectionSmallerAllow(self):
6067 """Test failing to replace a simple section with smaller data"""
6068 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
6069 try:
6070 state.SetAllowEntryContraction(True)
6071 with self.assertRaises(ValueError) as exc:
6072 self._RunReplaceCmd('section', new_data,
6073 dts='241_replace_section_simple.dts')
6074 finally:
6075 state.SetAllowEntryContraction(False)
6076
6077 # Since we have no information about the position of things within the
6078 # section, we cannot adjust the position of /section-u-boot so it ends
6079 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06006080 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07006081 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
6082 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06006083 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03006084
Simon Glass8fbca772022-08-13 11:40:48 -06006085 def testMkimageImagename(self):
6086 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006087 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006088 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06006089
6090 # Check that the data appears in the file somewhere
6091 self.assertIn(U_BOOT_SPL_DATA, data)
6092
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006093 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06006094 name = data[0x20:0x40]
6095
6096 # Build the filename that we expect to be placed in there, by virtue of
6097 # the -n paraameter
6098 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6099
6100 # Check that the image name is set to the temporary filename used
6101 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6102
Simon Glassb1669752022-08-13 11:40:49 -06006103 def testMkimageImage(self):
6104 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006105 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006106 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006107
6108 # Check that the data appears in the file somewhere
6109 self.assertIn(U_BOOT_SPL_DATA, data)
6110
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006111 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006112 name = data[0x20:0x40]
6113
6114 # Build the filename that we expect to be placed in there, by virtue of
6115 # the -n paraameter
6116 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6117
6118 # Check that the image name is set to the temporary filename used
6119 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6120
6121 # Check the corect data is in the imagename file
6122 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6123
6124 def testMkimageImageNoContent(self):
6125 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006126 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006127 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006128 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006129 self.assertIn('Could not complete processing of contents',
6130 str(exc.exception))
6131
6132 def testMkimageImageBad(self):
6133 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006134 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006135 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006136 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006137 self.assertIn('Cannot use both imagename node and data-to-imagename',
6138 str(exc.exception))
6139
Simon Glassbd5cd882022-08-13 11:40:50 -06006140 def testCollectionOther(self):
6141 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006142 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006143 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6144 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6145 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6146 data)
6147
6148 def testMkimageCollection(self):
6149 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006150 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006151 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006152 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6153 self.assertEqual(expect, data[:len(expect)])
6154
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006155 def testCompressDtbPrependInvalid(self):
6156 """Test that invalid header is detected"""
6157 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006158 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006159 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6160 "'u-boot-dtb': 'invalid'", str(e.exception))
6161
6162 def testCompressDtbPrependLength(self):
6163 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006164 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006165 image = control.images['image']
6166 entries = image.GetEntries()
6167 self.assertIn('u-boot-dtb', entries)
6168 u_boot_dtb = entries['u-boot-dtb']
6169 self.assertIn('fdtmap', entries)
6170 fdtmap = entries['fdtmap']
6171
6172 image_fname = tools.get_output_filename('image.bin')
6173 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6174 dtb = fdt.Fdt.FromData(orig)
6175 dtb.Scan()
6176 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6177 expected = {
6178 'u-boot:size': len(U_BOOT_DATA),
6179 'u-boot-dtb:uncomp-size': len(orig),
6180 'u-boot-dtb:size': u_boot_dtb.size,
6181 'fdtmap:size': fdtmap.size,
6182 'size': len(data),
6183 }
6184 self.assertEqual(expected, props)
6185
6186 # Check implementation
6187 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6188 rest = data[len(U_BOOT_DATA):]
6189 comp_data_len = struct.unpack('<I', rest[:4])[0]
6190 comp_data = rest[4:4 + comp_data_len]
6191 orig2 = self._decompress(comp_data)
6192 self.assertEqual(orig, orig2)
6193
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006194 def testInvalidCompress(self):
6195 """Test that invalid compress algorithm is detected"""
6196 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006197 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006198 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6199
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006200 def testCompUtilCompressions(self):
6201 """Test compression algorithms"""
6202 for bintool in self.comp_bintools.values():
6203 self._CheckBintool(bintool)
6204 data = bintool.compress(COMPRESS_DATA)
6205 self.assertNotEqual(COMPRESS_DATA, data)
6206 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006207 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006208
6209 def testCompUtilVersions(self):
6210 """Test tool version of compression algorithms"""
6211 for bintool in self.comp_bintools.values():
6212 self._CheckBintool(bintool)
6213 version = bintool.version()
6214 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6215
6216 def testCompUtilPadding(self):
6217 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006218 # Skip zstd because it doesn't support padding
6219 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006220 self._CheckBintool(bintool)
6221 data = bintool.compress(COMPRESS_DATA)
6222 self.assertNotEqual(COMPRESS_DATA, data)
6223 data += tools.get_bytes(0, 64)
6224 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006225 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006226
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006227 def testCompressDtbZstd(self):
6228 """Test that zstd compress of device-tree files failed"""
6229 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006230 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006231 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6232 "requires a length header", str(e.exception))
6233
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006234 def testMkimageMultipleDataFiles(self):
6235 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006236 self._SetupSplElf()
6237 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006238 data = self._DoReadFile('252_mkimage_mult_data.dts')
6239 # Size of files are packed in their 4B big-endian format
6240 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6241 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6242 # Size info is always followed by a 4B zero value.
6243 expect += tools.get_bytes(0, 4)
6244 expect += U_BOOT_TPL_DATA
6245 # All but last files are 4B-aligned
6246 align_pad = len(U_BOOT_TPL_DATA) % 4
6247 if align_pad:
6248 expect += tools.get_bytes(0, align_pad)
6249 expect += U_BOOT_SPL_DATA
6250 self.assertEqual(expect, data[-len(expect):])
6251
Marek Vasutf7413f02023-07-18 07:23:58 -06006252 def testMkimageMultipleExpanded(self):
6253 """Test passing multiple files to mkimage in a mkimage entry"""
6254 self._SetupSplElf()
6255 self._SetupTplElf()
6256 entry_args = {
6257 'spl-bss-pad': 'y',
6258 'spl-dtb': 'y',
6259 }
6260 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6261 use_expanded=True, entry_args=entry_args)[0]
6262 pad_len = 10
6263 tpl_expect = U_BOOT_TPL_DATA
6264 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6265 spl_expect += U_BOOT_SPL_DTB_DATA
6266
6267 content = data[0x40:]
6268 lens = struct.unpack('>III', content[:12])
6269
6270 # Size of files are packed in their 4B big-endian format
6271 # Size info is always followed by a 4B zero value.
6272 self.assertEqual(len(tpl_expect), lens[0])
6273 self.assertEqual(len(spl_expect), lens[1])
6274 self.assertEqual(0, lens[2])
6275
6276 rest = content[12:]
6277 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6278
6279 rest = rest[len(tpl_expect):]
6280 align_pad = len(tpl_expect) % 4
6281 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6282 rest = rest[align_pad:]
6283 self.assertEqual(spl_expect, rest)
6284
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006285 def testMkimageMultipleNoContent(self):
6286 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006287 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006288 with self.assertRaises(ValueError) as exc:
6289 self._DoReadFile('253_mkimage_mult_no_content.dts')
6290 self.assertIn('Could not complete processing of contents',
6291 str(exc.exception))
6292
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006293 def testMkimageFilename(self):
6294 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006295 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006296 retcode = self._DoTestFile('254_mkimage_filename.dts')
6297 self.assertEqual(0, retcode)
6298 fname = tools.get_output_filename('mkimage-test.bin')
6299 self.assertTrue(os.path.exists(fname))
6300
Simon Glass56d05412022-02-28 07:16:54 -07006301 def testVpl(self):
6302 """Test that an image with VPL and its device tree can be created"""
6303 # ELF file with a '__bss_size' symbol
6304 self._SetupVplElf()
6305 data = self._DoReadFile('255_u_boot_vpl.dts')
6306 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6307
6308 def testVplNoDtb(self):
6309 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6310 self._SetupVplElf()
6311 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6312 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6313 data[:len(U_BOOT_VPL_NODTB_DATA)])
6314
6315 def testExpandedVpl(self):
6316 """Test that an expanded entry type is selected for TPL when needed"""
6317 self._SetupVplElf()
6318
6319 entry_args = {
6320 'vpl-bss-pad': 'y',
6321 'vpl-dtb': 'y',
6322 }
6323 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6324 entry_args=entry_args)
6325 image = control.images['image']
6326 entries = image.GetEntries()
6327 self.assertEqual(1, len(entries))
6328
6329 # We only have u-boot-vpl, which be expanded
6330 self.assertIn('u-boot-vpl', entries)
6331 entry = entries['u-boot-vpl']
6332 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6333 subent = entry.GetEntries()
6334 self.assertEqual(3, len(subent))
6335 self.assertIn('u-boot-vpl-nodtb', subent)
6336 self.assertIn('u-boot-vpl-bss-pad', subent)
6337 self.assertIn('u-boot-vpl-dtb', subent)
6338
6339 def testVplBssPadMissing(self):
6340 """Test that a missing symbol is detected"""
6341 self._SetupVplElf('u_boot_ucode_ptr')
6342 with self.assertRaises(ValueError) as e:
6343 self._DoReadFile('258_vpl_bss_pad.dts')
6344 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6345 str(e.exception))
6346
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306347 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306348 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306349 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6350 self.assertEqual(0, retcode)
6351 image = control.images['test_image']
6352 fname = tools.get_output_filename('test_image.bin')
6353 sname = tools.get_output_filename('symlink_to_test.bin')
6354 self.assertTrue(os.path.islink(sname))
6355 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006356
Andrew Davis6b463da2023-07-22 00:14:44 +05306357 def testSymlinkOverwrite(self):
6358 """Test that symlinked images can be overwritten"""
6359 testdir = TestFunctional._MakeInputDir('symlinktest')
6360 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6361 # build the same image again in the same directory so that existing symlink is present
6362 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6363 fname = tools.get_output_filename('test_image.bin')
6364 sname = tools.get_output_filename('symlink_to_test.bin')
6365 self.assertTrue(os.path.islink(sname))
6366 self.assertEqual(os.readlink(sname), fname)
6367
Simon Glass37f85de2022-10-20 18:22:47 -06006368 def testSymbolsElf(self):
6369 """Test binman can assign symbols embedded in an ELF file"""
6370 if not elf.ELF_TOOLS:
6371 self.skipTest('Python elftools not available')
6372 self._SetupTplElf('u_boot_binman_syms')
6373 self._SetupVplElf('u_boot_binman_syms')
6374 self._SetupSplElf('u_boot_binman_syms')
6375 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6376 image_fname = tools.get_output_filename('image.bin')
6377
6378 image = control.images['image']
6379 entries = image.GetEntries()
6380
6381 for entry in entries.values():
6382 # No symbols in u-boot and it has faked contents anyway
6383 if entry.name == 'u-boot':
6384 continue
6385 edata = data[entry.image_pos:entry.image_pos + entry.size]
6386 efname = tools.get_output_filename(f'edata-{entry.name}')
6387 tools.write_file(efname, edata)
6388
6389 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6390 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6391 for name, sym in syms.items():
6392 msg = 'test'
6393 val = elf.GetSymbolValue(sym, edata, msg)
6394 entry_m = re_name.match(name)
6395 if entry_m:
6396 ename, prop = entry_m.group(1), entry_m.group(3)
6397 entry, entry_name, prop_name = image.LookupEntry(entries,
6398 name, msg)
6399 if prop_name == 'offset':
6400 expect_val = entry.offset
6401 elif prop_name == 'image_pos':
6402 expect_val = entry.image_pos
6403 elif prop_name == 'size':
6404 expect_val = entry.size
6405 self.assertEqual(expect_val, val)
6406
6407 def testSymbolsElfBad(self):
6408 """Check error when trying to write symbols without the elftools lib"""
6409 if not elf.ELF_TOOLS:
6410 self.skipTest('Python elftools not available')
6411 self._SetupTplElf('u_boot_binman_syms')
6412 self._SetupVplElf('u_boot_binman_syms')
6413 self._SetupSplElf('u_boot_binman_syms')
6414 try:
6415 elf.ELF_TOOLS = False
6416 with self.assertRaises(ValueError) as exc:
6417 self._DoReadFileDtb('260_symbols_elf.dts')
6418 finally:
6419 elf.ELF_TOOLS = True
6420 self.assertIn(
6421 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6422 'Cannot write symbols to an ELF file without Python elftools',
6423 str(exc.exception))
6424
Simon Glassde244162023-01-07 14:07:08 -07006425 def testSectionFilename(self):
6426 """Check writing of section contents to a file"""
6427 data = self._DoReadFile('261_section_fname.dts')
6428 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6429 tools.get_bytes(ord('!'), 7) +
6430 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6431 self.assertEqual(expected, data)
6432
6433 sect_fname = tools.get_output_filename('outfile.bin')
6434 self.assertTrue(os.path.exists(sect_fname))
6435 sect_data = tools.read_file(sect_fname)
6436 self.assertEqual(U_BOOT_DATA, sect_data)
6437
Simon Glass1e9e61c2023-01-07 14:07:12 -07006438 def testAbsent(self):
6439 """Check handling of absent entries"""
6440 data = self._DoReadFile('262_absent.dts')
6441 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6442
Simon Glassad5cfe12023-01-07 14:07:14 -07006443 def testPackTeeOsOptional(self):
6444 """Test that an image with an optional TEE binary can be created"""
6445 entry_args = {
6446 'tee-os-path': 'tee.elf',
6447 }
6448 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6449 entry_args=entry_args)[0]
6450 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6451
6452 def checkFitTee(self, dts, tee_fname):
6453 """Check that a tee-os entry works and returns data
6454
6455 Args:
6456 dts (str): Device tree filename to use
6457 tee_fname (str): filename containing tee-os
6458
6459 Returns:
6460 bytes: Image contents
6461 """
6462 if not elf.ELF_TOOLS:
6463 self.skipTest('Python elftools not available')
6464 entry_args = {
6465 'of-list': 'test-fdt1 test-fdt2',
6466 'default-dt': 'test-fdt2',
6467 'tee-os-path': tee_fname,
6468 }
6469 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6470 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6471 extra_indirs=[test_subdir])[0]
6472 return data
6473
6474 def testFitTeeOsOptionalFit(self):
6475 """Test an image with a FIT with an optional OP-TEE binary"""
6476 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6477
6478 # There should be only one node, holding the data set up in SetUpClass()
6479 # for tee.bin
6480 dtb = fdt.Fdt.FromData(data)
6481 dtb.Scan()
6482 node = dtb.GetNode('/images/tee-1')
6483 self.assertEqual(TEE_ADDR,
6484 fdt_util.fdt32_to_cpu(node.props['load'].value))
6485 self.assertEqual(TEE_ADDR,
6486 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6487 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6488
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006489 with test_util.capture_sys_output() as (stdout, stderr):
6490 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6491 err = stderr.getvalue()
6492 self.assertRegex(
6493 err,
6494 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6495
Simon Glassad5cfe12023-01-07 14:07:14 -07006496 def testFitTeeOsOptionalFitBad(self):
6497 """Test an image with a FIT with an optional OP-TEE binary"""
6498 with self.assertRaises(ValueError) as exc:
6499 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6500 self.assertIn(
6501 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6502 str(exc.exception))
6503
6504 def testFitTeeOsBad(self):
6505 """Test an OP-TEE binary with wrong formats"""
6506 self.make_tee_bin('tee.bad1', 123)
6507 with self.assertRaises(ValueError) as exc:
6508 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6509 self.assertIn(
6510 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6511 str(exc.exception))
6512
6513 self.make_tee_bin('tee.bad2', 0, b'extra data')
6514 with self.assertRaises(ValueError) as exc:
6515 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6516 self.assertIn(
6517 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6518 str(exc.exception))
6519
Simon Glass63328f12023-01-07 14:07:15 -07006520 def testExtblobOptional(self):
6521 """Test an image with an external blob that is optional"""
6522 with test_util.capture_sys_output() as (stdout, stderr):
6523 data = self._DoReadFile('266_blob_ext_opt.dts')
6524 self.assertEqual(REFCODE_DATA, data)
6525 err = stderr.getvalue()
6526 self.assertRegex(
6527 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006528 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006529
Simon Glass7447a9d2023-01-11 16:10:12 -07006530 def testSectionInner(self):
6531 """Test an inner section with a size"""
6532 data = self._DoReadFile('267_section_inner.dts')
6533 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6534 self.assertEqual(expected, data)
6535
Simon Glassa4948b22023-01-11 16:10:14 -07006536 def testNull(self):
6537 """Test an image with a null entry"""
6538 data = self._DoReadFile('268_null.dts')
6539 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6540
Simon Glassf1ee03b2023-01-11 16:10:16 -07006541 def testOverlap(self):
6542 """Test an image with a overlapping entry"""
6543 data = self._DoReadFile('269_overlap.dts')
6544 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6545
6546 image = control.images['image']
6547 entries = image.GetEntries()
6548
6549 self.assertIn('inset', entries)
6550 inset = entries['inset']
6551 self.assertEqual(1, inset.offset);
6552 self.assertEqual(1, inset.image_pos);
6553 self.assertEqual(2, inset.size);
6554
6555 def testOverlapNull(self):
6556 """Test an image with a null overlap"""
6557 data = self._DoReadFile('270_overlap_null.dts')
6558 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6559
6560 # Check the FMAP
6561 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6562 self.assertEqual(4, fhdr.nareas)
6563 fiter = iter(fentries)
6564
6565 fentry = next(fiter)
6566 self.assertEqual(b'SECTION', fentry.name)
6567 self.assertEqual(0, fentry.offset)
6568 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6569 self.assertEqual(0, fentry.flags)
6570
6571 fentry = next(fiter)
6572 self.assertEqual(b'U_BOOT', fentry.name)
6573 self.assertEqual(0, fentry.offset)
6574 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6575 self.assertEqual(0, fentry.flags)
6576
6577 # Make sure that the NULL entry appears in the FMAP
6578 fentry = next(fiter)
6579 self.assertEqual(b'NULL', fentry.name)
6580 self.assertEqual(1, fentry.offset)
6581 self.assertEqual(2, fentry.size)
6582 self.assertEqual(0, fentry.flags)
6583
6584 fentry = next(fiter)
6585 self.assertEqual(b'FMAP', fentry.name)
6586 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6587
6588 def testOverlapBad(self):
6589 """Test an image with a bad overlapping entry"""
6590 with self.assertRaises(ValueError) as exc:
6591 self._DoReadFile('271_overlap_bad.dts')
6592 self.assertIn(
6593 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6594 str(exc.exception))
6595
6596 def testOverlapNoOffset(self):
6597 """Test an image with a bad overlapping entry"""
6598 with self.assertRaises(ValueError) as exc:
6599 self._DoReadFile('272_overlap_no_size.dts')
6600 self.assertIn(
6601 "Node '/binman/inset': 'fill' entry is missing properties: size",
6602 str(exc.exception))
6603
Simon Glasse0035c92023-01-11 16:10:17 -07006604 def testBlobSymbol(self):
6605 """Test a blob with symbols read from an ELF file"""
6606 elf_fname = self.ElfTestFile('blob_syms')
6607 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6608 TestFunctional._MakeInputFile('blob_syms.bin',
6609 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6610
6611 data = self._DoReadFile('273_blob_symbol.dts')
6612
6613 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6614 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6615 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6616 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6617 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6618
6619 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6620 expected = sym_values
6621 self.assertEqual(expected, data[:len(expected)])
6622
Simon Glass49e9c002023-01-11 16:10:19 -07006623 def testOffsetFromElf(self):
6624 """Test a blob with symbols read from an ELF file"""
6625 elf_fname = self.ElfTestFile('blob_syms')
6626 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6627 TestFunctional._MakeInputFile('blob_syms.bin',
6628 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6629
6630 data = self._DoReadFile('274_offset_from_elf.dts')
6631
6632 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6633 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6634
6635 image = control.images['image']
6636 entries = image.GetEntries()
6637
6638 self.assertIn('inset', entries)
6639 inset = entries['inset']
6640
6641 self.assertEqual(base + 4, inset.offset);
6642 self.assertEqual(base + 4, inset.image_pos);
6643 self.assertEqual(4, inset.size);
6644
6645 self.assertIn('inset2', entries)
6646 inset = entries['inset2']
6647 self.assertEqual(base + 8, inset.offset);
6648 self.assertEqual(base + 8, inset.image_pos);
6649 self.assertEqual(4, inset.size);
6650
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006651 def testFitAlign(self):
6652 """Test an image with an FIT with aligned external data"""
6653 data = self._DoReadFile('275_fit_align.dts')
6654 self.assertEqual(4096, len(data))
6655
6656 dtb = fdt.Fdt.FromData(data)
6657 dtb.Scan()
6658
6659 props = self._GetPropTree(dtb, ['data-position'])
6660 expected = {
6661 'u-boot:data-position': 1024,
6662 'fdt-1:data-position': 2048,
6663 'fdt-2:data-position': 3072,
6664 }
6665 self.assertEqual(expected, props)
6666
Jonas Karlman490f73c2023-01-21 19:02:12 +00006667 def testFitFirmwareLoadables(self):
6668 """Test an image with an FIT that use fit,firmware"""
6669 if not elf.ELF_TOOLS:
6670 self.skipTest('Python elftools not available')
6671 entry_args = {
6672 'of-list': 'test-fdt1',
6673 'default-dt': 'test-fdt1',
6674 'atf-bl31-path': 'bl31.elf',
6675 'tee-os-path': 'missing.bin',
6676 }
6677 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006678 with test_util.capture_sys_output() as (stdout, stderr):
6679 data = self._DoReadFileDtb(
6680 '276_fit_firmware_loadables.dts',
6681 entry_args=entry_args,
6682 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006683
6684 dtb = fdt.Fdt.FromData(data)
6685 dtb.Scan()
6686
6687 node = dtb.GetNode('/configurations/conf-uboot-1')
6688 self.assertEqual('u-boot', node.props['firmware'].value)
6689 self.assertEqual(['atf-1', 'atf-2'],
6690 fdt_util.GetStringList(node, 'loadables'))
6691
6692 node = dtb.GetNode('/configurations/conf-atf-1')
6693 self.assertEqual('atf-1', node.props['firmware'].value)
6694 self.assertEqual(['u-boot', 'atf-2'],
6695 fdt_util.GetStringList(node, 'loadables'))
6696
6697 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6698 self.assertEqual('u-boot', node.props['firmware'].value)
6699 self.assertEqual(['atf-1', 'atf-2'],
6700 fdt_util.GetStringList(node, 'loadables'))
6701
6702 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6703 self.assertEqual('atf-1', node.props['firmware'].value)
6704 self.assertEqual(['u-boot', 'atf-2'],
6705 fdt_util.GetStringList(node, 'loadables'))
6706
6707 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6708 self.assertEqual('atf-1', node.props['firmware'].value)
6709 self.assertEqual(['u-boot', 'atf-2'],
6710 fdt_util.GetStringList(node, 'loadables'))
6711
Simon Glass9a1c7262023-02-22 12:14:49 -07006712 def testTooldir(self):
6713 """Test that we can specify the tooldir"""
6714 with test_util.capture_sys_output() as (stdout, stderr):
6715 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6716 'tool', '-l'))
6717 self.assertEqual('fred', bintool.Bintool.tooldir)
6718
6719 # Check that the toolpath is updated correctly
6720 self.assertEqual(['fred'], tools.tool_search_paths)
6721
6722 # Try with a few toolpaths; the tooldir should be at the end
6723 with test_util.capture_sys_output() as (stdout, stderr):
6724 self.assertEqual(0, self._DoBinman(
6725 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6726 'tool', '-l'))
6727 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6728
Simon Glass49b77e82023-03-02 17:02:44 -07006729 def testReplaceSectionEntry(self):
6730 """Test replacing an entry in a section"""
6731 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6732 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6733 expect_data, dts='241_replace_section_simple.dts')
6734 self.assertEqual(expect_data, entry_data)
6735
6736 entries = image.GetEntries()
6737 self.assertIn('section', entries)
6738 section = entries['section']
6739
6740 sect_entries = section.GetEntries()
6741 self.assertIn('blob', sect_entries)
6742 entry = sect_entries['blob']
6743 self.assertEqual(len(expect_data), entry.size)
6744
6745 fname = tools.get_output_filename('image-updated.bin')
6746 data = tools.read_file(fname)
6747
6748 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6749 self.assertEqual(expect_data, new_blob_data)
6750
6751 self.assertEqual(U_BOOT_DATA,
6752 data[entry.image_pos + len(expect_data):]
6753 [:len(U_BOOT_DATA)])
6754
6755 def testReplaceSectionDeep(self):
6756 """Test replacing an entry in two levels of sections"""
6757 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6758 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6759 'section/section/blob', expect_data,
6760 dts='278_replace_section_deep.dts')
6761 self.assertEqual(expect_data, entry_data)
6762
6763 entries = image.GetEntries()
6764 self.assertIn('section', entries)
6765 section = entries['section']
6766
6767 subentries = section.GetEntries()
6768 self.assertIn('section', subentries)
6769 section = subentries['section']
6770
6771 sect_entries = section.GetEntries()
6772 self.assertIn('blob', sect_entries)
6773 entry = sect_entries['blob']
6774 self.assertEqual(len(expect_data), entry.size)
6775
6776 fname = tools.get_output_filename('image-updated.bin')
6777 data = tools.read_file(fname)
6778
6779 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6780 self.assertEqual(expect_data, new_blob_data)
6781
6782 self.assertEqual(U_BOOT_DATA,
6783 data[entry.image_pos + len(expect_data):]
6784 [:len(U_BOOT_DATA)])
6785
6786 def testReplaceFitSibling(self):
6787 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006788 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006789 fname = TestFunctional._MakeInputFile('once', b'available once')
6790 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6791 os.remove(fname)
6792
6793 try:
6794 tmpdir, updated_fname = self._SetupImageInTmpdir()
6795
6796 fname = os.path.join(tmpdir, 'update-blob')
6797 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6798 tools.write_file(fname, expected)
6799
6800 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6801 data = tools.read_file(updated_fname)
6802 start = len(U_BOOT_DTB_DATA)
6803 self.assertEqual(expected, data[start:start + len(expected)])
6804 map_fname = os.path.join(tmpdir, 'image-updated.map')
6805 self.assertFalse(os.path.exists(map_fname))
6806 finally:
6807 shutil.rmtree(tmpdir)
6808
Simon Glassc3fe97f2023-03-02 17:02:45 -07006809 def testX509Cert(self):
6810 """Test creating an X509 certificate"""
6811 keyfile = self.TestFile('key.key')
6812 entry_args = {
6813 'keyfile': keyfile,
6814 }
6815 data = self._DoReadFileDtb('279_x509_cert.dts',
6816 entry_args=entry_args)[0]
6817 cert = data[:-4]
6818 self.assertEqual(U_BOOT_DATA, data[-4:])
6819
6820 # TODO: verify the signature
6821
6822 def testX509CertMissing(self):
6823 """Test that binman still produces an image if openssl is missing"""
6824 keyfile = self.TestFile('key.key')
6825 entry_args = {
6826 'keyfile': 'keyfile',
6827 }
6828 with test_util.capture_sys_output() as (_, stderr):
6829 self._DoTestFile('279_x509_cert.dts',
6830 force_missing_bintools='openssl',
6831 entry_args=entry_args)
6832 err = stderr.getvalue()
6833 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6834
Jonas Karlman35305492023-02-25 19:01:33 +00006835 def testPackRockchipTpl(self):
6836 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006837 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006838 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6839
Jonas Karlman1016ec72023-02-25 19:01:35 +00006840 def testMkimageMissingBlobMultiple(self):
6841 """Test missing blob with mkimage entry and multiple-data-files"""
6842 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006843 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006844 err = stderr.getvalue()
6845 self.assertIn("is missing external blobs and is non-functional", err)
6846
6847 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006848 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006849 self.assertIn("not found in input path", str(e.exception))
6850
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006851 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6852 """Prepare sign environment
6853
6854 Create private and public keys, add pubkey into dtb.
6855
6856 Returns:
6857 Tuple:
6858 FIT container
6859 Image name
6860 Private key
6861 DTB
6862 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006863 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006864 data = self._DoReadFileRealDtb(dts)
6865 updated_fname = tools.get_output_filename('image-updated.bin')
6866 tools.write_file(updated_fname, data)
6867 dtb = tools.get_output_filename('source.dtb')
6868 private_key = tools.get_output_filename('test_key.key')
6869 public_key = tools.get_output_filename('test_key.crt')
6870 fit = tools.get_output_filename('fit.fit')
6871 key_dir = tools.get_output_dir()
6872
6873 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6874 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6875 private_key, '-out', public_key)
6876 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6877 '-n', 'test_key', '-r', 'conf', dtb)
6878
6879 return fit, updated_fname, private_key, dtb
6880
6881 def testSignSimple(self):
6882 """Test that a FIT container can be signed in image"""
6883 is_signed = False
6884 fit, fname, private_key, dtb = self._PrepareSignEnv()
6885
6886 # do sign with private key
6887 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6888 ['fit'])
6889 is_signed = self._CheckSign(fit, dtb)
6890
6891 self.assertEqual(is_signed, True)
6892
6893 def testSignExactFIT(self):
6894 """Test that a FIT container can be signed and replaced in image"""
6895 is_signed = False
6896 fit, fname, private_key, dtb = self._PrepareSignEnv()
6897
6898 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6899 args = []
6900 if self.toolpath:
6901 for path in self.toolpath:
6902 args += ['--toolpath', path]
6903
6904 # do sign with private key
6905 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6906 'sha256,rsa4096', '-f', fit, 'fit')
6907 is_signed = self._CheckSign(fit, dtb)
6908
6909 self.assertEqual(is_signed, True)
6910
6911 def testSignNonFit(self):
6912 """Test a non-FIT entry cannot be signed"""
6913 is_signed = False
6914 fit, fname, private_key, _ = self._PrepareSignEnv(
6915 '281_sign_non_fit.dts')
6916
6917 # do sign with private key
6918 with self.assertRaises(ValueError) as e:
6919 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6920 'sha256,rsa4096', '-f', fit, 'u-boot')
6921 self.assertIn(
6922 "Node '/u-boot': Updating signatures is not supported with this entry type",
6923 str(e.exception))
6924
6925 def testSignMissingMkimage(self):
6926 """Test that FIT signing handles a missing mkimage tool"""
6927 fit, fname, private_key, _ = self._PrepareSignEnv()
6928
6929 # try to sign with a missing mkimage tool
6930 bintool.Bintool.set_missing_list(['mkimage'])
6931 with self.assertRaises(ValueError) as e:
6932 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6933 ['fit'])
6934 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6935
Simon Glass4abf7842023-07-18 07:23:54 -06006936 def testSymbolNoWrite(self):
6937 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006938 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006939 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6940 no_write_symbols=True)
6941
6942 def testSymbolNoWriteExpanded(self):
6943 """Test disabling of symbol writing in expanded entries"""
6944 entry_args = {
6945 'spl-dtb': '1',
6946 }
6947 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6948 U_BOOT_SPL_DTB_DATA, 0x38,
6949 entry_args=entry_args, use_expanded=True,
6950 no_write_symbols=True)
6951
Marek Vasutf7413f02023-07-18 07:23:58 -06006952 def testMkimageSpecial(self):
6953 """Test mkimage ignores special hash-1 node"""
6954 data = self._DoReadFile('283_mkimage_special.dts')
6955
6956 # Just check that the data appears in the file somewhere
6957 self.assertIn(U_BOOT_DATA, data)
6958
Simon Glass2d94c422023-07-18 07:23:59 -06006959 def testFitFdtList(self):
6960 """Test an image with an FIT with the fit,fdt-list-val option"""
6961 entry_args = {
6962 'default-dt': 'test-fdt2',
6963 }
6964 data = self._DoReadFileDtb(
6965 '284_fit_fdt_list.dts',
6966 entry_args=entry_args,
6967 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6968 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6969 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6970
Simon Glass83b8bfe2023-07-18 07:24:01 -06006971 def testSplEmptyBss(self):
6972 """Test an expanded SPL with a zero-size BSS"""
6973 # ELF file with a '__bss_size' symbol
6974 self._SetupSplElf(src_fname='bss_data_zero')
6975
6976 entry_args = {
6977 'spl-bss-pad': 'y',
6978 'spl-dtb': 'y',
6979 }
6980 data = self._DoReadFileDtb('285_spl_expand.dts',
6981 use_expanded=True, entry_args=entry_args)[0]
6982
Simon Glassfc792842023-07-18 07:24:04 -06006983 def testTemplate(self):
6984 """Test using a template"""
6985 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6986 data = self._DoReadFile('286_template.dts')
6987 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6988 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6989 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6990
Simon Glass09490b02023-07-22 21:43:52 -06006991 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6992 self.assertTrue(os.path.exists(dtb_fname1))
6993 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6994 dtb.Scan()
6995 node1 = dtb.GetNode('/binman/template')
6996 self.assertTrue(node1)
6997 vga = dtb.GetNode('/binman/first/intel-vga')
6998 self.assertTrue(vga)
6999
Simon Glass54825e12023-07-22 21:43:56 -06007000 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
7001 self.assertTrue(os.path.exists(dtb_fname2))
7002 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
7003 dtb2.Scan()
7004 node2 = dtb2.GetNode('/binman/template')
7005 self.assertFalse(node2)
7006
Simon Glass9909c112023-07-18 07:24:05 -06007007 def testTemplateBlobMulti(self):
7008 """Test using a template with 'multiple-images' enabled"""
7009 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
7010 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
7011 retcode = self._DoTestFile('287_template_multi.dts')
7012
7013 self.assertEqual(0, retcode)
7014 image = control.images['image']
7015 image_fname = tools.get_output_filename('my-image.bin')
7016 data = tools.read_file(image_fname)
7017 self.assertEqual(b'blob@@@@other', data)
7018
Simon Glass5dc511b2023-07-18 07:24:06 -06007019 def testTemplateFit(self):
7020 """Test using a template in a FIT"""
7021 fit_data = self._DoReadFile('288_template_fit.dts')
7022 fname = os.path.join(self._indir, 'fit_data.fit')
7023 tools.write_file(fname, fit_data)
7024 out = tools.run('dumpimage', '-l', fname)
7025
Simon Glassaa6e0552023-07-18 07:24:07 -06007026 def testTemplateSection(self):
7027 """Test using a template in a section (not at top level)"""
7028 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
7029 data = self._DoReadFile('289_template_section.dts')
7030 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
7031 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
7032 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
7033
Simon Glassf53a7bc2023-07-18 07:24:08 -06007034 def testMkimageSymbols(self):
7035 """Test using mkimage to build an image with symbols in it"""
7036 self._SetupSplElf('u_boot_binman_syms')
7037 data = self._DoReadFile('290_mkimage_sym.dts')
7038
7039 image = control.images['image']
7040 entries = image.GetEntries()
7041 self.assertIn('u-boot', entries)
7042 u_boot = entries['u-boot']
7043
7044 mkim = entries['mkimage']
7045 mkim_entries = mkim.GetEntries()
7046 self.assertIn('u-boot-spl', mkim_entries)
7047 spl = mkim_entries['u-boot-spl']
7048 self.assertIn('u-boot-spl2', mkim_entries)
7049 spl2 = mkim_entries['u-boot-spl2']
7050
7051 # skip the mkimage header and the area sizes
7052 mk_data = data[mkim.offset + 0x40:]
7053 size, term = struct.unpack('>LL', mk_data[:8])
7054
7055 # There should be only one image, so check that the zero terminator is
7056 # present
7057 self.assertEqual(0, term)
7058
7059 content = mk_data[8:8 + size]
7060
7061 # The image should contain the symbols from u_boot_binman_syms.c
7062 # Note that image_pos is adjusted by the base address of the image,
7063 # which is 0x10 in our test image
7064 spl_data = content[:0x18]
7065 content = content[0x1b:]
7066
7067 # After the header is a table of offsets for each image. There should
7068 # only be one image, then a 0 terminator, so figure out the real start
7069 # of the image data
7070 base = 0x40 + 8
7071
7072 # Check symbols in both u-boot-spl and u-boot-spl2
7073 for i in range(2):
7074 vals = struct.unpack('<LLQLL', spl_data)
7075
7076 # The image should contain the symbols from u_boot_binman_syms.c
7077 # Note that image_pos is adjusted by the base address of the image,
7078 # which is 0x10 in our 'u_boot_binman_syms' test image
7079 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
7080 self.assertEqual(base, vals[1])
7081 self.assertEqual(spl2.offset, vals[2])
7082 # figure out the internal positions of its components
7083 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
7084
7085 # Check that spl and spl2 are actually at the indicated positions
7086 self.assertEqual(
7087 elf.BINMAN_SYM_MAGIC_VALUE,
7088 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
7089 self.assertEqual(
7090 elf.BINMAN_SYM_MAGIC_VALUE,
7091 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
7092
7093 self.assertEqual(len(U_BOOT_DATA), vals[4])
7094
7095 # Move to next
7096 spl_data = content[:0x18]
7097
Simon Glass86b3e472023-07-22 21:43:57 -06007098 def testTemplatePhandle(self):
7099 """Test using a template in a node containing a phandle"""
7100 entry_args = {
7101 'atf-bl31-path': 'bl31.elf',
7102 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06007103 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007104 entry_args=entry_args)
7105 fname = tools.get_output_filename('image.bin')
7106 out = tools.run('dumpimage', '-l', fname)
7107
7108 # We should see the FIT description and one for each of the two images
7109 lines = out.splitlines()
7110 descs = [line.split()[-1] for line in lines if 'escription' in line]
7111 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7112
7113 def testTemplatePhandleDup(self):
7114 """Test using a template in a node containing a phandle"""
7115 entry_args = {
7116 'atf-bl31-path': 'bl31.elf',
7117 }
7118 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007119 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007120 entry_args=entry_args)
7121 self.assertIn(
7122 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7123 str(e.exception))
7124
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307125 def testTIBoardConfig(self):
7126 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007127 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307128 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7129
Neha Malcom Francis8cd04512024-01-05 17:09:17 +05307130 def testTIBoardConfigLint(self):
7131 """Test that an incorrectly linted config file would generate error"""
7132 with self.assertRaises(ValueError) as e:
7133 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7134 self.assertIn("Yamllint error", str(e.exception))
7135
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307136 def testTIBoardConfigCombined(self):
7137 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007138 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307139 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7140 self.assertGreater(data, configlen_noheader)
7141
7142 def testTIBoardConfigNoDataType(self):
7143 """Test that error is thrown when data type is not supported"""
7144 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007145 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307146 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007147
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307148 def testPackTiSecure(self):
7149 """Test that an image with a TI secured binary can be created"""
7150 keyfile = self.TestFile('key.key')
7151 entry_args = {
7152 'keyfile': keyfile,
7153 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007154 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307155 entry_args=entry_args)[0]
7156 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7157
Manorit Chawdhry2e523b02023-12-29 16:16:27 +05307158 def testPackTiSecureFirewall(self):
7159 """Test that an image with a TI secured binary can be created"""
7160 keyfile = self.TestFile('key.key')
7161 entry_args = {
7162 'keyfile': keyfile,
7163 }
7164 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7165 entry_args=entry_args)[0]
7166 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7167 entry_args=entry_args)[0]
7168 self.assertGreater(len(data_firewall),len(data_no_firewall))
7169
7170 def testPackTiSecureFirewallMissingProperty(self):
7171 """Test that an image with a TI secured binary can be created"""
7172 keyfile = self.TestFile('key.key')
7173 entry_args = {
7174 'keyfile': keyfile,
7175 }
7176 with self.assertRaises(ValueError) as e:
7177 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7178 entry_args=entry_args)[0]
7179 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7180
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307181 def testPackTiSecureMissingTool(self):
7182 """Test that an image with a TI secured binary (non-functional) can be created
7183 when openssl is missing"""
7184 keyfile = self.TestFile('key.key')
7185 entry_args = {
7186 'keyfile': keyfile,
7187 }
7188 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007189 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307190 force_missing_bintools='openssl',
7191 entry_args=entry_args)
7192 err = stderr.getvalue()
7193 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7194
7195 def testPackTiSecureROM(self):
7196 """Test that a ROM image with a TI secured binary can be created"""
7197 keyfile = self.TestFile('key.key')
7198 entry_args = {
7199 'keyfile': keyfile,
7200 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007201 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307202 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007203 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307204 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007205 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307206 entry_args=entry_args)[0]
7207 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7208 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7209 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7210
7211 def testPackTiSecureROMCombined(self):
7212 """Test that a ROM image with a TI secured binary can be created"""
7213 keyfile = self.TestFile('key.key')
7214 entry_args = {
7215 'keyfile': keyfile,
7216 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007217 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307218 entry_args=entry_args)[0]
7219 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7220
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007221 def testEncryptedNoAlgo(self):
7222 """Test encrypted node with missing required properties"""
7223 with self.assertRaises(ValueError) as e:
7224 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7225 self.assertIn(
7226 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7227 str(e.exception))
7228
7229 def testEncryptedInvalidIvfile(self):
7230 """Test encrypted node with invalid iv file"""
7231 with self.assertRaises(ValueError) as e:
7232 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7233 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7234 str(e.exception))
7235
7236 def testEncryptedMissingKey(self):
7237 """Test encrypted node with missing key properties"""
7238 with self.assertRaises(ValueError) as e:
7239 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7240 self.assertIn(
7241 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7242 str(e.exception))
7243
7244 def testEncryptedKeySource(self):
7245 """Test encrypted node with key-source property"""
7246 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7247
7248 dtb = fdt.Fdt.FromData(data)
7249 dtb.Scan()
7250
7251 node = dtb.GetNode('/images/u-boot/cipher')
7252 self.assertEqual('algo-name', node.props['algo'].value)
7253 self.assertEqual('key-source-value', node.props['key-source'].value)
7254 self.assertEqual(ENCRYPTED_IV_DATA,
7255 tools.to_bytes(''.join(node.props['iv'].value)))
7256 self.assertNotIn('key', node.props)
7257
7258 def testEncryptedKeyFile(self):
7259 """Test encrypted node with key-filename property"""
7260 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7261
7262 dtb = fdt.Fdt.FromData(data)
7263 dtb.Scan()
7264
7265 node = dtb.GetNode('/images/u-boot/cipher')
7266 self.assertEqual('algo-name', node.props['algo'].value)
7267 self.assertEqual(ENCRYPTED_IV_DATA,
7268 tools.to_bytes(''.join(node.props['iv'].value)))
7269 self.assertEqual(ENCRYPTED_KEY_DATA,
7270 tools.to_bytes(''.join(node.props['key'].value)))
7271 self.assertNotIn('key-source', node.props)
7272
Lukas Funkee901faf2023-07-18 13:53:13 +02007273
7274 def testSplPubkeyDtb(self):
Simon Glass4b861272024-07-20 11:49:41 +01007275 """Test u_boot_spl_pubkey_dtb etype"""
7276 data = tools.read_file(self.TestFile("key.pem"))
7277 self._MakeInputFile("key.crt", data)
7278 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7279 image = control.images['image']
7280 entries = image.GetEntries()
7281 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7282 dtb_data = dtb_entry.GetData()
7283 dtb = fdt.Fdt.FromData(dtb_data)
7284 dtb.Scan()
Lukas Funkee901faf2023-07-18 13:53:13 +02007285
Simon Glass4b861272024-07-20 11:49:41 +01007286 signature_node = dtb.GetNode('/signature')
7287 self.assertIsNotNone(signature_node)
7288 key_node = signature_node.FindNode("key-key")
7289 self.assertIsNotNone(key_node)
7290 self.assertEqual(fdt_util.GetString(key_node, "required"), "conf")
7291 self.assertEqual(fdt_util.GetString(key_node, "algo"), "sha384,rsa4096")
7292 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007293
Lukas Funke712e1062023-08-03 17:22:14 +02007294 def testXilinxBootgenSigning(self):
7295 """Test xilinx-bootgen etype"""
7296 bootgen = bintool.Bintool.create('bootgen')
7297 self._CheckBintool(bootgen)
7298 data = tools.read_file(self.TestFile("key.key"))
7299 self._MakeInputFile("psk.pem", data)
7300 self._MakeInputFile("ssk.pem", data)
7301 self._SetupPmuFwlElf()
7302 self._SetupSplElf()
7303 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7304 image_fname = tools.get_output_filename('image.bin')
7305
7306 # Read partition header table and check if authentication is enabled
7307 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7308 "-read", image_fname, "pht").splitlines()
7309 attributes = {"authentication": None,
7310 "core": None,
7311 "encryption": None}
7312
7313 for l in bootgen_out:
7314 for a in attributes.keys():
7315 if a in l:
7316 m = re.match(fr".*{a} \[([^]]+)\]", l)
7317 attributes[a] = m.group(1)
7318
7319 self.assertTrue(attributes['authentication'] == "rsa")
7320 self.assertTrue(attributes['core'] == "a53-0")
7321 self.assertTrue(attributes['encryption'] == "no")
7322
7323 def testXilinxBootgenSigningEncryption(self):
7324 """Test xilinx-bootgen etype"""
7325 bootgen = bintool.Bintool.create('bootgen')
7326 self._CheckBintool(bootgen)
7327 data = tools.read_file(self.TestFile("key.key"))
7328 self._MakeInputFile("psk.pem", data)
7329 self._MakeInputFile("ssk.pem", data)
7330 self._SetupPmuFwlElf()
7331 self._SetupSplElf()
7332 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7333 image_fname = tools.get_output_filename('image.bin')
7334
7335 # Read boot header in order to verify encryption source and
7336 # encryption parameter
7337 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7338 "-read", image_fname, "bh").splitlines()
7339 attributes = {"auth_only":
7340 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7341 "encryption_keystore":
7342 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7343 "value": None},
7344 }
7345
7346 for l in bootgen_out:
7347 for a in attributes.keys():
7348 if a in l:
7349 m = re.match(attributes[a]['re'], l)
7350 attributes[a] = m.group(1)
7351
7352 # Check if fsbl-attribute is set correctly
7353 self.assertTrue(attributes['auth_only'] == "true")
7354 # Check if key is stored in efuse
7355 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7356
7357 def testXilinxBootgenMissing(self):
7358 """Test that binman still produces an image if bootgen is missing"""
7359 data = tools.read_file(self.TestFile("key.key"))
7360 self._MakeInputFile("psk.pem", data)
7361 self._MakeInputFile("ssk.pem", data)
7362 self._SetupPmuFwlElf()
7363 self._SetupSplElf()
7364 with test_util.capture_sys_output() as (_, stderr):
7365 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7366 force_missing_bintools='bootgen')
7367 err = stderr.getvalue()
7368 self.assertRegex(err,
7369 "Image 'image'.*missing bintools.*: bootgen")
7370
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307371 def _GetCapsuleHeaders(self, data):
7372 """Get the capsule header contents
7373
7374 Args:
7375 data: Capsule file contents
7376
7377 Returns:
7378 Dict:
7379 key: Capsule Header name (str)
7380 value: Header field value (str)
7381 """
7382 capsule_file = os.path.join(self._indir, 'test.capsule')
7383 tools.write_file(capsule_file, data)
7384
7385 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7386 lines = out.splitlines()
7387
7388 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7389 vals = {}
7390 for line in lines:
7391 mat = re_line.match(line)
7392 if mat:
7393 vals[mat.group(1)] = mat.group(2)
7394
7395 return vals
7396
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307397 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7398 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307399 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7400 fmp_size = "00000010"
7401 fmp_fw_version = "00000002"
7402 capsule_image_index = "00000001"
7403 oemflag = "00018000"
7404 auth_hdr_revision = "00000200"
7405 auth_hdr_cert_type = "00000EF1"
7406
7407 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307408
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307409 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307410
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307411 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307412
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307413 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7414 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7415 self.assertEqual(capsule_image_index,
7416 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307417
7418 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307419 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7420
7421 if signed_capsule:
7422 self.assertEqual(auth_hdr_revision,
7423 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7424 self.assertEqual(auth_hdr_cert_type,
7425 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7426 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7427 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7428
7429 if version_check:
7430 self.assertEqual(fmp_signature,
7431 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7432 self.assertEqual(fmp_size,
7433 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7434 self.assertEqual(fmp_fw_version,
7435 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7436
7437 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307438
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307439 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7440 if accept_capsule:
7441 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7442 else:
7443 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7444
7445 hdr = self._GetCapsuleHeaders(data)
7446
7447 self.assertEqual(capsule_hdr_guid.upper(),
7448 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7449
7450 if accept_capsule:
7451 capsule_size = "0000002C"
7452 else:
7453 capsule_size = "0000001C"
7454 self.assertEqual(capsule_size,
7455 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7456
7457 if accept_capsule:
7458 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7459
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307460 def testCapsuleGen(self):
7461 """Test generation of EFI capsule"""
7462 data = self._DoReadFile('311_capsule.dts')
7463
7464 self._CheckCapsule(data)
7465
7466 def testSignedCapsuleGen(self):
7467 """Test generation of EFI capsule"""
7468 data = tools.read_file(self.TestFile("key.key"))
7469 self._MakeInputFile("key.key", data)
7470 data = tools.read_file(self.TestFile("key.pem"))
7471 self._MakeInputFile("key.crt", data)
7472
7473 data = self._DoReadFile('312_capsule_signed.dts')
7474
7475 self._CheckCapsule(data, signed_capsule=True)
7476
7477 def testCapsuleGenVersionSupport(self):
7478 """Test generation of EFI capsule with version support"""
7479 data = self._DoReadFile('313_capsule_version.dts')
7480
7481 self._CheckCapsule(data, version_check=True)
7482
7483 def testCapsuleGenSignedVer(self):
7484 """Test generation of signed EFI capsule with version information"""
7485 data = tools.read_file(self.TestFile("key.key"))
7486 self._MakeInputFile("key.key", data)
7487 data = tools.read_file(self.TestFile("key.pem"))
7488 self._MakeInputFile("key.crt", data)
7489
7490 data = self._DoReadFile('314_capsule_signed_ver.dts')
7491
7492 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7493
7494 def testCapsuleGenCapOemFlags(self):
7495 """Test generation of EFI capsule with OEM Flags set"""
7496 data = self._DoReadFile('315_capsule_oemflags.dts')
7497
7498 self._CheckCapsule(data, capoemflags=True)
7499
7500 def testCapsuleGenKeyMissing(self):
7501 """Test that binman errors out on missing key"""
7502 with self.assertRaises(ValueError) as e:
7503 self._DoReadFile('316_capsule_missing_key.dts')
7504
7505 self.assertIn("Both private key and public key certificate need to be provided",
7506 str(e.exception))
7507
7508 def testCapsuleGenIndexMissing(self):
7509 """Test that binman errors out on missing image index"""
7510 with self.assertRaises(ValueError) as e:
7511 self._DoReadFile('317_capsule_missing_index.dts')
7512
7513 self.assertIn("entry is missing properties: image-index",
7514 str(e.exception))
7515
7516 def testCapsuleGenGuidMissing(self):
7517 """Test that binman errors out on missing image GUID"""
7518 with self.assertRaises(ValueError) as e:
7519 self._DoReadFile('318_capsule_missing_guid.dts')
7520
7521 self.assertIn("entry is missing properties: image-guid",
7522 str(e.exception))
7523
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307524 def testCapsuleGenAcceptCapsule(self):
7525 """Test generationg of accept EFI capsule"""
7526 data = self._DoReadFile('319_capsule_accept.dts')
7527
7528 self._CheckEmptyCapsule(data, accept_capsule=True)
7529
7530 def testCapsuleGenRevertCapsule(self):
7531 """Test generationg of revert EFI capsule"""
7532 data = self._DoReadFile('320_capsule_revert.dts')
7533
7534 self._CheckEmptyCapsule(data)
7535
7536 def testCapsuleGenAcceptGuidMissing(self):
7537 """Test that binman errors out on missing image GUID for accept capsule"""
7538 with self.assertRaises(ValueError) as e:
7539 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7540
7541 self.assertIn("Image GUID needed for generating accept capsule",
7542 str(e.exception))
7543
7544 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7545 """Test that capsule-type is specified"""
7546 with self.assertRaises(ValueError) as e:
7547 self._DoReadFile('322_empty_capsule_type_missing.dts')
7548
7549 self.assertIn("entry is missing properties: capsule-type",
7550 str(e.exception))
7551
7552 def testCapsuleGenAcceptOrRevertMissing(self):
7553 """Test that both accept and revert capsule are not specified"""
7554 with self.assertRaises(ValueError) as e:
7555 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7556
Simon Glassa360b8f2024-06-23 11:55:06 -06007557 def test_assume_size(self):
7558 """Test handling of the assume-size property for external blob"""
7559 with self.assertRaises(ValueError) as e:
7560 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7561 allow_fake_blobs=True)
7562 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7563 str(e.exception))
7564
7565 def test_assume_size_ok(self):
7566 """Test handling of the assume-size where it fits OK"""
7567 with test_util.capture_sys_output() as (stdout, stderr):
7568 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7569 allow_fake_blobs=True)
7570 err = stderr.getvalue()
7571 self.assertRegex(
7572 err,
7573 "Image '.*' has faked external blobs and is non-functional: .*")
7574
7575 def test_assume_size_no_fake(self):
7576 """Test handling of the assume-size where it fits OK"""
7577 with test_util.capture_sys_output() as (stdout, stderr):
7578 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7579 err = stderr.getvalue()
7580 self.assertRegex(
7581 err,
7582 "Image '.*' is missing external blobs and is non-functional: .*")
7583
Simon Glass5f7aadf2024-07-20 11:49:47 +01007584 def SetupAlternateDts(self):
7585 """Compile the .dts test files for alternative-fdt
7586
7587 Returns:
7588 tuple:
7589 str: Test directory created
7590 list of str: '.bin' files which we expect Binman to create
7591 """
7592 testdir = TestFunctional._MakeInputDir('dtb')
7593 dtb_list = []
7594 for fname in glob.glob(f'{self.TestFile("alt_dts")}/*.dts'):
7595 tmp_fname = fdt_util.EnsureCompiled(fname, testdir)
7596 base = os.path.splitext(os.path.basename(fname))[0]
7597 dtb_list.append(base + '.bin')
7598 shutil.move(tmp_fname, os.path.join(testdir, base + '.dtb'))
7599
7600 return testdir, dtb_list
7601
Simon Glassf3598922024-07-20 11:49:45 +01007602 def CheckAlternates(self, dts, phase, xpl_data):
7603 """Run the test for the alterative-fdt etype
7604
7605 Args:
7606 dts (str): Devicetree file to process
7607 phase (str): Phase to process ('spl', 'tpl' or 'vpl')
7608 xpl_data (bytes): Expected data for the phase's binary
7609
7610 Returns:
7611 dict of .dtb files produced
7612 key: str filename
7613 value: Fdt object
7614 """
Simon Glass5f7aadf2024-07-20 11:49:47 +01007615 dtb_list = self.SetupAlternateDts()[1]
Simon Glassf3598922024-07-20 11:49:45 +01007616
7617 entry_args = {
7618 f'{phase}-dtb': '1',
7619 f'{phase}-bss-pad': 'y',
7620 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7621 }
7622 data = self._DoReadFileDtb(dts, use_real_dtb=True, update_dtb=True,
7623 use_expanded=True, entry_args=entry_args)[0]
7624 self.assertEqual(xpl_data, data[:len(xpl_data)])
7625 rest = data[len(xpl_data):]
7626 pad_len = 10
7627 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7628
7629 # Check the dtb is using the test file
7630 dtb_data = rest[pad_len:]
7631 dtb = fdt.Fdt.FromData(dtb_data)
7632 dtb.Scan()
7633 fdt_size = dtb.GetFdtObj().totalsize()
7634 self.assertEqual('model-not-set',
7635 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7636
7637 pad_len = 10
7638
7639 # Check the other output files
7640 dtbs = {}
7641 for fname in dtb_list:
7642 pathname = tools.get_output_filename(fname)
7643 self.assertTrue(os.path.exists(pathname))
7644
7645 data = tools.read_file(pathname)
7646 self.assertEqual(xpl_data, data[:len(xpl_data)])
7647 rest = data[len(xpl_data):]
7648
7649 self.assertEqual(tools.get_bytes(0, pad_len), rest[:pad_len])
7650 rest = rest[pad_len:]
7651
7652 dtb = fdt.Fdt.FromData(rest)
7653 dtb.Scan()
7654 dtbs[fname] = dtb
7655
7656 expected = 'one' if '1' in fname else 'two'
7657 self.assertEqual(f'u-boot,model-{expected}',
7658 fdt_util.GetString(dtb.GetRoot(), 'compatible'))
7659
7660 # Make sure the FDT is the same size as the 'main' one
7661 rest = rest[fdt_size:]
7662
7663 self.assertEqual(b'', rest)
7664 return dtbs
7665
7666 def testAlternatesFdt(self):
7667 """Test handling of alternates-fdt etype"""
7668 self._SetupTplElf()
7669 dtbs = self.CheckAlternates('328_alternates_fdt.dts', 'tpl',
7670 U_BOOT_TPL_NODTB_DATA)
7671 for dtb in dtbs.values():
7672 # Check for the node with the tag
7673 node = dtb.GetNode('/node')
7674 self.assertIsNotNone(node)
7675 self.assertEqual(5, len(node.props.keys()))
7676
7677 # Make sure the other node is still there
7678 self.assertIsNotNone(dtb.GetNode('/node/other-node'))
7679
7680 def testAlternatesFdtgrep(self):
7681 """Test handling of alternates-fdt etype using fdtgrep"""
7682 self._SetupTplElf()
7683 dtbs = self.CheckAlternates('329_alternates_fdtgrep.dts', 'tpl',
7684 U_BOOT_TPL_NODTB_DATA)
7685 for dtb in dtbs.values():
7686 # Check for the node with the tag
7687 node = dtb.GetNode('/node')
7688 self.assertIsNotNone(node)
7689 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7690 node.props.keys())
7691
7692 # Make sure the other node is gone
7693 self.assertIsNone(dtb.GetNode('/node/other-node'))
7694
7695 def testAlternatesFdtgrepVpl(self):
7696 """Test handling of alternates-fdt etype using fdtgrep with vpl"""
7697 self._SetupVplElf()
7698 dtbs = self.CheckAlternates('330_alternates_vpl.dts', 'vpl',
7699 U_BOOT_VPL_NODTB_DATA)
7700
7701 def testAlternatesFdtgrepSpl(self):
7702 """Test handling of alternates-fdt etype using fdtgrep with spl"""
7703 self._SetupSplElf()
7704 dtbs = self.CheckAlternates('331_alternates_spl.dts', 'spl',
7705 U_BOOT_SPL_NODTB_DATA)
7706
7707 def testAlternatesFdtgrepInval(self):
7708 """Test alternates-fdt etype using fdtgrep with invalid phase"""
7709 self._SetupSplElf()
7710 with self.assertRaises(ValueError) as e:
7711 dtbs = self.CheckAlternates('332_alternates_inval.dts', 'spl',
7712 U_BOOT_SPL_NODTB_DATA)
7713 self.assertIn("Invalid U-Boot phase 'bad-phase': Use tpl/vpl/spl",
7714 str(e.exception))
7715
Simon Glasscd2783e2024-07-20 11:49:46 +01007716 def testFitFdtListDir(self):
7717 """Test an image with an FIT with FDT images using fit,fdt-list-dir"""
Simon Glass1bba8942024-08-26 13:11:34 -06007718 old_dir = os.getcwd()
7719 try:
7720 os.chdir(self._indir)
7721 self.CheckFitFdt('333_fit_fdt_dir.dts', False)
7722 finally:
7723 os.chdir(old_dir)
Simon Glasscd2783e2024-07-20 11:49:46 +01007724
Simon Glassd2a9d6e2024-08-26 13:11:37 -06007725 def testFitFdtListDirDefault(self):
7726 """Test an FIT fit,fdt-list-dir where the default DT in is a subdir"""
7727 old_dir = os.getcwd()
7728 try:
7729 os.chdir(self._indir)
7730 self.CheckFitFdt('333_fit_fdt_dir.dts', False,
7731 default_dt='rockchip/test-fdt2')
7732 finally:
7733 os.chdir(old_dir)
7734
Simon Glass5f7aadf2024-07-20 11:49:47 +01007735 def testFitFdtCompat(self):
7736 """Test an image with an FIT with compatible in the config nodes"""
7737 entry_args = {
7738 'of-list': 'model1 model2',
7739 'default-dt': 'model2',
7740 }
7741 testdir, dtb_list = self.SetupAlternateDts()
7742 data = self._DoReadFileDtb(
7743 '334_fit_fdt_compat.dts', use_real_dtb=True, update_dtb=True,
7744 entry_args=entry_args, extra_indirs=[testdir])[0]
7745
7746 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7747
7748 fit = fdt.Fdt.FromData(fit_data)
7749 fit.Scan()
7750
7751 cnode = fit.GetNode('/configurations')
7752 self.assertIn('default', cnode.props)
7753 self.assertEqual('config-2', cnode.props['default'].value)
7754
7755 for seq in range(1, 2):
7756 name = f'config-{seq}'
7757 fnode = fit.GetNode('/configurations/%s' % name)
7758 self.assertIsNotNone(fnode)
7759 self.assertIn('compatible', fnode.props.keys())
7760 expected = 'one' if seq == 1 else 'two'
7761 self.assertEqual(f'u-boot,model-{expected}',
7762 fnode.props['compatible'].value)
7763
Simon Glassa04b9942024-07-20 11:49:48 +01007764 def testFitFdtPhase(self):
7765 """Test an image with an FIT with fdt-phase in the fdt nodes"""
7766 phase = 'tpl'
7767 entry_args = {
7768 f'{phase}-dtb': '1',
7769 f'{phase}-bss-pad': 'y',
7770 'of-spl-remove-props': 'prop-to-remove another-prop-to-get-rid-of',
7771 'of-list': 'model1 model2',
7772 'default-dt': 'model2',
7773 }
7774 testdir, dtb_list = self.SetupAlternateDts()
7775 data = self._DoReadFileDtb(
7776 '335_fit_fdt_phase.dts', use_real_dtb=True, update_dtb=True,
7777 entry_args=entry_args, extra_indirs=[testdir])[0]
7778 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
7779 fit = fdt.Fdt.FromData(fit_data)
7780 fit.Scan()
7781
7782 # Check that each FDT has only the expected properties for the phase
7783 for seq in range(1, 2):
7784 fnode = fit.GetNode(f'/images/fdt-{seq}')
7785 self.assertIsNotNone(fnode)
7786 dtb = fdt.Fdt.FromData(fnode.props['data'].bytes)
7787 dtb.Scan()
7788
7789 # Make sure that the 'bootph-pre-sram' tag in /node protects it from
7790 # removal
7791 node = dtb.GetNode('/node')
7792 self.assertIsNotNone(node)
7793 self.assertEqual({'some-prop', 'not-a-prop-to-remove'},
7794 node.props.keys())
7795
7796 # Make sure the other node is gone
7797 self.assertIsNone(dtb.GetNode('/node/other-node'))
7798
Simon Glassb553e8a2024-08-26 13:11:29 -06007799 def testMkeficapsuleMissing(self):
7800 """Test that binman complains if mkeficapsule is missing"""
7801 with self.assertRaises(ValueError) as e:
7802 self._DoTestFile('311_capsule.dts',
7803 force_missing_bintools='mkeficapsule')
7804 self.assertIn("Node '/binman/efi-capsule': Missing tool: 'mkeficapsule'",
7805 str(e.exception))
7806
7807 def testMkeficapsuleMissingOk(self):
7808 """Test that binman deals with mkeficapsule being missing"""
7809 with test_util.capture_sys_output() as (stdout, stderr):
7810 ret = self._DoTestFile('311_capsule.dts',
7811 force_missing_bintools='mkeficapsule',
7812 allow_missing=True)
7813 self.assertEqual(103, ret)
7814 err = stderr.getvalue()
7815 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkeficapsule")
7816
Simon Glass4b0f4142024-08-26 13:11:40 -06007817 def testSymbolsBase(self):
7818 """Test handling of symbols-base"""
7819 self.checkSymbols('336_symbols_base.dts', U_BOOT_SPL_DATA, 0x1c,
7820 symbols_base=0)
7821
7822 def testSymbolsBaseExpanded(self):
7823 """Test handling of symbols-base with expanded entries"""
7824 entry_args = {
7825 'spl-dtb': '1',
7826 }
7827 self.checkSymbols('337_symbols_base_expand.dts', U_BOOT_SPL_NODTB_DATA +
7828 U_BOOT_SPL_DTB_DATA, 0x38,
7829 entry_args=entry_args, use_expanded=True,
7830 symbols_base=0)
7831
Simon Glass3eb30a42024-08-26 13:11:42 -06007832 def testSymbolsCompressed(self):
7833 """Test binman complains about symbols from a compressed section"""
7834 with test_util.capture_sys_output() as (stdout, stderr):
7835 self.checkSymbols('338_symbols_comp.dts', U_BOOT_SPL_DATA, None)
7836 out = stdout.getvalue()
7837 self.assertIn('Symbol-writing: no value for /binman/section/u-boot',
7838 out)
7839
Simon Glass9c25ef22024-08-26 13:11:43 -06007840 def testNxpImx8Image(self):
7841 """Test that binman can produce an iMX8 image"""
7842 self._DoTestFile('339_nxp_imx8.dts')
7843
Alexander Kochetkova730a282024-09-16 11:24:46 +03007844 def testFitSignSimple(self):
7845 """Test that image with FIT and signature nodes can be signed"""
7846 if not elf.ELF_TOOLS:
7847 self.skipTest('Python elftools not available')
7848 entry_args = {
7849 'of-list': 'test-fdt1',
7850 'default-dt': 'test-fdt1',
7851 'atf-bl31-path': 'bl31.elf',
7852 }
7853 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7854 self._MakeInputFile("keys/rsa2048.key", data)
7855
7856 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7857 keys_subdir = os.path.join(self._indir, "keys")
7858 data = self._DoReadFileDtb(
7859 '340_fit_signature.dts',
7860 entry_args=entry_args,
7861 extra_indirs=[test_subdir, keys_subdir])[0]
7862
7863 dtb = fdt.Fdt.FromData(data)
7864 dtb.Scan()
7865
7866 conf = dtb.GetNode('/configurations/conf-uboot-1')
7867 self.assertIsNotNone(conf)
7868 signature = conf.FindNode('signature')
7869 self.assertIsNotNone(signature)
7870 self.assertIsNotNone(signature.props.get('value'))
7871
7872 images = dtb.GetNode('/images')
7873 self.assertIsNotNone(images)
7874 for subnode in images.subnodes:
7875 signature = subnode.FindNode('signature')
7876 self.assertIsNotNone(signature)
7877 self.assertIsNotNone(signature.props.get('value'))
7878
7879 def testFitSignKeyNotFound(self):
7880 """Test that missing keys raise an error"""
7881 if not elf.ELF_TOOLS:
7882 self.skipTest('Python elftools not available')
7883 entry_args = {
7884 'of-list': 'test-fdt1',
7885 'default-dt': 'test-fdt1',
7886 'atf-bl31-path': 'bl31.elf',
7887 }
7888 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7889 with self.assertRaises(ValueError) as e:
7890 self._DoReadFileDtb(
7891 '340_fit_signature.dts',
7892 entry_args=entry_args,
7893 extra_indirs=[test_subdir])[0]
7894 self.assertIn(
7895 'Filename \'rsa2048.key\' not found in input path',
7896 str(e.exception))
7897
7898 def testFitSignMultipleKeyPaths(self):
7899 """Test that keys found in multiple paths raise an error"""
7900 if not elf.ELF_TOOLS:
7901 self.skipTest('Python elftools not available')
7902 entry_args = {
7903 'of-list': 'test-fdt1',
7904 'default-dt': 'test-fdt1',
7905 'atf-bl31-path': 'bl31.elf',
7906 }
7907 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7908 self._MakeInputFile("keys1/rsa2048.key", data)
7909 data = tools.read_file(self.TestFile("340_rsa2048.key"))
7910 self._MakeInputFile("keys2/conf-rsa2048.key", data)
7911
7912 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7913 keys_subdir1 = os.path.join(self._indir, "keys1")
7914 keys_subdir2 = os.path.join(self._indir, "keys2")
7915 with self.assertRaises(ValueError) as e:
7916 self._DoReadFileDtb(
7917 '341_fit_signature.dts',
7918 entry_args=entry_args,
7919 extra_indirs=[test_subdir, keys_subdir1, keys_subdir2])[0]
7920 self.assertIn(
7921 'Node \'/binman/fit\': multiple key paths found',
7922 str(e.exception))
7923
7924 def testFitSignNoSingatureNodes(self):
7925 """Test that fit,sign doens't raise error if no signature nodes found"""
7926 if not elf.ELF_TOOLS:
7927 self.skipTest('Python elftools not available')
7928 entry_args = {
7929 'of-list': 'test-fdt1',
7930 'default-dt': 'test-fdt1',
7931 'atf-bl31-path': 'bl31.elf',
7932 }
7933 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
7934 self._DoReadFileDtb(
7935 '342_fit_signature.dts',
7936 entry_args=entry_args,
7937 extra_indirs=[test_subdir])[0]
7938
Simon Glassa360b8f2024-06-23 11:55:06 -06007939
Paul HENRYSff318462024-11-25 18:47:17 +01007940 def testSimpleFitEncryptedData(self):
7941 """Test an image with a FIT containing data to be encrypted"""
7942 data = tools.read_file(self.TestFile("aes256.bin"))
7943 self._MakeInputFile("keys/aes256.bin", data)
7944
7945 keys_subdir = os.path.join(self._indir, "keys")
7946 data = self._DoReadFileDtb(
7947 '343_fit_encrypt_data.dts',
7948 extra_indirs=[keys_subdir])[0]
7949
7950 fit = fdt.Fdt.FromData(data)
7951 fit.Scan()
7952
7953 # Extract the encrypted data and the Initialization Vector from the FIT
7954 node = fit.GetNode('/images/u-boot')
7955 subnode = fit.GetNode('/images/u-boot/cipher')
7956 data_size_unciphered = int.from_bytes(fit.GetProps(node)['data-size-unciphered'].bytes,
7957 byteorder='big')
7958 self.assertEqual(data_size_unciphered, len(U_BOOT_NODTB_DATA))
7959
7960 # Retrieve the key name from the FIT removing any null byte
7961 key_name = fit.GetProps(subnode)['key-name-hint'].bytes.replace(b'\x00', b'')
7962 with open(self.TestFile(key_name.decode('ascii') + '.bin'), 'rb') as file:
7963 key = file.read()
7964 iv = fit.GetProps(subnode)['iv'].bytes.hex()
7965 enc_data = fit.GetProps(node)['data'].bytes
7966 outdir = tools.get_output_dir()
7967 enc_data_file = os.path.join(outdir, 'encrypted_data.bin')
7968 tools.write_file(enc_data_file, enc_data)
7969 data_file = os.path.join(outdir, 'data.bin')
7970
7971 # Decrypt the encrypted data from the FIT and compare the data
7972 tools.run('openssl', 'enc', '-aes-256-cbc', '-nosalt', '-d', '-in',
7973 enc_data_file, '-out', data_file, '-K', key.hex(), '-iv', iv)
7974 with open(data_file, 'r') as file:
7975 dec_data = file.read()
7976 self.assertEqual(U_BOOT_NODTB_DATA, dec_data.encode('ascii'))
7977
7978 def testSimpleFitEncryptedDataMissingKey(self):
7979 """Test an image with a FIT containing data to be encrypted but with a missing key"""
7980 with self.assertRaises(ValueError) as e:
7981 self._DoReadFile('344_fit_encrypt_data_no_key.dts')
7982
7983 self.assertIn("Filename 'aes256.bin' not found in input path", str(e.exception))
7984
Paul HENRYS1b4bedb2024-11-25 18:54:21 +01007985 def testFitFdtName(self):
7986 """Test an image with an FIT with multiple FDT images using NAME"""
7987 self.CheckFitFdt('345_fit_fdt_name.dts', use_seq_num=False)
7988
Simon Glassac599912017-11-12 21:52:22 -07007989if __name__ == "__main__":
7990 unittest.main()