blob: e4da04030a51e6fe921497e53f49cafcf97e73f6 [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 Glassc585dd42020-04-17 18:09:03 -060010import gzip
Simon Glassae7cf032018-09-14 04:57:31 -060011import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glass45d556d2020-07-09 18:39:45 -060014import re
Simon Glass57454f42016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
Simon Glass162017b2022-01-09 20:13:57 -070020import unittest.mock
21import urllib.error
Simon Glass57454f42016-11-25 20:15:52 -070022
Simon Glass4eae9252022-01-09 20:13:50 -070023from binman import bintool
Simon Glassc585dd42020-04-17 18:09:03 -060024from binman import cbfs_util
25from binman import cmdline
26from binman import control
27from binman import elf
28from binman import elf_test
Simon Glass3efb2972021-11-23 21:08:59 -070029from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060030from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060031from binman import state
32from dtoc import fdt
33from dtoc import fdt_util
34from binman.etype import fdtmap
35from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060036from binman.image import Image
Simon Glass131444f2023-02-23 18:18:04 -070037from u_boot_pylib import command
38from u_boot_pylib import test_util
39from u_boot_pylib import tools
40from u_boot_pylib import tout
Simon Glass57454f42016-11-25 20:15:52 -070041
42# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060043U_BOOT_DATA = b'1234'
44U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +030045U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
46U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass56d05412022-02-28 07:16:54 -070047U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glass303f62f2019-05-17 22:00:46 -060048BLOB_DATA = b'89'
49ME_DATA = b'0abcd'
50VGA_DATA = b'vga'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +053051EFI_CAPSULE_DATA = b'efi'
Simon Glass303f62f2019-05-17 22:00:46 -060052U_BOOT_DTB_DATA = b'udtb'
53U_BOOT_SPL_DTB_DATA = b'spldtb'
54U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass56d05412022-02-28 07:16:54 -070055U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glass303f62f2019-05-17 22:00:46 -060056X86_START16_DATA = b'start16'
57X86_START16_SPL_DATA = b'start16spl'
58X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060059X86_RESET16_DATA = b'reset16'
60X86_RESET16_SPL_DATA = b'reset16spl'
61X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060062PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
63U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
64U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
65U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass56d05412022-02-28 07:16:54 -070066U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +030067U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
68U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
69U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glass303f62f2019-05-17 22:00:46 -060070FSP_DATA = b'fsp'
71CMC_DATA = b'cmc'
72VBT_DATA = b'vbt'
73MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060074TEXT_DATA = 'text'
75TEXT_DATA2 = 'text2'
76TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060077CROS_EC_RW_DATA = b'ecrw'
78GBB_DATA = b'gbbd'
79BMPBLK_DATA = b'bmp'
80VBLOCK_DATA = b'vblk'
81FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
82 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060083COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060084COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060085REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060086FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060087FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060088FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060089ATF_BL31_DATA = b'bl31'
Roger Quadros5cdcea02022-02-19 20:50:04 +020090TEE_OS_DATA = b'this is some tee OS data'
Neha Malcom Francis59be2552023-12-05 15:12:18 +053091TI_DM_DATA = b'tidmtidm'
Simon Glass3efb2972021-11-23 21:08:59 -070092ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080093OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050094SCP_DATA = b'scp'
Jonas Karlman35305492023-02-25 19:01:33 +000095ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glassa435cd12020-09-01 05:13:59 -060096TEST_FDT1_DATA = b'fdt1'
97TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060098ENV_DATA = b'var1=1\nvar2="2"'
Christian Taedcke62ac29a2023-07-17 09:05:54 +020099ENCRYPTED_IV_DATA = b'123456'
100ENCRYPTED_KEY_DATA = b'abcde'
Philippe Reynesebe96cb2022-03-28 22:57:04 +0200101PRE_LOAD_MAGIC = b'UBSH'
102PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
103PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530104TI_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 +0530105TI_UNSECURE_DATA = b'unsecuredata'
Simon Glassa435cd12020-09-01 05:13:59 -0600106
107# Subdirectory of the input dir to use to put test FDTs
108TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600109
Simon Glass2c6adba2019-07-20 12:23:47 -0600110# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600111EXTRACT_DTB_SIZE = 0x3c9
112
Simon Glass2c6adba2019-07-20 12:23:47 -0600113# Properties expected to be in the device tree when update_dtb is used
114BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
115
Simon Glassfb30e292019-07-20 12:23:51 -0600116# Extra properties expected to be in the device tree when allow-repack is used
117REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
118
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200119# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200120COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700121
Simon Glassad5cfe12023-01-07 14:07:14 -0700122TEE_ADDR = 0x5678
123
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530124# Firmware Management Protocol(FMP) GUID
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530125FW_MGMT_GUID = '6dcbd5ed-e82d-4c44-bda1-7194199ad92a'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530126# Image GUID specified in the DTS
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +0530127CAPSULE_IMAGE_GUID = '09d7cf52-0720-4710-91d1-08469b7fe9c8'
128# Windows cert GUID
129WIN_CERT_TYPE_EFI_GUID = '4aafd29d-68df-49ee-8aa9-347d375665a7'
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +0530130# Empty capsule GUIDs
131EMPTY_CAPSULE_ACCEPT_GUID = '0c996046-bcc0-4d04-85ec-e1fcedf1c6f8'
132EMPTY_CAPSULE_REVERT_GUID = 'acd58b4b-c0e8-475f-99b5-6b3f7e07aaf0'
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530133
Simon Glass57454f42016-11-25 20:15:52 -0700134class TestFunctional(unittest.TestCase):
135 """Functional tests for binman
136
137 Most of these use a sample .dts file to build an image and then check
138 that it looks correct. The sample files are in the test/ subdirectory
139 and are numbered.
140
141 For each entry type a very small test file is created using fixed
142 string contents. This makes it easy to test that things look right, and
143 debug problems.
144
145 In some cases a 'real' file must be used - these are also supplied in
146 the test/ diurectory.
147 """
148 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600149 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700150 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600151 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700152
Simon Glass57454f42016-11-25 20:15:52 -0700153 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600154 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
155 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700156
157 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600158 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700159
160 # Create some test files
161 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
162 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
163 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600164 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700165 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700166 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700167 TestFunctional._MakeInputFile('me.bin', ME_DATA)
168 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600169 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600170
Jagdish Gediya311d4842018-09-03 21:35:08 +0530171 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600172
Simon Glassabab18c2019-08-24 07:22:49 -0600173 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
174 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700175 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600176 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600177 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600178
179 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
180 X86_RESET16_DATA)
181 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
182 X86_RESET16_SPL_DATA)
183 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
184 X86_RESET16_TPL_DATA)
185
Simon Glass57454f42016-11-25 20:15:52 -0700186 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700187 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
188 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600189 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
190 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700191 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
192 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700193 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
194 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700195 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700196 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600197 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600198 TestFunctional._MakeInputDir('devkeys')
199 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600200 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600201 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600202 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600203 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700204
Simon Glassf6290892019-08-24 07:22:53 -0600205 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
206 elf_test.BuildElfTestFiles(cls._elf_testdir)
207
Simon Glass72232452016-11-25 20:15:53 -0700208 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600209 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700210 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700211
212 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600213 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700214
Simon Glass862f8e22019-08-24 07:22:43 -0600215 shutil.copytree(cls.TestFile('files'),
216 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600217
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530218 shutil.copytree(cls.TestFile('yaml'),
219 os.path.join(cls._indir, 'yaml'))
220
Simon Glass7ba33592018-09-14 04:57:26 -0600221 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600222 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600223 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200224 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Neha Malcom Francis59be2552023-12-05 15:12:18 +0530225 TestFunctional._MakeInputFile('dm.bin', TI_DM_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700226 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800227 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500228 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman35305492023-02-25 19:01:33 +0000229 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530230 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +0530231 TestFunctional._MakeInputFile('capsule_input.bin', EFI_CAPSULE_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600232
Simon Glassa435cd12020-09-01 05:13:59 -0600233 # Add a few .dtb files for testing
234 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
235 TEST_FDT1_DATA)
236 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
237 TEST_FDT2_DATA)
238
Simon Glassa0729502020-09-06 10:35:33 -0600239 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
240
Simon Glass5f423422022-03-05 20:19:12 -0700241 # ELF file with two sections in different parts of memory, used for both
242 # ATF and OP_TEE
243 TestFunctional._MakeInputFile('bl31.elf',
244 tools.read_file(cls.ElfTestFile('elf_sections')))
245 TestFunctional._MakeInputFile('tee.elf',
246 tools.read_file(cls.ElfTestFile('elf_sections')))
247
Simon Glassad5cfe12023-01-07 14:07:14 -0700248 # Newer OP_TEE file in v1 binary format
249 cls.make_tee_bin('tee.bin')
250
Christian Taedcke62ac29a2023-07-17 09:05:54 +0200251 # test files for encrypted tests
252 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
253 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
254
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200255 cls.comp_bintools = {}
256 for name in COMP_BINTOOLS:
257 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600258
Simon Glass57454f42016-11-25 20:15:52 -0700259 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600260 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700261 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600262 if cls.preserve_indir:
263 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600264 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600265 if cls._indir:
266 shutil.rmtree(cls._indir)
267 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700268
Simon Glass1c420c92019-07-08 13:18:49 -0600269 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600270 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600271 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600272 """Accept arguments controlling test execution
273
274 Args:
275 preserve_indir: Preserve the shared input directory used by all
276 tests in this class.
277 preserve_outdir: Preserve the output directories used by tests. Each
278 test has its own, so this is normally only useful when running a
279 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600280 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600281 """
282 cls.preserve_indir = preserve_indir
283 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600284 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600285 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600286
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200287 def _CheckBintool(self, bintool):
288 if not bintool.is_present():
289 self.skipTest('%s not available' % bintool.name)
290
Simon Glass1de34482019-07-08 13:18:53 -0600291 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200292 bintool = self.comp_bintools['lz4']
293 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600294
Simon Glassee9d10d2019-07-20 12:24:09 -0600295 def _CleanupOutputDir(self):
296 """Remove the temporary output directory"""
297 if self.preserve_outdirs:
298 print('Preserving output dir: %s' % tools.outdir)
299 else:
Simon Glass80025522022-01-29 14:14:04 -0700300 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600301
Simon Glass57454f42016-11-25 20:15:52 -0700302 def setUp(self):
303 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700304 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700305 command.test_result = None
306
307 def tearDown(self):
308 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600309 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700310
Simon Glassb3d6fc72019-07-20 12:24:10 -0600311 def _SetupImageInTmpdir(self):
312 """Set up the output image in a new temporary directory
313
314 This is used when an image has been generated in the output directory,
315 but we want to run binman again. This will create a new output
316 directory and fail to delete the original one.
317
318 This creates a new temporary directory, copies the image to it (with a
319 new name) and removes the old output directory.
320
321 Returns:
322 Tuple:
323 Temporary directory to use
324 New image filename
325 """
Simon Glass80025522022-01-29 14:14:04 -0700326 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600327 tmpdir = tempfile.mkdtemp(prefix='binman.')
328 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700329 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600330 self._CleanupOutputDir()
331 return tmpdir, updated_fname
332
Simon Glass8425a1f2018-07-17 13:25:48 -0600333 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600334 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600335 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
336 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
337 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700338 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600339
Simon Glass57454f42016-11-25 20:15:52 -0700340 def _RunBinman(self, *args, **kwargs):
341 """Run binman using the command line
342
343 Args:
344 Arguments to pass, as a list of strings
345 kwargs: Arguments to pass to Command.RunPipe()
346 """
Simon Glass840be732022-01-29 14:14:05 -0700347 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700348 capture=True, capture_stderr=True, raise_on_error=False)
349 if result.return_code and kwargs.get('raise_on_error', True):
350 raise Exception("Error running '%s': %s" % (' '.join(args),
351 result.stdout + result.stderr))
352 return result
353
Simon Glassf46732a2019-07-08 14:25:29 -0600354 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700355 """Run binman using directly (in the same process)
356
357 Args:
358 Arguments to pass, as a list of strings
359 Returns:
360 Return value (0 for success)
361 """
Simon Glassf46732a2019-07-08 14:25:29 -0600362 argv = list(argv)
363 args = cmdline.ParseArgs(argv)
364 args.pager = 'binman-invalid-pager'
365 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700366
367 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600368 # args.verbosity = tout.DEBUG
369 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700370
Simon Glass91710b32018-07-17 13:25:32 -0600371 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600372 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300373 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100374 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700375 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis6b463da2023-07-22 00:14:44 +0530376 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass57454f42016-11-25 20:15:52 -0700377 """Run binman with a given test file
378
379 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600380 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600381 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600382 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600383 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600384 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600385 entry_args: Dict of entry args to supply to binman
386 key: arg name
387 value: value of that arg
388 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600389 use_real_dtb: True to use the test file as the contents of
390 the u-boot-dtb entry. Normally this is not needed and the
391 test contents (the U_BOOT_DTB_DATA string) can be used.
392 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300393 use_expanded: True to use expanded entries where available, e.g.
394 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600395 verbosity: Verbosity level to use (0-3, None=don't set it)
396 allow_missing: Set the '--allow-missing' flag so that missing
397 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100398 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600399 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600400 threads: Number of threads to use (None for default, 0 for
401 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600402 test_section_timeout: True to force the first time to timeout, as
403 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600404 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass66152ce2022-01-09 20:14:09 -0700405 force_missing_tools (str): comma-separated list of bintools to
406 regard as missing
Andrew Davis6b463da2023-07-22 00:14:44 +0530407 output_dir: Specific output directory to use for image using -O
Simon Glass9a798402021-11-03 21:09:17 -0600408
409 Returns:
410 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700411 """
Simon Glassf46732a2019-07-08 14:25:29 -0600412 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700413 if debug:
414 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600415 if verbosity is not None:
416 args.append('-v%d' % verbosity)
417 elif self.verbosity:
418 args.append('-v%d' % self.verbosity)
419 if self.toolpath:
420 for path in self.toolpath:
421 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600422 if threads is not None:
423 args.append('-T%d' % threads)
424 if test_section_timeout:
425 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600426 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600427 if map:
428 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600429 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600430 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600431 if not use_real_dtb:
432 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300433 if not use_expanded:
434 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600435 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600436 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600437 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600438 if allow_missing:
439 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700440 if ignore_missing:
441 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100442 if allow_fake_blobs:
443 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700444 if force_missing_bintools:
445 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600446 if update_fdt_in_elf:
447 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600448 if images:
449 for image in images:
450 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600451 if extra_indirs:
452 for indir in extra_indirs:
453 args += ['-I', indir]
Andrew Davis6b463da2023-07-22 00:14:44 +0530454 if output_dir:
455 args += ['-O', output_dir]
Simon Glass075a45c2017-11-13 18:55:00 -0700456 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700457
458 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700459 """Set up a new test device-tree file
460
461 The given file is compiled and set up as the device tree to be used
462 for ths test.
463
464 Args:
465 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600466 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700467
468 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600469 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700470 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600471 tmpdir = tempfile.mkdtemp(prefix='binmant.')
472 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600473 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700474 data = fd.read()
475 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600476 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600477 return data
Simon Glass57454f42016-11-25 20:15:52 -0700478
Simon Glass56d05412022-02-28 07:16:54 -0700479 def _GetDtbContentsForSpls(self, dtb_data, name):
480 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600481
482 For testing we don't actually have different versions of the DTB. With
483 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
484 we don't normally have any unwanted nodes.
485
486 We still want the DTBs for SPL and TPL to be different though, since
487 otherwise it is confusing to know which one we are looking at. So add
488 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600489
490 Args:
491 dtb_data: dtb data to modify (this should be a value devicetree)
492 name: Name of a new property to add
493
494 Returns:
495 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600496 """
497 dtb = fdt.Fdt.FromData(dtb_data)
498 dtb.Scan()
499 dtb.GetNode('/binman').AddZeroProp(name)
500 dtb.Sync(auto_resize=True)
501 dtb.Pack()
502 return dtb.GetContents()
503
Simon Glassed930672021-03-18 20:25:05 +1300504 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
505 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600506 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700507 """Run binman and return the resulting image
508
509 This runs binman with a given test file and then reads the resulting
510 output file. It is a shortcut function since most tests need to do
511 these steps.
512
513 Raises an assertion failure if binman returns a non-zero exit code.
514
515 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600516 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700517 use_real_dtb: True to use the test file as the contents of
518 the u-boot-dtb entry. Normally this is not needed and the
519 test contents (the U_BOOT_DTB_DATA string) can be used.
520 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300521 use_expanded: True to use expanded entries where available, e.g.
522 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600523 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600524 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600525 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600526 entry_args: Dict of entry args to supply to binman
527 key: arg name
528 value: value of that arg
529 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
530 function. If reset_dtbs is True, then the original test dtb
531 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600532 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600533 threads: Number of threads to use (None for default, 0 for
534 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700535
536 Returns:
537 Tuple:
538 Resulting image contents
539 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600540 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600541 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700542 """
Simon Glass72232452016-11-25 20:15:53 -0700543 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700544 # Use the compiled test file as the u-boot-dtb input
545 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700546 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600547
548 # For testing purposes, make a copy of the DT for SPL and TPL. Add
549 # a node indicating which it is, so aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700550 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600551 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
552 outfile = os.path.join(self._indir, dtb_fname)
553 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700554 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700555
556 try:
Simon Glass91710b32018-07-17 13:25:32 -0600557 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600558 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600559 use_expanded=use_expanded, extra_indirs=extra_indirs,
560 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700561 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700562 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700563
564 # Find the (only) image, read it and return its contents
565 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700566 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600567 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600568 if map:
Simon Glass80025522022-01-29 14:14:04 -0700569 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600570 with open(map_fname) as fd:
571 map_data = fd.read()
572 else:
573 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600574 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600575 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700576 finally:
577 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600578 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600579 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700580
Simon Glass5b4bce32019-07-08 14:25:26 -0600581 def _DoReadFileRealDtb(self, fname):
582 """Run binman with a real .dtb file and return the resulting data
583
584 Args:
585 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
586
587 Returns:
588 Resulting image contents
589 """
590 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
591
Simon Glass72232452016-11-25 20:15:53 -0700592 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600593 """Helper function which discards the device-tree binary
594
595 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600596 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600597 use_real_dtb: True to use the test file as the contents of
598 the u-boot-dtb entry. Normally this is not needed and the
599 test contents (the U_BOOT_DTB_DATA string) can be used.
600 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600601
602 Returns:
603 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600604 """
Simon Glass72232452016-11-25 20:15:53 -0700605 return self._DoReadFileDtb(fname, use_real_dtb)[0]
606
Simon Glass57454f42016-11-25 20:15:52 -0700607 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600608 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700609 """Create a new test input file, creating directories as needed
610
611 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600612 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700613 contents: File contents to write in to the file
614 Returns:
615 Full pathname of file created
616 """
Simon Glass862f8e22019-08-24 07:22:43 -0600617 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700618 dirname = os.path.dirname(pathname)
619 if dirname and not os.path.exists(dirname):
620 os.makedirs(dirname)
621 with open(pathname, 'wb') as fd:
622 fd.write(contents)
623 return pathname
624
625 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600626 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600627 """Create a new test input directory, creating directories as needed
628
629 Args:
630 dirname: Directory name to create
631
632 Returns:
633 Full pathname of directory created
634 """
Simon Glass862f8e22019-08-24 07:22:43 -0600635 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600636 if not os.path.exists(pathname):
637 os.makedirs(pathname)
638 return pathname
639
640 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600641 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600642 """Set up an ELF file with a '_dt_ucode_base_size' symbol
643
644 Args:
645 Filename of ELF file to use as SPL
646 """
Simon Glass93a806f2019-08-24 07:22:59 -0600647 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700648 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600649
650 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600651 def _SetupTplElf(cls, src_fname='bss_data'):
652 """Set up an ELF file with a '_dt_ucode_base_size' symbol
653
654 Args:
655 Filename of ELF file to use as TPL
656 """
657 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700658 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600659
660 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700661 def _SetupVplElf(cls, src_fname='bss_data'):
662 """Set up an ELF file with a '_dt_ucode_base_size' symbol
663
664 Args:
665 Filename of ELF file to use as VPL
666 """
667 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
668 tools.read_file(cls.ElfTestFile(src_fname)))
669
670 @classmethod
Lukas Funkee901faf2023-07-18 13:53:13 +0200671 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
672 """Set up an ELF file with a '_dt_ucode_base_size' symbol
673
674 Args:
675 Filename of ELF file to use as VPL
676 """
677 TestFunctional._MakeInputFile('pmu-firmware.elf',
678 tools.read_file(cls.ElfTestFile(src_fname)))
679
680 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600681 def _SetupDescriptor(cls):
682 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
683 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
684
685 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600686 def TestFile(cls, fname):
687 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700688
Simon Glassf6290892019-08-24 07:22:53 -0600689 @classmethod
690 def ElfTestFile(cls, fname):
691 return os.path.join(cls._elf_testdir, fname)
692
Simon Glassad5cfe12023-01-07 14:07:14 -0700693 @classmethod
694 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
695 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
696 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
697 dummy, paged_sz) + U_BOOT_DATA
698 data += extra_data
699 TestFunctional._MakeInputFile(fname, data)
700
Simon Glass57454f42016-11-25 20:15:52 -0700701 def AssertInList(self, grep_list, target):
702 """Assert that at least one of a list of things is in a target
703
704 Args:
705 grep_list: List of strings to check
706 target: Target string
707 """
708 for grep in grep_list:
709 if grep in target:
710 return
Simon Glass848cdb52019-05-17 22:00:50 -0600711 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700712
713 def CheckNoGaps(self, entries):
714 """Check that all entries fit together without gaps
715
716 Args:
717 entries: List of entries to check
718 """
Simon Glasse8561af2018-08-01 15:22:37 -0600719 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700720 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600721 self.assertEqual(offset, entry.offset)
722 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700723
Simon Glass72232452016-11-25 20:15:53 -0700724 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600725 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700726
727 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600728 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700729
730 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600731 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700732 """
733 return struct.unpack('>L', dtb[4:8])[0]
734
Simon Glass0f621332019-07-08 14:25:27 -0600735 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600736 def AddNode(node, path):
737 if node.name != '/':
738 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600739 for prop in node.props.values():
740 if prop.name in prop_names:
741 prop_path = path + ':' + prop.name
742 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
743 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600744 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600745 AddNode(subnode, path)
746
747 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600748 AddNode(dtb.GetRoot(), '')
749 return tree
750
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000751 def _CheckSign(self, fit, key):
752 try:
753 tools.run('fit_check_sign', '-k', key, '-f', fit)
754 except:
755 self.fail('Expected signed FIT container')
756 return False
757 return True
758
Simon Glass57454f42016-11-25 20:15:52 -0700759 def testRun(self):
760 """Test a basic run with valid args"""
761 result = self._RunBinman('-h')
762
763 def testFullHelp(self):
764 """Test that the full help is displayed with -H"""
765 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300766 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500767 # Remove possible extraneous strings
768 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
769 gothelp = result.stdout.replace(extra, '')
770 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700771 self.assertEqual(0, len(result.stderr))
772 self.assertEqual(0, result.return_code)
773
774 def testFullHelpInternal(self):
775 """Test that the full help is displayed with -H"""
776 try:
777 command.test_result = command.CommandResult()
778 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300779 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700780 finally:
781 command.test_result = None
782
783 def testHelp(self):
784 """Test that the basic help is displayed with -h"""
785 result = self._RunBinman('-h')
786 self.assertTrue(len(result.stdout) > 200)
787 self.assertEqual(0, len(result.stderr))
788 self.assertEqual(0, result.return_code)
789
Simon Glass57454f42016-11-25 20:15:52 -0700790 def testBoard(self):
791 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600792 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700793 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300794 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700795 self.assertEqual(0, result)
796
797 def testNeedBoard(self):
798 """Test that we get an error when no board ius supplied"""
799 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600800 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700801 self.assertIn("Must provide a board to process (use -b <board>)",
802 str(e.exception))
803
804 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600805 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700806 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600807 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700808 # We get one error from libfdt, and a different one from fdtget.
809 self.AssertInList(["Couldn't open blob from 'missing_file'",
810 'No such file or directory'], str(e.exception))
811
812 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600813 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700814
815 Since this is a source file it should be compiled and the error
816 will come from the device-tree compiler (dtc).
817 """
818 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600819 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700820 self.assertIn("FATAL ERROR: Unable to parse input tree",
821 str(e.exception))
822
823 def testMissingNode(self):
824 """Test that a device tree without a 'binman' node generates an error"""
825 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600826 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700827 self.assertIn("does not have a 'binman' node", str(e.exception))
828
829 def testEmpty(self):
830 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600831 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700832 self.assertEqual(0, len(result.stderr))
833 self.assertEqual(0, result.return_code)
834
835 def testInvalidEntry(self):
836 """Test that an invalid entry is flagged"""
837 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600838 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600839 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700840 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
841 "'/binman/not-a-valid-type'", str(e.exception))
842
843 def testSimple(self):
844 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600845 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700846 self.assertEqual(U_BOOT_DATA, data)
847
Simon Glass075a45c2017-11-13 18:55:00 -0700848 def testSimpleDebug(self):
849 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600850 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700851
Simon Glass57454f42016-11-25 20:15:52 -0700852 def testDual(self):
853 """Test that we can handle creating two images
854
855 This also tests image padding.
856 """
Simon Glass511f6582018-10-01 12:22:30 -0600857 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700858 self.assertEqual(0, retcode)
859
860 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600861 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700862 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700863 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600864 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700865 data = fd.read()
866 self.assertEqual(U_BOOT_DATA, data)
867
868 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600869 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700870 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700871 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600872 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700873 data = fd.read()
874 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700875 self.assertEqual(tools.get_bytes(0, 3), data[:3])
876 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700877
878 def testBadAlign(self):
879 """Test that an invalid alignment value is detected"""
880 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600881 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700882 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
883 "of two", str(e.exception))
884
885 def testPackSimple(self):
886 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600887 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700888 self.assertEqual(0, retcode)
889 self.assertIn('image', control.images)
890 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600891 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700892 self.assertEqual(5, len(entries))
893
894 # First u-boot
895 self.assertIn('u-boot', entries)
896 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600897 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700898 self.assertEqual(len(U_BOOT_DATA), entry.size)
899
900 # Second u-boot, aligned to 16-byte boundary
901 self.assertIn('u-boot-align', entries)
902 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600903 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700904 self.assertEqual(len(U_BOOT_DATA), entry.size)
905
906 # Third u-boot, size 23 bytes
907 self.assertIn('u-boot-size', entries)
908 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600909 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700910 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
911 self.assertEqual(23, entry.size)
912
913 # Fourth u-boot, placed immediate after the above
914 self.assertIn('u-boot-next', entries)
915 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600916 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700917 self.assertEqual(len(U_BOOT_DATA), entry.size)
918
Simon Glasse8561af2018-08-01 15:22:37 -0600919 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700920 self.assertIn('u-boot-fixed', entries)
921 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600922 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700923 self.assertEqual(len(U_BOOT_DATA), entry.size)
924
Simon Glass39dd2152019-07-08 14:25:47 -0600925 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700926
927 def testPackExtra(self):
928 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600929 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
930 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700931
Simon Glass57454f42016-11-25 20:15:52 -0700932 self.assertIn('image', control.images)
933 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600934 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600935 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700936
Samuel Hollande2574022023-01-21 17:25:16 -0600937 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700938 self.assertIn('u-boot', entries)
939 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600940 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700941 self.assertEqual(3, entry.pad_before)
942 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600943 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700944 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
945 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600946 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700947
948 # Second u-boot has an aligned size, but it has no effect
949 self.assertIn('u-boot-align-size-nop', entries)
950 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600951 self.assertEqual(pos, entry.offset)
952 self.assertEqual(len(U_BOOT_DATA), entry.size)
953 self.assertEqual(U_BOOT_DATA, entry.data)
954 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
955 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700956
957 # Third u-boot has an aligned size too
958 self.assertIn('u-boot-align-size', entries)
959 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600960 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700961 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600962 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700963 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600964 data[pos:pos + entry.size])
965 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700966
967 # Fourth u-boot has an aligned end
968 self.assertIn('u-boot-align-end', entries)
969 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600970 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700971 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600972 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700973 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600974 data[pos:pos + entry.size])
975 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700976
977 # Fifth u-boot immediately afterwards
978 self.assertIn('u-boot-align-both', entries)
979 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600980 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700981 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600982 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700983 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600984 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700985
Samuel Hollande2574022023-01-21 17:25:16 -0600986 # Sixth u-boot with both minimum size and aligned size
987 self.assertIn('u-boot-min-size', entries)
988 entry = entries['u-boot-min-size']
989 self.assertEqual(128, entry.offset)
990 self.assertEqual(32, entry.size)
991 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
992 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
993 data[pos:pos + entry.size])
994
Simon Glass57454f42016-11-25 20:15:52 -0700995 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -0600996 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700997
Simon Glassafb9caa2020-10-26 17:40:10 -0600998 dtb = fdt.Fdt(out_dtb_fname)
999 dtb.Scan()
1000 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
1001 expected = {
1002 'image-pos': 0,
1003 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -06001004 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -06001005
1006 'u-boot:image-pos': 0,
1007 'u-boot:offset': 0,
1008 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
1009
1010 'u-boot-align-size-nop:image-pos': 12,
1011 'u-boot-align-size-nop:offset': 12,
1012 'u-boot-align-size-nop:size': 4,
1013
1014 'u-boot-align-size:image-pos': 16,
1015 'u-boot-align-size:offset': 16,
1016 'u-boot-align-size:size': 32,
1017
1018 'u-boot-align-end:image-pos': 48,
1019 'u-boot-align-end:offset': 48,
1020 'u-boot-align-end:size': 16,
1021
1022 'u-boot-align-both:image-pos': 64,
1023 'u-boot-align-both:offset': 64,
1024 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -06001025
1026 'u-boot-min-size:image-pos': 128,
1027 'u-boot-min-size:offset': 128,
1028 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -06001029 }
1030 self.assertEqual(expected, props)
1031
Simon Glass57454f42016-11-25 20:15:52 -07001032 def testPackAlignPowerOf2(self):
1033 """Test that invalid entry alignment is detected"""
1034 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001035 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001036 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1037 "of two", str(e.exception))
1038
1039 def testPackAlignSizePowerOf2(self):
1040 """Test that invalid entry size alignment is detected"""
1041 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001042 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001043 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1044 "power of two", str(e.exception))
1045
1046 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001047 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001048 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001049 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001050 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001051 "align 0x4 (4)", str(e.exception))
1052
1053 def testPackInvalidSizeAlign(self):
1054 """Test that invalid entry size alignment is detected"""
1055 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001056 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001057 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1058 "align-size 0x4 (4)", str(e.exception))
1059
1060 def testPackOverlap(self):
1061 """Test that overlapping regions are detected"""
1062 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001063 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001064 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001065 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1066 str(e.exception))
1067
1068 def testPackEntryOverflow(self):
1069 """Test that entries that overflow their size are detected"""
1070 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001071 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001072 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1073 "but entry size is 0x3 (3)", str(e.exception))
1074
1075 def testPackImageOverflow(self):
1076 """Test that entries which overflow the image size are detected"""
1077 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001078 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001079 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001080 "size 0x3 (3)", str(e.exception))
1081
1082 def testPackImageSize(self):
1083 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001084 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001085 self.assertEqual(0, retcode)
1086 self.assertIn('image', control.images)
1087 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001088 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001089
1090 def testPackImageSizeAlign(self):
1091 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001092 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001093 self.assertEqual(0, retcode)
1094 self.assertIn('image', control.images)
1095 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001096 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001097
1098 def testPackInvalidImageAlign(self):
1099 """Test that invalid image alignment is detected"""
1100 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001101 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001102 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001103 "align-size 0x8 (8)", str(e.exception))
1104
Simon Glass2a0fa982022-02-11 13:23:21 -07001105 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001106 """Test that invalid image alignment is detected"""
1107 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001108 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001109 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001110 "two", str(e.exception))
1111
1112 def testImagePadByte(self):
1113 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001114 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001115 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001116 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001117 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001118
1119 def testImageName(self):
1120 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001121 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001122 self.assertEqual(0, retcode)
1123 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001124 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001125 self.assertTrue(os.path.exists(fname))
1126
1127 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001128 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001129 self.assertTrue(os.path.exists(fname))
1130
1131 def testBlobFilename(self):
1132 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001133 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001134 self.assertEqual(BLOB_DATA, data)
1135
1136 def testPackSorted(self):
1137 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001138 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001139 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001140 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1141 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001142
Simon Glasse8561af2018-08-01 15:22:37 -06001143 def testPackZeroOffset(self):
1144 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001145 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001146 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001147 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001148 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001149 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1150 str(e.exception))
1151
1152 def testPackUbootDtb(self):
1153 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001154 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001155 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001156
1157 def testPackX86RomNoSize(self):
1158 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001159 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001160 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001161 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001162 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001163 "using end-at-4gb", str(e.exception))
1164
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301165 def test4gbAndSkipAtStartTogether(self):
1166 """Test that the end-at-4gb and skip-at-size property can't be used
1167 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001168 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301169 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001170 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001171 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301172 "'skip-at-start'", str(e.exception))
1173
Simon Glass72232452016-11-25 20:15:53 -07001174 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001175 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001176 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001177 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001178 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001179 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1180 "is outside the section '/binman' starting at "
1181 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001182 str(e.exception))
1183
1184 def testPackX86Rom(self):
1185 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001186 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001187 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001188 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1189 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001190
1191 def testPackX86RomMeNoDesc(self):
1192 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001193 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001194 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001195 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001196 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001197 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1198 str(e.exception))
1199 finally:
1200 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001201
1202 def testPackX86RomBadDesc(self):
1203 """Test that the Intel requires a descriptor entry"""
1204 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001205 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001206 self.assertIn("Node '/binman/intel-me': No offset set with "
1207 "offset-unset: should another entry provide this correct "
1208 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001209
1210 def testPackX86RomMe(self):
1211 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001212 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001213 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001214 if data[:0x1000] != expected_desc:
1215 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001216 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1217
1218 def testPackVga(self):
1219 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001220 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001221 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1222
1223 def testPackStart16(self):
1224 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001225 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001226 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1227
Jagdish Gediya311d4842018-09-03 21:35:08 +05301228 def testPackPowerpcMpc85xxBootpgResetvec(self):
1229 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1230 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001231 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301232 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1233
Simon Glass6ba679c2018-07-06 10:27:17 -06001234 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001235 """Handle running a test for insertion of microcode
1236
1237 Args:
1238 dts_fname: Name of test .dts file
1239 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001240 ucode_second: True if the microsecond entry is second instead of
1241 third
Simon Glass820af1d2018-07-06 10:27:16 -06001242
1243 Returns:
1244 Tuple:
1245 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001246 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001247 in the above (two 4-byte words)
1248 """
Simon Glass3d274232017-11-12 21:52:27 -07001249 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001250
1251 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001252 if ucode_second:
1253 ucode_content = data[len(nodtb_data):]
1254 ucode_pos = len(nodtb_data)
1255 dtb_with_ucode = ucode_content[16:]
1256 fdt_len = self.GetFdtLen(dtb_with_ucode)
1257 else:
1258 dtb_with_ucode = data[len(nodtb_data):]
1259 fdt_len = self.GetFdtLen(dtb_with_ucode)
1260 ucode_content = dtb_with_ucode[fdt_len:]
1261 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001262 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001263 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001264 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001265 dtb = fdt.FdtScan(fname)
1266 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001267 self.assertTrue(ucode)
1268 for node in ucode.subnodes:
1269 self.assertFalse(node.props.get('data'))
1270
Simon Glass72232452016-11-25 20:15:53 -07001271 # Check that the microcode appears immediately after the Fdt
1272 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001273 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001274 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1275 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001276 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001277
1278 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001279 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001280 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1281 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001282 u_boot = data[:len(nodtb_data)]
1283 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001284
1285 def testPackUbootMicrocode(self):
1286 """Test that x86 microcode can be handled correctly
1287
1288 We expect to see the following in the image, in order:
1289 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1290 place
1291 u-boot.dtb with the microcode removed
1292 the microcode
1293 """
Simon Glass511f6582018-10-01 12:22:30 -06001294 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001295 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001296 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1297 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001298
Simon Glassbac25c82017-05-27 07:38:26 -06001299 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001300 """Test that x86 microcode can be handled correctly
1301
1302 We expect to see the following in the image, in order:
1303 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1304 place
1305 u-boot.dtb with the microcode
1306 an empty microcode region
1307 """
1308 # We need the libfdt library to run this test since only that allows
1309 # finding the offset of a property. This is required by
1310 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001311 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001312
1313 second = data[len(U_BOOT_NODTB_DATA):]
1314
1315 fdt_len = self.GetFdtLen(second)
1316 third = second[fdt_len:]
1317 second = second[:fdt_len]
1318
Simon Glassbac25c82017-05-27 07:38:26 -06001319 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1320 self.assertIn(ucode_data, second)
1321 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001322
Simon Glassbac25c82017-05-27 07:38:26 -06001323 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001324 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001325 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1326 len(ucode_data))
1327 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001328 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1329 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001330
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001331 def testPackUbootSingleMicrocode(self):
1332 """Test that x86 microcode can be handled correctly with fdt_normal.
1333 """
Simon Glassbac25c82017-05-27 07:38:26 -06001334 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001335
Simon Glass996021e2016-11-25 20:15:54 -07001336 def testUBootImg(self):
1337 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001338 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001339 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001340
1341 def testNoMicrocode(self):
1342 """Test that a missing microcode region is detected"""
1343 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001344 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001345 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1346 "node found in ", str(e.exception))
1347
1348 def testMicrocodeWithoutNode(self):
1349 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1350 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001351 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001352 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1353 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1354
1355 def testMicrocodeWithoutNode2(self):
1356 """Test that a missing u-boot-ucode node is detected"""
1357 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001358 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001359 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1360 "microcode region u-boot-ucode", str(e.exception))
1361
1362 def testMicrocodeWithoutPtrInElf(self):
1363 """Test that a U-Boot binary without the microcode symbol is detected"""
1364 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001365 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001366 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001367 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001368
1369 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001370 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001371 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1372 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1373
1374 finally:
1375 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001376 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001377 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001378
1379 def testMicrocodeNotInImage(self):
1380 """Test that microcode must be placed within the image"""
1381 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001382 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001383 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1384 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001385 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001386
1387 def testWithoutMicrocode(self):
1388 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001389 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001390 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001391 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001392
1393 # Now check the device tree has no microcode
1394 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1395 second = data[len(U_BOOT_NODTB_DATA):]
1396
1397 fdt_len = self.GetFdtLen(second)
1398 self.assertEqual(dtb, second[:fdt_len])
1399
1400 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1401 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001402 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001403
1404 def testUnknownPosSize(self):
1405 """Test that microcode must be placed within the image"""
1406 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001407 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001408 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001409 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001410
1411 def testPackFsp(self):
1412 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001413 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001414 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1415
1416 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001417 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001418 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001419 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001420
1421 def testPackVbt(self):
1422 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001423 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001424 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001425
Simon Glass7f94e832017-11-12 21:52:25 -07001426 def testSplBssPad(self):
1427 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001428 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001429 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001430 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001431 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001432 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001433
Simon Glass04cda032018-10-01 21:12:42 -06001434 def testSplBssPadMissing(self):
1435 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001436 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001437 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001438 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001439 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1440 str(e.exception))
1441
Simon Glasse83679d2017-11-12 21:52:26 -07001442 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001443 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001444 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001445 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1446
Simon Glass6ba679c2018-07-06 10:27:17 -06001447 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1448 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001449
1450 We expect to see the following in the image, in order:
1451 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1452 correct place
1453 u-boot.dtb with the microcode removed
1454 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001455
1456 Args:
1457 dts: Device tree file to use for test
1458 ucode_second: True if the microsecond entry is second instead of
1459 third
Simon Glass3d274232017-11-12 21:52:27 -07001460 """
Simon Glass7057d022018-10-01 21:12:47 -06001461 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001462 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1463 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001464 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1465 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001466
Simon Glass6ba679c2018-07-06 10:27:17 -06001467 def testPackUbootSplMicrocode(self):
1468 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001469 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001470 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001471
1472 def testPackUbootSplMicrocodeReorder(self):
1473 """Test that order doesn't matter for microcode entries
1474
1475 This is the same as testPackUbootSplMicrocode but when we process the
1476 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1477 entry, so we reply on binman to try later.
1478 """
Simon Glass511f6582018-10-01 12:22:30 -06001479 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001480 ucode_second=True)
1481
Simon Glassa409c932017-11-12 21:52:28 -07001482 def testPackMrc(self):
1483 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001484 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001485 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1486
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001487 def testSplDtb(self):
1488 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001489 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001490 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001491 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1492
Simon Glass0a6da312017-11-13 18:54:56 -07001493 def testSplNoDtb(self):
1494 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001495 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001496 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001497 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1498
Simon Glass7098b7f2021-03-21 18:24:30 +13001499 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4abf7842023-07-18 07:23:54 -06001500 use_expanded=False, no_write_symbols=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001501 """Check the image contains the expected symbol values
1502
1503 Args:
1504 dts: Device tree file to use for test
1505 base_data: Data before and after 'u-boot' section
1506 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001507 entry_args: Dict of entry args to supply to binman
1508 key: arg name
1509 value: value of that arg
1510 use_expanded: True to use expanded entries where available, e.g.
1511 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001512 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001513 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001514 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1515 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001516 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001517 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001518 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001519
Simon Glass7057d022018-10-01 21:12:47 -06001520 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001521 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1522 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001523 # The image should contain the symbols from u_boot_binman_syms.c
1524 # Note that image_pos is adjusted by the base address of the image,
1525 # which is 0x10 in our test image
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001526 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1527 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glass31e04cb2021-03-18 20:24:56 +13001528 0x10 + u_boot_offset, 0x04)
Simon Glass4abf7842023-07-18 07:23:54 -06001529 if no_write_symbols:
1530 expected = (base_data +
1531 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1532 U_BOOT_DATA + base_data)
1533 else:
1534 expected = (sym_values + base_data[24:] +
1535 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1536 base_data[24:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001537 self.assertEqual(expected, data)
1538
Simon Glass31e04cb2021-03-18 20:24:56 +13001539 def testSymbols(self):
1540 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001541 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001542
1543 def testSymbolsNoDtb(self):
1544 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001545 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001546 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1547 0x38)
1548
Simon Glasse76a3e62018-06-01 09:38:11 -06001549 def testPackUnitAddress(self):
1550 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001551 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001552 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1553
Simon Glassa91e1152018-06-01 09:38:16 -06001554 def testSections(self):
1555 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001556 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001557 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1558 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1559 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001560 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001561
Simon Glass30732662018-06-01 09:38:20 -06001562 def testMap(self):
1563 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001564 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001565 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700156600000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600156700000000 00000000 00000010 section@0
156800000000 00000000 00000004 u-boot
156900000010 00000010 00000010 section@1
157000000010 00000000 00000004 u-boot
157100000020 00000020 00000004 section@2
157200000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001573''', map_data)
1574
Simon Glass3b78d532018-06-01 09:38:21 -06001575 def testNamePrefix(self):
1576 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001577 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001578 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700157900000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600158000000000 00000000 00000010 section@0
158100000000 00000000 00000004 ro-u-boot
158200000010 00000010 00000010 section@1
158300000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001584''', map_data)
1585
Simon Glass6ba679c2018-07-06 10:27:17 -06001586 def testUnknownContents(self):
1587 """Test that obtaining the contents works as expected"""
1588 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001589 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001590 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001591 "processing of contents: remaining ["
1592 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001593
Simon Glass2e1169f2018-07-06 10:27:19 -06001594 def testBadChangeSize(self):
1595 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001596 try:
1597 state.SetAllowEntryExpansion(False)
1598 with self.assertRaises(ValueError) as e:
1599 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001600 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001601 str(e.exception))
1602 finally:
1603 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001604
Simon Glassa87014e2018-07-06 10:27:42 -06001605 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001606 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001607 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001608 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001609 dtb = fdt.Fdt(out_dtb_fname)
1610 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001611 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001612 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001613 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001614 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001615 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001616 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001617 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001618 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001619 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001620 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001621 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001622 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001623 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001624
Simon Glasse8561af2018-08-01 15:22:37 -06001625 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001626 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001627 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001628 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001629 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001630 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001631 'size': 40
1632 }, props)
1633
1634 def testUpdateFdtBad(self):
1635 """Test that we detect when ProcessFdt never completes"""
1636 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001637 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001638 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001639 '[<binman.etype._testing.Entry__testing',
1640 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001641
Simon Glass91710b32018-07-17 13:25:32 -06001642 def testEntryArgs(self):
1643 """Test passing arguments to entries from the command line"""
1644 entry_args = {
1645 'test-str-arg': 'test1',
1646 'test-int-arg': '456',
1647 }
Simon Glass511f6582018-10-01 12:22:30 -06001648 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001649 self.assertIn('image', control.images)
1650 entry = control.images['image'].GetEntries()['_testing']
1651 self.assertEqual('test0', entry.test_str_fdt)
1652 self.assertEqual('test1', entry.test_str_arg)
1653 self.assertEqual(123, entry.test_int_fdt)
1654 self.assertEqual(456, entry.test_int_arg)
1655
1656 def testEntryArgsMissing(self):
1657 """Test missing arguments and properties"""
1658 entry_args = {
1659 'test-int-arg': '456',
1660 }
Simon Glass511f6582018-10-01 12:22:30 -06001661 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001662 entry = control.images['image'].GetEntries()['_testing']
1663 self.assertEqual('test0', entry.test_str_fdt)
1664 self.assertEqual(None, entry.test_str_arg)
1665 self.assertEqual(None, entry.test_int_fdt)
1666 self.assertEqual(456, entry.test_int_arg)
1667
1668 def testEntryArgsRequired(self):
1669 """Test missing arguments and properties"""
1670 entry_args = {
1671 'test-int-arg': '456',
1672 }
1673 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001674 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001675 self.assertIn("Node '/binman/_testing': "
1676 'Missing required properties/entry args: test-str-arg, '
1677 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001678 str(e.exception))
1679
1680 def testEntryArgsInvalidFormat(self):
1681 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001682 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1683 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001684 with self.assertRaises(ValueError) as e:
1685 self._DoBinman(*args)
1686 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1687
1688 def testEntryArgsInvalidInteger(self):
1689 """Test that an invalid entry-argument integer is detected"""
1690 entry_args = {
1691 'test-int-arg': 'abc',
1692 }
1693 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001694 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001695 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1696 "'test-int-arg' (value 'abc') to integer",
1697 str(e.exception))
1698
1699 def testEntryArgsInvalidDatatype(self):
1700 """Test that an invalid entry-argument datatype is detected
1701
1702 This test could be written in entry_test.py except that it needs
1703 access to control.entry_args, which seems more than that module should
1704 be able to see.
1705 """
1706 entry_args = {
1707 'test-bad-datatype-arg': '12',
1708 }
1709 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001710 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001711 entry_args=entry_args)
1712 self.assertIn('GetArg() internal error: Unknown data type ',
1713 str(e.exception))
1714
Simon Glass2ca52032018-07-17 13:25:33 -06001715 def testText(self):
1716 """Test for a text entry type"""
1717 entry_args = {
1718 'test-id': TEXT_DATA,
1719 'test-id2': TEXT_DATA2,
1720 'test-id3': TEXT_DATA3,
1721 }
Simon Glass511f6582018-10-01 12:22:30 -06001722 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001723 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001724 expected = (tools.to_bytes(TEXT_DATA) +
1725 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1726 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001727 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001728 self.assertEqual(expected, data)
1729
Simon Glass969616c2018-07-17 13:25:36 -06001730 def testEntryDocs(self):
1731 """Test for creation of entry documentation"""
1732 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001733 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001734 self.assertTrue(len(stdout.getvalue()) > 0)
1735
1736 def testEntryDocsMissing(self):
1737 """Test handling of missing entry documentation"""
1738 with self.assertRaises(ValueError) as e:
1739 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001740 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001741 self.assertIn('Documentation is missing for modules: u_boot',
1742 str(e.exception))
1743
Simon Glass704784b2018-07-17 13:25:38 -06001744 def testFmap(self):
1745 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001746 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001747 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001748 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1749 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001750 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001751 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001752 self.assertEqual(1, fhdr.ver_major)
1753 self.assertEqual(0, fhdr.ver_minor)
1754 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001755 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001756 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001757 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001758 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001759 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001760
Simon Glass82059c22021-04-03 11:05:09 +13001761 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001762 self.assertEqual(b'SECTION0', fentry.name)
1763 self.assertEqual(0, fentry.offset)
1764 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001765 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001766
1767 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001768 self.assertEqual(b'RO_U_BOOT', fentry.name)
1769 self.assertEqual(0, fentry.offset)
1770 self.assertEqual(4, fentry.size)
1771 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001772
Simon Glass82059c22021-04-03 11:05:09 +13001773 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001774 self.assertEqual(b'SECTION1', fentry.name)
1775 self.assertEqual(16, fentry.offset)
1776 self.assertEqual(16, fentry.size)
1777 self.assertEqual(0, fentry.flags)
1778
1779 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001780 self.assertEqual(b'RW_U_BOOT', fentry.name)
1781 self.assertEqual(16, fentry.offset)
1782 self.assertEqual(4, fentry.size)
1783 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001784
Simon Glass82059c22021-04-03 11:05:09 +13001785 fentry = next(fiter)
1786 self.assertEqual(b'FMAP', fentry.name)
1787 self.assertEqual(32, fentry.offset)
1788 self.assertEqual(expect_size, fentry.size)
1789 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001790
Simon Glassdb168d42018-07-17 13:25:39 -06001791 def testBlobNamedByArg(self):
1792 """Test we can add a blob with the filename coming from an entry arg"""
1793 entry_args = {
1794 'cros-ec-rw-path': 'ecrw.bin',
1795 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001796 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001797
Simon Glass53f53992018-07-17 13:25:40 -06001798 def testFill(self):
1799 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001800 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001801 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001802 self.assertEqual(expected, data)
1803
1804 def testFillNoSize(self):
1805 """Test for an fill entry type with no size"""
1806 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001807 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001808 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001809 str(e.exception))
1810
Simon Glassc1ae83c2018-07-17 13:25:44 -06001811 def _HandleGbbCommand(self, pipe_list):
1812 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001813 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001814 fname = pipe_list[0][-1]
1815 # Append our GBB data to the file, which will happen every time the
1816 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001817 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001818 fd.write(GBB_DATA)
1819 return command.CommandResult()
1820
1821 def testGbb(self):
1822 """Test for the Chromium OS Google Binary Block"""
1823 command.test_result = self._HandleGbbCommand
1824 entry_args = {
1825 'keydir': 'devkeys',
1826 'bmpblk': 'bmpblk.bin',
1827 }
Simon Glass511f6582018-10-01 12:22:30 -06001828 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001829
1830 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001831 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1832 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001833 self.assertEqual(expected, data)
1834
1835 def testGbbTooSmall(self):
1836 """Test for the Chromium OS Google Binary Block being large enough"""
1837 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001838 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001839 self.assertIn("Node '/binman/gbb': GBB is too small",
1840 str(e.exception))
1841
1842 def testGbbNoSize(self):
1843 """Test for the Chromium OS Google Binary Block having a size"""
1844 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001845 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001846 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1847 str(e.exception))
1848
Simon Glass66152ce2022-01-09 20:14:09 -07001849 def testGbbMissing(self):
1850 """Test that binman still produces an image if futility is missing"""
1851 entry_args = {
1852 'keydir': 'devkeys',
1853 }
1854 with test_util.capture_sys_output() as (_, stderr):
1855 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1856 entry_args=entry_args)
1857 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001858 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001859
Simon Glass5c350162018-07-17 13:25:47 -06001860 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001861 """Fake calls to the futility utility
1862
1863 The expected pipe is:
1864
1865 [('futility', 'vbutil_firmware', '--vblock',
1866 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1867 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1868 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1869 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1870
1871 This writes to the output file (here, 'vblock.vblock'). If
1872 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1873 of the input data (here, 'input.vblock').
1874 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001875 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001876 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001877 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001878 if self._hash_data:
1879 infile = pipe_list[0][11]
1880 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001881 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001882 m.update(data)
1883 fd.write(m.digest())
1884 else:
1885 fd.write(VBLOCK_DATA)
1886
Simon Glass5c350162018-07-17 13:25:47 -06001887 return command.CommandResult()
1888
1889 def testVblock(self):
1890 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001891 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001892 command.test_result = self._HandleVblockCommand
1893 entry_args = {
1894 'keydir': 'devkeys',
1895 }
Simon Glass511f6582018-10-01 12:22:30 -06001896 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001897 entry_args=entry_args)
1898 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1899 self.assertEqual(expected, data)
1900
1901 def testVblockNoContent(self):
1902 """Test we detect a vblock which has no content to sign"""
1903 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001904 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001905 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001906 'property', str(e.exception))
1907
1908 def testVblockBadPhandle(self):
1909 """Test that we detect a vblock with an invalid phandle in contents"""
1910 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001911 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001912 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1913 '1000', str(e.exception))
1914
1915 def testVblockBadEntry(self):
1916 """Test that we detect an entry that points to a non-entry"""
1917 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001918 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001919 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1920 "'other'", str(e.exception))
1921
Simon Glass220c6222021-01-06 21:35:17 -07001922 def testVblockContent(self):
1923 """Test that the vblock signs the right data"""
1924 self._hash_data = True
1925 command.test_result = self._HandleVblockCommand
1926 entry_args = {
1927 'keydir': 'devkeys',
1928 }
1929 data = self._DoReadFileDtb(
1930 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1931 entry_args=entry_args)[0]
1932 hashlen = 32 # SHA256 hash is 32 bytes
1933 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1934 hashval = data[-hashlen:]
1935 dtb = data[len(U_BOOT_DATA):-hashlen]
1936
1937 expected_data = U_BOOT_DATA + dtb
1938
1939 # The hashval should be a hash of the dtb
1940 m = hashlib.sha256()
1941 m.update(expected_data)
1942 expected_hashval = m.digest()
1943 self.assertEqual(expected_hashval, hashval)
1944
Simon Glass66152ce2022-01-09 20:14:09 -07001945 def testVblockMissing(self):
1946 """Test that binman still produces an image if futility is missing"""
1947 entry_args = {
1948 'keydir': 'devkeys',
1949 }
1950 with test_util.capture_sys_output() as (_, stderr):
1951 self._DoTestFile('074_vblock.dts',
1952 force_missing_bintools='futility',
1953 entry_args=entry_args)
1954 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001955 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001956
Simon Glass8425a1f2018-07-17 13:25:48 -06001957 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001958 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001959 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001960 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001961 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001962 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1963
Simon Glass24b97442018-07-17 13:25:51 -06001964 def testUsesPos(self):
1965 """Test that the 'pos' property cannot be used anymore"""
1966 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001967 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001968 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1969 "'pos'", str(e.exception))
1970
Simon Glass274bf092018-09-14 04:57:08 -06001971 def testFillZero(self):
1972 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001973 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001974 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001975
Simon Glass267de432018-09-14 04:57:09 -06001976 def testTextMissing(self):
1977 """Test for a text entry type where there is no text"""
1978 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001979 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001980 self.assertIn("Node '/binman/text': No value provided for text label "
1981 "'test-id'", str(e.exception))
1982
Simon Glassed40e962018-09-14 04:57:10 -06001983 def testPackStart16Tpl(self):
1984 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001985 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001986 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1987
Simon Glass3b376c32018-09-14 04:57:12 -06001988 def testSelectImage(self):
1989 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001990 expected = 'Skipping images: image1'
1991
1992 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001993 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001994 with test_util.capture_sys_output() as (stdout, stderr):
1995 retcode = self._DoTestFile('006_dual_image.dts',
1996 verbosity=verbosity,
1997 images=['image2'])
1998 self.assertEqual(0, retcode)
1999 if verbosity:
2000 self.assertIn(expected, stdout.getvalue())
2001 else:
2002 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06002003
Simon Glass80025522022-01-29 14:14:04 -07002004 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
2005 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06002006 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06002007
Simon Glasse219aa42018-09-14 04:57:24 -06002008 def testUpdateFdtAll(self):
2009 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06002010 self._SetupSplElf()
2011 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06002012 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06002013
2014 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06002015 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002016 'image-pos': 0,
2017 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06002018 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07002019 'section:image-pos': 0,
2020 'section:size': 565,
2021 'section/u-boot-dtb:offset': 0,
2022 'section/u-boot-dtb:image-pos': 0,
2023 'section/u-boot-dtb:size': 565,
2024 'u-boot-spl-dtb:offset': 565,
2025 'u-boot-spl-dtb:image-pos': 565,
2026 'u-boot-spl-dtb:size': 585,
2027 'u-boot-tpl-dtb:offset': 1150,
2028 'u-boot-tpl-dtb:image-pos': 1150,
2029 'u-boot-tpl-dtb:size': 585,
2030 'u-boot-vpl-dtb:image-pos': 1735,
2031 'u-boot-vpl-dtb:offset': 1735,
2032 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002033 }
2034
2035 # We expect three device-tree files in the output, one after the other.
2036 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2037 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2038 # main U-Boot tree. All three should have the same postions and offset.
2039 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002040 self.maxDiff = None
2041 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002042 dtb = fdt.Fdt.FromData(data[start:])
2043 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002044 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002045 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002046 expected = dict(base_expected)
2047 if item:
2048 expected[item] = 0
2049 self.assertEqual(expected, props)
2050 start += dtb._fdt_obj.totalsize()
2051
2052 def testUpdateFdtOutput(self):
2053 """Test that output DTB files are updated"""
2054 try:
Simon Glass511f6582018-10-01 12:22:30 -06002055 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002056 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2057
2058 # Unfortunately, compiling a source file always results in a file
2059 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002060 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002061 # binman as a file called u-boot.dtb. To fix this, copy the file
2062 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002063 start = 0
2064 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002065 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002066 dtb = fdt.Fdt.FromData(data[start:])
2067 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002068 pathname = tools.get_output_filename(os.path.split(fname)[1])
2069 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002070 name = os.path.split(fname)[0]
2071
2072 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002073 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002074 else:
2075 orig_indata = dtb_data
2076 self.assertNotEqual(outdata, orig_indata,
2077 "Expected output file '%s' be updated" % pathname)
2078 self.assertEqual(outdata, data[start:start + size],
2079 "Expected output file '%s' to match output image" %
2080 pathname)
2081 start += size
2082 finally:
2083 self._ResetDtbs()
2084
Simon Glass7ba33592018-09-14 04:57:26 -06002085 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002086 bintool = self.comp_bintools['lz4']
2087 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002088
2089 def testCompress(self):
2090 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002091 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002092 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002093 use_real_dtb=True, update_dtb=True)
2094 dtb = fdt.Fdt(out_dtb_fname)
2095 dtb.Scan()
2096 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2097 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00002098 self.assertEqual(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002099
2100 # Do a sanity check on various fields
2101 image = control.images['image']
2102 entries = image.GetEntries()
2103 self.assertEqual(1, len(entries))
2104
2105 entry = entries['blob']
2106 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2107 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2108 orig = self._decompress(entry.data)
2109 self.assertEqual(orig, entry.uncomp_data)
2110
Simon Glass72eeff12020-10-26 17:40:16 -06002111 self.assertEqual(image.data, entry.data)
2112
Simon Glass7ba33592018-09-14 04:57:26 -06002113 expected = {
2114 'blob:uncomp-size': len(COMPRESS_DATA),
2115 'blob:size': len(data),
2116 'size': len(data),
2117 }
2118 self.assertEqual(expected, props)
2119
Simon Glassac6328c2018-09-14 04:57:28 -06002120 def testFiles(self):
2121 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002122 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002123 self.assertEqual(FILES_DATA, data)
2124
2125 def testFilesCompress(self):
2126 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002127 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002128 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002129
2130 image = control.images['image']
2131 entries = image.GetEntries()
2132 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002133 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002134
Simon Glass303f62f2019-05-17 22:00:46 -06002135 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002136 for i in range(1, 3):
2137 key = '%d.dat' % i
2138 start = entries[key].image_pos
2139 len = entries[key].size
2140 chunk = data[start:start + len]
2141 orig += self._decompress(chunk)
2142
2143 self.assertEqual(FILES_DATA, orig)
2144
2145 def testFilesMissing(self):
2146 """Test missing files"""
2147 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002148 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002149 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2150 'no files', str(e.exception))
2151
2152 def testFilesNoPattern(self):
2153 """Test missing files"""
2154 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002155 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002156 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2157 str(e.exception))
2158
Simon Glassdd156a42022-03-05 20:18:59 -07002159 def testExtendSize(self):
2160 """Test an extending entry"""
2161 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002162 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002163 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2164 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2165 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2166 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002167 self.assertEqual(expect, data)
2168 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700216900000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600217000000000 00000000 00000008 fill
217100000008 00000008 00000004 u-boot
21720000000c 0000000c 00000004 section
21730000000c 00000000 00000003 intel-mrc
217400000010 00000010 00000004 u-boot2
217500000014 00000014 0000000c section2
217600000014 00000000 00000008 fill
21770000001c 00000008 00000004 u-boot
217800000020 00000020 00000008 fill2
2179''', map_data)
2180
Simon Glassdd156a42022-03-05 20:18:59 -07002181 def testExtendSizeBad(self):
2182 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002183 with test_util.capture_sys_output() as (stdout, stderr):
2184 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002185 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002186 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2187 'expanding entry', str(e.exception))
2188
Simon Glassae7cf032018-09-14 04:57:31 -06002189 def testHash(self):
2190 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002191 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002192 use_real_dtb=True, update_dtb=True)
2193 dtb = fdt.Fdt(out_dtb_fname)
2194 dtb.Scan()
2195 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2196 m = hashlib.sha256()
2197 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002198 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002199
2200 def testHashNoAlgo(self):
2201 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002202 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002203 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2204 'hash node', str(e.exception))
2205
2206 def testHashBadAlgo(self):
2207 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002208 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002209 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002210 str(e.exception))
2211
2212 def testHashSection(self):
2213 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002214 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002215 use_real_dtb=True, update_dtb=True)
2216 dtb = fdt.Fdt(out_dtb_fname)
2217 dtb.Scan()
2218 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2219 m = hashlib.sha256()
2220 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002221 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002222 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002223
Simon Glass3fb4f422018-09-14 04:57:32 -06002224 def testPackUBootTplMicrocode(self):
2225 """Test that x86 microcode can be handled correctly in TPL
2226
2227 We expect to see the following in the image, in order:
2228 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2229 place
2230 u-boot-tpl.dtb with the microcode removed
2231 the microcode
2232 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002233 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002234 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002235 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002236 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2237 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002238
Simon Glassc64aea52018-09-14 04:57:34 -06002239 def testFmapX86(self):
2240 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002241 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002242 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002243 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002244 self.assertEqual(expected, data[:32])
2245 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2246
2247 self.assertEqual(0x100, fhdr.image_size)
2248
2249 self.assertEqual(0, fentries[0].offset)
2250 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002251 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002252
2253 self.assertEqual(4, fentries[1].offset)
2254 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002255 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002256
2257 self.assertEqual(32, fentries[2].offset)
2258 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2259 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002260 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002261
2262 def testFmapX86Section(self):
2263 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002264 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002265 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002266 self.assertEqual(expected, data[:32])
2267 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2268
Simon Glassb1d414c2021-04-03 11:05:10 +13002269 self.assertEqual(0x180, fhdr.image_size)
2270 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002271 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002272
Simon Glass82059c22021-04-03 11:05:09 +13002273 fentry = next(fiter)
2274 self.assertEqual(b'U_BOOT', fentry.name)
2275 self.assertEqual(0, fentry.offset)
2276 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002277
Simon Glass82059c22021-04-03 11:05:09 +13002278 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002279 self.assertEqual(b'SECTION', fentry.name)
2280 self.assertEqual(4, fentry.offset)
2281 self.assertEqual(0x20 + expect_size, fentry.size)
2282
2283 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002284 self.assertEqual(b'INTEL_MRC', fentry.name)
2285 self.assertEqual(4, fentry.offset)
2286 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002287
Simon Glass82059c22021-04-03 11:05:09 +13002288 fentry = next(fiter)
2289 self.assertEqual(b'FMAP', fentry.name)
2290 self.assertEqual(36, fentry.offset)
2291 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002292
Simon Glassb1714232018-09-14 04:57:35 -06002293 def testElf(self):
2294 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002295 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002296 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002297 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002298 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002299 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002300
Simon Glass0d673792019-07-08 13:18:25 -06002301 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002302 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002303 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002304 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002305 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002306 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002307
Simon Glasscd817d52018-09-14 04:57:36 -06002308 def testPackOverlapMap(self):
2309 """Test that overlapping regions are detected"""
2310 with test_util.capture_sys_output() as (stdout, stderr):
2311 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002312 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002313 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002314 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2315 stdout.getvalue())
2316
2317 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002318 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002319 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002320 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002321 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002322<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002323<none> 00000000 00000004 u-boot
2324<none> 00000003 00000004 u-boot-align
2325''', map_data)
2326
Simon Glass0d673792019-07-08 13:18:25 -06002327 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002328 """Test that an image with an Intel Reference code binary works"""
2329 data = self._DoReadFile('100_intel_refcode.dts')
2330 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2331
Simon Glasseb023b32019-04-25 21:58:39 -06002332 def testSectionOffset(self):
2333 """Tests use of a section with an offset"""
2334 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2335 map=True)
2336 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700233700000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600233800000004 00000004 00000010 section@0
233900000004 00000000 00000004 u-boot
234000000018 00000018 00000010 section@1
234100000018 00000000 00000004 u-boot
23420000002c 0000002c 00000004 section@2
23430000002c 00000000 00000004 u-boot
2344''', map_data)
2345 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002346 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2347 tools.get_bytes(0x21, 12) +
2348 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2349 tools.get_bytes(0x61, 12) +
2350 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2351 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002352
Simon Glass1de34482019-07-08 13:18:53 -06002353 def testCbfsRaw(self):
2354 """Test base handling of a Coreboot Filesystem (CBFS)
2355
2356 The exact contents of the CBFS is verified by similar tests in
2357 cbfs_util_test.py. The tests here merely check that the files added to
2358 the CBFS can be found in the final image.
2359 """
2360 data = self._DoReadFile('102_cbfs_raw.dts')
2361 size = 0xb0
2362
2363 cbfs = cbfs_util.CbfsReader(data)
2364 self.assertEqual(size, cbfs.rom_size)
2365
2366 self.assertIn('u-boot-dtb', cbfs.files)
2367 cfile = cbfs.files['u-boot-dtb']
2368 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2369
2370 def testCbfsArch(self):
2371 """Test on non-x86 architecture"""
2372 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2373 size = 0x100
2374
2375 cbfs = cbfs_util.CbfsReader(data)
2376 self.assertEqual(size, cbfs.rom_size)
2377
2378 self.assertIn('u-boot-dtb', cbfs.files)
2379 cfile = cbfs.files['u-boot-dtb']
2380 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2381
2382 def testCbfsStage(self):
2383 """Tests handling of a Coreboot Filesystem (CBFS)"""
2384 if not elf.ELF_TOOLS:
2385 self.skipTest('Python elftools not available')
2386 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2387 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2388 size = 0xb0
2389
2390 data = self._DoReadFile('104_cbfs_stage.dts')
2391 cbfs = cbfs_util.CbfsReader(data)
2392 self.assertEqual(size, cbfs.rom_size)
2393
2394 self.assertIn('u-boot', cbfs.files)
2395 cfile = cbfs.files['u-boot']
2396 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2397
2398 def testCbfsRawCompress(self):
2399 """Test handling of compressing raw files"""
2400 self._CheckLz4()
2401 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2402 size = 0x140
2403
2404 cbfs = cbfs_util.CbfsReader(data)
2405 self.assertIn('u-boot', cbfs.files)
2406 cfile = cbfs.files['u-boot']
2407 self.assertEqual(COMPRESS_DATA, cfile.data)
2408
2409 def testCbfsBadArch(self):
2410 """Test handling of a bad architecture"""
2411 with self.assertRaises(ValueError) as e:
2412 self._DoReadFile('106_cbfs_bad_arch.dts')
2413 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2414
2415 def testCbfsNoSize(self):
2416 """Test handling of a missing size property"""
2417 with self.assertRaises(ValueError) as e:
2418 self._DoReadFile('107_cbfs_no_size.dts')
2419 self.assertIn('entry must have a size property', str(e.exception))
2420
Simon Glass3e28f4f2021-11-23 11:03:54 -07002421 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002422 """Test handling of a CBFS entry which does not provide contentsy"""
2423 with self.assertRaises(ValueError) as e:
2424 self._DoReadFile('108_cbfs_no_contents.dts')
2425 self.assertIn('Could not complete processing of contents',
2426 str(e.exception))
2427
2428 def testCbfsBadCompress(self):
2429 """Test handling of a bad architecture"""
2430 with self.assertRaises(ValueError) as e:
2431 self._DoReadFile('109_cbfs_bad_compress.dts')
2432 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2433 str(e.exception))
2434
2435 def testCbfsNamedEntries(self):
2436 """Test handling of named entries"""
2437 data = self._DoReadFile('110_cbfs_name.dts')
2438
2439 cbfs = cbfs_util.CbfsReader(data)
2440 self.assertIn('FRED', cbfs.files)
2441 cfile1 = cbfs.files['FRED']
2442 self.assertEqual(U_BOOT_DATA, cfile1.data)
2443
2444 self.assertIn('hello', cbfs.files)
2445 cfile2 = cbfs.files['hello']
2446 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2447
Simon Glass759af872019-07-08 13:18:54 -06002448 def _SetupIfwi(self, fname):
2449 """Set up to run an IFWI test
2450
2451 Args:
2452 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2453 """
2454 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002455 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002456
2457 # Intel Integrated Firmware Image (IFWI) file
2458 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2459 data = fd.read()
2460 TestFunctional._MakeInputFile(fname,data)
2461
2462 def _CheckIfwi(self, data):
2463 """Check that an image with an IFWI contains the correct output
2464
2465 Args:
2466 data: Conents of output file
2467 """
Simon Glass80025522022-01-29 14:14:04 -07002468 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002469 if data[:0x1000] != expected_desc:
2470 self.fail('Expected descriptor binary at start of image')
2471
2472 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002473 image_fname = tools.get_output_filename('image.bin')
2474 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002475 ifwitool = bintool.Bintool.create('ifwitool')
2476 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002477
Simon Glass80025522022-01-29 14:14:04 -07002478 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002479 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002480
2481 def testPackX86RomIfwi(self):
2482 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2483 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002484 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002485 self._CheckIfwi(data)
2486
2487 def testPackX86RomIfwiNoDesc(self):
2488 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2489 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002490 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002491 self._CheckIfwi(data)
2492
2493 def testPackX86RomIfwiNoData(self):
2494 """Test that an x86 ROM with IFWI handles missing data"""
2495 self._SetupIfwi('ifwi.bin')
2496 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002497 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002498 self.assertIn('Could not complete processing of contents',
2499 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002500
Simon Glass66152ce2022-01-09 20:14:09 -07002501 def testIfwiMissing(self):
2502 """Test that binman still produces an image if ifwitool is missing"""
2503 self._SetupIfwi('fitimage.bin')
2504 with test_util.capture_sys_output() as (_, stderr):
2505 self._DoTestFile('111_x86_rom_ifwi.dts',
2506 force_missing_bintools='ifwitool')
2507 err = stderr.getvalue()
2508 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002509 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002510
Simon Glassc2f1aed2019-07-08 13:18:56 -06002511 def testCbfsOffset(self):
2512 """Test a CBFS with files at particular offsets
2513
2514 Like all CFBS tests, this is just checking the logic that calls
2515 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2516 """
2517 data = self._DoReadFile('114_cbfs_offset.dts')
2518 size = 0x200
2519
2520 cbfs = cbfs_util.CbfsReader(data)
2521 self.assertEqual(size, cbfs.rom_size)
2522
2523 self.assertIn('u-boot', cbfs.files)
2524 cfile = cbfs.files['u-boot']
2525 self.assertEqual(U_BOOT_DATA, cfile.data)
2526 self.assertEqual(0x40, cfile.cbfs_offset)
2527
2528 self.assertIn('u-boot-dtb', cbfs.files)
2529 cfile2 = cbfs.files['u-boot-dtb']
2530 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2531 self.assertEqual(0x140, cfile2.cbfs_offset)
2532
Simon Glass0f621332019-07-08 14:25:27 -06002533 def testFdtmap(self):
2534 """Test an FDT map can be inserted in the image"""
2535 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2536 fdtmap_data = data[len(U_BOOT_DATA):]
2537 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002538 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002539 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002540
2541 fdt_data = fdtmap_data[16:]
2542 dtb = fdt.Fdt.FromData(fdt_data)
2543 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002544 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002545 self.assertEqual({
2546 'image-pos': 0,
2547 'offset': 0,
2548 'u-boot:offset': 0,
2549 'u-boot:size': len(U_BOOT_DATA),
2550 'u-boot:image-pos': 0,
2551 'fdtmap:image-pos': 4,
2552 'fdtmap:offset': 4,
2553 'fdtmap:size': len(fdtmap_data),
2554 'size': len(data),
2555 }, props)
2556
2557 def testFdtmapNoMatch(self):
2558 """Check handling of an FDT map when the section cannot be found"""
2559 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2560
2561 # Mangle the section name, which should cause a mismatch between the
2562 # correct FDT path and the one expected by the section
2563 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002564 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002565 entries = image.GetEntries()
2566 fdtmap = entries['fdtmap']
2567 with self.assertRaises(ValueError) as e:
2568 fdtmap._GetFdtmap()
2569 self.assertIn("Cannot locate node for path '/binman-suffix'",
2570 str(e.exception))
2571
Simon Glasscec34ba2019-07-08 14:25:28 -06002572 def testFdtmapHeader(self):
2573 """Test an FDT map and image header can be inserted in the image"""
2574 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2575 fdtmap_pos = len(U_BOOT_DATA)
2576 fdtmap_data = data[fdtmap_pos:]
2577 fdt_data = fdtmap_data[16:]
2578 dtb = fdt.Fdt.FromData(fdt_data)
2579 fdt_size = dtb.GetFdtObj().totalsize()
2580 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002581 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002582 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2583 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2584
2585 def testFdtmapHeaderStart(self):
2586 """Test an image header can be inserted at the image start"""
2587 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2588 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2589 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002590 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002591 offset = struct.unpack('<I', hdr_data[4:])[0]
2592 self.assertEqual(fdtmap_pos, offset)
2593
2594 def testFdtmapHeaderPos(self):
2595 """Test an image header can be inserted at a chosen position"""
2596 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2597 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2598 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002599 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002600 offset = struct.unpack('<I', hdr_data[4:])[0]
2601 self.assertEqual(fdtmap_pos, offset)
2602
2603 def testHeaderMissingFdtmap(self):
2604 """Test an image header requires an fdtmap"""
2605 with self.assertRaises(ValueError) as e:
2606 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2607 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2608 str(e.exception))
2609
2610 def testHeaderNoLocation(self):
2611 """Test an image header with a no specified location is detected"""
2612 with self.assertRaises(ValueError) as e:
2613 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2614 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2615 str(e.exception))
2616
Simon Glasse61b6f62019-07-08 14:25:37 -06002617 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002618 """Test extending an entry after it is packed"""
2619 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002620 self.assertEqual(b'aaa', data[:3])
2621 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2622 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002623
Simon Glassdd156a42022-03-05 20:18:59 -07002624 def testEntryExtendBad(self):
2625 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002626 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002627 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002628 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002629 str(e.exception))
2630
Simon Glassdd156a42022-03-05 20:18:59 -07002631 def testEntryExtendSection(self):
2632 """Test extending an entry within a section after it is packed"""
2633 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002634 self.assertEqual(b'aaa', data[:3])
2635 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2636 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002637
Simon Glass90d29682019-07-08 14:25:38 -06002638 def testCompressDtb(self):
2639 """Test that compress of device-tree files is supported"""
2640 self._CheckLz4()
2641 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2642 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2643 comp_data = data[len(U_BOOT_DATA):]
2644 orig = self._decompress(comp_data)
2645 dtb = fdt.Fdt.FromData(orig)
2646 dtb.Scan()
2647 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2648 expected = {
2649 'u-boot:size': len(U_BOOT_DATA),
2650 'u-boot-dtb:uncomp-size': len(orig),
2651 'u-boot-dtb:size': len(comp_data),
2652 'size': len(data),
2653 }
2654 self.assertEqual(expected, props)
2655
Simon Glass151bbbf2019-07-08 14:25:41 -06002656 def testCbfsUpdateFdt(self):
2657 """Test that we can update the device tree with CBFS offset/size info"""
2658 self._CheckLz4()
2659 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2660 update_dtb=True)
2661 dtb = fdt.Fdt(out_dtb_fname)
2662 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002663 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002664 del props['cbfs/u-boot:size']
2665 self.assertEqual({
2666 'offset': 0,
2667 'size': len(data),
2668 'image-pos': 0,
2669 'cbfs:offset': 0,
2670 'cbfs:size': len(data),
2671 'cbfs:image-pos': 0,
Simon Glassfa144222023-10-14 14:40:28 -06002672 'cbfs/u-boot:offset': 0x30,
Simon Glass151bbbf2019-07-08 14:25:41 -06002673 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002674 'cbfs/u-boot:image-pos': 0x30,
2675 'cbfs/u-boot-dtb:offset': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002676 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
Simon Glassfa144222023-10-14 14:40:28 -06002677 'cbfs/u-boot-dtb:image-pos': 0xa4,
Simon Glass151bbbf2019-07-08 14:25:41 -06002678 }, props)
2679
Simon Glass3c9b4f22019-07-08 14:25:42 -06002680 def testCbfsBadType(self):
2681 """Test an image header with a no specified location is detected"""
2682 with self.assertRaises(ValueError) as e:
2683 self._DoReadFile('126_cbfs_bad_type.dts')
2684 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2685
Simon Glass6b156f82019-07-08 14:25:43 -06002686 def testList(self):
2687 """Test listing the files in an image"""
2688 self._CheckLz4()
2689 data = self._DoReadFile('127_list.dts')
2690 image = control.images['image']
2691 entries = image.BuildEntryList()
2692 self.assertEqual(7, len(entries))
2693
2694 ent = entries[0]
2695 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002696 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002697 self.assertEqual('section', ent.etype)
2698 self.assertEqual(len(data), ent.size)
2699 self.assertEqual(0, ent.image_pos)
2700 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002701 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002702
2703 ent = entries[1]
2704 self.assertEqual(1, ent.indent)
2705 self.assertEqual('u-boot', ent.name)
2706 self.assertEqual('u-boot', ent.etype)
2707 self.assertEqual(len(U_BOOT_DATA), ent.size)
2708 self.assertEqual(0, ent.image_pos)
2709 self.assertEqual(None, ent.uncomp_size)
2710 self.assertEqual(0, ent.offset)
2711
2712 ent = entries[2]
2713 self.assertEqual(1, ent.indent)
2714 self.assertEqual('section', ent.name)
2715 self.assertEqual('section', ent.etype)
2716 section_size = ent.size
2717 self.assertEqual(0x100, ent.image_pos)
2718 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002719 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002720
2721 ent = entries[3]
2722 self.assertEqual(2, ent.indent)
2723 self.assertEqual('cbfs', ent.name)
2724 self.assertEqual('cbfs', ent.etype)
2725 self.assertEqual(0x400, ent.size)
2726 self.assertEqual(0x100, ent.image_pos)
2727 self.assertEqual(None, ent.uncomp_size)
2728 self.assertEqual(0, ent.offset)
2729
2730 ent = entries[4]
2731 self.assertEqual(3, ent.indent)
2732 self.assertEqual('u-boot', ent.name)
2733 self.assertEqual('u-boot', ent.etype)
2734 self.assertEqual(len(U_BOOT_DATA), ent.size)
2735 self.assertEqual(0x138, ent.image_pos)
2736 self.assertEqual(None, ent.uncomp_size)
2737 self.assertEqual(0x38, ent.offset)
2738
2739 ent = entries[5]
2740 self.assertEqual(3, ent.indent)
2741 self.assertEqual('u-boot-dtb', ent.name)
2742 self.assertEqual('text', ent.etype)
2743 self.assertGreater(len(COMPRESS_DATA), ent.size)
2744 self.assertEqual(0x178, ent.image_pos)
2745 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2746 self.assertEqual(0x78, ent.offset)
2747
2748 ent = entries[6]
2749 self.assertEqual(2, ent.indent)
2750 self.assertEqual('u-boot-dtb', ent.name)
2751 self.assertEqual('u-boot-dtb', ent.etype)
2752 self.assertEqual(0x500, ent.image_pos)
2753 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2754 dtb_size = ent.size
2755 # Compressing this data expands it since headers are added
2756 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2757 self.assertEqual(0x400, ent.offset)
2758
2759 self.assertEqual(len(data), 0x100 + section_size)
2760 self.assertEqual(section_size, 0x400 + dtb_size)
2761
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002762 def testFindFdtmap(self):
2763 """Test locating an FDT map in an image"""
2764 self._CheckLz4()
2765 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2766 image = control.images['image']
2767 entries = image.GetEntries()
2768 entry = entries['fdtmap']
2769 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2770
2771 def testFindFdtmapMissing(self):
2772 """Test failing to locate an FDP map"""
2773 data = self._DoReadFile('005_simple.dts')
2774 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2775
Simon Glassed39a3c2019-07-08 14:25:45 -06002776 def testFindImageHeader(self):
2777 """Test locating a image header"""
2778 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002779 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002780 image = control.images['image']
2781 entries = image.GetEntries()
2782 entry = entries['fdtmap']
2783 # The header should point to the FDT map
2784 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2785
2786 def testFindImageHeaderStart(self):
2787 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002788 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002789 image = control.images['image']
2790 entries = image.GetEntries()
2791 entry = entries['fdtmap']
2792 # The header should point to the FDT map
2793 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2794
2795 def testFindImageHeaderMissing(self):
2796 """Test failing to locate an image header"""
2797 data = self._DoReadFile('005_simple.dts')
2798 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2799
Simon Glassb8424fa2019-07-08 14:25:46 -06002800 def testReadImage(self):
2801 """Test reading an image and accessing its FDT map"""
2802 self._CheckLz4()
2803 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002804 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002805 orig_image = control.images['image']
2806 image = Image.FromFile(image_fname)
2807 self.assertEqual(orig_image.GetEntries().keys(),
2808 image.GetEntries().keys())
2809
2810 orig_entry = orig_image.GetEntries()['fdtmap']
2811 entry = image.GetEntries()['fdtmap']
Brandon Maiera657bc62024-06-04 16:16:05 +00002812 self.assertEqual(orig_entry.offset, entry.offset)
2813 self.assertEqual(orig_entry.size, entry.size)
2814 self.assertEqual(orig_entry.image_pos, entry.image_pos)
Simon Glassb8424fa2019-07-08 14:25:46 -06002815
2816 def testReadImageNoHeader(self):
2817 """Test accessing an image's FDT map without an image header"""
2818 self._CheckLz4()
2819 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002820 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002821 image = Image.FromFile(image_fname)
2822 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002823 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002824
2825 def testReadImageFail(self):
2826 """Test failing to read an image image's FDT map"""
2827 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002828 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002829 with self.assertRaises(ValueError) as e:
2830 image = Image.FromFile(image_fname)
2831 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002832
Simon Glassb2fd11d2019-07-08 14:25:48 -06002833 def testListCmd(self):
2834 """Test listing the files in an image using an Fdtmap"""
2835 self._CheckLz4()
2836 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2837
2838 # lz4 compression size differs depending on the version
2839 image = control.images['image']
2840 entries = image.GetEntries()
2841 section_size = entries['section'].size
2842 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2843 fdtmap_offset = entries['fdtmap'].offset
2844
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002845 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002846 try:
2847 tmpdir, updated_fname = self._SetupImageInTmpdir()
2848 with test_util.capture_sys_output() as (stdout, stderr):
2849 self._DoBinman('ls', '-i', updated_fname)
2850 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002851 if tmpdir:
2852 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002853 lines = stdout.getvalue().splitlines()
2854 expected = [
2855'Name Image-pos Size Entry-type Offset Uncomp-size',
2856'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002857'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002858' u-boot 0 4 u-boot 0',
2859' section 100 %x section 100' % section_size,
2860' cbfs 100 400 cbfs 0',
Simon Glassfa144222023-10-14 14:40:28 -06002861' u-boot 120 4 u-boot 20',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002862' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002863' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002864' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002865 (fdtmap_offset, fdtmap_offset),
2866' image-header bf8 8 image-header bf8',
2867 ]
2868 self.assertEqual(expected, lines)
2869
2870 def testListCmdFail(self):
2871 """Test failing to list an image"""
2872 self._DoReadFile('005_simple.dts')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002873 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06002874 try:
2875 tmpdir, updated_fname = self._SetupImageInTmpdir()
2876 with self.assertRaises(ValueError) as e:
2877 self._DoBinman('ls', '-i', updated_fname)
2878 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01002879 if tmpdir:
2880 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002881 self.assertIn("Cannot find FDT map in image", str(e.exception))
2882
2883 def _RunListCmd(self, paths, expected):
2884 """List out entries and check the result
2885
2886 Args:
2887 paths: List of paths to pass to the list command
2888 expected: Expected list of filenames to be returned, in order
2889 """
2890 self._CheckLz4()
2891 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002892 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002893 image = Image.FromFile(image_fname)
2894 lines = image.GetListEntries(paths)[1]
2895 files = [line[0].strip() for line in lines[1:]]
2896 self.assertEqual(expected, files)
2897
2898 def testListCmdSection(self):
2899 """Test listing the files in a section"""
2900 self._RunListCmd(['section'],
2901 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2902
2903 def testListCmdFile(self):
2904 """Test listing a particular file"""
2905 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2906
2907 def testListCmdWildcard(self):
2908 """Test listing a wildcarded file"""
2909 self._RunListCmd(['*boot*'],
2910 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2911
2912 def testListCmdWildcardMulti(self):
2913 """Test listing a wildcarded file"""
2914 self._RunListCmd(['*cb*', '*head*'],
2915 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2916
2917 def testListCmdEmpty(self):
2918 """Test listing a wildcarded file"""
2919 self._RunListCmd(['nothing'], [])
2920
2921 def testListCmdPath(self):
2922 """Test listing the files in a sub-entry of a section"""
2923 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2924
Simon Glass4c613bf2019-07-08 14:25:50 -06002925 def _RunExtractCmd(self, entry_name, decomp=True):
2926 """Extract an entry from an image
2927
2928 Args:
2929 entry_name: Entry name to extract
2930 decomp: True to decompress the data if compressed, False to leave
2931 it in its raw uncompressed format
2932
2933 Returns:
2934 data from entry
2935 """
2936 self._CheckLz4()
2937 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002938 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002939 return control.ReadEntry(image_fname, entry_name, decomp)
2940
2941 def testExtractSimple(self):
2942 """Test extracting a single file"""
2943 data = self._RunExtractCmd('u-boot')
2944 self.assertEqual(U_BOOT_DATA, data)
2945
Simon Glass980a2842019-07-08 14:25:52 -06002946 def testExtractSection(self):
2947 """Test extracting the files in a section"""
2948 data = self._RunExtractCmd('section')
2949 cbfs_data = data[:0x400]
2950 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002951 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002952 dtb_data = data[0x400:]
2953 dtb = self._decompress(dtb_data)
2954 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2955
2956 def testExtractCompressed(self):
2957 """Test extracting compressed data"""
2958 data = self._RunExtractCmd('section/u-boot-dtb')
2959 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2960
2961 def testExtractRaw(self):
2962 """Test extracting compressed data without decompressing it"""
2963 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2964 dtb = self._decompress(data)
2965 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2966
2967 def testExtractCbfs(self):
2968 """Test extracting CBFS data"""
2969 data = self._RunExtractCmd('section/cbfs/u-boot')
2970 self.assertEqual(U_BOOT_DATA, data)
2971
2972 def testExtractCbfsCompressed(self):
2973 """Test extracting CBFS compressed data"""
2974 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2975 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2976
2977 def testExtractCbfsRaw(self):
2978 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002979 bintool = self.comp_bintools['lzma_alone']
2980 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06002981 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002982 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06002983 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2984
Simon Glass4c613bf2019-07-08 14:25:50 -06002985 def testExtractBadEntry(self):
2986 """Test extracting a bad section path"""
2987 with self.assertRaises(ValueError) as e:
2988 self._RunExtractCmd('section/does-not-exist')
2989 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2990 str(e.exception))
2991
2992 def testExtractMissingFile(self):
2993 """Test extracting file that does not exist"""
2994 with self.assertRaises(IOError) as e:
2995 control.ReadEntry('missing-file', 'name')
2996
2997 def testExtractBadFile(self):
2998 """Test extracting an invalid file"""
2999 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07003000 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06003001 with self.assertRaises(ValueError) as e:
3002 control.ReadEntry(fname, 'name')
3003
Simon Glass980a2842019-07-08 14:25:52 -06003004 def testExtractCmd(self):
3005 """Test extracting a file fron an image on the command line"""
3006 self._CheckLz4()
3007 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06003008 fname = os.path.join(self._indir, 'output.extact')
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003009 tmpdir = None
Simon Glassb3d6fc72019-07-20 12:24:10 -06003010 try:
3011 tmpdir, updated_fname = self._SetupImageInTmpdir()
3012 with test_util.capture_sys_output() as (stdout, stderr):
3013 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3014 '-f', fname)
3015 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01003016 if tmpdir:
3017 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07003018 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003019 self.assertEqual(U_BOOT_DATA, data)
3020
3021 def testExtractOneEntry(self):
3022 """Test extracting a single entry fron an image """
3023 self._CheckLz4()
3024 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003025 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003026 fname = os.path.join(self._indir, 'output.extact')
3027 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003028 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003029 self.assertEqual(U_BOOT_DATA, data)
3030
3031 def _CheckExtractOutput(self, decomp):
3032 """Helper to test file output with and without decompression
3033
3034 Args:
3035 decomp: True to decompress entry data, False to output it raw
3036 """
3037 def _CheckPresent(entry_path, expect_data, expect_size=None):
3038 """Check and remove expected file
3039
3040 This checks the data/size of a file and removes the file both from
3041 the outfiles set and from the output directory. Once all files are
3042 processed, both the set and directory should be empty.
3043
3044 Args:
3045 entry_path: Entry path
3046 expect_data: Data to expect in file, or None to skip check
3047 expect_size: Size of data to expect in file, or None to skip
3048 """
3049 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003050 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003051 os.remove(path)
3052 if expect_data:
3053 self.assertEqual(expect_data, data)
3054 elif expect_size:
3055 self.assertEqual(expect_size, len(data))
3056 outfiles.remove(path)
3057
3058 def _CheckDirPresent(name):
3059 """Remove expected directory
3060
3061 This gives an error if the directory does not exist as expected
3062
3063 Args:
3064 name: Name of directory to remove
3065 """
3066 path = os.path.join(outdir, name)
3067 os.rmdir(path)
3068
3069 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003070 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003071 outdir = os.path.join(self._indir, 'extract')
3072 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3073
3074 # Create a set of all file that were output (should be 9)
3075 outfiles = set()
3076 for root, dirs, files in os.walk(outdir):
3077 outfiles |= set([os.path.join(root, fname) for fname in files])
3078 self.assertEqual(9, len(outfiles))
3079 self.assertEqual(9, len(einfos))
3080
3081 image = control.images['image']
3082 entries = image.GetEntries()
3083
3084 # Check the 9 files in various ways
3085 section = entries['section']
3086 section_entries = section.GetEntries()
3087 cbfs_entries = section_entries['cbfs'].GetEntries()
3088 _CheckPresent('u-boot', U_BOOT_DATA)
3089 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3090 dtb_len = EXTRACT_DTB_SIZE
3091 if not decomp:
3092 dtb_len = cbfs_entries['u-boot-dtb'].size
3093 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3094 if not decomp:
3095 dtb_len = section_entries['u-boot-dtb'].size
3096 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3097
3098 fdtmap = entries['fdtmap']
3099 _CheckPresent('fdtmap', fdtmap.data)
3100 hdr = entries['image-header']
3101 _CheckPresent('image-header', hdr.data)
3102
3103 _CheckPresent('section/root', section.data)
3104 cbfs = section_entries['cbfs']
3105 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003106 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003107 _CheckPresent('root', data)
3108
3109 # There should be no files left. Remove all the directories to check.
3110 # If there are any files/dirs remaining, one of these checks will fail.
3111 self.assertEqual(0, len(outfiles))
3112 _CheckDirPresent('section/cbfs')
3113 _CheckDirPresent('section')
3114 _CheckDirPresent('')
3115 self.assertFalse(os.path.exists(outdir))
3116
3117 def testExtractAllEntries(self):
3118 """Test extracting all entries"""
3119 self._CheckLz4()
3120 self._CheckExtractOutput(decomp=True)
3121
3122 def testExtractAllEntriesRaw(self):
3123 """Test extracting all entries without decompressing them"""
3124 self._CheckLz4()
3125 self._CheckExtractOutput(decomp=False)
3126
3127 def testExtractSelectedEntries(self):
3128 """Test extracting some entries"""
3129 self._CheckLz4()
3130 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003131 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003132 outdir = os.path.join(self._indir, 'extract')
3133 einfos = control.ExtractEntries(image_fname, None, outdir,
3134 ['*cb*', '*head*'])
3135
3136 # File output is tested by testExtractAllEntries(), so just check that
3137 # the expected entries are selected
3138 names = [einfo.name for einfo in einfos]
3139 self.assertEqual(names,
3140 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3141
3142 def testExtractNoEntryPaths(self):
3143 """Test extracting some entries"""
3144 self._CheckLz4()
3145 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003146 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003147 with self.assertRaises(ValueError) as e:
3148 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003149 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003150 str(e.exception))
3151
3152 def testExtractTooManyEntryPaths(self):
3153 """Test extracting some entries"""
3154 self._CheckLz4()
3155 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003156 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003157 with self.assertRaises(ValueError) as e:
3158 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003159 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003160 str(e.exception))
3161
Simon Glass52d06212019-07-08 14:25:53 -06003162 def testPackAlignSection(self):
3163 """Test that sections can have alignment"""
3164 self._DoReadFile('131_pack_align_section.dts')
3165
3166 self.assertIn('image', control.images)
3167 image = control.images['image']
3168 entries = image.GetEntries()
3169 self.assertEqual(3, len(entries))
3170
3171 # First u-boot
3172 self.assertIn('u-boot', entries)
3173 entry = entries['u-boot']
3174 self.assertEqual(0, entry.offset)
3175 self.assertEqual(0, entry.image_pos)
3176 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3177 self.assertEqual(len(U_BOOT_DATA), entry.size)
3178
3179 # Section0
3180 self.assertIn('section0', entries)
3181 section0 = entries['section0']
3182 self.assertEqual(0x10, section0.offset)
3183 self.assertEqual(0x10, section0.image_pos)
3184 self.assertEqual(len(U_BOOT_DATA), section0.size)
3185
3186 # Second u-boot
3187 section_entries = section0.GetEntries()
3188 self.assertIn('u-boot', section_entries)
3189 entry = section_entries['u-boot']
3190 self.assertEqual(0, entry.offset)
3191 self.assertEqual(0x10, entry.image_pos)
3192 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3193 self.assertEqual(len(U_BOOT_DATA), entry.size)
3194
3195 # Section1
3196 self.assertIn('section1', entries)
3197 section1 = entries['section1']
3198 self.assertEqual(0x14, section1.offset)
3199 self.assertEqual(0x14, section1.image_pos)
3200 self.assertEqual(0x20, section1.size)
3201
3202 # Second u-boot
3203 section_entries = section1.GetEntries()
3204 self.assertIn('u-boot', section_entries)
3205 entry = section_entries['u-boot']
3206 self.assertEqual(0, entry.offset)
3207 self.assertEqual(0x14, entry.image_pos)
3208 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3209 self.assertEqual(len(U_BOOT_DATA), entry.size)
3210
3211 # Section2
3212 self.assertIn('section2', section_entries)
3213 section2 = section_entries['section2']
3214 self.assertEqual(0x4, section2.offset)
3215 self.assertEqual(0x18, section2.image_pos)
3216 self.assertEqual(4, section2.size)
3217
3218 # Third u-boot
3219 section_entries = section2.GetEntries()
3220 self.assertIn('u-boot', section_entries)
3221 entry = section_entries['u-boot']
3222 self.assertEqual(0, entry.offset)
3223 self.assertEqual(0x18, entry.image_pos)
3224 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3225 self.assertEqual(len(U_BOOT_DATA), entry.size)
3226
Simon Glassf8a54bc2019-07-20 12:23:56 -06003227 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3228 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003229 """Replace an entry in an image
3230
3231 This writes the entry data to update it, then opens the updated file and
3232 returns the value that it now finds there.
3233
3234 Args:
3235 entry_name: Entry name to replace
3236 data: Data to replace it with
3237 decomp: True to compress the data if needed, False if data is
3238 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003239 allow_resize: True to allow entries to change size, False to raise
3240 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003241
3242 Returns:
3243 Tuple:
3244 data from entry
3245 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003246 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003247 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003248 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003249 update_dtb=True)[1]
3250
3251 self.assertIn('image', control.images)
3252 image = control.images['image']
3253 entries = image.GetEntries()
3254 orig_dtb_data = entries['u-boot-dtb'].data
3255 orig_fdtmap_data = entries['fdtmap'].data
3256
Simon Glass80025522022-01-29 14:14:04 -07003257 image_fname = tools.get_output_filename('image.bin')
3258 updated_fname = tools.get_output_filename('image-updated.bin')
3259 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003260 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3261 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003262 data = control.ReadEntry(updated_fname, entry_name, decomp)
3263
Simon Glassf8a54bc2019-07-20 12:23:56 -06003264 # The DT data should not change unless resized:
3265 if not allow_resize:
3266 new_dtb_data = entries['u-boot-dtb'].data
3267 self.assertEqual(new_dtb_data, orig_dtb_data)
3268 new_fdtmap_data = entries['fdtmap'].data
3269 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003270
Simon Glassf8a54bc2019-07-20 12:23:56 -06003271 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003272
3273 def testReplaceSimple(self):
3274 """Test replacing a single file"""
3275 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003276 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3277 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003278 self.assertEqual(expected, data)
3279
3280 # Test that the state looks right. There should be an FDT for the fdtmap
3281 # that we jsut read back in, and it should match what we find in the
3282 # 'control' tables. Checking for an FDT that does not exist should
3283 # return None.
3284 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003285 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003286 self.assertEqual(expected_fdtmap, fdtmap)
3287
3288 dtb = state.GetFdtForEtype('fdtmap')
3289 self.assertEqual(dtb.GetContents(), fdtmap)
3290
3291 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3292 self.assertIsNone(missing_path)
3293 self.assertIsNone(missing_fdtmap)
3294
3295 missing_dtb = state.GetFdtForEtype('missing')
3296 self.assertIsNone(missing_dtb)
3297
3298 self.assertEqual('/binman', state.fdt_path_prefix)
3299
3300 def testReplaceResizeFail(self):
3301 """Test replacing a file by something larger"""
3302 expected = U_BOOT_DATA + b'x'
3303 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003304 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3305 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003306 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3307 str(e.exception))
3308
3309 def testReplaceMulti(self):
3310 """Test replacing entry data where multiple images are generated"""
3311 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3312 update_dtb=True)[0]
3313 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003314 updated_fname = tools.get_output_filename('image-updated.bin')
3315 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003316 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003317 control.WriteEntry(updated_fname, entry_name, expected,
3318 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003319 data = control.ReadEntry(updated_fname, entry_name)
3320 self.assertEqual(expected, data)
3321
3322 # Check the state looks right.
3323 self.assertEqual('/binman/image', state.fdt_path_prefix)
3324
3325 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003326 image_fname = tools.get_output_filename('first-image.bin')
3327 updated_fname = tools.get_output_filename('first-updated.bin')
3328 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003329 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003330 control.WriteEntry(updated_fname, entry_name, expected,
3331 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003332 data = control.ReadEntry(updated_fname, entry_name)
3333 self.assertEqual(expected, data)
3334
3335 # Check the state looks right.
3336 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003337
Simon Glassfb30e292019-07-20 12:23:51 -06003338 def testUpdateFdtAllRepack(self):
3339 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003340 self._SetupSplElf()
3341 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003342 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3343 SECTION_SIZE = 0x300
3344 DTB_SIZE = 602
3345 FDTMAP_SIZE = 608
3346 base_expected = {
3347 'offset': 0,
3348 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3349 'image-pos': 0,
3350 'section:offset': 0,
3351 'section:size': SECTION_SIZE,
3352 'section:image-pos': 0,
3353 'section/u-boot-dtb:offset': 4,
3354 'section/u-boot-dtb:size': 636,
3355 'section/u-boot-dtb:image-pos': 4,
3356 'u-boot-spl-dtb:offset': SECTION_SIZE,
3357 'u-boot-spl-dtb:size': DTB_SIZE,
3358 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3359 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3360 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3361 'u-boot-tpl-dtb:size': DTB_SIZE,
3362 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3363 'fdtmap:size': FDTMAP_SIZE,
3364 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3365 }
3366 main_expected = {
3367 'section:orig-size': SECTION_SIZE,
3368 'section/u-boot-dtb:orig-offset': 4,
3369 }
3370
3371 # We expect three device-tree files in the output, with the first one
3372 # within a fixed-size section.
3373 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3374 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3375 # main U-Boot tree. All three should have the same positions and offset
3376 # except that the main tree should include the main_expected properties
3377 start = 4
3378 for item in ['', 'spl', 'tpl', None]:
3379 if item is None:
3380 start += 16 # Move past fdtmap header
3381 dtb = fdt.Fdt.FromData(data[start:])
3382 dtb.Scan()
3383 props = self._GetPropTree(dtb,
3384 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3385 prefix='/' if item is None else '/binman/')
3386 expected = dict(base_expected)
3387 if item:
3388 expected[item] = 0
3389 else:
3390 # Main DTB and fdtdec should include the 'orig-' properties
3391 expected.update(main_expected)
3392 # Helpful for debugging:
3393 #for prop in sorted(props):
3394 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3395 self.assertEqual(expected, props)
3396 if item == '':
3397 start = SECTION_SIZE
3398 else:
3399 start += dtb._fdt_obj.totalsize()
3400
Simon Glass11453762019-07-20 12:23:55 -06003401 def testFdtmapHeaderMiddle(self):
3402 """Test an FDT map in the middle of an image when it should be at end"""
3403 with self.assertRaises(ValueError) as e:
3404 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3405 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3406 str(e.exception))
3407
3408 def testFdtmapHeaderStartBad(self):
3409 """Test an FDT map in middle of an image when it should be at start"""
3410 with self.assertRaises(ValueError) as e:
3411 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3412 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3413 str(e.exception))
3414
3415 def testFdtmapHeaderEndBad(self):
3416 """Test an FDT map at the start of an image when it should be at end"""
3417 with self.assertRaises(ValueError) as e:
3418 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3419 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3420 str(e.exception))
3421
3422 def testFdtmapHeaderNoSize(self):
3423 """Test an image header at the end of an image with undefined size"""
3424 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3425
Simon Glassf8a54bc2019-07-20 12:23:56 -06003426 def testReplaceResize(self):
3427 """Test replacing a single file in an entry with a larger file"""
3428 expected = U_BOOT_DATA + b'x'
3429 data, _, image = self._RunReplaceCmd('u-boot', expected,
3430 dts='139_replace_repack.dts')
3431 self.assertEqual(expected, data)
3432
3433 entries = image.GetEntries()
3434 dtb_data = entries['u-boot-dtb'].data
3435 dtb = fdt.Fdt.FromData(dtb_data)
3436 dtb.Scan()
3437
3438 # The u-boot section should now be larger in the dtb
3439 node = dtb.GetNode('/binman/u-boot')
3440 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3441
3442 # Same for the fdtmap
3443 fdata = entries['fdtmap'].data
3444 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3445 fdtb.Scan()
3446 fnode = fdtb.GetNode('/u-boot')
3447 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3448
3449 def testReplaceResizeNoRepack(self):
3450 """Test replacing an entry with a larger file when not allowed"""
3451 expected = U_BOOT_DATA + b'x'
3452 with self.assertRaises(ValueError) as e:
3453 self._RunReplaceCmd('u-boot', expected)
3454 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3455 str(e.exception))
3456
Simon Glass9d8ee322019-07-20 12:23:58 -06003457 def testEntryShrink(self):
3458 """Test contracting an entry after it is packed"""
3459 try:
3460 state.SetAllowEntryContraction(True)
3461 data = self._DoReadFileDtb('140_entry_shrink.dts',
3462 update_dtb=True)[0]
3463 finally:
3464 state.SetAllowEntryContraction(False)
3465 self.assertEqual(b'a', data[:1])
3466 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3467 self.assertEqual(b'a', data[-1:])
3468
3469 def testEntryShrinkFail(self):
3470 """Test not being allowed to contract an entry after it is packed"""
3471 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3472
3473 # In this case there is a spare byte at the end of the data. The size of
3474 # the contents is only 1 byte but we still have the size before it
3475 # shrunk.
3476 self.assertEqual(b'a\0', data[:2])
3477 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3478 self.assertEqual(b'a\0', data[-2:])
3479
Simon Glass70e32982019-07-20 12:24:01 -06003480 def testDescriptorOffset(self):
3481 """Test that the Intel descriptor is always placed at at the start"""
3482 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3483 image = control.images['image']
3484 entries = image.GetEntries()
3485 desc = entries['intel-descriptor']
3486 self.assertEqual(0xff800000, desc.offset);
3487 self.assertEqual(0xff800000, desc.image_pos);
3488
Simon Glass37fdd142019-07-20 12:24:06 -06003489 def testReplaceCbfs(self):
3490 """Test replacing a single file in CBFS without changing the size"""
3491 self._CheckLz4()
3492 expected = b'x' * len(U_BOOT_DATA)
3493 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003494 updated_fname = tools.get_output_filename('image-updated.bin')
3495 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003496 entry_name = 'section/cbfs/u-boot'
3497 control.WriteEntry(updated_fname, entry_name, expected,
3498 allow_resize=True)
3499 data = control.ReadEntry(updated_fname, entry_name)
3500 self.assertEqual(expected, data)
3501
3502 def testReplaceResizeCbfs(self):
3503 """Test replacing a single file in CBFS with one of a different size"""
3504 self._CheckLz4()
3505 expected = U_BOOT_DATA + b'x'
3506 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003507 updated_fname = tools.get_output_filename('image-updated.bin')
3508 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003509 entry_name = 'section/cbfs/u-boot'
3510 control.WriteEntry(updated_fname, entry_name, expected,
3511 allow_resize=True)
3512 data = control.ReadEntry(updated_fname, entry_name)
3513 self.assertEqual(expected, data)
3514
Simon Glass30033c22019-07-20 12:24:15 -06003515 def _SetupForReplace(self):
3516 """Set up some files to use to replace entries
3517
3518 This generates an image, copies it to a new file, extracts all the files
3519 in it and updates some of them
3520
3521 Returns:
3522 List
3523 Image filename
3524 Output directory
3525 Expected values for updated entries, each a string
3526 """
3527 data = self._DoReadFileRealDtb('143_replace_all.dts')
3528
Simon Glass80025522022-01-29 14:14:04 -07003529 updated_fname = tools.get_output_filename('image-updated.bin')
3530 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003531
3532 outdir = os.path.join(self._indir, 'extract')
3533 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3534
3535 expected1 = b'x' + U_BOOT_DATA + b'y'
3536 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003537 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003538
3539 expected2 = b'a' + U_BOOT_DATA + b'b'
3540 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003541 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003542
3543 expected_text = b'not the same text'
3544 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003545 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003546
3547 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3548 dtb = fdt.FdtScan(dtb_fname)
3549 node = dtb.GetNode('/binman/text')
3550 node.AddString('my-property', 'the value')
3551 dtb.Sync(auto_resize=True)
3552 dtb.Flush()
3553
3554 return updated_fname, outdir, expected1, expected2, expected_text
3555
3556 def _CheckReplaceMultiple(self, entry_paths):
3557 """Handle replacing the contents of multiple entries
3558
3559 Args:
3560 entry_paths: List of entry paths to replace
3561
3562 Returns:
3563 List
3564 Dict of entries in the image:
3565 key: Entry name
3566 Value: Entry object
3567 Expected values for updated entries, each a string
3568 """
3569 updated_fname, outdir, expected1, expected2, expected_text = (
3570 self._SetupForReplace())
3571 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3572
3573 image = Image.FromFile(updated_fname)
3574 image.LoadData()
3575 return image.GetEntries(), expected1, expected2, expected_text
3576
3577 def testReplaceAll(self):
3578 """Test replacing the contents of all entries"""
3579 entries, expected1, expected2, expected_text = (
3580 self._CheckReplaceMultiple([]))
3581 data = entries['u-boot'].data
3582 self.assertEqual(expected1, data)
3583
3584 data = entries['u-boot2'].data
3585 self.assertEqual(expected2, data)
3586
3587 data = entries['text'].data
3588 self.assertEqual(expected_text, data)
3589
3590 # Check that the device tree is updated
3591 data = entries['u-boot-dtb'].data
3592 dtb = fdt.Fdt.FromData(data)
3593 dtb.Scan()
3594 node = dtb.GetNode('/binman/text')
3595 self.assertEqual('the value', node.props['my-property'].value)
3596
3597 def testReplaceSome(self):
3598 """Test replacing the contents of a few entries"""
3599 entries, expected1, expected2, expected_text = (
3600 self._CheckReplaceMultiple(['u-boot2', 'text']))
3601
3602 # This one should not change
3603 data = entries['u-boot'].data
3604 self.assertEqual(U_BOOT_DATA, data)
3605
3606 data = entries['u-boot2'].data
3607 self.assertEqual(expected2, data)
3608
3609 data = entries['text'].data
3610 self.assertEqual(expected_text, data)
3611
3612 def testReplaceCmd(self):
3613 """Test replacing a file fron an image on the command line"""
3614 self._DoReadFileRealDtb('143_replace_all.dts')
3615
3616 try:
3617 tmpdir, updated_fname = self._SetupImageInTmpdir()
3618
3619 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3620 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003621 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003622
3623 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003624 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003625 self.assertEqual(expected, data[:len(expected)])
3626 map_fname = os.path.join(tmpdir, 'image-updated.map')
3627 self.assertFalse(os.path.exists(map_fname))
3628 finally:
3629 shutil.rmtree(tmpdir)
3630
3631 def testReplaceCmdSome(self):
3632 """Test replacing some files fron an image on the command line"""
3633 updated_fname, outdir, expected1, expected2, expected_text = (
3634 self._SetupForReplace())
3635
3636 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3637 'u-boot2', 'text')
3638
Simon Glass80025522022-01-29 14:14:04 -07003639 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003640 image = Image.FromFile(updated_fname)
3641 image.LoadData()
3642 entries = image.GetEntries()
3643
3644 # This one should not change
3645 data = entries['u-boot'].data
3646 self.assertEqual(U_BOOT_DATA, data)
3647
3648 data = entries['u-boot2'].data
3649 self.assertEqual(expected2, data)
3650
3651 data = entries['text'].data
3652 self.assertEqual(expected_text, data)
3653
3654 def testReplaceMissing(self):
3655 """Test replacing entries where the file is missing"""
3656 updated_fname, outdir, expected1, expected2, expected_text = (
3657 self._SetupForReplace())
3658
3659 # Remove one of the files, to generate a warning
3660 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3661 os.remove(u_boot_fname1)
3662
3663 with test_util.capture_sys_output() as (stdout, stderr):
3664 control.ReplaceEntries(updated_fname, None, outdir, [])
3665 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003666 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003667
3668 def testReplaceCmdMap(self):
3669 """Test replacing a file fron an image on the command line"""
3670 self._DoReadFileRealDtb('143_replace_all.dts')
3671
3672 try:
3673 tmpdir, updated_fname = self._SetupImageInTmpdir()
3674
3675 fname = os.path.join(self._indir, 'update-u-boot.bin')
3676 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003677 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003678
3679 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3680 '-f', fname, '-m')
3681 map_fname = os.path.join(tmpdir, 'image-updated.map')
3682 self.assertTrue(os.path.exists(map_fname))
3683 finally:
3684 shutil.rmtree(tmpdir)
3685
3686 def testReplaceNoEntryPaths(self):
3687 """Test replacing an entry without an entry path"""
3688 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003689 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003690 with self.assertRaises(ValueError) as e:
3691 control.ReplaceEntries(image_fname, 'fname', None, [])
3692 self.assertIn('Must specify an entry path to read with -f',
3693 str(e.exception))
3694
3695 def testReplaceTooManyEntryPaths(self):
3696 """Test extracting some entries"""
3697 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003698 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003699 with self.assertRaises(ValueError) as e:
3700 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3701 self.assertIn('Must specify exactly one entry path to write with -f',
3702 str(e.exception))
3703
Simon Glass0b074d62019-08-24 07:22:48 -06003704 def testPackReset16(self):
3705 """Test that an image with an x86 reset16 region can be created"""
3706 data = self._DoReadFile('144_x86_reset16.dts')
3707 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3708
3709 def testPackReset16Spl(self):
3710 """Test that an image with an x86 reset16-spl region can be created"""
3711 data = self._DoReadFile('145_x86_reset16_spl.dts')
3712 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3713
3714 def testPackReset16Tpl(self):
3715 """Test that an image with an x86 reset16-tpl region can be created"""
3716 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3717 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3718
Simon Glass232f90c2019-08-24 07:22:50 -06003719 def testPackIntelFit(self):
3720 """Test that an image with an Intel FIT and pointer can be created"""
3721 data = self._DoReadFile('147_intel_fit.dts')
3722 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3723 fit = data[16:32];
3724 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3725 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3726
3727 image = control.images['image']
3728 entries = image.GetEntries()
3729 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3730 self.assertEqual(expected_ptr, ptr)
3731
3732 def testPackIntelFitMissing(self):
3733 """Test detection of a FIT pointer with not FIT region"""
3734 with self.assertRaises(ValueError) as e:
3735 self._DoReadFile('148_intel_fit_missing.dts')
3736 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3737 str(e.exception))
3738
Simon Glass72555fa2019-11-06 17:22:44 -07003739 def _CheckSymbolsTplSection(self, dts, expected_vals):
3740 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003741 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003742 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003743 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003744 self.assertEqual(expected1, data[:upto1])
3745
3746 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003747 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003748 self.assertEqual(expected2, data[upto1:upto2])
3749
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003750 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003751 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003752 self.assertEqual(expected3, data[upto2:upto3])
3753
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003754 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003755 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3756
3757 def testSymbolsTplSection(self):
3758 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3759 self._SetupSplElf('u_boot_binman_syms')
3760 self._SetupTplElf('u_boot_binman_syms')
3761 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003762 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003763
3764 def testSymbolsTplSectionX86(self):
3765 """Test binman can assign symbols in a section with end-at-4gb"""
3766 self._SetupSplElf('u_boot_binman_syms_x86')
3767 self._SetupTplElf('u_boot_binman_syms_x86')
3768 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003769 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003770 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003771
Simon Glass98c59572019-08-24 07:23:03 -06003772 def testPackX86RomIfwiSectiom(self):
3773 """Test that a section can be placed in an IFWI region"""
3774 self._SetupIfwi('fitimage.bin')
3775 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3776 self._CheckIfwi(data)
3777
Simon Glassba7985d2019-08-24 07:23:07 -06003778 def testPackFspM(self):
3779 """Test that an image with a FSP memory-init binary can be created"""
3780 data = self._DoReadFile('152_intel_fsp_m.dts')
3781 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3782
Simon Glass4d9086d2019-10-20 21:31:35 -06003783 def testPackFspS(self):
3784 """Test that an image with a FSP silicon-init binary can be created"""
3785 data = self._DoReadFile('153_intel_fsp_s.dts')
3786 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003787
Simon Glass9ea87b22019-10-20 21:31:36 -06003788 def testPackFspT(self):
3789 """Test that an image with a FSP temp-ram-init binary can be created"""
3790 data = self._DoReadFile('154_intel_fsp_t.dts')
3791 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3792
Simon Glass48f3aad2020-07-09 18:39:31 -06003793 def testMkimage(self):
3794 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003795 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003796 data = self._DoReadFile('156_mkimage.dts')
3797
3798 # Just check that the data appears in the file somewhere
3799 self.assertIn(U_BOOT_SPL_DATA, data)
3800
Simon Glass66152ce2022-01-09 20:14:09 -07003801 def testMkimageMissing(self):
3802 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003803 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003804 with test_util.capture_sys_output() as (_, stderr):
3805 self._DoTestFile('156_mkimage.dts',
3806 force_missing_bintools='mkimage')
3807 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003808 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003809
Simon Glass5e560182020-07-09 18:39:36 -06003810 def testExtblob(self):
3811 """Test an image with an external blob"""
3812 data = self._DoReadFile('157_blob_ext.dts')
3813 self.assertEqual(REFCODE_DATA, data)
3814
3815 def testExtblobMissing(self):
3816 """Test an image with a missing external blob"""
3817 with self.assertRaises(ValueError) as e:
3818 self._DoReadFile('158_blob_ext_missing.dts')
3819 self.assertIn("Filename 'missing-file' not found in input path",
3820 str(e.exception))
3821
Simon Glass5d94cc62020-07-09 18:39:38 -06003822 def testExtblobMissingOk(self):
3823 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003824 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003825 ret = self._DoTestFile('158_blob_ext_missing.dts',
3826 allow_missing=True)
3827 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003828 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003829 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003830 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003831 self.assertIn('Some images are invalid', err)
3832
3833 def testExtblobMissingOkFlag(self):
3834 """Test an image with an missing external blob allowed with -W"""
3835 with test_util.capture_sys_output() as (stdout, stderr):
3836 ret = self._DoTestFile('158_blob_ext_missing.dts',
3837 allow_missing=True, ignore_missing=True)
3838 self.assertEqual(0, ret)
3839 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003840 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003841 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003842 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003843
3844 def testExtblobMissingOkSect(self):
3845 """Test an image with an missing external blob that is allowed"""
3846 with test_util.capture_sys_output() as (stdout, stderr):
3847 self._DoTestFile('159_blob_ext_missing_sect.dts',
3848 allow_missing=True)
3849 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003850 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003851
Simon Glasse88cef92020-07-09 18:39:41 -06003852 def testPackX86RomMeMissingDesc(self):
3853 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003854 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003855 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003856 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003857 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003858
3859 def testPackX86RomMissingIfwi(self):
3860 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3861 self._SetupIfwi('fitimage.bin')
3862 pathname = os.path.join(self._indir, 'fitimage.bin')
3863 os.remove(pathname)
3864 with test_util.capture_sys_output() as (stdout, stderr):
3865 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3866 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003867 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003868
Simon Glass2a0fa982022-02-11 13:23:21 -07003869 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003870 """Test that zero-size overlapping regions are ignored"""
3871 self._DoTestFile('160_pack_overlap_zero.dts')
3872
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003873 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003874 # The data should be inside the FIT
3875 dtb = fdt.Fdt.FromData(fit_data)
3876 dtb.Scan()
3877 fnode = dtb.GetNode('/images/kernel')
3878 self.assertIn('data', fnode.props)
3879
3880 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003881 tools.write_file(fname, fit_data)
3882 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003883
3884 # Check a few features to make sure the plumbing works. We don't need
3885 # to test the operation of mkimage or dumpimage here. First convert the
3886 # output into a dict where the keys are the fields printed by dumpimage
3887 # and the values are a list of values for each field
3888 lines = out.splitlines()
3889
3890 # Converts "Compression: gzip compressed" into two groups:
3891 # 'Compression' and 'gzip compressed'
3892 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3893 vals = collections.defaultdict(list)
3894 for line in lines:
3895 mat = re_line.match(line)
3896 vals[mat.group(1)].append(mat.group(2))
3897
Brandon Maiera657bc62024-06-04 16:16:05 +00003898 self.assertEqual('FIT description: test-desc', lines[0])
Simon Glass45d556d2020-07-09 18:39:45 -06003899 self.assertIn('Created:', lines[1])
3900 self.assertIn('Image 0 (kernel)', vals)
3901 self.assertIn('Hash value', vals)
3902 data_sizes = vals.get('Data Size')
3903 self.assertIsNotNone(data_sizes)
3904 self.assertEqual(2, len(data_sizes))
3905 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003906 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3907 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3908
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003909 # Check if entry listing correctly omits /images/
3910 image = control.images['image']
3911 fit_entry = image.GetEntries()['fit']
3912 subentries = list(fit_entry.GetEntries().keys())
3913 expected = ['kernel', 'fdt-1']
3914 self.assertEqual(expected, subentries)
3915
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003916 def testSimpleFit(self):
3917 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003918 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003919 data = self._DoReadFile('161_fit.dts')
3920 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3921 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3922 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3923
3924 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3925
3926 def testSimpleFitExpandsSubentries(self):
3927 """Test that FIT images expand their subentries"""
3928 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3929 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3930 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3931 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3932
3933 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003934
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003935 def testSimpleFitImagePos(self):
3936 """Test that we have correct image-pos for FIT subentries"""
3937 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3938 update_dtb=True)
3939 dtb = fdt.Fdt(out_dtb_fname)
3940 dtb.Scan()
3941 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3942
Simon Glassb7bad182022-03-05 20:19:01 -07003943 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003944 self.assertEqual({
3945 'image-pos': 0,
3946 'offset': 0,
3947 'size': 1890,
3948
3949 'u-boot:image-pos': 0,
3950 'u-boot:offset': 0,
3951 'u-boot:size': 4,
3952
3953 'fit:image-pos': 4,
3954 'fit:offset': 4,
3955 'fit:size': 1840,
3956
Simon Glassb7bad182022-03-05 20:19:01 -07003957 'fit/images/kernel:image-pos': 304,
3958 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003959 'fit/images/kernel:size': 4,
3960
Simon Glassb7bad182022-03-05 20:19:01 -07003961 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003962 'fit/images/kernel/u-boot:offset': 0,
3963 'fit/images/kernel/u-boot:size': 4,
3964
Simon Glassb7bad182022-03-05 20:19:01 -07003965 'fit/images/fdt-1:image-pos': 552,
3966 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003967 'fit/images/fdt-1:size': 6,
3968
Simon Glassb7bad182022-03-05 20:19:01 -07003969 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003970 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3971 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3972
3973 'u-boot-nodtb:image-pos': 1844,
3974 'u-boot-nodtb:offset': 1844,
3975 'u-boot-nodtb:size': 46,
3976 }, props)
3977
3978 # Actually check the data is where we think it is
3979 for node, expected in [
3980 ("u-boot", U_BOOT_DATA),
3981 ("fit/images/kernel", U_BOOT_DATA),
3982 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3983 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3984 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3985 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3986 ]:
3987 image_pos = props[f"{node}:image-pos"]
3988 size = props[f"{node}:size"]
3989 self.assertEqual(len(expected), size)
3990 self.assertEqual(expected, data[image_pos:image_pos+size])
3991
Simon Glass45d556d2020-07-09 18:39:45 -06003992 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003993 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003994 data = self._DoReadFile('162_fit_external.dts')
3995 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3996
Simon Glass7932c882022-01-09 20:13:39 -07003997 # Size of the external-data region as set up by mkimage
3998 external_data_size = len(U_BOOT_DATA) + 2
3999 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07004000 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07004001 len(U_BOOT_NODTB_DATA))
4002
Simon Glass45d556d2020-07-09 18:39:45 -06004003 # The data should be outside the FIT
4004 dtb = fdt.Fdt.FromData(fit_data)
4005 dtb.Scan()
4006 fnode = dtb.GetNode('/images/kernel')
4007 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07004008 self.assertEqual(len(U_BOOT_DATA),
4009 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4010 fit_pos = 0x400;
4011 self.assertEqual(
4012 fit_pos,
4013 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4014
Brandon Maiera657bc62024-06-04 16:16:05 +00004015 self.assertEqual(expected_size, len(data))
Simon Glass7932c882022-01-09 20:13:39 -07004016 actual_pos = len(U_BOOT_DATA) + fit_pos
4017 self.assertEqual(U_BOOT_DATA + b'aa',
4018 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004019
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004020 def testFitExternalImagePos(self):
4021 """Test that we have correct image-pos for external FIT subentries"""
4022 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4023 update_dtb=True)
4024 dtb = fdt.Fdt(out_dtb_fname)
4025 dtb.Scan()
4026 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4027
4028 self.assertEqual({
4029 'image-pos': 0,
4030 'offset': 0,
4031 'size': 1082,
4032
4033 'u-boot:image-pos': 0,
4034 'u-boot:offset': 0,
4035 'u-boot:size': 4,
4036
4037 'fit:size': 1032,
4038 'fit:offset': 4,
4039 'fit:image-pos': 4,
4040
4041 'fit/images/kernel:size': 4,
4042 'fit/images/kernel:offset': 1024,
4043 'fit/images/kernel:image-pos': 1028,
4044
4045 'fit/images/kernel/u-boot:size': 4,
4046 'fit/images/kernel/u-boot:offset': 0,
4047 'fit/images/kernel/u-boot:image-pos': 1028,
4048
4049 'fit/images/fdt-1:size': 2,
4050 'fit/images/fdt-1:offset': 1028,
4051 'fit/images/fdt-1:image-pos': 1032,
4052
4053 'fit/images/fdt-1/_testing:size': 2,
4054 'fit/images/fdt-1/_testing:offset': 0,
4055 'fit/images/fdt-1/_testing:image-pos': 1032,
4056
4057 'u-boot-nodtb:image-pos': 1036,
4058 'u-boot-nodtb:offset': 1036,
4059 'u-boot-nodtb:size': 46,
4060 }, props)
4061
4062 # Actually check the data is where we think it is
4063 for node, expected in [
4064 ("u-boot", U_BOOT_DATA),
4065 ("fit/images/kernel", U_BOOT_DATA),
4066 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4067 ("fit/images/fdt-1", b'aa'),
4068 ("fit/images/fdt-1/_testing", b'aa'),
4069 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4070 ]:
4071 image_pos = props[f"{node}:image-pos"]
4072 size = props[f"{node}:size"]
4073 self.assertEqual(len(expected), size)
4074 self.assertEqual(expected, data[image_pos:image_pos+size])
4075
Simon Glass66152ce2022-01-09 20:14:09 -07004076 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004077 """Test that binman complains if mkimage is missing"""
4078 with self.assertRaises(ValueError) as e:
4079 self._DoTestFile('162_fit_external.dts',
4080 force_missing_bintools='mkimage')
4081 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4082 str(e.exception))
4083
4084 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004085 """Test that binman still produces a FIT image if mkimage is missing"""
4086 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004087 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004088 force_missing_bintools='mkimage')
4089 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004090 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004091
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004092 def testSectionIgnoreHashSignature(self):
4093 """Test that sections ignore hash, signature nodes for its data"""
4094 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4095 expected = (U_BOOT_DATA + U_BOOT_DATA)
4096 self.assertEqual(expected, data)
4097
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004098 def testPadInSections(self):
4099 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004100 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4101 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004102 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4103 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004104 U_BOOT_DATA)
4105 self.assertEqual(expected, data)
4106
Simon Glassd12599d2020-10-26 17:40:09 -06004107 dtb = fdt.Fdt(out_dtb_fname)
4108 dtb.Scan()
4109 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4110 expected = {
4111 'image-pos': 0,
4112 'offset': 0,
4113 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4114
4115 'section:image-pos': 0,
4116 'section:offset': 0,
4117 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4118
4119 'section/before:image-pos': 0,
4120 'section/before:offset': 0,
4121 'section/before:size': len(U_BOOT_DATA),
4122
4123 'section/u-boot:image-pos': 4,
4124 'section/u-boot:offset': 4,
4125 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4126
4127 'section/after:image-pos': 26,
4128 'section/after:offset': 26,
4129 'section/after:size': len(U_BOOT_DATA),
4130 }
4131 self.assertEqual(expected, props)
4132
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004133 def testFitImageSubentryAlignment(self):
4134 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004135 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004136 entry_args = {
4137 'test-id': TEXT_DATA,
4138 }
4139 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4140 entry_args=entry_args)
4141 dtb = fdt.Fdt.FromData(data)
4142 dtb.Scan()
4143
4144 node = dtb.GetNode('/images/kernel')
4145 data = dtb.GetProps(node)["data"].bytes
4146 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004147 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4148 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004149 self.assertEqual(expected, data)
4150
4151 node = dtb.GetNode('/images/fdt-1')
4152 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004153 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4154 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004155 U_BOOT_DTB_DATA)
4156 self.assertEqual(expected, data)
4157
4158 def testFitExtblobMissingOk(self):
4159 """Test a FIT with a missing external blob that is allowed"""
4160 with test_util.capture_sys_output() as (stdout, stderr):
4161 self._DoTestFile('168_fit_missing_blob.dts',
4162 allow_missing=True)
4163 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004164 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004165
Simon Glass21db0ff2020-09-01 05:13:54 -06004166 def testBlobNamedByArgMissing(self):
4167 """Test handling of a missing entry arg"""
4168 with self.assertRaises(ValueError) as e:
4169 self._DoReadFile('068_blob_named_by_arg.dts')
4170 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4171 str(e.exception))
4172
Simon Glass559c4de2020-09-01 05:13:58 -06004173 def testPackBl31(self):
4174 """Test that an image with an ATF BL31 binary can be created"""
4175 data = self._DoReadFile('169_atf_bl31.dts')
4176 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4177
Samuel Holland9d8cc632020-10-21 21:12:15 -05004178 def testPackScp(self):
4179 """Test that an image with an SCP binary can be created"""
4180 data = self._DoReadFile('172_scp.dts')
4181 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4182
Simon Glassa435cd12020-09-01 05:13:59 -06004183 def testFitFdt(self):
4184 """Test an image with an FIT with multiple FDT images"""
4185 def _CheckFdt(seq, expected_data):
4186 """Check the FDT nodes
4187
4188 Args:
4189 seq: Sequence number to check (0 or 1)
4190 expected_data: Expected contents of 'data' property
4191 """
4192 name = 'fdt-%d' % seq
4193 fnode = dtb.GetNode('/images/%s' % name)
4194 self.assertIsNotNone(fnode)
4195 self.assertEqual({'description','type', 'compression', 'data'},
4196 set(fnode.props.keys()))
4197 self.assertEqual(expected_data, fnode.props['data'].bytes)
4198 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4199 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004200 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004201
4202 def _CheckConfig(seq, expected_data):
4203 """Check the configuration nodes
4204
4205 Args:
4206 seq: Sequence number to check (0 or 1)
4207 expected_data: Expected contents of 'data' property
4208 """
4209 cnode = dtb.GetNode('/configurations')
4210 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004211 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004212
4213 name = 'config-%d' % seq
4214 fnode = dtb.GetNode('/configurations/%s' % name)
4215 self.assertIsNotNone(fnode)
4216 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4217 set(fnode.props.keys()))
4218 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4219 fnode.props['description'].value)
4220 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4221
4222 entry_args = {
4223 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004224 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004225 }
4226 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004227 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004228 entry_args=entry_args,
4229 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4230 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4231 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4232
4233 dtb = fdt.Fdt.FromData(fit_data)
4234 dtb.Scan()
4235 fnode = dtb.GetNode('/images/kernel')
4236 self.assertIn('data', fnode.props)
4237
4238 # Check all the properties in fdt-1 and fdt-2
4239 _CheckFdt(1, TEST_FDT1_DATA)
4240 _CheckFdt(2, TEST_FDT2_DATA)
4241
4242 # Check configurations
4243 _CheckConfig(1, TEST_FDT1_DATA)
4244 _CheckConfig(2, TEST_FDT2_DATA)
4245
4246 def testFitFdtMissingList(self):
4247 """Test handling of a missing 'of-list' entry arg"""
4248 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004249 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004250 self.assertIn("Generator node requires 'of-list' entry argument",
4251 str(e.exception))
4252
4253 def testFitFdtEmptyList(self):
4254 """Test handling of an empty 'of-list' entry arg"""
4255 entry_args = {
4256 'of-list': '',
4257 }
4258 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4259
4260 def testFitFdtMissingProp(self):
4261 """Test handling of a missing 'fit,fdt-list' property"""
4262 with self.assertRaises(ValueError) as e:
4263 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4264 self.assertIn("Generator node requires 'fit,fdt-list' property",
4265 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004266
Simon Glass1032acc2020-09-06 10:39:08 -06004267 def testFitFdtMissing(self):
4268 """Test handling of a missing 'default-dt' entry arg"""
4269 entry_args = {
4270 'of-list': 'test-fdt1 test-fdt2',
4271 }
4272 with self.assertRaises(ValueError) as e:
4273 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004274 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004275 entry_args=entry_args,
4276 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4277 self.assertIn("Generated 'default' node requires default-dt entry argument",
4278 str(e.exception))
4279
4280 def testFitFdtNotInList(self):
4281 """Test handling of a default-dt that is not in the of-list"""
4282 entry_args = {
4283 'of-list': 'test-fdt1 test-fdt2',
4284 'default-dt': 'test-fdt3',
4285 }
4286 with self.assertRaises(ValueError) as e:
4287 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004288 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004289 entry_args=entry_args,
4290 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4291 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4292 str(e.exception))
4293
Simon Glassa820af72020-09-06 10:39:09 -06004294 def testFitExtblobMissingHelp(self):
4295 """Test display of help messages when an external blob is missing"""
4296 control.missing_blob_help = control._ReadMissingBlobHelp()
4297 control.missing_blob_help['wibble'] = 'Wibble test'
4298 control.missing_blob_help['another'] = 'Another test'
4299 with test_util.capture_sys_output() as (stdout, stderr):
4300 self._DoTestFile('168_fit_missing_blob.dts',
4301 allow_missing=True)
4302 err = stderr.getvalue()
4303
4304 # We can get the tag from the name, the type or the missing-msg
4305 # property. Check all three.
4306 self.assertIn('You may need to build ARM Trusted', err)
4307 self.assertIn('Wibble test', err)
4308 self.assertIn('Another test', err)
4309
Simon Glass6f1f4d42020-09-06 10:35:32 -06004310 def testMissingBlob(self):
4311 """Test handling of a blob containing a missing file"""
4312 with self.assertRaises(ValueError) as e:
4313 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4314 self.assertIn("Filename 'missing' not found in input path",
4315 str(e.exception))
4316
Simon Glassa0729502020-09-06 10:35:33 -06004317 def testEnvironment(self):
4318 """Test adding a U-Boot environment"""
4319 data = self._DoReadFile('174_env.dts')
4320 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4321 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4322 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4323 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4324 env)
4325
4326 def testEnvironmentNoSize(self):
4327 """Test that a missing 'size' property is detected"""
4328 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004329 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004330 self.assertIn("'u-boot-env' entry must have a size property",
4331 str(e.exception))
4332
4333 def testEnvironmentTooSmall(self):
4334 """Test handling of an environment that does not fit"""
4335 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004336 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004337
4338 # checksum, start byte, environment with \0 terminator, final \0
4339 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4340 short = need - 0x8
4341 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4342 str(e.exception))
4343
Simon Glassd1fdf752020-10-26 17:40:01 -06004344 def testSkipAtStart(self):
4345 """Test handling of skip-at-start section"""
4346 data = self._DoReadFile('177_skip_at_start.dts')
4347 self.assertEqual(U_BOOT_DATA, data)
4348
4349 image = control.images['image']
4350 entries = image.GetEntries()
4351 section = entries['section']
4352 self.assertEqual(0, section.offset)
4353 self.assertEqual(len(U_BOOT_DATA), section.size)
4354 self.assertEqual(U_BOOT_DATA, section.GetData())
4355
4356 entry = section.GetEntries()['u-boot']
4357 self.assertEqual(16, entry.offset)
4358 self.assertEqual(len(U_BOOT_DATA), entry.size)
4359 self.assertEqual(U_BOOT_DATA, entry.data)
4360
4361 def testSkipAtStartPad(self):
4362 """Test handling of skip-at-start section with padded entry"""
4363 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004364 before = tools.get_bytes(0, 8)
4365 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004366 all = before + U_BOOT_DATA + after
4367 self.assertEqual(all, data)
4368
4369 image = control.images['image']
4370 entries = image.GetEntries()
4371 section = entries['section']
4372 self.assertEqual(0, section.offset)
4373 self.assertEqual(len(all), section.size)
4374 self.assertEqual(all, section.GetData())
4375
4376 entry = section.GetEntries()['u-boot']
4377 self.assertEqual(16, entry.offset)
4378 self.assertEqual(len(all), entry.size)
4379 self.assertEqual(U_BOOT_DATA, entry.data)
4380
4381 def testSkipAtStartSectionPad(self):
4382 """Test handling of skip-at-start section with padding"""
4383 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004384 before = tools.get_bytes(0, 8)
4385 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004386 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004387 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004388
4389 image = control.images['image']
4390 entries = image.GetEntries()
4391 section = entries['section']
4392 self.assertEqual(0, section.offset)
4393 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004394 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004395 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004396
4397 entry = section.GetEntries()['u-boot']
4398 self.assertEqual(16, entry.offset)
4399 self.assertEqual(len(U_BOOT_DATA), entry.size)
4400 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004401
Simon Glassbb395742020-10-26 17:40:14 -06004402 def testSectionPad(self):
4403 """Testing padding with sections"""
4404 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004405 expected = (tools.get_bytes(ord('&'), 3) +
4406 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004407 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004408 tools.get_bytes(ord('!'), 1) +
4409 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004410 self.assertEqual(expected, data)
4411
4412 def testSectionAlign(self):
4413 """Testing alignment with sections"""
4414 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4415 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004416 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004417 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004418 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004419 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004420 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4421 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004422 self.assertEqual(expected, data)
4423
Simon Glassd92c8362020-10-26 17:40:25 -06004424 def testCompressImage(self):
4425 """Test compression of the entire image"""
4426 self._CheckLz4()
4427 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4428 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4429 dtb = fdt.Fdt(out_dtb_fname)
4430 dtb.Scan()
4431 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4432 'uncomp-size'])
4433 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004434 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004435
4436 # Do a sanity check on various fields
4437 image = control.images['image']
4438 entries = image.GetEntries()
4439 self.assertEqual(2, len(entries))
4440
4441 entry = entries['blob']
4442 self.assertEqual(COMPRESS_DATA, entry.data)
4443 self.assertEqual(len(COMPRESS_DATA), entry.size)
4444
4445 entry = entries['u-boot']
4446 self.assertEqual(U_BOOT_DATA, entry.data)
4447 self.assertEqual(len(U_BOOT_DATA), entry.size)
4448
4449 self.assertEqual(len(data), image.size)
4450 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4451 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4452 orig = self._decompress(image.data)
4453 self.assertEqual(orig, image.uncomp_data)
4454
4455 expected = {
4456 'blob:offset': 0,
4457 'blob:size': len(COMPRESS_DATA),
4458 'u-boot:offset': len(COMPRESS_DATA),
4459 'u-boot:size': len(U_BOOT_DATA),
4460 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4461 'offset': 0,
4462 'image-pos': 0,
4463 'size': len(data),
4464 }
4465 self.assertEqual(expected, props)
4466
4467 def testCompressImageLess(self):
4468 """Test compression where compression reduces the image size"""
4469 self._CheckLz4()
4470 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4471 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4472 dtb = fdt.Fdt(out_dtb_fname)
4473 dtb.Scan()
4474 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4475 'uncomp-size'])
4476 orig = self._decompress(data)
4477
Brandon Maiera657bc62024-06-04 16:16:05 +00004478 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004479
4480 # Do a sanity check on various fields
4481 image = control.images['image']
4482 entries = image.GetEntries()
4483 self.assertEqual(2, len(entries))
4484
4485 entry = entries['blob']
4486 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4487 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4488
4489 entry = entries['u-boot']
4490 self.assertEqual(U_BOOT_DATA, entry.data)
4491 self.assertEqual(len(U_BOOT_DATA), entry.size)
4492
4493 self.assertEqual(len(data), image.size)
4494 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4495 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4496 image.uncomp_size)
4497 orig = self._decompress(image.data)
4498 self.assertEqual(orig, image.uncomp_data)
4499
4500 expected = {
4501 'blob:offset': 0,
4502 'blob:size': len(COMPRESS_DATA_BIG),
4503 'u-boot:offset': len(COMPRESS_DATA_BIG),
4504 'u-boot:size': len(U_BOOT_DATA),
4505 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4506 'offset': 0,
4507 'image-pos': 0,
4508 'size': len(data),
4509 }
4510 self.assertEqual(expected, props)
4511
4512 def testCompressSectionSize(self):
4513 """Test compression of a section with a fixed size"""
4514 self._CheckLz4()
4515 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4516 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4517 dtb = fdt.Fdt(out_dtb_fname)
4518 dtb.Scan()
4519 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4520 'uncomp-size'])
4521 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004522 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004523 expected = {
4524 'section/blob:offset': 0,
4525 'section/blob:size': len(COMPRESS_DATA),
4526 'section/u-boot:offset': len(COMPRESS_DATA),
4527 'section/u-boot:size': len(U_BOOT_DATA),
4528 'section:offset': 0,
4529 'section:image-pos': 0,
4530 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4531 'section:size': 0x30,
4532 'offset': 0,
4533 'image-pos': 0,
4534 'size': 0x30,
4535 }
4536 self.assertEqual(expected, props)
4537
4538 def testCompressSection(self):
4539 """Test compression of a section with no fixed size"""
4540 self._CheckLz4()
4541 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4542 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4543 dtb = fdt.Fdt(out_dtb_fname)
4544 dtb.Scan()
4545 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4546 'uncomp-size'])
4547 orig = self._decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00004548 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, orig)
Simon Glassd92c8362020-10-26 17:40:25 -06004549 expected = {
4550 'section/blob:offset': 0,
4551 'section/blob:size': len(COMPRESS_DATA),
4552 'section/u-boot:offset': len(COMPRESS_DATA),
4553 'section/u-boot:size': len(U_BOOT_DATA),
4554 'section:offset': 0,
4555 'section:image-pos': 0,
4556 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4557 'section:size': len(data),
4558 'offset': 0,
4559 'image-pos': 0,
4560 'size': len(data),
4561 }
4562 self.assertEqual(expected, props)
4563
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004564 def testLz4Missing(self):
4565 """Test that binman still produces an image if lz4 is missing"""
4566 with test_util.capture_sys_output() as (_, stderr):
4567 self._DoTestFile('185_compress_section.dts',
4568 force_missing_bintools='lz4')
4569 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004570 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004571
Simon Glassd92c8362020-10-26 17:40:25 -06004572 def testCompressExtra(self):
4573 """Test compression of a section with no fixed size"""
4574 self._CheckLz4()
4575 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4576 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4577 dtb = fdt.Fdt(out_dtb_fname)
4578 dtb.Scan()
4579 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4580 'uncomp-size'])
4581
4582 base = data[len(U_BOOT_DATA):]
Brandon Maiera657bc62024-06-04 16:16:05 +00004583 self.assertEqual(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
Simon Glassd92c8362020-10-26 17:40:25 -06004584 rest = base[len(U_BOOT_DATA):]
4585
4586 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004587 bintool = self.comp_bintools['lz4']
4588 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004589 data1 = rest[:len(expect1)]
4590 section1 = self._decompress(data1)
Brandon Maiera657bc62024-06-04 16:16:05 +00004591 self.assertEqual(expect1, data1)
4592 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, section1)
Simon Glassd92c8362020-10-26 17:40:25 -06004593 rest1 = rest[len(expect1):]
4594
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004595 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004596 data2 = rest1[:len(expect2)]
4597 section2 = self._decompress(data2)
Brandon Maiera657bc62024-06-04 16:16:05 +00004598 self.assertEqual(expect2, data2)
4599 self.assertEqual(COMPRESS_DATA + COMPRESS_DATA, section2)
Simon Glassd92c8362020-10-26 17:40:25 -06004600 rest2 = rest1[len(expect2):]
4601
4602 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4603 len(expect2) + len(U_BOOT_DATA))
Brandon Maiera657bc62024-06-04 16:16:05 +00004604 #self.assertEqual(expect_size, len(data))
Simon Glassd92c8362020-10-26 17:40:25 -06004605
Brandon Maiera657bc62024-06-04 16:16:05 +00004606 #self.assertEqual(U_BOOT_DATA, rest2)
Simon Glassd92c8362020-10-26 17:40:25 -06004607
4608 self.maxDiff = None
4609 expected = {
4610 'u-boot:offset': 0,
4611 'u-boot:image-pos': 0,
4612 'u-boot:size': len(U_BOOT_DATA),
4613
4614 'base:offset': len(U_BOOT_DATA),
4615 'base:image-pos': len(U_BOOT_DATA),
4616 'base:size': len(data) - len(U_BOOT_DATA),
4617 'base/u-boot:offset': 0,
4618 'base/u-boot:image-pos': len(U_BOOT_DATA),
4619 'base/u-boot:size': len(U_BOOT_DATA),
4620 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4621 len(expect2),
4622 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4623 len(expect2),
4624 'base/u-boot2:size': len(U_BOOT_DATA),
4625
4626 'base/section:offset': len(U_BOOT_DATA),
4627 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4628 'base/section:size': len(expect1),
4629 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4630 'base/section/blob:offset': 0,
4631 'base/section/blob:size': len(COMPRESS_DATA),
4632 'base/section/u-boot:offset': len(COMPRESS_DATA),
4633 'base/section/u-boot:size': len(U_BOOT_DATA),
4634
4635 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4636 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4637 'base/section2:size': len(expect2),
4638 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4639 'base/section2/blob:offset': 0,
4640 'base/section2/blob:size': len(COMPRESS_DATA),
4641 'base/section2/blob2:offset': len(COMPRESS_DATA),
4642 'base/section2/blob2:size': len(COMPRESS_DATA),
4643
4644 'offset': 0,
4645 'image-pos': 0,
4646 'size': len(data),
4647 }
4648 self.assertEqual(expected, props)
4649
Simon Glassecbe4732021-01-06 21:35:15 -07004650 def testSymbolsSubsection(self):
4651 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004652 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004653
Simon Glass3fb25402021-01-06 21:35:16 -07004654 def testReadImageEntryArg(self):
4655 """Test reading an image that would need an entry arg to generate"""
4656 entry_args = {
4657 'cros-ec-rw-path': 'ecrw.bin',
4658 }
4659 data = self.data = self._DoReadFileDtb(
4660 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4661 entry_args=entry_args)
4662
Simon Glass80025522022-01-29 14:14:04 -07004663 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004664 orig_image = control.images['image']
4665
4666 # This should not generate an error about the missing 'cros-ec-rw-path'
4667 # since we are reading the image from a file. Compare with
4668 # testEntryArgsRequired()
4669 image = Image.FromFile(image_fname)
4670 self.assertEqual(orig_image.GetEntries().keys(),
4671 image.GetEntries().keys())
4672
Simon Glassa2af7302021-01-06 21:35:18 -07004673 def testFilesAlign(self):
4674 """Test alignment with files"""
4675 data = self._DoReadFile('190_files_align.dts')
4676
4677 # The first string is 15 bytes so will align to 16
4678 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4679 self.assertEqual(expect, data)
4680
Simon Glassdb84b562021-01-06 21:35:19 -07004681 def testReadImageSkip(self):
4682 """Test reading an image and accessing its FDT map"""
4683 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004684 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004685 orig_image = control.images['image']
4686 image = Image.FromFile(image_fname)
4687 self.assertEqual(orig_image.GetEntries().keys(),
4688 image.GetEntries().keys())
4689
4690 orig_entry = orig_image.GetEntries()['fdtmap']
4691 entry = image.GetEntries()['fdtmap']
4692 self.assertEqual(orig_entry.offset, entry.offset)
4693 self.assertEqual(orig_entry.size, entry.size)
4694 self.assertEqual(16, entry.image_pos)
4695
4696 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4697
Brandon Maiera657bc62024-06-04 16:16:05 +00004698 self.assertEqual(U_BOOT_DATA, u_boot.ReadData())
Simon Glassdb84b562021-01-06 21:35:19 -07004699
Simon Glassc98de972021-03-18 20:24:57 +13004700 def testTplNoDtb(self):
4701 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004702 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004703 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4704 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4705 data[:len(U_BOOT_TPL_NODTB_DATA)])
4706
Simon Glass63f41d42021-03-18 20:24:58 +13004707 def testTplBssPad(self):
4708 """Test that we can pad TPL's BSS with zeros"""
4709 # ELF file with a '__bss_size' symbol
4710 self._SetupTplElf()
4711 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004712 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004713 data)
4714
4715 def testTplBssPadMissing(self):
4716 """Test that a missing symbol is detected"""
4717 self._SetupTplElf('u_boot_ucode_ptr')
4718 with self.assertRaises(ValueError) as e:
4719 self._DoReadFile('193_tpl_bss_pad.dts')
4720 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4721 str(e.exception))
4722
Simon Glass718b5292021-03-18 20:25:07 +13004723 def checkDtbSizes(self, data, pad_len, start):
4724 """Check the size arguments in a dtb embedded in an image
4725
4726 Args:
4727 data: The image data
4728 pad_len: Length of the pad section in the image, in bytes
4729 start: Start offset of the devicetree to examine, within the image
4730
4731 Returns:
4732 Size of the devicetree in bytes
4733 """
4734 dtb_data = data[start:]
4735 dtb = fdt.Fdt.FromData(dtb_data)
4736 fdt_size = dtb.GetFdtObj().totalsize()
4737 dtb.Scan()
4738 props = self._GetPropTree(dtb, 'size')
4739 self.assertEqual({
4740 'size': len(data),
4741 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4742 'u-boot-spl/u-boot-spl-dtb:size': 801,
4743 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4744 'u-boot-spl:size': 860,
4745 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4746 'u-boot/u-boot-dtb:size': 781,
4747 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4748 'u-boot:size': 827,
4749 }, props)
4750 return fdt_size
4751
4752 def testExpanded(self):
4753 """Test that an expanded entry type is selected when needed"""
4754 self._SetupSplElf()
4755 self._SetupTplElf()
4756
4757 # SPL has a devicetree, TPL does not
4758 entry_args = {
4759 'spl-dtb': '1',
4760 'spl-bss-pad': 'y',
4761 'tpl-dtb': '',
4762 }
4763 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4764 entry_args=entry_args)
4765 image = control.images['image']
4766 entries = image.GetEntries()
4767 self.assertEqual(3, len(entries))
4768
4769 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4770 self.assertIn('u-boot', entries)
4771 entry = entries['u-boot']
4772 self.assertEqual('u-boot-expanded', entry.etype)
4773 subent = entry.GetEntries()
4774 self.assertEqual(2, len(subent))
4775 self.assertIn('u-boot-nodtb', subent)
4776 self.assertIn('u-boot-dtb', subent)
4777
4778 # Second, u-boot-spl, which should be expanded into three parts
4779 self.assertIn('u-boot-spl', entries)
4780 entry = entries['u-boot-spl']
4781 self.assertEqual('u-boot-spl-expanded', entry.etype)
4782 subent = entry.GetEntries()
4783 self.assertEqual(3, len(subent))
4784 self.assertIn('u-boot-spl-nodtb', subent)
4785 self.assertIn('u-boot-spl-bss-pad', subent)
4786 self.assertIn('u-boot-spl-dtb', subent)
4787
4788 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4789 # devicetree
4790 self.assertIn('u-boot-tpl', entries)
4791 entry = entries['u-boot-tpl']
4792 self.assertEqual('u-boot-tpl', entry.etype)
4793 self.assertEqual(None, entry.GetEntries())
4794
4795 def testExpandedTpl(self):
4796 """Test that an expanded entry type is selected for TPL when needed"""
4797 self._SetupTplElf()
4798
4799 entry_args = {
4800 'tpl-bss-pad': 'y',
4801 'tpl-dtb': 'y',
4802 }
4803 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4804 entry_args=entry_args)
4805 image = control.images['image']
4806 entries = image.GetEntries()
4807 self.assertEqual(1, len(entries))
4808
4809 # We only have u-boot-tpl, which be expanded
4810 self.assertIn('u-boot-tpl', entries)
4811 entry = entries['u-boot-tpl']
4812 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4813 subent = entry.GetEntries()
4814 self.assertEqual(3, len(subent))
4815 self.assertIn('u-boot-tpl-nodtb', subent)
4816 self.assertIn('u-boot-tpl-bss-pad', subent)
4817 self.assertIn('u-boot-tpl-dtb', subent)
4818
4819 def testExpandedNoPad(self):
4820 """Test an expanded entry without BSS pad enabled"""
4821 self._SetupSplElf()
4822 self._SetupTplElf()
4823
4824 # SPL has a devicetree, TPL does not
4825 entry_args = {
4826 'spl-dtb': 'something',
4827 'spl-bss-pad': 'n',
4828 'tpl-dtb': '',
4829 }
4830 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4831 entry_args=entry_args)
4832 image = control.images['image']
4833 entries = image.GetEntries()
4834
4835 # Just check u-boot-spl, which should be expanded into two parts
4836 self.assertIn('u-boot-spl', entries)
4837 entry = entries['u-boot-spl']
4838 self.assertEqual('u-boot-spl-expanded', entry.etype)
4839 subent = entry.GetEntries()
4840 self.assertEqual(2, len(subent))
4841 self.assertIn('u-boot-spl-nodtb', subent)
4842 self.assertIn('u-boot-spl-dtb', subent)
4843
4844 def testExpandedTplNoPad(self):
4845 """Test that an expanded entry type with padding disabled in TPL"""
4846 self._SetupTplElf()
4847
4848 entry_args = {
4849 'tpl-bss-pad': '',
4850 'tpl-dtb': 'y',
4851 }
4852 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4853 entry_args=entry_args)
4854 image = control.images['image']
4855 entries = image.GetEntries()
4856 self.assertEqual(1, len(entries))
4857
4858 # We only have u-boot-tpl, which be expanded
4859 self.assertIn('u-boot-tpl', entries)
4860 entry = entries['u-boot-tpl']
4861 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4862 subent = entry.GetEntries()
4863 self.assertEqual(2, len(subent))
4864 self.assertIn('u-boot-tpl-nodtb', subent)
4865 self.assertIn('u-boot-tpl-dtb', subent)
4866
4867 def testFdtInclude(self):
4868 """Test that an Fdt is update within all binaries"""
4869 self._SetupSplElf()
4870 self._SetupTplElf()
4871
4872 # SPL has a devicetree, TPL does not
4873 self.maxDiff = None
4874 entry_args = {
4875 'spl-dtb': '1',
4876 'spl-bss-pad': 'y',
4877 'tpl-dtb': '',
4878 }
4879 # Build the image. It includes two separate devicetree binaries, each
4880 # with their own contents, but all contain the binman definition.
4881 data = self._DoReadFileDtb(
4882 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4883 update_dtb=True, entry_args=entry_args)[0]
4884 pad_len = 10
4885
4886 # Check the U-Boot dtb
4887 start = len(U_BOOT_NODTB_DATA)
4888 fdt_size = self.checkDtbSizes(data, pad_len, start)
4889
4890 # Now check SPL
4891 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4892 fdt_size = self.checkDtbSizes(data, pad_len, start)
4893
4894 # TPL has no devicetree
4895 start += fdt_size + len(U_BOOT_TPL_DATA)
4896 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004897
Simon Glass7098b7f2021-03-21 18:24:30 +13004898 def testSymbolsExpanded(self):
4899 """Test binman can assign symbols in expanded entries"""
4900 entry_args = {
4901 'spl-dtb': '1',
4902 }
4903 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4904 U_BOOT_SPL_DTB_DATA, 0x38,
4905 entry_args=entry_args, use_expanded=True)
4906
Simon Glasse1915782021-03-21 18:24:31 +13004907 def testCollection(self):
4908 """Test a collection"""
4909 data = self._DoReadFile('198_collection.dts')
4910 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004911 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4912 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004913 data)
4914
Simon Glass27a7f772021-03-21 18:24:32 +13004915 def testCollectionSection(self):
4916 """Test a collection where a section must be built first"""
4917 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004918 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004919 # building the contents, producing an error is anything is still
4920 # missing.
4921 data = self._DoReadFile('199_collection_section.dts')
4922 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004923 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4924 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004925 data)
4926
Simon Glassf427c5f2021-03-21 18:24:33 +13004927 def testAlignDefault(self):
4928 """Test that default alignment works on sections"""
4929 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004930 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004931 U_BOOT_DATA)
4932 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004933 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004934 # No alignment within the nested section
4935 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4936 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004937 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004938 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004939
Bin Mengc0b15742021-05-10 20:23:33 +08004940 def testPackOpenSBI(self):
4941 """Test that an image with an OpenSBI binary can be created"""
4942 data = self._DoReadFile('201_opensbi.dts')
4943 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4944
Simon Glass76f496d2021-07-06 10:36:37 -06004945 def testSectionsSingleThread(self):
4946 """Test sections without multithreading"""
4947 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004948 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4949 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4950 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004951 self.assertEqual(expected, data)
4952
4953 def testThreadTimeout(self):
4954 """Test handling a thread that takes too long"""
4955 with self.assertRaises(ValueError) as e:
4956 self._DoTestFile('202_section_timeout.dts',
4957 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004958 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004959
Simon Glass748a1d42021-07-06 10:36:41 -06004960 def testTiming(self):
4961 """Test output of timing information"""
4962 data = self._DoReadFile('055_sections.dts')
4963 with test_util.capture_sys_output() as (stdout, stderr):
4964 state.TimingShow()
4965 self.assertIn('read:', stdout.getvalue())
4966 self.assertIn('compress:', stdout.getvalue())
4967
Simon Glassadfb8492021-11-03 21:09:18 -06004968 def testUpdateFdtInElf(self):
4969 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004970 if not elf.ELF_TOOLS:
4971 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004972 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4973 outfile = os.path.join(self._indir, 'u-boot.out')
4974 begin_sym = 'dtb_embed_begin'
4975 end_sym = 'dtb_embed_end'
4976 retcode = self._DoTestFile(
4977 '060_fdt_update.dts', update_dtb=True,
4978 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4979 self.assertEqual(0, retcode)
4980
4981 # Check that the output file does in fact contact a dtb with the binman
4982 # definition in the correct place
4983 syms = elf.GetSymbolFileOffset(infile,
4984 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004985 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004986 dtb_data = data[syms['dtb_embed_begin'].offset:
4987 syms['dtb_embed_end'].offset]
4988
4989 dtb = fdt.Fdt.FromData(dtb_data)
4990 dtb.Scan()
4991 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4992 self.assertEqual({
4993 'image-pos': 0,
4994 'offset': 0,
4995 '_testing:offset': 32,
4996 '_testing:size': 2,
4997 '_testing:image-pos': 32,
4998 'section@0/u-boot:offset': 0,
4999 'section@0/u-boot:size': len(U_BOOT_DATA),
5000 'section@0/u-boot:image-pos': 0,
5001 'section@0:offset': 0,
5002 'section@0:size': 16,
5003 'section@0:image-pos': 0,
5004
5005 'section@1/u-boot:offset': 0,
5006 'section@1/u-boot:size': len(U_BOOT_DATA),
5007 'section@1/u-boot:image-pos': 16,
5008 'section@1:offset': 16,
5009 'section@1:size': 16,
5010 'section@1:image-pos': 16,
5011 'size': 40
5012 }, props)
5013
5014 def testUpdateFdtInElfInvalid(self):
5015 """Test that invalid args are detected with --update-fdt-in-elf"""
5016 with self.assertRaises(ValueError) as e:
5017 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5018 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5019 str(e.exception))
5020
5021 def testUpdateFdtInElfNoSyms(self):
5022 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005023 if not elf.ELF_TOOLS:
5024 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005025 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5026 outfile = ''
5027 begin_sym = 'wrong_begin'
5028 end_sym = 'wrong_end'
5029 with self.assertRaises(ValueError) as e:
5030 self._DoTestFile(
5031 '060_fdt_update.dts',
5032 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5033 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5034 str(e.exception))
5035
5036 def testUpdateFdtInElfTooSmall(self):
5037 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005038 if not elf.ELF_TOOLS:
5039 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005040 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5041 outfile = os.path.join(self._indir, 'u-boot.out')
5042 begin_sym = 'dtb_embed_begin'
5043 end_sym = 'dtb_embed_end'
5044 with self.assertRaises(ValueError) as e:
5045 self._DoTestFile(
5046 '060_fdt_update.dts', update_dtb=True,
5047 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5048 self.assertRegex(
5049 str(e.exception),
5050 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5051
Simon Glass88e04da2021-11-23 11:03:42 -07005052 def testVersion(self):
5053 """Test we can get the binman version"""
5054 version = '(unreleased)'
5055 self.assertEqual(version, state.GetVersion(self._indir))
5056
5057 with self.assertRaises(SystemExit):
5058 with test_util.capture_sys_output() as (_, stderr):
5059 self._DoBinman('-V')
5060 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5061
5062 # Try running the tool too, just to be safe
5063 result = self._RunBinman('-V')
5064 self.assertEqual('Binman %s\n' % version, result.stderr)
5065
5066 # Set up a version file to make sure that works
5067 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005068 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005069 binary=False)
5070 self.assertEqual(version, state.GetVersion(self._indir))
5071
Simon Glass637958f2021-11-23 21:09:50 -07005072 def testAltFormat(self):
5073 """Test that alternative formats can be used to extract"""
5074 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5075
5076 try:
5077 tmpdir, updated_fname = self._SetupImageInTmpdir()
5078 with test_util.capture_sys_output() as (stdout, _):
5079 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5080 self.assertEqual(
5081 '''Flag (-F) Entry type Description
5082fdt fdtmap Extract the devicetree blob from the fdtmap
5083''',
5084 stdout.getvalue())
5085
5086 dtb = os.path.join(tmpdir, 'fdt.dtb')
5087 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5088 dtb, 'fdtmap')
5089
5090 # Check that we can read it and it can be scanning, meaning it does
5091 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005092 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005093 dtb = fdt.Fdt.FromData(data)
5094 dtb.Scan()
5095
5096 # Now check u-boot which has no alt_format
5097 fname = os.path.join(tmpdir, 'fdt.dtb')
5098 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5099 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005100 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005101 self.assertEqual(U_BOOT_DATA, data)
5102
5103 finally:
5104 shutil.rmtree(tmpdir)
5105
Simon Glass0b00ae62021-11-23 21:09:52 -07005106 def testExtblobList(self):
5107 """Test an image with an external blob list"""
5108 data = self._DoReadFile('215_blob_ext_list.dts')
5109 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5110
5111 def testExtblobListMissing(self):
5112 """Test an image with a missing external blob"""
5113 with self.assertRaises(ValueError) as e:
5114 self._DoReadFile('216_blob_ext_list_missing.dts')
5115 self.assertIn("Filename 'missing-file' not found in input path",
5116 str(e.exception))
5117
5118 def testExtblobListMissingOk(self):
5119 """Test an image with an missing external blob that is allowed"""
5120 with test_util.capture_sys_output() as (stdout, stderr):
5121 self._DoTestFile('216_blob_ext_list_missing.dts',
5122 allow_missing=True)
5123 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005124 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005125
Simon Glass3efb2972021-11-23 21:08:59 -07005126 def testFip(self):
5127 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5128 data = self._DoReadFile('203_fip.dts')
5129 hdr, fents = fip_util.decode_fip(data)
5130 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5131 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5132 self.assertEqual(0x123, hdr.flags)
5133
5134 self.assertEqual(2, len(fents))
5135
5136 fent = fents[0]
5137 self.assertEqual(
5138 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5139 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5140 self.assertEqual('soc-fw', fent.fip_type)
5141 self.assertEqual(0x88, fent.offset)
5142 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5143 self.assertEqual(0x123456789abcdef, fent.flags)
5144 self.assertEqual(ATF_BL31_DATA, fent.data)
5145 self.assertEqual(True, fent.valid)
5146
5147 fent = fents[1]
5148 self.assertEqual(
5149 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5150 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5151 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5152 self.assertEqual(0x8c, fent.offset)
5153 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5154 self.assertEqual(0, fent.flags)
5155 self.assertEqual(ATF_BL2U_DATA, fent.data)
5156 self.assertEqual(True, fent.valid)
5157
5158 def testFipOther(self):
5159 """Basic FIP with something that isn't a external blob"""
5160 data = self._DoReadFile('204_fip_other.dts')
5161 hdr, fents = fip_util.decode_fip(data)
5162
5163 self.assertEqual(2, len(fents))
5164 fent = fents[1]
5165 self.assertEqual('rot-cert', fent.fip_type)
5166 self.assertEqual(b'aa', fent.data)
5167
Simon Glass3efb2972021-11-23 21:08:59 -07005168 def testFipNoType(self):
5169 """FIP with an entry of an unknown type"""
5170 with self.assertRaises(ValueError) as e:
5171 self._DoReadFile('205_fip_no_type.dts')
5172 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5173 str(e.exception))
5174
5175 def testFipUuid(self):
5176 """Basic FIP with a manual uuid"""
5177 data = self._DoReadFile('206_fip_uuid.dts')
5178 hdr, fents = fip_util.decode_fip(data)
5179
5180 self.assertEqual(2, len(fents))
5181 fent = fents[1]
5182 self.assertEqual(None, fent.fip_type)
5183 self.assertEqual(
5184 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5185 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5186 fent.uuid)
5187 self.assertEqual(U_BOOT_DATA, fent.data)
5188
5189 def testFipLs(self):
5190 """Test listing a FIP"""
5191 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5192 hdr, fents = fip_util.decode_fip(data)
5193
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005194 tmpdir = None
Simon Glass3efb2972021-11-23 21:08:59 -07005195 try:
5196 tmpdir, updated_fname = self._SetupImageInTmpdir()
5197 with test_util.capture_sys_output() as (stdout, stderr):
5198 self._DoBinman('ls', '-i', updated_fname)
5199 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005200 if tmpdir:
5201 shutil.rmtree(tmpdir)
Simon Glass3efb2972021-11-23 21:08:59 -07005202 lines = stdout.getvalue().splitlines()
5203 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005204'Name Image-pos Size Entry-type Offset Uncomp-size',
5205'--------------------------------------------------------------',
5206'image 0 2d3 section 0',
5207' atf-fip 0 90 atf-fip 0',
5208' soc-fw 88 4 blob-ext 88',
5209' u-boot 8c 4 u-boot 8c',
5210' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005211]
5212 self.assertEqual(expected, lines)
5213
5214 image = control.images['image']
5215 entries = image.GetEntries()
5216 fdtmap = entries['fdtmap']
5217
5218 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5219 magic = fdtmap_data[:8]
5220 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005221 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005222
5223 fdt_data = fdtmap_data[16:]
5224 dtb = fdt.Fdt.FromData(fdt_data)
5225 dtb.Scan()
5226 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5227 self.assertEqual({
5228 'atf-fip/soc-fw:image-pos': 136,
5229 'atf-fip/soc-fw:offset': 136,
5230 'atf-fip/soc-fw:size': 4,
5231 'atf-fip/u-boot:image-pos': 140,
5232 'atf-fip/u-boot:offset': 140,
5233 'atf-fip/u-boot:size': 4,
5234 'atf-fip:image-pos': 0,
5235 'atf-fip:offset': 0,
5236 'atf-fip:size': 144,
5237 'image-pos': 0,
5238 'offset': 0,
5239 'fdtmap:image-pos': fdtmap.image_pos,
5240 'fdtmap:offset': fdtmap.offset,
5241 'fdtmap:size': len(fdtmap_data),
5242 'size': len(data),
5243 }, props)
5244
5245 def testFipExtractOneEntry(self):
5246 """Test extracting a single entry fron an FIP"""
5247 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005248 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005249 fname = os.path.join(self._indir, 'output.extact')
5250 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005251 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005252 self.assertEqual(U_BOOT_DATA, data)
5253
5254 def testFipReplace(self):
5255 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005256 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005257 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005258 updated_fname = tools.get_output_filename('image-updated.bin')
5259 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005260 entry_name = 'atf-fip/u-boot'
5261 control.WriteEntry(updated_fname, entry_name, expected,
5262 allow_resize=True)
5263 actual = control.ReadEntry(updated_fname, entry_name)
5264 self.assertEqual(expected, actual)
5265
Simon Glass80025522022-01-29 14:14:04 -07005266 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005267 hdr, fents = fip_util.decode_fip(new_data)
5268
5269 self.assertEqual(2, len(fents))
5270
5271 # Check that the FIP entry is updated
5272 fent = fents[1]
5273 self.assertEqual(0x8c, fent.offset)
5274 self.assertEqual(len(expected), fent.size)
5275 self.assertEqual(0, fent.flags)
5276 self.assertEqual(expected, fent.data)
5277 self.assertEqual(True, fent.valid)
5278
5279 def testFipMissing(self):
5280 with test_util.capture_sys_output() as (stdout, stderr):
5281 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5282 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005283 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005284
5285 def testFipSize(self):
5286 """Test a FIP with a size property"""
5287 data = self._DoReadFile('210_fip_size.dts')
5288 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5289 hdr, fents = fip_util.decode_fip(data)
5290 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5291 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5292
5293 self.assertEqual(1, len(fents))
5294
5295 fent = fents[0]
5296 self.assertEqual('soc-fw', fent.fip_type)
5297 self.assertEqual(0x60, fent.offset)
5298 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5299 self.assertEqual(ATF_BL31_DATA, fent.data)
5300 self.assertEqual(True, fent.valid)
5301
5302 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005303 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005304
5305 def testFipBadAlign(self):
5306 """Test that an invalid alignment value in a FIP is detected"""
5307 with self.assertRaises(ValueError) as e:
5308 self._DoTestFile('211_fip_bad_align.dts')
5309 self.assertIn(
5310 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5311 str(e.exception))
5312
5313 def testFipCollection(self):
5314 """Test using a FIP in a collection"""
5315 data = self._DoReadFile('212_fip_collection.dts')
5316 entry1 = control.images['image'].GetEntries()['collection']
5317 data1 = data[:entry1.size]
5318 hdr1, fents2 = fip_util.decode_fip(data1)
5319
5320 entry2 = control.images['image'].GetEntries()['atf-fip']
5321 data2 = data[entry2.offset:entry2.offset + entry2.size]
5322 hdr1, fents2 = fip_util.decode_fip(data2)
5323
5324 # The 'collection' entry should have U-Boot included at the end
5325 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5326 self.assertEqual(data1, data2 + U_BOOT_DATA)
5327 self.assertEqual(U_BOOT_DATA, data1[-4:])
5328
5329 # There should be a U-Boot after the final FIP
5330 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005331
Simon Glassccae6862022-01-12 13:10:35 -07005332 def testFakeBlob(self):
5333 """Test handling of faking an external blob"""
5334 with test_util.capture_sys_output() as (stdout, stderr):
5335 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5336 allow_fake_blobs=True)
5337 err = stderr.getvalue()
5338 self.assertRegex(
5339 err,
5340 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005341
Simon Glassceb5f912022-01-09 20:13:46 -07005342 def testExtblobListFaked(self):
5343 """Test an extblob with missing external blob that are faked"""
5344 with test_util.capture_sys_output() as (stdout, stderr):
5345 self._DoTestFile('216_blob_ext_list_missing.dts',
5346 allow_fake_blobs=True)
5347 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005348 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005349
Simon Glass162017b2022-01-09 20:13:57 -07005350 def testListBintools(self):
5351 args = ['tool', '--list']
5352 with test_util.capture_sys_output() as (stdout, _):
5353 self._DoBinman(*args)
5354 out = stdout.getvalue().splitlines()
5355 self.assertTrue(len(out) >= 2)
5356
5357 def testFetchBintools(self):
5358 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005359 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005360 raise urllib.error.URLError('my error')
5361
5362 args = ['tool']
5363 with self.assertRaises(ValueError) as e:
5364 self._DoBinman(*args)
5365 self.assertIn("Invalid arguments to 'tool' subcommand",
5366 str(e.exception))
5367
5368 args = ['tool', '--fetch']
5369 with self.assertRaises(ValueError) as e:
5370 self._DoBinman(*args)
5371 self.assertIn('Please specify bintools to fetch', str(e.exception))
5372
5373 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005374 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005375 side_effect=fail_download):
5376 with test_util.capture_sys_output() as (stdout, _):
5377 self._DoBinman(*args)
5378 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5379
Simon Glass620c4462022-01-09 20:14:11 -07005380 def testBintoolDocs(self):
5381 """Test for creation of bintool documentation"""
5382 with test_util.capture_sys_output() as (stdout, stderr):
5383 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5384 self.assertTrue(len(stdout.getvalue()) > 0)
5385
5386 def testBintoolDocsMissing(self):
5387 """Test handling of missing bintool documentation"""
5388 with self.assertRaises(ValueError) as e:
5389 with test_util.capture_sys_output() as (stdout, stderr):
5390 control.write_bintool_docs(
5391 control.bintool.Bintool.get_tool_list(), 'mkimage')
5392 self.assertIn('Documentation is missing for modules: mkimage',
5393 str(e.exception))
5394
Jan Kiszka58c407f2022-01-28 20:37:53 +01005395 def testListWithGenNode(self):
5396 """Check handling of an FDT map when the section cannot be found"""
5397 entry_args = {
5398 'of-list': 'test-fdt1 test-fdt2',
5399 }
5400 data = self._DoReadFileDtb(
5401 '219_fit_gennode.dts',
5402 entry_args=entry_args,
5403 use_real_dtb=True,
5404 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5405
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005406 tmpdir = None
Jan Kiszka58c407f2022-01-28 20:37:53 +01005407 try:
5408 tmpdir, updated_fname = self._SetupImageInTmpdir()
5409 with test_util.capture_sys_output() as (stdout, stderr):
5410 self._RunBinman('ls', '-i', updated_fname)
5411 finally:
Heinrich Schuchardt53f6f592023-12-16 00:26:04 +01005412 if tmpdir:
5413 shutil.rmtree(tmpdir)
Jan Kiszka58c407f2022-01-28 20:37:53 +01005414
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005415 def testFitSubentryUsesBintool(self):
5416 """Test that binman FIT subentries can use bintools"""
5417 command.test_result = self._HandleGbbCommand
5418 entry_args = {
5419 'keydir': 'devkeys',
5420 'bmpblk': 'bmpblk.bin',
5421 }
5422 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5423 entry_args=entry_args)
5424
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005425 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5426 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005427 self.assertIn(expected, data)
5428
5429 def testFitSubentryMissingBintool(self):
5430 """Test that binman reports missing bintools for FIT subentries"""
5431 entry_args = {
5432 'keydir': 'devkeys',
5433 }
5434 with test_util.capture_sys_output() as (_, stderr):
5435 self._DoTestFile('220_fit_subentry_bintool.dts',
5436 force_missing_bintools='futility', entry_args=entry_args)
5437 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005438 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005439
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005440 def testFitSubentryHashSubnode(self):
5441 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005442 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005443 data, _, _, out_dtb_name = self._DoReadFileDtb(
5444 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5445
5446 mkimage_dtb = fdt.Fdt.FromData(data)
5447 mkimage_dtb.Scan()
5448 binman_dtb = fdt.Fdt(out_dtb_name)
5449 binman_dtb.Scan()
5450
5451 # Check that binman didn't add hash values
5452 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5453 self.assertNotIn('value', fnode.props)
5454
5455 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5456 self.assertNotIn('value', fnode.props)
5457
5458 # Check that mkimage added hash values
5459 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5460 self.assertIn('value', fnode.props)
5461
5462 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5463 self.assertIn('value', fnode.props)
5464
Roger Quadros5cdcea02022-02-19 20:50:04 +02005465 def testPackTeeOs(self):
5466 """Test that an image with an TEE binary can be created"""
5467 data = self._DoReadFile('222_tee_os.dts')
5468 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5469
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305470 def testPackTiDm(self):
5471 """Test that an image with a TI DM binary can be created"""
5472 data = self._DoReadFile('225_ti_dm.dts')
5473 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5474
Simon Glass912339f2022-02-08 11:50:03 -07005475 def testFitFdtOper(self):
5476 """Check handling of a specified FIT operation"""
5477 entry_args = {
5478 'of-list': 'test-fdt1 test-fdt2',
5479 'default-dt': 'test-fdt2',
5480 }
5481 self._DoReadFileDtb(
5482 '223_fit_fdt_oper.dts',
5483 entry_args=entry_args,
5484 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5485
5486 def testFitFdtBadOper(self):
5487 """Check handling of an FDT map when the section cannot be found"""
5488 with self.assertRaises(ValueError) as exc:
5489 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005490 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005491 str(exc.exception))
5492
Simon Glassdd156a42022-03-05 20:18:59 -07005493 def test_uses_expand_size(self):
5494 """Test that the 'expand-size' property cannot be used anymore"""
5495 with self.assertRaises(ValueError) as e:
5496 data = self._DoReadFile('225_expand_size_bad.dts')
5497 self.assertIn(
5498 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5499 str(e.exception))
5500
Simon Glass5f423422022-03-05 20:19:12 -07005501 def testFitSplitElf(self):
5502 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005503 if not elf.ELF_TOOLS:
5504 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005505 entry_args = {
5506 'of-list': 'test-fdt1 test-fdt2',
5507 'default-dt': 'test-fdt2',
5508 'atf-bl31-path': 'bl31.elf',
5509 'tee-os-path': 'tee.elf',
5510 }
5511 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5512 data = self._DoReadFileDtb(
5513 '226_fit_split_elf.dts',
5514 entry_args=entry_args,
5515 extra_indirs=[test_subdir])[0]
5516
5517 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5518 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5519
5520 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5521 'data', 'load'}
5522 dtb = fdt.Fdt.FromData(fit_data)
5523 dtb.Scan()
5524
5525 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5526 segments, entry = elf.read_loadable_segments(elf_data)
5527
5528 # We assume there are two segments
Brandon Maiera657bc62024-06-04 16:16:05 +00005529 self.assertEqual(2, len(segments))
Simon Glass5f423422022-03-05 20:19:12 -07005530
5531 atf1 = dtb.GetNode('/images/atf-1')
5532 _, start, data = segments[0]
5533 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5534 self.assertEqual(entry,
5535 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5536 self.assertEqual(start,
5537 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5538 self.assertEqual(data, atf1.props['data'].bytes)
5539
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005540 hash_node = atf1.FindNode('hash')
5541 self.assertIsNotNone(hash_node)
5542 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5543
Simon Glass5f423422022-03-05 20:19:12 -07005544 atf2 = dtb.GetNode('/images/atf-2')
5545 self.assertEqual(base_keys, atf2.props.keys())
5546 _, start, data = segments[1]
5547 self.assertEqual(start,
5548 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5549 self.assertEqual(data, atf2.props['data'].bytes)
5550
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005551 hash_node = atf2.FindNode('hash')
5552 self.assertIsNotNone(hash_node)
5553 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5554
5555 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5556 self.assertIsNotNone(hash_node)
5557 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5558
Simon Glass5f423422022-03-05 20:19:12 -07005559 conf = dtb.GetNode('/configurations')
5560 self.assertEqual({'default'}, conf.props.keys())
5561
5562 for subnode in conf.subnodes:
5563 self.assertEqual({'description', 'fdt', 'loadables'},
5564 subnode.props.keys())
5565 self.assertEqual(
5566 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5567 fdt_util.GetStringList(subnode, 'loadables'))
5568
5569 def _check_bad_fit(self, dts):
5570 """Check a bad FIT
5571
5572 This runs with the given dts and returns the assertion raised
5573
5574 Args:
5575 dts (str): dts filename to use
5576
5577 Returns:
5578 str: Assertion string raised
5579 """
5580 entry_args = {
5581 'of-list': 'test-fdt1 test-fdt2',
5582 'default-dt': 'test-fdt2',
5583 'atf-bl31-path': 'bl31.elf',
5584 'tee-os-path': 'tee.elf',
5585 }
5586 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5587 with self.assertRaises(ValueError) as exc:
5588 self._DoReadFileDtb(dts, entry_args=entry_args,
5589 extra_indirs=[test_subdir])[0]
5590 return str(exc.exception)
5591
5592 def testFitSplitElfBadElf(self):
5593 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005594 if not elf.ELF_TOOLS:
5595 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005596 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5597 entry_args = {
5598 'of-list': 'test-fdt1 test-fdt2',
5599 'default-dt': 'test-fdt2',
5600 'atf-bl31-path': 'bad.elf',
5601 'tee-os-path': 'tee.elf',
5602 }
5603 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5604 with self.assertRaises(ValueError) as exc:
5605 self._DoReadFileDtb(
5606 '226_fit_split_elf.dts',
5607 entry_args=entry_args,
5608 extra_indirs=[test_subdir])[0]
5609 self.assertIn(
5610 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5611 str(exc.exception))
5612
Simon Glass5f423422022-03-05 20:19:12 -07005613 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005614 """Test an split-elf FIT with a missing ELF file
5615
5616 Args:
5617 kwargs (dict of str): Arguments to pass to _DoTestFile()
5618
5619 Returns:
5620 tuple:
5621 str: stdout result
5622 str: stderr result
5623 """
Simon Glass5f423422022-03-05 20:19:12 -07005624 entry_args = {
5625 'of-list': 'test-fdt1 test-fdt2',
5626 'default-dt': 'test-fdt2',
5627 'atf-bl31-path': 'bl31.elf',
5628 'tee-os-path': 'missing.elf',
5629 }
5630 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5631 with test_util.capture_sys_output() as (stdout, stderr):
5632 self._DoTestFile(
5633 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005634 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5635 out = stdout.getvalue()
5636 err = stderr.getvalue()
5637 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005638
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005639 def testFitSplitElfBadDirective(self):
5640 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5641 if not elf.ELF_TOOLS:
5642 self.skipTest('Python elftools not available')
5643 err = self._check_bad_fit('227_fit_bad_dir.dts')
5644 self.assertIn(
5645 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5646 err)
5647
5648 def testFitSplitElfBadDirectiveConfig(self):
5649 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5650 if not elf.ELF_TOOLS:
5651 self.skipTest('Python elftools not available')
5652 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5653 self.assertEqual(
5654 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5655 err)
5656
5657
Simon Glass5f423422022-03-05 20:19:12 -07005658 def testFitSplitElfMissing(self):
5659 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005660 if not elf.ELF_TOOLS:
5661 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005662 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005663 self.assertRegex(
5664 err,
5665 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005666 self.assertNotRegex(out, '.*Faked blob.*')
5667 fname = tools.get_output_filename('binman-fake/missing.elf')
5668 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005669
5670 def testFitSplitElfFaked(self):
5671 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005672 if not elf.ELF_TOOLS:
5673 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005674 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005675 self.assertRegex(
5676 err,
5677 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005678 self.assertRegex(
5679 out,
5680 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5681 fname = tools.get_output_filename('binman-fake/missing.elf')
5682 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005683
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005684 def testMkimageMissingBlob(self):
5685 """Test using mkimage to build an image"""
5686 with test_util.capture_sys_output() as (stdout, stderr):
5687 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5688 allow_fake_blobs=True)
5689 err = stderr.getvalue()
5690 self.assertRegex(
5691 err,
5692 "Image '.*' has faked external blobs and is non-functional: .*")
5693
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005694 def testPreLoad(self):
5695 """Test an image with a pre-load header"""
5696 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005697 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005698 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005699 data = self._DoReadFileDtb(
5700 '230_pre_load.dts', entry_args=entry_args,
5701 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005702 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5703 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5704 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Simon Glasse2dfb962023-07-24 09:19:57 -06005705
5706 def testPreLoadNoKey(self):
5707 """Test an image with a pre-load heade0r with missing key"""
5708 with self.assertRaises(FileNotFoundError) as exc:
5709 self._DoReadFile('230_pre_load.dts')
5710 self.assertIn("No such file or directory: 'dev.key'",
5711 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005712
5713 def testPreLoadPkcs(self):
5714 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005715 entry_args = {
5716 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5717 }
5718 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5719 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005720 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5721 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5722 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5723
5724 def testPreLoadPss(self):
5725 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005726 entry_args = {
5727 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5728 }
5729 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5730 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005731 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5732 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5733 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5734
5735 def testPreLoadInvalidPadding(self):
5736 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005737 entry_args = {
5738 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5739 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005740 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005741 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5742 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005743
5744 def testPreLoadInvalidSha(self):
5745 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005746 entry_args = {
5747 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5748 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005749 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005750 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5751 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005752
5753 def testPreLoadInvalidAlgo(self):
5754 """Test an image with a pre-load header with an invalid algo"""
5755 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005756 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005757
5758 def testPreLoadInvalidKey(self):
5759 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005760 entry_args = {
5761 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5762 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005763 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005764 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5765 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005766
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005767 def _CheckSafeUniqueNames(self, *images):
5768 """Check all entries of given images for unsafe unique names"""
5769 for image in images:
5770 entries = {}
5771 image._CollectEntries(entries, {}, image)
5772 for entry in entries.values():
5773 uniq = entry.GetUniqueName()
5774
5775 # Used as part of a filename, so must not be absolute paths.
5776 self.assertFalse(os.path.isabs(uniq))
5777
5778 def testSafeUniqueNames(self):
5779 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005780 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005781
5782 orig_image = control.images['image']
5783 image_fname = tools.get_output_filename('image.bin')
5784 image = Image.FromFile(image_fname)
5785
5786 self._CheckSafeUniqueNames(orig_image, image)
5787
5788 def testSafeUniqueNamesMulti(self):
5789 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005790 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005791
5792 orig_image = control.images['image']
5793 image_fname = tools.get_output_filename('image.bin')
5794 image = Image.FromFile(image_fname)
5795
5796 self._CheckSafeUniqueNames(orig_image, image)
5797
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005798 def testReplaceCmdWithBintool(self):
5799 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005800 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005801 expected = U_BOOT_DATA + b'aa'
5802 self.assertEqual(expected, data[:len(expected)])
5803
5804 try:
5805 tmpdir, updated_fname = self._SetupImageInTmpdir()
5806 fname = os.path.join(tmpdir, 'update-testing.bin')
5807 tools.write_file(fname, b'zz')
5808 self._DoBinman('replace', '-i', updated_fname,
5809 '_testing', '-f', fname)
5810
5811 data = tools.read_file(updated_fname)
5812 expected = U_BOOT_DATA + b'zz'
5813 self.assertEqual(expected, data[:len(expected)])
5814 finally:
5815 shutil.rmtree(tmpdir)
5816
5817 def testReplaceCmdOtherWithBintool(self):
5818 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005819 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005820 expected = U_BOOT_DATA + b'aa'
5821 self.assertEqual(expected, data[:len(expected)])
5822
5823 try:
5824 tmpdir, updated_fname = self._SetupImageInTmpdir()
5825 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5826 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5827 self._DoBinman('replace', '-i', updated_fname,
5828 'u-boot', '-f', fname)
5829
5830 data = tools.read_file(updated_fname)
5831 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5832 self.assertEqual(expected, data[:len(expected)])
5833 finally:
5834 shutil.rmtree(tmpdir)
5835
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005836 def testReplaceResizeNoRepackSameSize(self):
5837 """Test replacing entries with same-size data without repacking"""
5838 expected = b'x' * len(U_BOOT_DATA)
5839 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5840 self.assertEqual(expected, data)
5841
5842 path, fdtmap = state.GetFdtContents('fdtmap')
5843 self.assertIsNotNone(path)
5844 self.assertEqual(expected_fdtmap, fdtmap)
5845
5846 def testReplaceResizeNoRepackSmallerSize(self):
5847 """Test replacing entries with smaller-size data without repacking"""
5848 new_data = b'x'
5849 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5850 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5851 self.assertEqual(expected, data)
5852
5853 path, fdtmap = state.GetFdtContents('fdtmap')
5854 self.assertIsNotNone(path)
5855 self.assertEqual(expected_fdtmap, fdtmap)
5856
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005857 def testExtractFit(self):
5858 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005859 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005860 image_fname = tools.get_output_filename('image.bin')
5861
5862 fit_data = control.ReadEntry(image_fname, 'fit')
5863 fit = fdt.Fdt.FromData(fit_data)
5864 fit.Scan()
5865
5866 # Check subentry data inside the extracted fit
5867 for node_path, expected in [
5868 ('/images/kernel', U_BOOT_DATA),
5869 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5870 ('/images/scr-1', COMPRESS_DATA),
5871 ]:
5872 node = fit.GetNode(node_path)
5873 data = fit.GetProps(node)['data'].bytes
5874 self.assertEqual(expected, data)
5875
5876 def testExtractFitSubentries(self):
5877 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005878 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005879 image_fname = tools.get_output_filename('image.bin')
5880
5881 for entry_path, expected in [
5882 ('fit/kernel', U_BOOT_DATA),
5883 ('fit/kernel/u-boot', U_BOOT_DATA),
5884 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5885 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5886 ('fit/scr-1', COMPRESS_DATA),
5887 ('fit/scr-1/blob', COMPRESS_DATA),
5888 ]:
5889 data = control.ReadEntry(image_fname, entry_path)
5890 self.assertEqual(expected, data)
5891
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005892 def testReplaceFitSubentryLeafSameSize(self):
5893 """Test replacing a FIT leaf subentry with same-size data"""
5894 new_data = b'x' * len(U_BOOT_DATA)
5895 data, expected_fdtmap, _ = self._RunReplaceCmd(
5896 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005897 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005898 self.assertEqual(new_data, data)
5899
5900 path, fdtmap = state.GetFdtContents('fdtmap')
5901 self.assertIsNotNone(path)
5902 self.assertEqual(expected_fdtmap, fdtmap)
5903
5904 def testReplaceFitSubentryLeafBiggerSize(self):
5905 """Test replacing a FIT leaf subentry with bigger-size data"""
5906 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5907 data, expected_fdtmap, _ = self._RunReplaceCmd(
5908 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005909 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005910 self.assertEqual(new_data, data)
5911
5912 # Will be repacked, so fdtmap must change
5913 path, fdtmap = state.GetFdtContents('fdtmap')
5914 self.assertIsNotNone(path)
5915 self.assertNotEqual(expected_fdtmap, fdtmap)
5916
5917 def testReplaceFitSubentryLeafSmallerSize(self):
5918 """Test replacing a FIT leaf subentry with smaller-size data"""
5919 new_data = b'x'
5920 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5921 data, expected_fdtmap, _ = self._RunReplaceCmd(
5922 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005923 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005924 self.assertEqual(expected, data)
5925
5926 path, fdtmap = state.GetFdtContents('fdtmap')
5927 self.assertIsNotNone(path)
5928 self.assertEqual(expected_fdtmap, fdtmap)
5929
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005930 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005931 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005932 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005933 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5934 new_data, dts='241_replace_section_simple.dts')
5935 self.assertEqual(new_data, data)
5936
5937 entries = image.GetEntries()
5938 self.assertIn('section', entries)
5939 entry = entries['section']
5940 self.assertEqual(len(new_data), entry.size)
5941
5942 def testReplaceSectionLarger(self):
5943 """Test replacing a simple section with larger data"""
5944 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5945 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5946 new_data, dts='241_replace_section_simple.dts')
5947 self.assertEqual(new_data, data)
5948
5949 entries = image.GetEntries()
5950 self.assertIn('section', entries)
5951 entry = entries['section']
5952 self.assertEqual(len(new_data), entry.size)
5953 fentry = entries['fdtmap']
5954 self.assertEqual(entry.offset + entry.size, fentry.offset)
5955
5956 def testReplaceSectionSmaller(self):
5957 """Test replacing a simple section with smaller data"""
5958 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5959 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5960 new_data, dts='241_replace_section_simple.dts')
5961 self.assertEqual(new_data, data)
5962
5963 # The new size is the same as the old, just with a pad byte at the end
5964 entries = image.GetEntries()
5965 self.assertIn('section', entries)
5966 entry = entries['section']
5967 self.assertEqual(len(new_data), entry.size)
5968
5969 def testReplaceSectionSmallerAllow(self):
5970 """Test failing to replace a simple section with smaller data"""
5971 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5972 try:
5973 state.SetAllowEntryContraction(True)
5974 with self.assertRaises(ValueError) as exc:
5975 self._RunReplaceCmd('section', new_data,
5976 dts='241_replace_section_simple.dts')
5977 finally:
5978 state.SetAllowEntryContraction(False)
5979
5980 # Since we have no information about the position of things within the
5981 # section, we cannot adjust the position of /section-u-boot so it ends
5982 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06005983 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07005984 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5985 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06005986 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005987
Simon Glass8fbca772022-08-13 11:40:48 -06005988 def testMkimageImagename(self):
5989 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005990 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005991 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005992
5993 # Check that the data appears in the file somewhere
5994 self.assertIn(U_BOOT_SPL_DATA, data)
5995
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005996 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005997 name = data[0x20:0x40]
5998
5999 # Build the filename that we expect to be placed in there, by virtue of
6000 # the -n paraameter
6001 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
6002
6003 # Check that the image name is set to the temporary filename used
6004 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6005
Simon Glassb1669752022-08-13 11:40:49 -06006006 def testMkimageImage(self):
6007 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006008 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006009 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006010
6011 # Check that the data appears in the file somewhere
6012 self.assertIn(U_BOOT_SPL_DATA, data)
6013
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006014 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006015 name = data[0x20:0x40]
6016
6017 # Build the filename that we expect to be placed in there, by virtue of
6018 # the -n paraameter
6019 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6020
6021 # Check that the image name is set to the temporary filename used
6022 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6023
6024 # Check the corect data is in the imagename file
6025 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6026
6027 def testMkimageImageNoContent(self):
6028 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006029 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006030 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006031 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006032 self.assertIn('Could not complete processing of contents',
6033 str(exc.exception))
6034
6035 def testMkimageImageBad(self):
6036 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006037 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006038 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006039 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006040 self.assertIn('Cannot use both imagename node and data-to-imagename',
6041 str(exc.exception))
6042
Simon Glassbd5cd882022-08-13 11:40:50 -06006043 def testCollectionOther(self):
6044 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006045 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006046 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6047 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6048 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6049 data)
6050
6051 def testMkimageCollection(self):
6052 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006053 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006054 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006055 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6056 self.assertEqual(expect, data[:len(expect)])
6057
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006058 def testCompressDtbPrependInvalid(self):
6059 """Test that invalid header is detected"""
6060 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006061 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006062 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6063 "'u-boot-dtb': 'invalid'", str(e.exception))
6064
6065 def testCompressDtbPrependLength(self):
6066 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006067 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006068 image = control.images['image']
6069 entries = image.GetEntries()
6070 self.assertIn('u-boot-dtb', entries)
6071 u_boot_dtb = entries['u-boot-dtb']
6072 self.assertIn('fdtmap', entries)
6073 fdtmap = entries['fdtmap']
6074
6075 image_fname = tools.get_output_filename('image.bin')
6076 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6077 dtb = fdt.Fdt.FromData(orig)
6078 dtb.Scan()
6079 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6080 expected = {
6081 'u-boot:size': len(U_BOOT_DATA),
6082 'u-boot-dtb:uncomp-size': len(orig),
6083 'u-boot-dtb:size': u_boot_dtb.size,
6084 'fdtmap:size': fdtmap.size,
6085 'size': len(data),
6086 }
6087 self.assertEqual(expected, props)
6088
6089 # Check implementation
6090 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6091 rest = data[len(U_BOOT_DATA):]
6092 comp_data_len = struct.unpack('<I', rest[:4])[0]
6093 comp_data = rest[4:4 + comp_data_len]
6094 orig2 = self._decompress(comp_data)
6095 self.assertEqual(orig, orig2)
6096
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006097 def testInvalidCompress(self):
6098 """Test that invalid compress algorithm is detected"""
6099 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006100 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006101 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6102
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006103 def testCompUtilCompressions(self):
6104 """Test compression algorithms"""
6105 for bintool in self.comp_bintools.values():
6106 self._CheckBintool(bintool)
6107 data = bintool.compress(COMPRESS_DATA)
6108 self.assertNotEqual(COMPRESS_DATA, data)
6109 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006110 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006111
6112 def testCompUtilVersions(self):
6113 """Test tool version of compression algorithms"""
6114 for bintool in self.comp_bintools.values():
6115 self._CheckBintool(bintool)
6116 version = bintool.version()
6117 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6118
6119 def testCompUtilPadding(self):
6120 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006121 # Skip zstd because it doesn't support padding
6122 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006123 self._CheckBintool(bintool)
6124 data = bintool.compress(COMPRESS_DATA)
6125 self.assertNotEqual(COMPRESS_DATA, data)
6126 data += tools.get_bytes(0, 64)
6127 orig = bintool.decompress(data)
Brandon Maiera657bc62024-06-04 16:16:05 +00006128 self.assertEqual(COMPRESS_DATA, orig)
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006129
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006130 def testCompressDtbZstd(self):
6131 """Test that zstd compress of device-tree files failed"""
6132 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006133 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006134 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6135 "requires a length header", str(e.exception))
6136
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006137 def testMkimageMultipleDataFiles(self):
6138 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006139 self._SetupSplElf()
6140 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006141 data = self._DoReadFile('252_mkimage_mult_data.dts')
6142 # Size of files are packed in their 4B big-endian format
6143 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6144 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6145 # Size info is always followed by a 4B zero value.
6146 expect += tools.get_bytes(0, 4)
6147 expect += U_BOOT_TPL_DATA
6148 # All but last files are 4B-aligned
6149 align_pad = len(U_BOOT_TPL_DATA) % 4
6150 if align_pad:
6151 expect += tools.get_bytes(0, align_pad)
6152 expect += U_BOOT_SPL_DATA
6153 self.assertEqual(expect, data[-len(expect):])
6154
Marek Vasutf7413f02023-07-18 07:23:58 -06006155 def testMkimageMultipleExpanded(self):
6156 """Test passing multiple files to mkimage in a mkimage entry"""
6157 self._SetupSplElf()
6158 self._SetupTplElf()
6159 entry_args = {
6160 'spl-bss-pad': 'y',
6161 'spl-dtb': 'y',
6162 }
6163 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6164 use_expanded=True, entry_args=entry_args)[0]
6165 pad_len = 10
6166 tpl_expect = U_BOOT_TPL_DATA
6167 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6168 spl_expect += U_BOOT_SPL_DTB_DATA
6169
6170 content = data[0x40:]
6171 lens = struct.unpack('>III', content[:12])
6172
6173 # Size of files are packed in their 4B big-endian format
6174 # Size info is always followed by a 4B zero value.
6175 self.assertEqual(len(tpl_expect), lens[0])
6176 self.assertEqual(len(spl_expect), lens[1])
6177 self.assertEqual(0, lens[2])
6178
6179 rest = content[12:]
6180 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6181
6182 rest = rest[len(tpl_expect):]
6183 align_pad = len(tpl_expect) % 4
6184 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6185 rest = rest[align_pad:]
6186 self.assertEqual(spl_expect, rest)
6187
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006188 def testMkimageMultipleNoContent(self):
6189 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006190 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006191 with self.assertRaises(ValueError) as exc:
6192 self._DoReadFile('253_mkimage_mult_no_content.dts')
6193 self.assertIn('Could not complete processing of contents',
6194 str(exc.exception))
6195
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006196 def testMkimageFilename(self):
6197 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006198 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006199 retcode = self._DoTestFile('254_mkimage_filename.dts')
6200 self.assertEqual(0, retcode)
6201 fname = tools.get_output_filename('mkimage-test.bin')
6202 self.assertTrue(os.path.exists(fname))
6203
Simon Glass56d05412022-02-28 07:16:54 -07006204 def testVpl(self):
6205 """Test that an image with VPL and its device tree can be created"""
6206 # ELF file with a '__bss_size' symbol
6207 self._SetupVplElf()
6208 data = self._DoReadFile('255_u_boot_vpl.dts')
6209 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6210
6211 def testVplNoDtb(self):
6212 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6213 self._SetupVplElf()
6214 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6215 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6216 data[:len(U_BOOT_VPL_NODTB_DATA)])
6217
6218 def testExpandedVpl(self):
6219 """Test that an expanded entry type is selected for TPL when needed"""
6220 self._SetupVplElf()
6221
6222 entry_args = {
6223 'vpl-bss-pad': 'y',
6224 'vpl-dtb': 'y',
6225 }
6226 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6227 entry_args=entry_args)
6228 image = control.images['image']
6229 entries = image.GetEntries()
6230 self.assertEqual(1, len(entries))
6231
6232 # We only have u-boot-vpl, which be expanded
6233 self.assertIn('u-boot-vpl', entries)
6234 entry = entries['u-boot-vpl']
6235 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6236 subent = entry.GetEntries()
6237 self.assertEqual(3, len(subent))
6238 self.assertIn('u-boot-vpl-nodtb', subent)
6239 self.assertIn('u-boot-vpl-bss-pad', subent)
6240 self.assertIn('u-boot-vpl-dtb', subent)
6241
6242 def testVplBssPadMissing(self):
6243 """Test that a missing symbol is detected"""
6244 self._SetupVplElf('u_boot_ucode_ptr')
6245 with self.assertRaises(ValueError) as e:
6246 self._DoReadFile('258_vpl_bss_pad.dts')
6247 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6248 str(e.exception))
6249
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306250 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306251 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306252 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6253 self.assertEqual(0, retcode)
6254 image = control.images['test_image']
6255 fname = tools.get_output_filename('test_image.bin')
6256 sname = tools.get_output_filename('symlink_to_test.bin')
6257 self.assertTrue(os.path.islink(sname))
6258 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006259
Andrew Davis6b463da2023-07-22 00:14:44 +05306260 def testSymlinkOverwrite(self):
6261 """Test that symlinked images can be overwritten"""
6262 testdir = TestFunctional._MakeInputDir('symlinktest')
6263 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6264 # build the same image again in the same directory so that existing symlink is present
6265 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6266 fname = tools.get_output_filename('test_image.bin')
6267 sname = tools.get_output_filename('symlink_to_test.bin')
6268 self.assertTrue(os.path.islink(sname))
6269 self.assertEqual(os.readlink(sname), fname)
6270
Simon Glass37f85de2022-10-20 18:22:47 -06006271 def testSymbolsElf(self):
6272 """Test binman can assign symbols embedded in an ELF file"""
6273 if not elf.ELF_TOOLS:
6274 self.skipTest('Python elftools not available')
6275 self._SetupTplElf('u_boot_binman_syms')
6276 self._SetupVplElf('u_boot_binman_syms')
6277 self._SetupSplElf('u_boot_binman_syms')
6278 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6279 image_fname = tools.get_output_filename('image.bin')
6280
6281 image = control.images['image']
6282 entries = image.GetEntries()
6283
6284 for entry in entries.values():
6285 # No symbols in u-boot and it has faked contents anyway
6286 if entry.name == 'u-boot':
6287 continue
6288 edata = data[entry.image_pos:entry.image_pos + entry.size]
6289 efname = tools.get_output_filename(f'edata-{entry.name}')
6290 tools.write_file(efname, edata)
6291
6292 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6293 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6294 for name, sym in syms.items():
6295 msg = 'test'
6296 val = elf.GetSymbolValue(sym, edata, msg)
6297 entry_m = re_name.match(name)
6298 if entry_m:
6299 ename, prop = entry_m.group(1), entry_m.group(3)
6300 entry, entry_name, prop_name = image.LookupEntry(entries,
6301 name, msg)
6302 if prop_name == 'offset':
6303 expect_val = entry.offset
6304 elif prop_name == 'image_pos':
6305 expect_val = entry.image_pos
6306 elif prop_name == 'size':
6307 expect_val = entry.size
6308 self.assertEqual(expect_val, val)
6309
6310 def testSymbolsElfBad(self):
6311 """Check error when trying to write symbols without the elftools lib"""
6312 if not elf.ELF_TOOLS:
6313 self.skipTest('Python elftools not available')
6314 self._SetupTplElf('u_boot_binman_syms')
6315 self._SetupVplElf('u_boot_binman_syms')
6316 self._SetupSplElf('u_boot_binman_syms')
6317 try:
6318 elf.ELF_TOOLS = False
6319 with self.assertRaises(ValueError) as exc:
6320 self._DoReadFileDtb('260_symbols_elf.dts')
6321 finally:
6322 elf.ELF_TOOLS = True
6323 self.assertIn(
6324 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6325 'Cannot write symbols to an ELF file without Python elftools',
6326 str(exc.exception))
6327
Simon Glassde244162023-01-07 14:07:08 -07006328 def testSectionFilename(self):
6329 """Check writing of section contents to a file"""
6330 data = self._DoReadFile('261_section_fname.dts')
6331 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6332 tools.get_bytes(ord('!'), 7) +
6333 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6334 self.assertEqual(expected, data)
6335
6336 sect_fname = tools.get_output_filename('outfile.bin')
6337 self.assertTrue(os.path.exists(sect_fname))
6338 sect_data = tools.read_file(sect_fname)
6339 self.assertEqual(U_BOOT_DATA, sect_data)
6340
Simon Glass1e9e61c2023-01-07 14:07:12 -07006341 def testAbsent(self):
6342 """Check handling of absent entries"""
6343 data = self._DoReadFile('262_absent.dts')
6344 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6345
Simon Glassad5cfe12023-01-07 14:07:14 -07006346 def testPackTeeOsOptional(self):
6347 """Test that an image with an optional TEE binary can be created"""
6348 entry_args = {
6349 'tee-os-path': 'tee.elf',
6350 }
6351 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6352 entry_args=entry_args)[0]
6353 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6354
6355 def checkFitTee(self, dts, tee_fname):
6356 """Check that a tee-os entry works and returns data
6357
6358 Args:
6359 dts (str): Device tree filename to use
6360 tee_fname (str): filename containing tee-os
6361
6362 Returns:
6363 bytes: Image contents
6364 """
6365 if not elf.ELF_TOOLS:
6366 self.skipTest('Python elftools not available')
6367 entry_args = {
6368 'of-list': 'test-fdt1 test-fdt2',
6369 'default-dt': 'test-fdt2',
6370 'tee-os-path': tee_fname,
6371 }
6372 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6373 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6374 extra_indirs=[test_subdir])[0]
6375 return data
6376
6377 def testFitTeeOsOptionalFit(self):
6378 """Test an image with a FIT with an optional OP-TEE binary"""
6379 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6380
6381 # There should be only one node, holding the data set up in SetUpClass()
6382 # for tee.bin
6383 dtb = fdt.Fdt.FromData(data)
6384 dtb.Scan()
6385 node = dtb.GetNode('/images/tee-1')
6386 self.assertEqual(TEE_ADDR,
6387 fdt_util.fdt32_to_cpu(node.props['load'].value))
6388 self.assertEqual(TEE_ADDR,
6389 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6390 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6391
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006392 with test_util.capture_sys_output() as (stdout, stderr):
6393 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6394 err = stderr.getvalue()
6395 self.assertRegex(
6396 err,
6397 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6398
Simon Glassad5cfe12023-01-07 14:07:14 -07006399 def testFitTeeOsOptionalFitBad(self):
6400 """Test an image with a FIT with an optional OP-TEE binary"""
6401 with self.assertRaises(ValueError) as exc:
6402 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6403 self.assertIn(
6404 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6405 str(exc.exception))
6406
6407 def testFitTeeOsBad(self):
6408 """Test an OP-TEE binary with wrong formats"""
6409 self.make_tee_bin('tee.bad1', 123)
6410 with self.assertRaises(ValueError) as exc:
6411 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6412 self.assertIn(
6413 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6414 str(exc.exception))
6415
6416 self.make_tee_bin('tee.bad2', 0, b'extra data')
6417 with self.assertRaises(ValueError) as exc:
6418 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6419 self.assertIn(
6420 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6421 str(exc.exception))
6422
Simon Glass63328f12023-01-07 14:07:15 -07006423 def testExtblobOptional(self):
6424 """Test an image with an external blob that is optional"""
6425 with test_util.capture_sys_output() as (stdout, stderr):
6426 data = self._DoReadFile('266_blob_ext_opt.dts')
6427 self.assertEqual(REFCODE_DATA, data)
6428 err = stderr.getvalue()
6429 self.assertRegex(
6430 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006431 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006432
Simon Glass7447a9d2023-01-11 16:10:12 -07006433 def testSectionInner(self):
6434 """Test an inner section with a size"""
6435 data = self._DoReadFile('267_section_inner.dts')
6436 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6437 self.assertEqual(expected, data)
6438
Simon Glassa4948b22023-01-11 16:10:14 -07006439 def testNull(self):
6440 """Test an image with a null entry"""
6441 data = self._DoReadFile('268_null.dts')
6442 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6443
Simon Glassf1ee03b2023-01-11 16:10:16 -07006444 def testOverlap(self):
6445 """Test an image with a overlapping entry"""
6446 data = self._DoReadFile('269_overlap.dts')
6447 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6448
6449 image = control.images['image']
6450 entries = image.GetEntries()
6451
6452 self.assertIn('inset', entries)
6453 inset = entries['inset']
6454 self.assertEqual(1, inset.offset);
6455 self.assertEqual(1, inset.image_pos);
6456 self.assertEqual(2, inset.size);
6457
6458 def testOverlapNull(self):
6459 """Test an image with a null overlap"""
6460 data = self._DoReadFile('270_overlap_null.dts')
6461 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6462
6463 # Check the FMAP
6464 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6465 self.assertEqual(4, fhdr.nareas)
6466 fiter = iter(fentries)
6467
6468 fentry = next(fiter)
6469 self.assertEqual(b'SECTION', fentry.name)
6470 self.assertEqual(0, fentry.offset)
6471 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6472 self.assertEqual(0, fentry.flags)
6473
6474 fentry = next(fiter)
6475 self.assertEqual(b'U_BOOT', fentry.name)
6476 self.assertEqual(0, fentry.offset)
6477 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6478 self.assertEqual(0, fentry.flags)
6479
6480 # Make sure that the NULL entry appears in the FMAP
6481 fentry = next(fiter)
6482 self.assertEqual(b'NULL', fentry.name)
6483 self.assertEqual(1, fentry.offset)
6484 self.assertEqual(2, fentry.size)
6485 self.assertEqual(0, fentry.flags)
6486
6487 fentry = next(fiter)
6488 self.assertEqual(b'FMAP', fentry.name)
6489 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6490
6491 def testOverlapBad(self):
6492 """Test an image with a bad overlapping entry"""
6493 with self.assertRaises(ValueError) as exc:
6494 self._DoReadFile('271_overlap_bad.dts')
6495 self.assertIn(
6496 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6497 str(exc.exception))
6498
6499 def testOverlapNoOffset(self):
6500 """Test an image with a bad overlapping entry"""
6501 with self.assertRaises(ValueError) as exc:
6502 self._DoReadFile('272_overlap_no_size.dts')
6503 self.assertIn(
6504 "Node '/binman/inset': 'fill' entry is missing properties: size",
6505 str(exc.exception))
6506
Simon Glasse0035c92023-01-11 16:10:17 -07006507 def testBlobSymbol(self):
6508 """Test a blob with symbols read from an ELF file"""
6509 elf_fname = self.ElfTestFile('blob_syms')
6510 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6511 TestFunctional._MakeInputFile('blob_syms.bin',
6512 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6513
6514 data = self._DoReadFile('273_blob_symbol.dts')
6515
6516 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6517 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6518 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6519 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6520 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6521
6522 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6523 expected = sym_values
6524 self.assertEqual(expected, data[:len(expected)])
6525
Simon Glass49e9c002023-01-11 16:10:19 -07006526 def testOffsetFromElf(self):
6527 """Test a blob with symbols read from an ELF file"""
6528 elf_fname = self.ElfTestFile('blob_syms')
6529 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6530 TestFunctional._MakeInputFile('blob_syms.bin',
6531 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6532
6533 data = self._DoReadFile('274_offset_from_elf.dts')
6534
6535 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6536 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6537
6538 image = control.images['image']
6539 entries = image.GetEntries()
6540
6541 self.assertIn('inset', entries)
6542 inset = entries['inset']
6543
6544 self.assertEqual(base + 4, inset.offset);
6545 self.assertEqual(base + 4, inset.image_pos);
6546 self.assertEqual(4, inset.size);
6547
6548 self.assertIn('inset2', entries)
6549 inset = entries['inset2']
6550 self.assertEqual(base + 8, inset.offset);
6551 self.assertEqual(base + 8, inset.image_pos);
6552 self.assertEqual(4, inset.size);
6553
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006554 def testFitAlign(self):
6555 """Test an image with an FIT with aligned external data"""
6556 data = self._DoReadFile('275_fit_align.dts')
6557 self.assertEqual(4096, len(data))
6558
6559 dtb = fdt.Fdt.FromData(data)
6560 dtb.Scan()
6561
6562 props = self._GetPropTree(dtb, ['data-position'])
6563 expected = {
6564 'u-boot:data-position': 1024,
6565 'fdt-1:data-position': 2048,
6566 'fdt-2:data-position': 3072,
6567 }
6568 self.assertEqual(expected, props)
6569
Jonas Karlman490f73c2023-01-21 19:02:12 +00006570 def testFitFirmwareLoadables(self):
6571 """Test an image with an FIT that use fit,firmware"""
6572 if not elf.ELF_TOOLS:
6573 self.skipTest('Python elftools not available')
6574 entry_args = {
6575 'of-list': 'test-fdt1',
6576 'default-dt': 'test-fdt1',
6577 'atf-bl31-path': 'bl31.elf',
6578 'tee-os-path': 'missing.bin',
6579 }
6580 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006581 with test_util.capture_sys_output() as (stdout, stderr):
6582 data = self._DoReadFileDtb(
6583 '276_fit_firmware_loadables.dts',
6584 entry_args=entry_args,
6585 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006586
6587 dtb = fdt.Fdt.FromData(data)
6588 dtb.Scan()
6589
6590 node = dtb.GetNode('/configurations/conf-uboot-1')
6591 self.assertEqual('u-boot', node.props['firmware'].value)
6592 self.assertEqual(['atf-1', 'atf-2'],
6593 fdt_util.GetStringList(node, 'loadables'))
6594
6595 node = dtb.GetNode('/configurations/conf-atf-1')
6596 self.assertEqual('atf-1', node.props['firmware'].value)
6597 self.assertEqual(['u-boot', 'atf-2'],
6598 fdt_util.GetStringList(node, 'loadables'))
6599
6600 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6601 self.assertEqual('u-boot', node.props['firmware'].value)
6602 self.assertEqual(['atf-1', 'atf-2'],
6603 fdt_util.GetStringList(node, 'loadables'))
6604
6605 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6606 self.assertEqual('atf-1', node.props['firmware'].value)
6607 self.assertEqual(['u-boot', 'atf-2'],
6608 fdt_util.GetStringList(node, 'loadables'))
6609
6610 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6611 self.assertEqual('atf-1', node.props['firmware'].value)
6612 self.assertEqual(['u-boot', 'atf-2'],
6613 fdt_util.GetStringList(node, 'loadables'))
6614
Simon Glass9a1c7262023-02-22 12:14:49 -07006615 def testTooldir(self):
6616 """Test that we can specify the tooldir"""
6617 with test_util.capture_sys_output() as (stdout, stderr):
6618 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6619 'tool', '-l'))
6620 self.assertEqual('fred', bintool.Bintool.tooldir)
6621
6622 # Check that the toolpath is updated correctly
6623 self.assertEqual(['fred'], tools.tool_search_paths)
6624
6625 # Try with a few toolpaths; the tooldir should be at the end
6626 with test_util.capture_sys_output() as (stdout, stderr):
6627 self.assertEqual(0, self._DoBinman(
6628 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6629 'tool', '-l'))
6630 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6631
Simon Glass49b77e82023-03-02 17:02:44 -07006632 def testReplaceSectionEntry(self):
6633 """Test replacing an entry in a section"""
6634 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6635 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6636 expect_data, dts='241_replace_section_simple.dts')
6637 self.assertEqual(expect_data, entry_data)
6638
6639 entries = image.GetEntries()
6640 self.assertIn('section', entries)
6641 section = entries['section']
6642
6643 sect_entries = section.GetEntries()
6644 self.assertIn('blob', sect_entries)
6645 entry = sect_entries['blob']
6646 self.assertEqual(len(expect_data), entry.size)
6647
6648 fname = tools.get_output_filename('image-updated.bin')
6649 data = tools.read_file(fname)
6650
6651 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6652 self.assertEqual(expect_data, new_blob_data)
6653
6654 self.assertEqual(U_BOOT_DATA,
6655 data[entry.image_pos + len(expect_data):]
6656 [:len(U_BOOT_DATA)])
6657
6658 def testReplaceSectionDeep(self):
6659 """Test replacing an entry in two levels of sections"""
6660 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6661 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6662 'section/section/blob', expect_data,
6663 dts='278_replace_section_deep.dts')
6664 self.assertEqual(expect_data, entry_data)
6665
6666 entries = image.GetEntries()
6667 self.assertIn('section', entries)
6668 section = entries['section']
6669
6670 subentries = section.GetEntries()
6671 self.assertIn('section', subentries)
6672 section = subentries['section']
6673
6674 sect_entries = section.GetEntries()
6675 self.assertIn('blob', sect_entries)
6676 entry = sect_entries['blob']
6677 self.assertEqual(len(expect_data), entry.size)
6678
6679 fname = tools.get_output_filename('image-updated.bin')
6680 data = tools.read_file(fname)
6681
6682 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6683 self.assertEqual(expect_data, new_blob_data)
6684
6685 self.assertEqual(U_BOOT_DATA,
6686 data[entry.image_pos + len(expect_data):]
6687 [:len(U_BOOT_DATA)])
6688
6689 def testReplaceFitSibling(self):
6690 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006691 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006692 fname = TestFunctional._MakeInputFile('once', b'available once')
6693 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6694 os.remove(fname)
6695
6696 try:
6697 tmpdir, updated_fname = self._SetupImageInTmpdir()
6698
6699 fname = os.path.join(tmpdir, 'update-blob')
6700 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6701 tools.write_file(fname, expected)
6702
6703 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6704 data = tools.read_file(updated_fname)
6705 start = len(U_BOOT_DTB_DATA)
6706 self.assertEqual(expected, data[start:start + len(expected)])
6707 map_fname = os.path.join(tmpdir, 'image-updated.map')
6708 self.assertFalse(os.path.exists(map_fname))
6709 finally:
6710 shutil.rmtree(tmpdir)
6711
Simon Glassc3fe97f2023-03-02 17:02:45 -07006712 def testX509Cert(self):
6713 """Test creating an X509 certificate"""
6714 keyfile = self.TestFile('key.key')
6715 entry_args = {
6716 'keyfile': keyfile,
6717 }
6718 data = self._DoReadFileDtb('279_x509_cert.dts',
6719 entry_args=entry_args)[0]
6720 cert = data[:-4]
6721 self.assertEqual(U_BOOT_DATA, data[-4:])
6722
6723 # TODO: verify the signature
6724
6725 def testX509CertMissing(self):
6726 """Test that binman still produces an image if openssl is missing"""
6727 keyfile = self.TestFile('key.key')
6728 entry_args = {
6729 'keyfile': 'keyfile',
6730 }
6731 with test_util.capture_sys_output() as (_, stderr):
6732 self._DoTestFile('279_x509_cert.dts',
6733 force_missing_bintools='openssl',
6734 entry_args=entry_args)
6735 err = stderr.getvalue()
6736 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6737
Jonas Karlman35305492023-02-25 19:01:33 +00006738 def testPackRockchipTpl(self):
6739 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006740 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006741 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6742
Jonas Karlman1016ec72023-02-25 19:01:35 +00006743 def testMkimageMissingBlobMultiple(self):
6744 """Test missing blob with mkimage entry and multiple-data-files"""
6745 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006746 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006747 err = stderr.getvalue()
6748 self.assertIn("is missing external blobs and is non-functional", err)
6749
6750 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006751 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006752 self.assertIn("not found in input path", str(e.exception))
6753
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006754 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6755 """Prepare sign environment
6756
6757 Create private and public keys, add pubkey into dtb.
6758
6759 Returns:
6760 Tuple:
6761 FIT container
6762 Image name
6763 Private key
6764 DTB
6765 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006766 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006767 data = self._DoReadFileRealDtb(dts)
6768 updated_fname = tools.get_output_filename('image-updated.bin')
6769 tools.write_file(updated_fname, data)
6770 dtb = tools.get_output_filename('source.dtb')
6771 private_key = tools.get_output_filename('test_key.key')
6772 public_key = tools.get_output_filename('test_key.crt')
6773 fit = tools.get_output_filename('fit.fit')
6774 key_dir = tools.get_output_dir()
6775
6776 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6777 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6778 private_key, '-out', public_key)
6779 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6780 '-n', 'test_key', '-r', 'conf', dtb)
6781
6782 return fit, updated_fname, private_key, dtb
6783
6784 def testSignSimple(self):
6785 """Test that a FIT container can be signed in image"""
6786 is_signed = False
6787 fit, fname, private_key, dtb = self._PrepareSignEnv()
6788
6789 # do sign with private key
6790 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6791 ['fit'])
6792 is_signed = self._CheckSign(fit, dtb)
6793
6794 self.assertEqual(is_signed, True)
6795
6796 def testSignExactFIT(self):
6797 """Test that a FIT container can be signed and replaced in image"""
6798 is_signed = False
6799 fit, fname, private_key, dtb = self._PrepareSignEnv()
6800
6801 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6802 args = []
6803 if self.toolpath:
6804 for path in self.toolpath:
6805 args += ['--toolpath', path]
6806
6807 # do sign with private key
6808 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6809 'sha256,rsa4096', '-f', fit, 'fit')
6810 is_signed = self._CheckSign(fit, dtb)
6811
6812 self.assertEqual(is_signed, True)
6813
6814 def testSignNonFit(self):
6815 """Test a non-FIT entry cannot be signed"""
6816 is_signed = False
6817 fit, fname, private_key, _ = self._PrepareSignEnv(
6818 '281_sign_non_fit.dts')
6819
6820 # do sign with private key
6821 with self.assertRaises(ValueError) as e:
6822 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6823 'sha256,rsa4096', '-f', fit, 'u-boot')
6824 self.assertIn(
6825 "Node '/u-boot': Updating signatures is not supported with this entry type",
6826 str(e.exception))
6827
6828 def testSignMissingMkimage(self):
6829 """Test that FIT signing handles a missing mkimage tool"""
6830 fit, fname, private_key, _ = self._PrepareSignEnv()
6831
6832 # try to sign with a missing mkimage tool
6833 bintool.Bintool.set_missing_list(['mkimage'])
6834 with self.assertRaises(ValueError) as e:
6835 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6836 ['fit'])
6837 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6838
Simon Glass4abf7842023-07-18 07:23:54 -06006839 def testSymbolNoWrite(self):
6840 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006841 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006842 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6843 no_write_symbols=True)
6844
6845 def testSymbolNoWriteExpanded(self):
6846 """Test disabling of symbol writing in expanded entries"""
6847 entry_args = {
6848 'spl-dtb': '1',
6849 }
6850 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6851 U_BOOT_SPL_DTB_DATA, 0x38,
6852 entry_args=entry_args, use_expanded=True,
6853 no_write_symbols=True)
6854
Marek Vasutf7413f02023-07-18 07:23:58 -06006855 def testMkimageSpecial(self):
6856 """Test mkimage ignores special hash-1 node"""
6857 data = self._DoReadFile('283_mkimage_special.dts')
6858
6859 # Just check that the data appears in the file somewhere
6860 self.assertIn(U_BOOT_DATA, data)
6861
Simon Glass2d94c422023-07-18 07:23:59 -06006862 def testFitFdtList(self):
6863 """Test an image with an FIT with the fit,fdt-list-val option"""
6864 entry_args = {
6865 'default-dt': 'test-fdt2',
6866 }
6867 data = self._DoReadFileDtb(
6868 '284_fit_fdt_list.dts',
6869 entry_args=entry_args,
6870 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6871 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6872 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6873
Simon Glass83b8bfe2023-07-18 07:24:01 -06006874 def testSplEmptyBss(self):
6875 """Test an expanded SPL with a zero-size BSS"""
6876 # ELF file with a '__bss_size' symbol
6877 self._SetupSplElf(src_fname='bss_data_zero')
6878
6879 entry_args = {
6880 'spl-bss-pad': 'y',
6881 'spl-dtb': 'y',
6882 }
6883 data = self._DoReadFileDtb('285_spl_expand.dts',
6884 use_expanded=True, entry_args=entry_args)[0]
6885
Simon Glassfc792842023-07-18 07:24:04 -06006886 def testTemplate(self):
6887 """Test using a template"""
6888 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6889 data = self._DoReadFile('286_template.dts')
6890 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6891 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6892 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6893
Simon Glass09490b02023-07-22 21:43:52 -06006894 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6895 self.assertTrue(os.path.exists(dtb_fname1))
6896 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6897 dtb.Scan()
6898 node1 = dtb.GetNode('/binman/template')
6899 self.assertTrue(node1)
6900 vga = dtb.GetNode('/binman/first/intel-vga')
6901 self.assertTrue(vga)
6902
Simon Glass54825e12023-07-22 21:43:56 -06006903 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6904 self.assertTrue(os.path.exists(dtb_fname2))
6905 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6906 dtb2.Scan()
6907 node2 = dtb2.GetNode('/binman/template')
6908 self.assertFalse(node2)
6909
Simon Glass9909c112023-07-18 07:24:05 -06006910 def testTemplateBlobMulti(self):
6911 """Test using a template with 'multiple-images' enabled"""
6912 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6913 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6914 retcode = self._DoTestFile('287_template_multi.dts')
6915
6916 self.assertEqual(0, retcode)
6917 image = control.images['image']
6918 image_fname = tools.get_output_filename('my-image.bin')
6919 data = tools.read_file(image_fname)
6920 self.assertEqual(b'blob@@@@other', data)
6921
Simon Glass5dc511b2023-07-18 07:24:06 -06006922 def testTemplateFit(self):
6923 """Test using a template in a FIT"""
6924 fit_data = self._DoReadFile('288_template_fit.dts')
6925 fname = os.path.join(self._indir, 'fit_data.fit')
6926 tools.write_file(fname, fit_data)
6927 out = tools.run('dumpimage', '-l', fname)
6928
Simon Glassaa6e0552023-07-18 07:24:07 -06006929 def testTemplateSection(self):
6930 """Test using a template in a section (not at top level)"""
6931 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6932 data = self._DoReadFile('289_template_section.dts')
6933 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6934 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6935 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6936
Simon Glassf53a7bc2023-07-18 07:24:08 -06006937 def testMkimageSymbols(self):
6938 """Test using mkimage to build an image with symbols in it"""
6939 self._SetupSplElf('u_boot_binman_syms')
6940 data = self._DoReadFile('290_mkimage_sym.dts')
6941
6942 image = control.images['image']
6943 entries = image.GetEntries()
6944 self.assertIn('u-boot', entries)
6945 u_boot = entries['u-boot']
6946
6947 mkim = entries['mkimage']
6948 mkim_entries = mkim.GetEntries()
6949 self.assertIn('u-boot-spl', mkim_entries)
6950 spl = mkim_entries['u-boot-spl']
6951 self.assertIn('u-boot-spl2', mkim_entries)
6952 spl2 = mkim_entries['u-boot-spl2']
6953
6954 # skip the mkimage header and the area sizes
6955 mk_data = data[mkim.offset + 0x40:]
6956 size, term = struct.unpack('>LL', mk_data[:8])
6957
6958 # There should be only one image, so check that the zero terminator is
6959 # present
6960 self.assertEqual(0, term)
6961
6962 content = mk_data[8:8 + size]
6963
6964 # The image should contain the symbols from u_boot_binman_syms.c
6965 # Note that image_pos is adjusted by the base address of the image,
6966 # which is 0x10 in our test image
6967 spl_data = content[:0x18]
6968 content = content[0x1b:]
6969
6970 # After the header is a table of offsets for each image. There should
6971 # only be one image, then a 0 terminator, so figure out the real start
6972 # of the image data
6973 base = 0x40 + 8
6974
6975 # Check symbols in both u-boot-spl and u-boot-spl2
6976 for i in range(2):
6977 vals = struct.unpack('<LLQLL', spl_data)
6978
6979 # The image should contain the symbols from u_boot_binman_syms.c
6980 # Note that image_pos is adjusted by the base address of the image,
6981 # which is 0x10 in our 'u_boot_binman_syms' test image
6982 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6983 self.assertEqual(base, vals[1])
6984 self.assertEqual(spl2.offset, vals[2])
6985 # figure out the internal positions of its components
6986 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6987
6988 # Check that spl and spl2 are actually at the indicated positions
6989 self.assertEqual(
6990 elf.BINMAN_SYM_MAGIC_VALUE,
6991 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6992 self.assertEqual(
6993 elf.BINMAN_SYM_MAGIC_VALUE,
6994 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6995
6996 self.assertEqual(len(U_BOOT_DATA), vals[4])
6997
6998 # Move to next
6999 spl_data = content[:0x18]
7000
Simon Glass86b3e472023-07-22 21:43:57 -06007001 def testTemplatePhandle(self):
7002 """Test using a template in a node containing a phandle"""
7003 entry_args = {
7004 'atf-bl31-path': 'bl31.elf',
7005 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06007006 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007007 entry_args=entry_args)
7008 fname = tools.get_output_filename('image.bin')
7009 out = tools.run('dumpimage', '-l', fname)
7010
7011 # We should see the FIT description and one for each of the two images
7012 lines = out.splitlines()
7013 descs = [line.split()[-1] for line in lines if 'escription' in line]
7014 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7015
7016 def testTemplatePhandleDup(self):
7017 """Test using a template in a node containing a phandle"""
7018 entry_args = {
7019 'atf-bl31-path': 'bl31.elf',
7020 }
7021 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007022 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007023 entry_args=entry_args)
7024 self.assertIn(
7025 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7026 str(e.exception))
7027
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307028 def testTIBoardConfig(self):
7029 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007030 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307031 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7032
Neha Malcom Francis8cd04512024-01-05 17:09:17 +05307033 def testTIBoardConfigLint(self):
7034 """Test that an incorrectly linted config file would generate error"""
7035 with self.assertRaises(ValueError) as e:
7036 data = self._DoReadFile('323_ti_board_cfg_phony.dts')
7037 self.assertIn("Yamllint error", str(e.exception))
7038
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307039 def testTIBoardConfigCombined(self):
7040 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007041 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307042 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7043 self.assertGreater(data, configlen_noheader)
7044
7045 def testTIBoardConfigNoDataType(self):
7046 """Test that error is thrown when data type is not supported"""
7047 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007048 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307049 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007050
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307051 def testPackTiSecure(self):
7052 """Test that an image with a TI secured binary can be created"""
7053 keyfile = self.TestFile('key.key')
7054 entry_args = {
7055 'keyfile': keyfile,
7056 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007057 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307058 entry_args=entry_args)[0]
7059 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7060
Manorit Chawdhry2e523b02023-12-29 16:16:27 +05307061 def testPackTiSecureFirewall(self):
7062 """Test that an image with a TI secured binary can be created"""
7063 keyfile = self.TestFile('key.key')
7064 entry_args = {
7065 'keyfile': keyfile,
7066 }
7067 data_no_firewall = self._DoReadFileDtb('296_ti_secure.dts',
7068 entry_args=entry_args)[0]
7069 data_firewall = self._DoReadFileDtb('324_ti_secure_firewall.dts',
7070 entry_args=entry_args)[0]
7071 self.assertGreater(len(data_firewall),len(data_no_firewall))
7072
7073 def testPackTiSecureFirewallMissingProperty(self):
7074 """Test that an image with a TI secured binary can be created"""
7075 keyfile = self.TestFile('key.key')
7076 entry_args = {
7077 'keyfile': keyfile,
7078 }
7079 with self.assertRaises(ValueError) as e:
7080 data_firewall = self._DoReadFileDtb('325_ti_secure_firewall_missing_property.dts',
7081 entry_args=entry_args)[0]
7082 self.assertRegex(str(e.exception), "Node '/binman/ti-secure': Subnode 'firewall-0-2' is missing properties: id,region")
7083
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307084 def testPackTiSecureMissingTool(self):
7085 """Test that an image with a TI secured binary (non-functional) can be created
7086 when openssl is missing"""
7087 keyfile = self.TestFile('key.key')
7088 entry_args = {
7089 'keyfile': keyfile,
7090 }
7091 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007092 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307093 force_missing_bintools='openssl',
7094 entry_args=entry_args)
7095 err = stderr.getvalue()
7096 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7097
7098 def testPackTiSecureROM(self):
7099 """Test that a ROM image with a TI secured binary can be created"""
7100 keyfile = self.TestFile('key.key')
7101 entry_args = {
7102 'keyfile': keyfile,
7103 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007104 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307105 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007106 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307107 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007108 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307109 entry_args=entry_args)[0]
7110 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7111 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7112 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7113
7114 def testPackTiSecureROMCombined(self):
7115 """Test that a ROM image with a TI secured binary can be created"""
7116 keyfile = self.TestFile('key.key')
7117 entry_args = {
7118 'keyfile': keyfile,
7119 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007120 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307121 entry_args=entry_args)[0]
7122 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7123
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007124 def testEncryptedNoAlgo(self):
7125 """Test encrypted node with missing required properties"""
7126 with self.assertRaises(ValueError) as e:
7127 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7128 self.assertIn(
7129 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7130 str(e.exception))
7131
7132 def testEncryptedInvalidIvfile(self):
7133 """Test encrypted node with invalid iv file"""
7134 with self.assertRaises(ValueError) as e:
7135 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7136 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7137 str(e.exception))
7138
7139 def testEncryptedMissingKey(self):
7140 """Test encrypted node with missing key properties"""
7141 with self.assertRaises(ValueError) as e:
7142 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7143 self.assertIn(
7144 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7145 str(e.exception))
7146
7147 def testEncryptedKeySource(self):
7148 """Test encrypted node with key-source property"""
7149 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7150
7151 dtb = fdt.Fdt.FromData(data)
7152 dtb.Scan()
7153
7154 node = dtb.GetNode('/images/u-boot/cipher')
7155 self.assertEqual('algo-name', node.props['algo'].value)
7156 self.assertEqual('key-source-value', node.props['key-source'].value)
7157 self.assertEqual(ENCRYPTED_IV_DATA,
7158 tools.to_bytes(''.join(node.props['iv'].value)))
7159 self.assertNotIn('key', node.props)
7160
7161 def testEncryptedKeyFile(self):
7162 """Test encrypted node with key-filename property"""
7163 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7164
7165 dtb = fdt.Fdt.FromData(data)
7166 dtb.Scan()
7167
7168 node = dtb.GetNode('/images/u-boot/cipher')
7169 self.assertEqual('algo-name', node.props['algo'].value)
7170 self.assertEqual(ENCRYPTED_IV_DATA,
7171 tools.to_bytes(''.join(node.props['iv'].value)))
7172 self.assertEqual(ENCRYPTED_KEY_DATA,
7173 tools.to_bytes(''.join(node.props['key'].value)))
7174 self.assertNotIn('key-source', node.props)
7175
Lukas Funkee901faf2023-07-18 13:53:13 +02007176
7177 def testSplPubkeyDtb(self):
7178 """Test u_boot_spl_pubkey_dtb etype"""
7179 data = tools.read_file(self.TestFile("key.pem"))
7180 self._MakeInputFile("key.crt", data)
7181 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7182 image = control.images['image']
7183 entries = image.GetEntries()
7184 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7185 dtb_data = dtb_entry.GetData()
7186 dtb = fdt.Fdt.FromData(dtb_data)
7187 dtb.Scan()
7188
7189 signature_node = dtb.GetNode('/signature')
7190 self.assertIsNotNone(signature_node)
7191 key_node = signature_node.FindNode("key-key")
7192 self.assertIsNotNone(key_node)
7193 self.assertEqual(fdt_util.GetString(key_node, "required"),
7194 "conf")
7195 self.assertEqual(fdt_util.GetString(key_node, "algo"),
7196 "sha384,rsa4096")
7197 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"),
7198 "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007199
Lukas Funke712e1062023-08-03 17:22:14 +02007200 def testXilinxBootgenSigning(self):
7201 """Test xilinx-bootgen etype"""
7202 bootgen = bintool.Bintool.create('bootgen')
7203 self._CheckBintool(bootgen)
7204 data = tools.read_file(self.TestFile("key.key"))
7205 self._MakeInputFile("psk.pem", data)
7206 self._MakeInputFile("ssk.pem", data)
7207 self._SetupPmuFwlElf()
7208 self._SetupSplElf()
7209 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7210 image_fname = tools.get_output_filename('image.bin')
7211
7212 # Read partition header table and check if authentication is enabled
7213 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7214 "-read", image_fname, "pht").splitlines()
7215 attributes = {"authentication": None,
7216 "core": None,
7217 "encryption": None}
7218
7219 for l in bootgen_out:
7220 for a in attributes.keys():
7221 if a in l:
7222 m = re.match(fr".*{a} \[([^]]+)\]", l)
7223 attributes[a] = m.group(1)
7224
7225 self.assertTrue(attributes['authentication'] == "rsa")
7226 self.assertTrue(attributes['core'] == "a53-0")
7227 self.assertTrue(attributes['encryption'] == "no")
7228
7229 def testXilinxBootgenSigningEncryption(self):
7230 """Test xilinx-bootgen etype"""
7231 bootgen = bintool.Bintool.create('bootgen')
7232 self._CheckBintool(bootgen)
7233 data = tools.read_file(self.TestFile("key.key"))
7234 self._MakeInputFile("psk.pem", data)
7235 self._MakeInputFile("ssk.pem", data)
7236 self._SetupPmuFwlElf()
7237 self._SetupSplElf()
7238 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7239 image_fname = tools.get_output_filename('image.bin')
7240
7241 # Read boot header in order to verify encryption source and
7242 # encryption parameter
7243 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7244 "-read", image_fname, "bh").splitlines()
7245 attributes = {"auth_only":
7246 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7247 "encryption_keystore":
7248 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7249 "value": None},
7250 }
7251
7252 for l in bootgen_out:
7253 for a in attributes.keys():
7254 if a in l:
7255 m = re.match(attributes[a]['re'], l)
7256 attributes[a] = m.group(1)
7257
7258 # Check if fsbl-attribute is set correctly
7259 self.assertTrue(attributes['auth_only'] == "true")
7260 # Check if key is stored in efuse
7261 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7262
7263 def testXilinxBootgenMissing(self):
7264 """Test that binman still produces an image if bootgen is missing"""
7265 data = tools.read_file(self.TestFile("key.key"))
7266 self._MakeInputFile("psk.pem", data)
7267 self._MakeInputFile("ssk.pem", data)
7268 self._SetupPmuFwlElf()
7269 self._SetupSplElf()
7270 with test_util.capture_sys_output() as (_, stderr):
7271 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7272 force_missing_bintools='bootgen')
7273 err = stderr.getvalue()
7274 self.assertRegex(err,
7275 "Image 'image'.*missing bintools.*: bootgen")
7276
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307277 def _GetCapsuleHeaders(self, data):
7278 """Get the capsule header contents
7279
7280 Args:
7281 data: Capsule file contents
7282
7283 Returns:
7284 Dict:
7285 key: Capsule Header name (str)
7286 value: Header field value (str)
7287 """
7288 capsule_file = os.path.join(self._indir, 'test.capsule')
7289 tools.write_file(capsule_file, data)
7290
7291 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7292 lines = out.splitlines()
7293
7294 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7295 vals = {}
7296 for line in lines:
7297 mat = re_line.match(line)
7298 if mat:
7299 vals[mat.group(1)] = mat.group(2)
7300
7301 return vals
7302
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307303 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7304 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307305 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7306 fmp_size = "00000010"
7307 fmp_fw_version = "00000002"
7308 capsule_image_index = "00000001"
7309 oemflag = "00018000"
7310 auth_hdr_revision = "00000200"
7311 auth_hdr_cert_type = "00000EF1"
7312
7313 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307314
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307315 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307316
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307317 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307318
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307319 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7320 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7321 self.assertEqual(capsule_image_index,
7322 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307323
7324 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307325 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7326
7327 if signed_capsule:
7328 self.assertEqual(auth_hdr_revision,
7329 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7330 self.assertEqual(auth_hdr_cert_type,
7331 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7332 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7333 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7334
7335 if version_check:
7336 self.assertEqual(fmp_signature,
7337 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7338 self.assertEqual(fmp_size,
7339 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7340 self.assertEqual(fmp_fw_version,
7341 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7342
7343 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307344
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307345 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7346 if accept_capsule:
7347 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7348 else:
7349 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7350
7351 hdr = self._GetCapsuleHeaders(data)
7352
7353 self.assertEqual(capsule_hdr_guid.upper(),
7354 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7355
7356 if accept_capsule:
7357 capsule_size = "0000002C"
7358 else:
7359 capsule_size = "0000001C"
7360 self.assertEqual(capsule_size,
7361 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7362
7363 if accept_capsule:
7364 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7365
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307366 def testCapsuleGen(self):
7367 """Test generation of EFI capsule"""
7368 data = self._DoReadFile('311_capsule.dts')
7369
7370 self._CheckCapsule(data)
7371
7372 def testSignedCapsuleGen(self):
7373 """Test generation of EFI capsule"""
7374 data = tools.read_file(self.TestFile("key.key"))
7375 self._MakeInputFile("key.key", data)
7376 data = tools.read_file(self.TestFile("key.pem"))
7377 self._MakeInputFile("key.crt", data)
7378
7379 data = self._DoReadFile('312_capsule_signed.dts')
7380
7381 self._CheckCapsule(data, signed_capsule=True)
7382
7383 def testCapsuleGenVersionSupport(self):
7384 """Test generation of EFI capsule with version support"""
7385 data = self._DoReadFile('313_capsule_version.dts')
7386
7387 self._CheckCapsule(data, version_check=True)
7388
7389 def testCapsuleGenSignedVer(self):
7390 """Test generation of signed EFI capsule with version information"""
7391 data = tools.read_file(self.TestFile("key.key"))
7392 self._MakeInputFile("key.key", data)
7393 data = tools.read_file(self.TestFile("key.pem"))
7394 self._MakeInputFile("key.crt", data)
7395
7396 data = self._DoReadFile('314_capsule_signed_ver.dts')
7397
7398 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7399
7400 def testCapsuleGenCapOemFlags(self):
7401 """Test generation of EFI capsule with OEM Flags set"""
7402 data = self._DoReadFile('315_capsule_oemflags.dts')
7403
7404 self._CheckCapsule(data, capoemflags=True)
7405
7406 def testCapsuleGenKeyMissing(self):
7407 """Test that binman errors out on missing key"""
7408 with self.assertRaises(ValueError) as e:
7409 self._DoReadFile('316_capsule_missing_key.dts')
7410
7411 self.assertIn("Both private key and public key certificate need to be provided",
7412 str(e.exception))
7413
7414 def testCapsuleGenIndexMissing(self):
7415 """Test that binman errors out on missing image index"""
7416 with self.assertRaises(ValueError) as e:
7417 self._DoReadFile('317_capsule_missing_index.dts')
7418
7419 self.assertIn("entry is missing properties: image-index",
7420 str(e.exception))
7421
7422 def testCapsuleGenGuidMissing(self):
7423 """Test that binman errors out on missing image GUID"""
7424 with self.assertRaises(ValueError) as e:
7425 self._DoReadFile('318_capsule_missing_guid.dts')
7426
7427 self.assertIn("entry is missing properties: image-guid",
7428 str(e.exception))
7429
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307430 def testCapsuleGenAcceptCapsule(self):
7431 """Test generationg of accept EFI capsule"""
7432 data = self._DoReadFile('319_capsule_accept.dts')
7433
7434 self._CheckEmptyCapsule(data, accept_capsule=True)
7435
7436 def testCapsuleGenRevertCapsule(self):
7437 """Test generationg of revert EFI capsule"""
7438 data = self._DoReadFile('320_capsule_revert.dts')
7439
7440 self._CheckEmptyCapsule(data)
7441
7442 def testCapsuleGenAcceptGuidMissing(self):
7443 """Test that binman errors out on missing image GUID for accept capsule"""
7444 with self.assertRaises(ValueError) as e:
7445 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7446
7447 self.assertIn("Image GUID needed for generating accept capsule",
7448 str(e.exception))
7449
7450 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7451 """Test that capsule-type is specified"""
7452 with self.assertRaises(ValueError) as e:
7453 self._DoReadFile('322_empty_capsule_type_missing.dts')
7454
7455 self.assertIn("entry is missing properties: capsule-type",
7456 str(e.exception))
7457
7458 def testCapsuleGenAcceptOrRevertMissing(self):
7459 """Test that both accept and revert capsule are not specified"""
7460 with self.assertRaises(ValueError) as e:
7461 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7462
Simon Glassa360b8f2024-06-23 11:55:06 -06007463 def test_assume_size(self):
7464 """Test handling of the assume-size property for external blob"""
7465 with self.assertRaises(ValueError) as e:
7466 self._DoTestFile('326_assume_size.dts', allow_missing=True,
7467 allow_fake_blobs=True)
7468 self.assertIn("contents size 0xa (10) exceeds section size 0x9 (9)",
7469 str(e.exception))
7470
7471 def test_assume_size_ok(self):
7472 """Test handling of the assume-size where it fits OK"""
7473 with test_util.capture_sys_output() as (stdout, stderr):
7474 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True,
7475 allow_fake_blobs=True)
7476 err = stderr.getvalue()
7477 self.assertRegex(
7478 err,
7479 "Image '.*' has faked external blobs and is non-functional: .*")
7480
7481 def test_assume_size_no_fake(self):
7482 """Test handling of the assume-size where it fits OK"""
7483 with test_util.capture_sys_output() as (stdout, stderr):
7484 self._DoTestFile('327_assume_size_ok.dts', allow_missing=True)
7485 err = stderr.getvalue()
7486 self.assertRegex(
7487 err,
7488 "Image '.*' is missing external blobs and is non-functional: .*")
7489
7490
Simon Glassac599912017-11-12 21:52:22 -07007491if __name__ == "__main__":
7492 unittest.main()