blob: a273120d9f9b9d9c69b517dce96125ce2a695c15 [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)
2098 self.assertEquals(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']
2812 self.assertEquals(orig_entry.offset, entry.offset)
2813 self.assertEquals(orig_entry.size, entry.size)
2814 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2815
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
Simon Glassb3d6fc72019-07-20 12:24:10 -06002845 try:
2846 tmpdir, updated_fname = self._SetupImageInTmpdir()
2847 with test_util.capture_sys_output() as (stdout, stderr):
2848 self._DoBinman('ls', '-i', updated_fname)
2849 finally:
2850 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002851 lines = stdout.getvalue().splitlines()
2852 expected = [
2853'Name Image-pos Size Entry-type Offset Uncomp-size',
2854'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002855'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002856' u-boot 0 4 u-boot 0',
2857' section 100 %x section 100' % section_size,
2858' cbfs 100 400 cbfs 0',
Simon Glassfa144222023-10-14 14:40:28 -06002859' u-boot 120 4 u-boot 20',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002860' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002861' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002862' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002863 (fdtmap_offset, fdtmap_offset),
2864' image-header bf8 8 image-header bf8',
2865 ]
2866 self.assertEqual(expected, lines)
2867
2868 def testListCmdFail(self):
2869 """Test failing to list an image"""
2870 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002871 try:
2872 tmpdir, updated_fname = self._SetupImageInTmpdir()
2873 with self.assertRaises(ValueError) as e:
2874 self._DoBinman('ls', '-i', updated_fname)
2875 finally:
2876 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002877 self.assertIn("Cannot find FDT map in image", str(e.exception))
2878
2879 def _RunListCmd(self, paths, expected):
2880 """List out entries and check the result
2881
2882 Args:
2883 paths: List of paths to pass to the list command
2884 expected: Expected list of filenames to be returned, in order
2885 """
2886 self._CheckLz4()
2887 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002888 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002889 image = Image.FromFile(image_fname)
2890 lines = image.GetListEntries(paths)[1]
2891 files = [line[0].strip() for line in lines[1:]]
2892 self.assertEqual(expected, files)
2893
2894 def testListCmdSection(self):
2895 """Test listing the files in a section"""
2896 self._RunListCmd(['section'],
2897 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2898
2899 def testListCmdFile(self):
2900 """Test listing a particular file"""
2901 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2902
2903 def testListCmdWildcard(self):
2904 """Test listing a wildcarded file"""
2905 self._RunListCmd(['*boot*'],
2906 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2907
2908 def testListCmdWildcardMulti(self):
2909 """Test listing a wildcarded file"""
2910 self._RunListCmd(['*cb*', '*head*'],
2911 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2912
2913 def testListCmdEmpty(self):
2914 """Test listing a wildcarded file"""
2915 self._RunListCmd(['nothing'], [])
2916
2917 def testListCmdPath(self):
2918 """Test listing the files in a sub-entry of a section"""
2919 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2920
Simon Glass4c613bf2019-07-08 14:25:50 -06002921 def _RunExtractCmd(self, entry_name, decomp=True):
2922 """Extract an entry from an image
2923
2924 Args:
2925 entry_name: Entry name to extract
2926 decomp: True to decompress the data if compressed, False to leave
2927 it in its raw uncompressed format
2928
2929 Returns:
2930 data from entry
2931 """
2932 self._CheckLz4()
2933 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002934 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002935 return control.ReadEntry(image_fname, entry_name, decomp)
2936
2937 def testExtractSimple(self):
2938 """Test extracting a single file"""
2939 data = self._RunExtractCmd('u-boot')
2940 self.assertEqual(U_BOOT_DATA, data)
2941
Simon Glass980a2842019-07-08 14:25:52 -06002942 def testExtractSection(self):
2943 """Test extracting the files in a section"""
2944 data = self._RunExtractCmd('section')
2945 cbfs_data = data[:0x400]
2946 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002947 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002948 dtb_data = data[0x400:]
2949 dtb = self._decompress(dtb_data)
2950 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2951
2952 def testExtractCompressed(self):
2953 """Test extracting compressed data"""
2954 data = self._RunExtractCmd('section/u-boot-dtb')
2955 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2956
2957 def testExtractRaw(self):
2958 """Test extracting compressed data without decompressing it"""
2959 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2960 dtb = self._decompress(data)
2961 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2962
2963 def testExtractCbfs(self):
2964 """Test extracting CBFS data"""
2965 data = self._RunExtractCmd('section/cbfs/u-boot')
2966 self.assertEqual(U_BOOT_DATA, data)
2967
2968 def testExtractCbfsCompressed(self):
2969 """Test extracting CBFS compressed data"""
2970 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2971 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2972
2973 def testExtractCbfsRaw(self):
2974 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002975 bintool = self.comp_bintools['lzma_alone']
2976 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06002977 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002978 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06002979 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2980
Simon Glass4c613bf2019-07-08 14:25:50 -06002981 def testExtractBadEntry(self):
2982 """Test extracting a bad section path"""
2983 with self.assertRaises(ValueError) as e:
2984 self._RunExtractCmd('section/does-not-exist')
2985 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2986 str(e.exception))
2987
2988 def testExtractMissingFile(self):
2989 """Test extracting file that does not exist"""
2990 with self.assertRaises(IOError) as e:
2991 control.ReadEntry('missing-file', 'name')
2992
2993 def testExtractBadFile(self):
2994 """Test extracting an invalid file"""
2995 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002996 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002997 with self.assertRaises(ValueError) as e:
2998 control.ReadEntry(fname, 'name')
2999
Simon Glass980a2842019-07-08 14:25:52 -06003000 def testExtractCmd(self):
3001 """Test extracting a file fron an image on the command line"""
3002 self._CheckLz4()
3003 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06003004 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06003005 try:
3006 tmpdir, updated_fname = self._SetupImageInTmpdir()
3007 with test_util.capture_sys_output() as (stdout, stderr):
3008 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
3009 '-f', fname)
3010 finally:
3011 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07003012 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003013 self.assertEqual(U_BOOT_DATA, data)
3014
3015 def testExtractOneEntry(self):
3016 """Test extracting a single entry fron an image """
3017 self._CheckLz4()
3018 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003019 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003020 fname = os.path.join(self._indir, 'output.extact')
3021 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07003022 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06003023 self.assertEqual(U_BOOT_DATA, data)
3024
3025 def _CheckExtractOutput(self, decomp):
3026 """Helper to test file output with and without decompression
3027
3028 Args:
3029 decomp: True to decompress entry data, False to output it raw
3030 """
3031 def _CheckPresent(entry_path, expect_data, expect_size=None):
3032 """Check and remove expected file
3033
3034 This checks the data/size of a file and removes the file both from
3035 the outfiles set and from the output directory. Once all files are
3036 processed, both the set and directory should be empty.
3037
3038 Args:
3039 entry_path: Entry path
3040 expect_data: Data to expect in file, or None to skip check
3041 expect_size: Size of data to expect in file, or None to skip
3042 """
3043 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003044 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003045 os.remove(path)
3046 if expect_data:
3047 self.assertEqual(expect_data, data)
3048 elif expect_size:
3049 self.assertEqual(expect_size, len(data))
3050 outfiles.remove(path)
3051
3052 def _CheckDirPresent(name):
3053 """Remove expected directory
3054
3055 This gives an error if the directory does not exist as expected
3056
3057 Args:
3058 name: Name of directory to remove
3059 """
3060 path = os.path.join(outdir, name)
3061 os.rmdir(path)
3062
3063 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003064 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003065 outdir = os.path.join(self._indir, 'extract')
3066 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3067
3068 # Create a set of all file that were output (should be 9)
3069 outfiles = set()
3070 for root, dirs, files in os.walk(outdir):
3071 outfiles |= set([os.path.join(root, fname) for fname in files])
3072 self.assertEqual(9, len(outfiles))
3073 self.assertEqual(9, len(einfos))
3074
3075 image = control.images['image']
3076 entries = image.GetEntries()
3077
3078 # Check the 9 files in various ways
3079 section = entries['section']
3080 section_entries = section.GetEntries()
3081 cbfs_entries = section_entries['cbfs'].GetEntries()
3082 _CheckPresent('u-boot', U_BOOT_DATA)
3083 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3084 dtb_len = EXTRACT_DTB_SIZE
3085 if not decomp:
3086 dtb_len = cbfs_entries['u-boot-dtb'].size
3087 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3088 if not decomp:
3089 dtb_len = section_entries['u-boot-dtb'].size
3090 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3091
3092 fdtmap = entries['fdtmap']
3093 _CheckPresent('fdtmap', fdtmap.data)
3094 hdr = entries['image-header']
3095 _CheckPresent('image-header', hdr.data)
3096
3097 _CheckPresent('section/root', section.data)
3098 cbfs = section_entries['cbfs']
3099 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003100 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003101 _CheckPresent('root', data)
3102
3103 # There should be no files left. Remove all the directories to check.
3104 # If there are any files/dirs remaining, one of these checks will fail.
3105 self.assertEqual(0, len(outfiles))
3106 _CheckDirPresent('section/cbfs')
3107 _CheckDirPresent('section')
3108 _CheckDirPresent('')
3109 self.assertFalse(os.path.exists(outdir))
3110
3111 def testExtractAllEntries(self):
3112 """Test extracting all entries"""
3113 self._CheckLz4()
3114 self._CheckExtractOutput(decomp=True)
3115
3116 def testExtractAllEntriesRaw(self):
3117 """Test extracting all entries without decompressing them"""
3118 self._CheckLz4()
3119 self._CheckExtractOutput(decomp=False)
3120
3121 def testExtractSelectedEntries(self):
3122 """Test extracting some entries"""
3123 self._CheckLz4()
3124 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003125 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003126 outdir = os.path.join(self._indir, 'extract')
3127 einfos = control.ExtractEntries(image_fname, None, outdir,
3128 ['*cb*', '*head*'])
3129
3130 # File output is tested by testExtractAllEntries(), so just check that
3131 # the expected entries are selected
3132 names = [einfo.name for einfo in einfos]
3133 self.assertEqual(names,
3134 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3135
3136 def testExtractNoEntryPaths(self):
3137 """Test extracting some entries"""
3138 self._CheckLz4()
3139 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003140 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003141 with self.assertRaises(ValueError) as e:
3142 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003143 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003144 str(e.exception))
3145
3146 def testExtractTooManyEntryPaths(self):
3147 """Test extracting some entries"""
3148 self._CheckLz4()
3149 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003150 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003151 with self.assertRaises(ValueError) as e:
3152 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003153 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003154 str(e.exception))
3155
Simon Glass52d06212019-07-08 14:25:53 -06003156 def testPackAlignSection(self):
3157 """Test that sections can have alignment"""
3158 self._DoReadFile('131_pack_align_section.dts')
3159
3160 self.assertIn('image', control.images)
3161 image = control.images['image']
3162 entries = image.GetEntries()
3163 self.assertEqual(3, len(entries))
3164
3165 # First u-boot
3166 self.assertIn('u-boot', entries)
3167 entry = entries['u-boot']
3168 self.assertEqual(0, entry.offset)
3169 self.assertEqual(0, entry.image_pos)
3170 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3171 self.assertEqual(len(U_BOOT_DATA), entry.size)
3172
3173 # Section0
3174 self.assertIn('section0', entries)
3175 section0 = entries['section0']
3176 self.assertEqual(0x10, section0.offset)
3177 self.assertEqual(0x10, section0.image_pos)
3178 self.assertEqual(len(U_BOOT_DATA), section0.size)
3179
3180 # Second u-boot
3181 section_entries = section0.GetEntries()
3182 self.assertIn('u-boot', section_entries)
3183 entry = section_entries['u-boot']
3184 self.assertEqual(0, entry.offset)
3185 self.assertEqual(0x10, entry.image_pos)
3186 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3187 self.assertEqual(len(U_BOOT_DATA), entry.size)
3188
3189 # Section1
3190 self.assertIn('section1', entries)
3191 section1 = entries['section1']
3192 self.assertEqual(0x14, section1.offset)
3193 self.assertEqual(0x14, section1.image_pos)
3194 self.assertEqual(0x20, section1.size)
3195
3196 # Second u-boot
3197 section_entries = section1.GetEntries()
3198 self.assertIn('u-boot', section_entries)
3199 entry = section_entries['u-boot']
3200 self.assertEqual(0, entry.offset)
3201 self.assertEqual(0x14, entry.image_pos)
3202 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3203 self.assertEqual(len(U_BOOT_DATA), entry.size)
3204
3205 # Section2
3206 self.assertIn('section2', section_entries)
3207 section2 = section_entries['section2']
3208 self.assertEqual(0x4, section2.offset)
3209 self.assertEqual(0x18, section2.image_pos)
3210 self.assertEqual(4, section2.size)
3211
3212 # Third u-boot
3213 section_entries = section2.GetEntries()
3214 self.assertIn('u-boot', section_entries)
3215 entry = section_entries['u-boot']
3216 self.assertEqual(0, entry.offset)
3217 self.assertEqual(0x18, entry.image_pos)
3218 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3219 self.assertEqual(len(U_BOOT_DATA), entry.size)
3220
Simon Glassf8a54bc2019-07-20 12:23:56 -06003221 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3222 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003223 """Replace an entry in an image
3224
3225 This writes the entry data to update it, then opens the updated file and
3226 returns the value that it now finds there.
3227
3228 Args:
3229 entry_name: Entry name to replace
3230 data: Data to replace it with
3231 decomp: True to compress the data if needed, False if data is
3232 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003233 allow_resize: True to allow entries to change size, False to raise
3234 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003235
3236 Returns:
3237 Tuple:
3238 data from entry
3239 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003240 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003241 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003242 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003243 update_dtb=True)[1]
3244
3245 self.assertIn('image', control.images)
3246 image = control.images['image']
3247 entries = image.GetEntries()
3248 orig_dtb_data = entries['u-boot-dtb'].data
3249 orig_fdtmap_data = entries['fdtmap'].data
3250
Simon Glass80025522022-01-29 14:14:04 -07003251 image_fname = tools.get_output_filename('image.bin')
3252 updated_fname = tools.get_output_filename('image-updated.bin')
3253 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003254 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3255 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003256 data = control.ReadEntry(updated_fname, entry_name, decomp)
3257
Simon Glassf8a54bc2019-07-20 12:23:56 -06003258 # The DT data should not change unless resized:
3259 if not allow_resize:
3260 new_dtb_data = entries['u-boot-dtb'].data
3261 self.assertEqual(new_dtb_data, orig_dtb_data)
3262 new_fdtmap_data = entries['fdtmap'].data
3263 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003264
Simon Glassf8a54bc2019-07-20 12:23:56 -06003265 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003266
3267 def testReplaceSimple(self):
3268 """Test replacing a single file"""
3269 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003270 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3271 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003272 self.assertEqual(expected, data)
3273
3274 # Test that the state looks right. There should be an FDT for the fdtmap
3275 # that we jsut read back in, and it should match what we find in the
3276 # 'control' tables. Checking for an FDT that does not exist should
3277 # return None.
3278 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003279 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003280 self.assertEqual(expected_fdtmap, fdtmap)
3281
3282 dtb = state.GetFdtForEtype('fdtmap')
3283 self.assertEqual(dtb.GetContents(), fdtmap)
3284
3285 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3286 self.assertIsNone(missing_path)
3287 self.assertIsNone(missing_fdtmap)
3288
3289 missing_dtb = state.GetFdtForEtype('missing')
3290 self.assertIsNone(missing_dtb)
3291
3292 self.assertEqual('/binman', state.fdt_path_prefix)
3293
3294 def testReplaceResizeFail(self):
3295 """Test replacing a file by something larger"""
3296 expected = U_BOOT_DATA + b'x'
3297 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003298 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3299 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003300 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3301 str(e.exception))
3302
3303 def testReplaceMulti(self):
3304 """Test replacing entry data where multiple images are generated"""
3305 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3306 update_dtb=True)[0]
3307 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003308 updated_fname = tools.get_output_filename('image-updated.bin')
3309 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003310 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003311 control.WriteEntry(updated_fname, entry_name, expected,
3312 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003313 data = control.ReadEntry(updated_fname, entry_name)
3314 self.assertEqual(expected, data)
3315
3316 # Check the state looks right.
3317 self.assertEqual('/binman/image', state.fdt_path_prefix)
3318
3319 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003320 image_fname = tools.get_output_filename('first-image.bin')
3321 updated_fname = tools.get_output_filename('first-updated.bin')
3322 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003323 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003324 control.WriteEntry(updated_fname, entry_name, expected,
3325 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003326 data = control.ReadEntry(updated_fname, entry_name)
3327 self.assertEqual(expected, data)
3328
3329 # Check the state looks right.
3330 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003331
Simon Glassfb30e292019-07-20 12:23:51 -06003332 def testUpdateFdtAllRepack(self):
3333 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003334 self._SetupSplElf()
3335 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003336 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3337 SECTION_SIZE = 0x300
3338 DTB_SIZE = 602
3339 FDTMAP_SIZE = 608
3340 base_expected = {
3341 'offset': 0,
3342 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3343 'image-pos': 0,
3344 'section:offset': 0,
3345 'section:size': SECTION_SIZE,
3346 'section:image-pos': 0,
3347 'section/u-boot-dtb:offset': 4,
3348 'section/u-boot-dtb:size': 636,
3349 'section/u-boot-dtb:image-pos': 4,
3350 'u-boot-spl-dtb:offset': SECTION_SIZE,
3351 'u-boot-spl-dtb:size': DTB_SIZE,
3352 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3353 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3354 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3355 'u-boot-tpl-dtb:size': DTB_SIZE,
3356 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3357 'fdtmap:size': FDTMAP_SIZE,
3358 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3359 }
3360 main_expected = {
3361 'section:orig-size': SECTION_SIZE,
3362 'section/u-boot-dtb:orig-offset': 4,
3363 }
3364
3365 # We expect three device-tree files in the output, with the first one
3366 # within a fixed-size section.
3367 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3368 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3369 # main U-Boot tree. All three should have the same positions and offset
3370 # except that the main tree should include the main_expected properties
3371 start = 4
3372 for item in ['', 'spl', 'tpl', None]:
3373 if item is None:
3374 start += 16 # Move past fdtmap header
3375 dtb = fdt.Fdt.FromData(data[start:])
3376 dtb.Scan()
3377 props = self._GetPropTree(dtb,
3378 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3379 prefix='/' if item is None else '/binman/')
3380 expected = dict(base_expected)
3381 if item:
3382 expected[item] = 0
3383 else:
3384 # Main DTB and fdtdec should include the 'orig-' properties
3385 expected.update(main_expected)
3386 # Helpful for debugging:
3387 #for prop in sorted(props):
3388 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3389 self.assertEqual(expected, props)
3390 if item == '':
3391 start = SECTION_SIZE
3392 else:
3393 start += dtb._fdt_obj.totalsize()
3394
Simon Glass11453762019-07-20 12:23:55 -06003395 def testFdtmapHeaderMiddle(self):
3396 """Test an FDT map in the middle of an image when it should be at end"""
3397 with self.assertRaises(ValueError) as e:
3398 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3399 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3400 str(e.exception))
3401
3402 def testFdtmapHeaderStartBad(self):
3403 """Test an FDT map in middle of an image when it should be at start"""
3404 with self.assertRaises(ValueError) as e:
3405 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3406 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3407 str(e.exception))
3408
3409 def testFdtmapHeaderEndBad(self):
3410 """Test an FDT map at the start of an image when it should be at end"""
3411 with self.assertRaises(ValueError) as e:
3412 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3413 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3414 str(e.exception))
3415
3416 def testFdtmapHeaderNoSize(self):
3417 """Test an image header at the end of an image with undefined size"""
3418 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3419
Simon Glassf8a54bc2019-07-20 12:23:56 -06003420 def testReplaceResize(self):
3421 """Test replacing a single file in an entry with a larger file"""
3422 expected = U_BOOT_DATA + b'x'
3423 data, _, image = self._RunReplaceCmd('u-boot', expected,
3424 dts='139_replace_repack.dts')
3425 self.assertEqual(expected, data)
3426
3427 entries = image.GetEntries()
3428 dtb_data = entries['u-boot-dtb'].data
3429 dtb = fdt.Fdt.FromData(dtb_data)
3430 dtb.Scan()
3431
3432 # The u-boot section should now be larger in the dtb
3433 node = dtb.GetNode('/binman/u-boot')
3434 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3435
3436 # Same for the fdtmap
3437 fdata = entries['fdtmap'].data
3438 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3439 fdtb.Scan()
3440 fnode = fdtb.GetNode('/u-boot')
3441 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3442
3443 def testReplaceResizeNoRepack(self):
3444 """Test replacing an entry with a larger file when not allowed"""
3445 expected = U_BOOT_DATA + b'x'
3446 with self.assertRaises(ValueError) as e:
3447 self._RunReplaceCmd('u-boot', expected)
3448 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3449 str(e.exception))
3450
Simon Glass9d8ee322019-07-20 12:23:58 -06003451 def testEntryShrink(self):
3452 """Test contracting an entry after it is packed"""
3453 try:
3454 state.SetAllowEntryContraction(True)
3455 data = self._DoReadFileDtb('140_entry_shrink.dts',
3456 update_dtb=True)[0]
3457 finally:
3458 state.SetAllowEntryContraction(False)
3459 self.assertEqual(b'a', data[:1])
3460 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3461 self.assertEqual(b'a', data[-1:])
3462
3463 def testEntryShrinkFail(self):
3464 """Test not being allowed to contract an entry after it is packed"""
3465 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3466
3467 # In this case there is a spare byte at the end of the data. The size of
3468 # the contents is only 1 byte but we still have the size before it
3469 # shrunk.
3470 self.assertEqual(b'a\0', data[:2])
3471 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3472 self.assertEqual(b'a\0', data[-2:])
3473
Simon Glass70e32982019-07-20 12:24:01 -06003474 def testDescriptorOffset(self):
3475 """Test that the Intel descriptor is always placed at at the start"""
3476 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3477 image = control.images['image']
3478 entries = image.GetEntries()
3479 desc = entries['intel-descriptor']
3480 self.assertEqual(0xff800000, desc.offset);
3481 self.assertEqual(0xff800000, desc.image_pos);
3482
Simon Glass37fdd142019-07-20 12:24:06 -06003483 def testReplaceCbfs(self):
3484 """Test replacing a single file in CBFS without changing the size"""
3485 self._CheckLz4()
3486 expected = b'x' * len(U_BOOT_DATA)
3487 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003488 updated_fname = tools.get_output_filename('image-updated.bin')
3489 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003490 entry_name = 'section/cbfs/u-boot'
3491 control.WriteEntry(updated_fname, entry_name, expected,
3492 allow_resize=True)
3493 data = control.ReadEntry(updated_fname, entry_name)
3494 self.assertEqual(expected, data)
3495
3496 def testReplaceResizeCbfs(self):
3497 """Test replacing a single file in CBFS with one of a different size"""
3498 self._CheckLz4()
3499 expected = U_BOOT_DATA + b'x'
3500 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003501 updated_fname = tools.get_output_filename('image-updated.bin')
3502 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003503 entry_name = 'section/cbfs/u-boot'
3504 control.WriteEntry(updated_fname, entry_name, expected,
3505 allow_resize=True)
3506 data = control.ReadEntry(updated_fname, entry_name)
3507 self.assertEqual(expected, data)
3508
Simon Glass30033c22019-07-20 12:24:15 -06003509 def _SetupForReplace(self):
3510 """Set up some files to use to replace entries
3511
3512 This generates an image, copies it to a new file, extracts all the files
3513 in it and updates some of them
3514
3515 Returns:
3516 List
3517 Image filename
3518 Output directory
3519 Expected values for updated entries, each a string
3520 """
3521 data = self._DoReadFileRealDtb('143_replace_all.dts')
3522
Simon Glass80025522022-01-29 14:14:04 -07003523 updated_fname = tools.get_output_filename('image-updated.bin')
3524 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003525
3526 outdir = os.path.join(self._indir, 'extract')
3527 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3528
3529 expected1 = b'x' + U_BOOT_DATA + b'y'
3530 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003531 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003532
3533 expected2 = b'a' + U_BOOT_DATA + b'b'
3534 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003535 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003536
3537 expected_text = b'not the same text'
3538 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003539 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003540
3541 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3542 dtb = fdt.FdtScan(dtb_fname)
3543 node = dtb.GetNode('/binman/text')
3544 node.AddString('my-property', 'the value')
3545 dtb.Sync(auto_resize=True)
3546 dtb.Flush()
3547
3548 return updated_fname, outdir, expected1, expected2, expected_text
3549
3550 def _CheckReplaceMultiple(self, entry_paths):
3551 """Handle replacing the contents of multiple entries
3552
3553 Args:
3554 entry_paths: List of entry paths to replace
3555
3556 Returns:
3557 List
3558 Dict of entries in the image:
3559 key: Entry name
3560 Value: Entry object
3561 Expected values for updated entries, each a string
3562 """
3563 updated_fname, outdir, expected1, expected2, expected_text = (
3564 self._SetupForReplace())
3565 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3566
3567 image = Image.FromFile(updated_fname)
3568 image.LoadData()
3569 return image.GetEntries(), expected1, expected2, expected_text
3570
3571 def testReplaceAll(self):
3572 """Test replacing the contents of all entries"""
3573 entries, expected1, expected2, expected_text = (
3574 self._CheckReplaceMultiple([]))
3575 data = entries['u-boot'].data
3576 self.assertEqual(expected1, data)
3577
3578 data = entries['u-boot2'].data
3579 self.assertEqual(expected2, data)
3580
3581 data = entries['text'].data
3582 self.assertEqual(expected_text, data)
3583
3584 # Check that the device tree is updated
3585 data = entries['u-boot-dtb'].data
3586 dtb = fdt.Fdt.FromData(data)
3587 dtb.Scan()
3588 node = dtb.GetNode('/binman/text')
3589 self.assertEqual('the value', node.props['my-property'].value)
3590
3591 def testReplaceSome(self):
3592 """Test replacing the contents of a few entries"""
3593 entries, expected1, expected2, expected_text = (
3594 self._CheckReplaceMultiple(['u-boot2', 'text']))
3595
3596 # This one should not change
3597 data = entries['u-boot'].data
3598 self.assertEqual(U_BOOT_DATA, data)
3599
3600 data = entries['u-boot2'].data
3601 self.assertEqual(expected2, data)
3602
3603 data = entries['text'].data
3604 self.assertEqual(expected_text, data)
3605
3606 def testReplaceCmd(self):
3607 """Test replacing a file fron an image on the command line"""
3608 self._DoReadFileRealDtb('143_replace_all.dts')
3609
3610 try:
3611 tmpdir, updated_fname = self._SetupImageInTmpdir()
3612
3613 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3614 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003615 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003616
3617 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003618 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003619 self.assertEqual(expected, data[:len(expected)])
3620 map_fname = os.path.join(tmpdir, 'image-updated.map')
3621 self.assertFalse(os.path.exists(map_fname))
3622 finally:
3623 shutil.rmtree(tmpdir)
3624
3625 def testReplaceCmdSome(self):
3626 """Test replacing some files fron an image on the command line"""
3627 updated_fname, outdir, expected1, expected2, expected_text = (
3628 self._SetupForReplace())
3629
3630 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3631 'u-boot2', 'text')
3632
Simon Glass80025522022-01-29 14:14:04 -07003633 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003634 image = Image.FromFile(updated_fname)
3635 image.LoadData()
3636 entries = image.GetEntries()
3637
3638 # This one should not change
3639 data = entries['u-boot'].data
3640 self.assertEqual(U_BOOT_DATA, data)
3641
3642 data = entries['u-boot2'].data
3643 self.assertEqual(expected2, data)
3644
3645 data = entries['text'].data
3646 self.assertEqual(expected_text, data)
3647
3648 def testReplaceMissing(self):
3649 """Test replacing entries where the file is missing"""
3650 updated_fname, outdir, expected1, expected2, expected_text = (
3651 self._SetupForReplace())
3652
3653 # Remove one of the files, to generate a warning
3654 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3655 os.remove(u_boot_fname1)
3656
3657 with test_util.capture_sys_output() as (stdout, stderr):
3658 control.ReplaceEntries(updated_fname, None, outdir, [])
3659 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003660 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003661
3662 def testReplaceCmdMap(self):
3663 """Test replacing a file fron an image on the command line"""
3664 self._DoReadFileRealDtb('143_replace_all.dts')
3665
3666 try:
3667 tmpdir, updated_fname = self._SetupImageInTmpdir()
3668
3669 fname = os.path.join(self._indir, 'update-u-boot.bin')
3670 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003671 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003672
3673 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3674 '-f', fname, '-m')
3675 map_fname = os.path.join(tmpdir, 'image-updated.map')
3676 self.assertTrue(os.path.exists(map_fname))
3677 finally:
3678 shutil.rmtree(tmpdir)
3679
3680 def testReplaceNoEntryPaths(self):
3681 """Test replacing an entry without an entry path"""
3682 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003683 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003684 with self.assertRaises(ValueError) as e:
3685 control.ReplaceEntries(image_fname, 'fname', None, [])
3686 self.assertIn('Must specify an entry path to read with -f',
3687 str(e.exception))
3688
3689 def testReplaceTooManyEntryPaths(self):
3690 """Test extracting some entries"""
3691 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003692 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003693 with self.assertRaises(ValueError) as e:
3694 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3695 self.assertIn('Must specify exactly one entry path to write with -f',
3696 str(e.exception))
3697
Simon Glass0b074d62019-08-24 07:22:48 -06003698 def testPackReset16(self):
3699 """Test that an image with an x86 reset16 region can be created"""
3700 data = self._DoReadFile('144_x86_reset16.dts')
3701 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3702
3703 def testPackReset16Spl(self):
3704 """Test that an image with an x86 reset16-spl region can be created"""
3705 data = self._DoReadFile('145_x86_reset16_spl.dts')
3706 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3707
3708 def testPackReset16Tpl(self):
3709 """Test that an image with an x86 reset16-tpl region can be created"""
3710 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3711 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3712
Simon Glass232f90c2019-08-24 07:22:50 -06003713 def testPackIntelFit(self):
3714 """Test that an image with an Intel FIT and pointer can be created"""
3715 data = self._DoReadFile('147_intel_fit.dts')
3716 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3717 fit = data[16:32];
3718 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3719 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3720
3721 image = control.images['image']
3722 entries = image.GetEntries()
3723 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3724 self.assertEqual(expected_ptr, ptr)
3725
3726 def testPackIntelFitMissing(self):
3727 """Test detection of a FIT pointer with not FIT region"""
3728 with self.assertRaises(ValueError) as e:
3729 self._DoReadFile('148_intel_fit_missing.dts')
3730 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3731 str(e.exception))
3732
Simon Glass72555fa2019-11-06 17:22:44 -07003733 def _CheckSymbolsTplSection(self, dts, expected_vals):
3734 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003735 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003736 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003737 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003738 self.assertEqual(expected1, data[:upto1])
3739
3740 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003741 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003742 self.assertEqual(expected2, data[upto1:upto2])
3743
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003744 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003745 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003746 self.assertEqual(expected3, data[upto2:upto3])
3747
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003748 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003749 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3750
3751 def testSymbolsTplSection(self):
3752 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3753 self._SetupSplElf('u_boot_binman_syms')
3754 self._SetupTplElf('u_boot_binman_syms')
3755 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003756 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003757
3758 def testSymbolsTplSectionX86(self):
3759 """Test binman can assign symbols in a section with end-at-4gb"""
3760 self._SetupSplElf('u_boot_binman_syms_x86')
3761 self._SetupTplElf('u_boot_binman_syms_x86')
3762 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003763 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003764 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003765
Simon Glass98c59572019-08-24 07:23:03 -06003766 def testPackX86RomIfwiSectiom(self):
3767 """Test that a section can be placed in an IFWI region"""
3768 self._SetupIfwi('fitimage.bin')
3769 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3770 self._CheckIfwi(data)
3771
Simon Glassba7985d2019-08-24 07:23:07 -06003772 def testPackFspM(self):
3773 """Test that an image with a FSP memory-init binary can be created"""
3774 data = self._DoReadFile('152_intel_fsp_m.dts')
3775 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3776
Simon Glass4d9086d2019-10-20 21:31:35 -06003777 def testPackFspS(self):
3778 """Test that an image with a FSP silicon-init binary can be created"""
3779 data = self._DoReadFile('153_intel_fsp_s.dts')
3780 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003781
Simon Glass9ea87b22019-10-20 21:31:36 -06003782 def testPackFspT(self):
3783 """Test that an image with a FSP temp-ram-init binary can be created"""
3784 data = self._DoReadFile('154_intel_fsp_t.dts')
3785 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3786
Simon Glass48f3aad2020-07-09 18:39:31 -06003787 def testMkimage(self):
3788 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003789 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003790 data = self._DoReadFile('156_mkimage.dts')
3791
3792 # Just check that the data appears in the file somewhere
3793 self.assertIn(U_BOOT_SPL_DATA, data)
3794
Simon Glass66152ce2022-01-09 20:14:09 -07003795 def testMkimageMissing(self):
3796 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003797 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003798 with test_util.capture_sys_output() as (_, stderr):
3799 self._DoTestFile('156_mkimage.dts',
3800 force_missing_bintools='mkimage')
3801 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003802 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003803
Simon Glass5e560182020-07-09 18:39:36 -06003804 def testExtblob(self):
3805 """Test an image with an external blob"""
3806 data = self._DoReadFile('157_blob_ext.dts')
3807 self.assertEqual(REFCODE_DATA, data)
3808
3809 def testExtblobMissing(self):
3810 """Test an image with a missing external blob"""
3811 with self.assertRaises(ValueError) as e:
3812 self._DoReadFile('158_blob_ext_missing.dts')
3813 self.assertIn("Filename 'missing-file' not found in input path",
3814 str(e.exception))
3815
Simon Glass5d94cc62020-07-09 18:39:38 -06003816 def testExtblobMissingOk(self):
3817 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003818 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003819 ret = self._DoTestFile('158_blob_ext_missing.dts',
3820 allow_missing=True)
3821 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003822 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003823 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003824 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003825 self.assertIn('Some images are invalid', err)
3826
3827 def testExtblobMissingOkFlag(self):
3828 """Test an image with an missing external blob allowed with -W"""
3829 with test_util.capture_sys_output() as (stdout, stderr):
3830 ret = self._DoTestFile('158_blob_ext_missing.dts',
3831 allow_missing=True, ignore_missing=True)
3832 self.assertEqual(0, ret)
3833 err = stderr.getvalue()
Jonas Karlmanda423fc2023-07-18 20:34:39 +00003834 self.assertIn('(missing-file)', err)
Simon Glass49cd2b32023-02-07 14:34:18 -07003835 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003836 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003837
3838 def testExtblobMissingOkSect(self):
3839 """Test an image with an missing external blob that is allowed"""
3840 with test_util.capture_sys_output() as (stdout, stderr):
3841 self._DoTestFile('159_blob_ext_missing_sect.dts',
3842 allow_missing=True)
3843 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003844 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003845
Simon Glasse88cef92020-07-09 18:39:41 -06003846 def testPackX86RomMeMissingDesc(self):
3847 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003848 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003849 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003850 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003851 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003852
3853 def testPackX86RomMissingIfwi(self):
3854 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3855 self._SetupIfwi('fitimage.bin')
3856 pathname = os.path.join(self._indir, 'fitimage.bin')
3857 os.remove(pathname)
3858 with test_util.capture_sys_output() as (stdout, stderr):
3859 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3860 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003861 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003862
Simon Glass2a0fa982022-02-11 13:23:21 -07003863 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003864 """Test that zero-size overlapping regions are ignored"""
3865 self._DoTestFile('160_pack_overlap_zero.dts')
3866
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003867 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003868 # The data should be inside the FIT
3869 dtb = fdt.Fdt.FromData(fit_data)
3870 dtb.Scan()
3871 fnode = dtb.GetNode('/images/kernel')
3872 self.assertIn('data', fnode.props)
3873
3874 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003875 tools.write_file(fname, fit_data)
3876 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003877
3878 # Check a few features to make sure the plumbing works. We don't need
3879 # to test the operation of mkimage or dumpimage here. First convert the
3880 # output into a dict where the keys are the fields printed by dumpimage
3881 # and the values are a list of values for each field
3882 lines = out.splitlines()
3883
3884 # Converts "Compression: gzip compressed" into two groups:
3885 # 'Compression' and 'gzip compressed'
3886 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3887 vals = collections.defaultdict(list)
3888 for line in lines:
3889 mat = re_line.match(line)
3890 vals[mat.group(1)].append(mat.group(2))
3891
3892 self.assertEquals('FIT description: test-desc', lines[0])
3893 self.assertIn('Created:', lines[1])
3894 self.assertIn('Image 0 (kernel)', vals)
3895 self.assertIn('Hash value', vals)
3896 data_sizes = vals.get('Data Size')
3897 self.assertIsNotNone(data_sizes)
3898 self.assertEqual(2, len(data_sizes))
3899 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003900 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3901 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3902
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003903 # Check if entry listing correctly omits /images/
3904 image = control.images['image']
3905 fit_entry = image.GetEntries()['fit']
3906 subentries = list(fit_entry.GetEntries().keys())
3907 expected = ['kernel', 'fdt-1']
3908 self.assertEqual(expected, subentries)
3909
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003910 def testSimpleFit(self):
3911 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003912 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003913 data = self._DoReadFile('161_fit.dts')
3914 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3915 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3916 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3917
3918 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3919
3920 def testSimpleFitExpandsSubentries(self):
3921 """Test that FIT images expand their subentries"""
3922 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3923 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3924 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3925 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3926
3927 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003928
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003929 def testSimpleFitImagePos(self):
3930 """Test that we have correct image-pos for FIT subentries"""
3931 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3932 update_dtb=True)
3933 dtb = fdt.Fdt(out_dtb_fname)
3934 dtb.Scan()
3935 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3936
Simon Glassb7bad182022-03-05 20:19:01 -07003937 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003938 self.assertEqual({
3939 'image-pos': 0,
3940 'offset': 0,
3941 'size': 1890,
3942
3943 'u-boot:image-pos': 0,
3944 'u-boot:offset': 0,
3945 'u-boot:size': 4,
3946
3947 'fit:image-pos': 4,
3948 'fit:offset': 4,
3949 'fit:size': 1840,
3950
Simon Glassb7bad182022-03-05 20:19:01 -07003951 'fit/images/kernel:image-pos': 304,
3952 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003953 'fit/images/kernel:size': 4,
3954
Simon Glassb7bad182022-03-05 20:19:01 -07003955 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003956 'fit/images/kernel/u-boot:offset': 0,
3957 'fit/images/kernel/u-boot:size': 4,
3958
Simon Glassb7bad182022-03-05 20:19:01 -07003959 'fit/images/fdt-1:image-pos': 552,
3960 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003961 'fit/images/fdt-1:size': 6,
3962
Simon Glassb7bad182022-03-05 20:19:01 -07003963 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003964 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3965 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3966
3967 'u-boot-nodtb:image-pos': 1844,
3968 'u-boot-nodtb:offset': 1844,
3969 'u-boot-nodtb:size': 46,
3970 }, props)
3971
3972 # Actually check the data is where we think it is
3973 for node, expected in [
3974 ("u-boot", U_BOOT_DATA),
3975 ("fit/images/kernel", U_BOOT_DATA),
3976 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3977 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3978 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3979 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3980 ]:
3981 image_pos = props[f"{node}:image-pos"]
3982 size = props[f"{node}:size"]
3983 self.assertEqual(len(expected), size)
3984 self.assertEqual(expected, data[image_pos:image_pos+size])
3985
Simon Glass45d556d2020-07-09 18:39:45 -06003986 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003987 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003988 data = self._DoReadFile('162_fit_external.dts')
3989 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3990
Simon Glass7932c882022-01-09 20:13:39 -07003991 # Size of the external-data region as set up by mkimage
3992 external_data_size = len(U_BOOT_DATA) + 2
3993 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003994 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003995 len(U_BOOT_NODTB_DATA))
3996
Simon Glass45d556d2020-07-09 18:39:45 -06003997 # The data should be outside the FIT
3998 dtb = fdt.Fdt.FromData(fit_data)
3999 dtb.Scan()
4000 fnode = dtb.GetNode('/images/kernel')
4001 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07004002 self.assertEqual(len(U_BOOT_DATA),
4003 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
4004 fit_pos = 0x400;
4005 self.assertEqual(
4006 fit_pos,
4007 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
4008
4009 self.assertEquals(expected_size, len(data))
4010 actual_pos = len(U_BOOT_DATA) + fit_pos
4011 self.assertEqual(U_BOOT_DATA + b'aa',
4012 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06004013
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03004014 def testFitExternalImagePos(self):
4015 """Test that we have correct image-pos for external FIT subentries"""
4016 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4017 update_dtb=True)
4018 dtb = fdt.Fdt(out_dtb_fname)
4019 dtb.Scan()
4020 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4021
4022 self.assertEqual({
4023 'image-pos': 0,
4024 'offset': 0,
4025 'size': 1082,
4026
4027 'u-boot:image-pos': 0,
4028 'u-boot:offset': 0,
4029 'u-boot:size': 4,
4030
4031 'fit:size': 1032,
4032 'fit:offset': 4,
4033 'fit:image-pos': 4,
4034
4035 'fit/images/kernel:size': 4,
4036 'fit/images/kernel:offset': 1024,
4037 'fit/images/kernel:image-pos': 1028,
4038
4039 'fit/images/kernel/u-boot:size': 4,
4040 'fit/images/kernel/u-boot:offset': 0,
4041 'fit/images/kernel/u-boot:image-pos': 1028,
4042
4043 'fit/images/fdt-1:size': 2,
4044 'fit/images/fdt-1:offset': 1028,
4045 'fit/images/fdt-1:image-pos': 1032,
4046
4047 'fit/images/fdt-1/_testing:size': 2,
4048 'fit/images/fdt-1/_testing:offset': 0,
4049 'fit/images/fdt-1/_testing:image-pos': 1032,
4050
4051 'u-boot-nodtb:image-pos': 1036,
4052 'u-boot-nodtb:offset': 1036,
4053 'u-boot-nodtb:size': 46,
4054 }, props)
4055
4056 # Actually check the data is where we think it is
4057 for node, expected in [
4058 ("u-boot", U_BOOT_DATA),
4059 ("fit/images/kernel", U_BOOT_DATA),
4060 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4061 ("fit/images/fdt-1", b'aa'),
4062 ("fit/images/fdt-1/_testing", b'aa'),
4063 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4064 ]:
4065 image_pos = props[f"{node}:image-pos"]
4066 size = props[f"{node}:size"]
4067 self.assertEqual(len(expected), size)
4068 self.assertEqual(expected, data[image_pos:image_pos+size])
4069
Simon Glass66152ce2022-01-09 20:14:09 -07004070 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004071 """Test that binman complains if mkimage is missing"""
4072 with self.assertRaises(ValueError) as e:
4073 self._DoTestFile('162_fit_external.dts',
4074 force_missing_bintools='mkimage')
4075 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4076 str(e.exception))
4077
4078 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004079 """Test that binman still produces a FIT image if mkimage is missing"""
4080 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004081 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004082 force_missing_bintools='mkimage')
4083 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004084 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004085
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004086 def testSectionIgnoreHashSignature(self):
4087 """Test that sections ignore hash, signature nodes for its data"""
4088 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4089 expected = (U_BOOT_DATA + U_BOOT_DATA)
4090 self.assertEqual(expected, data)
4091
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004092 def testPadInSections(self):
4093 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004094 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4095 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004096 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4097 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004098 U_BOOT_DATA)
4099 self.assertEqual(expected, data)
4100
Simon Glassd12599d2020-10-26 17:40:09 -06004101 dtb = fdt.Fdt(out_dtb_fname)
4102 dtb.Scan()
4103 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4104 expected = {
4105 'image-pos': 0,
4106 'offset': 0,
4107 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4108
4109 'section:image-pos': 0,
4110 'section:offset': 0,
4111 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4112
4113 'section/before:image-pos': 0,
4114 'section/before:offset': 0,
4115 'section/before:size': len(U_BOOT_DATA),
4116
4117 'section/u-boot:image-pos': 4,
4118 'section/u-boot:offset': 4,
4119 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4120
4121 'section/after:image-pos': 26,
4122 'section/after:offset': 26,
4123 'section/after:size': len(U_BOOT_DATA),
4124 }
4125 self.assertEqual(expected, props)
4126
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004127 def testFitImageSubentryAlignment(self):
4128 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004129 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004130 entry_args = {
4131 'test-id': TEXT_DATA,
4132 }
4133 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4134 entry_args=entry_args)
4135 dtb = fdt.Fdt.FromData(data)
4136 dtb.Scan()
4137
4138 node = dtb.GetNode('/images/kernel')
4139 data = dtb.GetProps(node)["data"].bytes
4140 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004141 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4142 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004143 self.assertEqual(expected, data)
4144
4145 node = dtb.GetNode('/images/fdt-1')
4146 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004147 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4148 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004149 U_BOOT_DTB_DATA)
4150 self.assertEqual(expected, data)
4151
4152 def testFitExtblobMissingOk(self):
4153 """Test a FIT with a missing external blob that is allowed"""
4154 with test_util.capture_sys_output() as (stdout, stderr):
4155 self._DoTestFile('168_fit_missing_blob.dts',
4156 allow_missing=True)
4157 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004158 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004159
Simon Glass21db0ff2020-09-01 05:13:54 -06004160 def testBlobNamedByArgMissing(self):
4161 """Test handling of a missing entry arg"""
4162 with self.assertRaises(ValueError) as e:
4163 self._DoReadFile('068_blob_named_by_arg.dts')
4164 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4165 str(e.exception))
4166
Simon Glass559c4de2020-09-01 05:13:58 -06004167 def testPackBl31(self):
4168 """Test that an image with an ATF BL31 binary can be created"""
4169 data = self._DoReadFile('169_atf_bl31.dts')
4170 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4171
Samuel Holland9d8cc632020-10-21 21:12:15 -05004172 def testPackScp(self):
4173 """Test that an image with an SCP binary can be created"""
4174 data = self._DoReadFile('172_scp.dts')
4175 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4176
Simon Glassa435cd12020-09-01 05:13:59 -06004177 def testFitFdt(self):
4178 """Test an image with an FIT with multiple FDT images"""
4179 def _CheckFdt(seq, expected_data):
4180 """Check the FDT nodes
4181
4182 Args:
4183 seq: Sequence number to check (0 or 1)
4184 expected_data: Expected contents of 'data' property
4185 """
4186 name = 'fdt-%d' % seq
4187 fnode = dtb.GetNode('/images/%s' % name)
4188 self.assertIsNotNone(fnode)
4189 self.assertEqual({'description','type', 'compression', 'data'},
4190 set(fnode.props.keys()))
4191 self.assertEqual(expected_data, fnode.props['data'].bytes)
4192 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4193 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004194 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004195
4196 def _CheckConfig(seq, expected_data):
4197 """Check the configuration nodes
4198
4199 Args:
4200 seq: Sequence number to check (0 or 1)
4201 expected_data: Expected contents of 'data' property
4202 """
4203 cnode = dtb.GetNode('/configurations')
4204 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004205 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004206
4207 name = 'config-%d' % seq
4208 fnode = dtb.GetNode('/configurations/%s' % name)
4209 self.assertIsNotNone(fnode)
4210 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4211 set(fnode.props.keys()))
4212 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4213 fnode.props['description'].value)
4214 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4215
4216 entry_args = {
4217 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004218 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004219 }
4220 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004221 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004222 entry_args=entry_args,
4223 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4224 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4225 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4226
4227 dtb = fdt.Fdt.FromData(fit_data)
4228 dtb.Scan()
4229 fnode = dtb.GetNode('/images/kernel')
4230 self.assertIn('data', fnode.props)
4231
4232 # Check all the properties in fdt-1 and fdt-2
4233 _CheckFdt(1, TEST_FDT1_DATA)
4234 _CheckFdt(2, TEST_FDT2_DATA)
4235
4236 # Check configurations
4237 _CheckConfig(1, TEST_FDT1_DATA)
4238 _CheckConfig(2, TEST_FDT2_DATA)
4239
4240 def testFitFdtMissingList(self):
4241 """Test handling of a missing 'of-list' entry arg"""
4242 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004243 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004244 self.assertIn("Generator node requires 'of-list' entry argument",
4245 str(e.exception))
4246
4247 def testFitFdtEmptyList(self):
4248 """Test handling of an empty 'of-list' entry arg"""
4249 entry_args = {
4250 'of-list': '',
4251 }
4252 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4253
4254 def testFitFdtMissingProp(self):
4255 """Test handling of a missing 'fit,fdt-list' property"""
4256 with self.assertRaises(ValueError) as e:
4257 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4258 self.assertIn("Generator node requires 'fit,fdt-list' property",
4259 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004260
Simon Glass1032acc2020-09-06 10:39:08 -06004261 def testFitFdtMissing(self):
4262 """Test handling of a missing 'default-dt' entry arg"""
4263 entry_args = {
4264 'of-list': 'test-fdt1 test-fdt2',
4265 }
4266 with self.assertRaises(ValueError) as e:
4267 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004268 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004269 entry_args=entry_args,
4270 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4271 self.assertIn("Generated 'default' node requires default-dt entry argument",
4272 str(e.exception))
4273
4274 def testFitFdtNotInList(self):
4275 """Test handling of a default-dt that is not in the of-list"""
4276 entry_args = {
4277 'of-list': 'test-fdt1 test-fdt2',
4278 'default-dt': 'test-fdt3',
4279 }
4280 with self.assertRaises(ValueError) as e:
4281 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004282 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004283 entry_args=entry_args,
4284 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4285 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4286 str(e.exception))
4287
Simon Glassa820af72020-09-06 10:39:09 -06004288 def testFitExtblobMissingHelp(self):
4289 """Test display of help messages when an external blob is missing"""
4290 control.missing_blob_help = control._ReadMissingBlobHelp()
4291 control.missing_blob_help['wibble'] = 'Wibble test'
4292 control.missing_blob_help['another'] = 'Another test'
4293 with test_util.capture_sys_output() as (stdout, stderr):
4294 self._DoTestFile('168_fit_missing_blob.dts',
4295 allow_missing=True)
4296 err = stderr.getvalue()
4297
4298 # We can get the tag from the name, the type or the missing-msg
4299 # property. Check all three.
4300 self.assertIn('You may need to build ARM Trusted', err)
4301 self.assertIn('Wibble test', err)
4302 self.assertIn('Another test', err)
4303
Simon Glass6f1f4d42020-09-06 10:35:32 -06004304 def testMissingBlob(self):
4305 """Test handling of a blob containing a missing file"""
4306 with self.assertRaises(ValueError) as e:
4307 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4308 self.assertIn("Filename 'missing' not found in input path",
4309 str(e.exception))
4310
Simon Glassa0729502020-09-06 10:35:33 -06004311 def testEnvironment(self):
4312 """Test adding a U-Boot environment"""
4313 data = self._DoReadFile('174_env.dts')
4314 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4315 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4316 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4317 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4318 env)
4319
4320 def testEnvironmentNoSize(self):
4321 """Test that a missing 'size' property is detected"""
4322 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004323 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004324 self.assertIn("'u-boot-env' entry must have a size property",
4325 str(e.exception))
4326
4327 def testEnvironmentTooSmall(self):
4328 """Test handling of an environment that does not fit"""
4329 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004330 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004331
4332 # checksum, start byte, environment with \0 terminator, final \0
4333 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4334 short = need - 0x8
4335 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4336 str(e.exception))
4337
Simon Glassd1fdf752020-10-26 17:40:01 -06004338 def testSkipAtStart(self):
4339 """Test handling of skip-at-start section"""
4340 data = self._DoReadFile('177_skip_at_start.dts')
4341 self.assertEqual(U_BOOT_DATA, data)
4342
4343 image = control.images['image']
4344 entries = image.GetEntries()
4345 section = entries['section']
4346 self.assertEqual(0, section.offset)
4347 self.assertEqual(len(U_BOOT_DATA), section.size)
4348 self.assertEqual(U_BOOT_DATA, section.GetData())
4349
4350 entry = section.GetEntries()['u-boot']
4351 self.assertEqual(16, entry.offset)
4352 self.assertEqual(len(U_BOOT_DATA), entry.size)
4353 self.assertEqual(U_BOOT_DATA, entry.data)
4354
4355 def testSkipAtStartPad(self):
4356 """Test handling of skip-at-start section with padded entry"""
4357 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004358 before = tools.get_bytes(0, 8)
4359 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004360 all = before + U_BOOT_DATA + after
4361 self.assertEqual(all, data)
4362
4363 image = control.images['image']
4364 entries = image.GetEntries()
4365 section = entries['section']
4366 self.assertEqual(0, section.offset)
4367 self.assertEqual(len(all), section.size)
4368 self.assertEqual(all, section.GetData())
4369
4370 entry = section.GetEntries()['u-boot']
4371 self.assertEqual(16, entry.offset)
4372 self.assertEqual(len(all), entry.size)
4373 self.assertEqual(U_BOOT_DATA, entry.data)
4374
4375 def testSkipAtStartSectionPad(self):
4376 """Test handling of skip-at-start section with padding"""
4377 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004378 before = tools.get_bytes(0, 8)
4379 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004380 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004381 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004382
4383 image = control.images['image']
4384 entries = image.GetEntries()
4385 section = entries['section']
4386 self.assertEqual(0, section.offset)
4387 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004388 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004389 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004390
4391 entry = section.GetEntries()['u-boot']
4392 self.assertEqual(16, entry.offset)
4393 self.assertEqual(len(U_BOOT_DATA), entry.size)
4394 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004395
Simon Glassbb395742020-10-26 17:40:14 -06004396 def testSectionPad(self):
4397 """Testing padding with sections"""
4398 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004399 expected = (tools.get_bytes(ord('&'), 3) +
4400 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004401 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004402 tools.get_bytes(ord('!'), 1) +
4403 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004404 self.assertEqual(expected, data)
4405
4406 def testSectionAlign(self):
4407 """Testing alignment with sections"""
4408 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4409 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004410 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004411 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004412 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004413 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004414 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4415 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004416 self.assertEqual(expected, data)
4417
Simon Glassd92c8362020-10-26 17:40:25 -06004418 def testCompressImage(self):
4419 """Test compression of the entire image"""
4420 self._CheckLz4()
4421 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4422 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4423 dtb = fdt.Fdt(out_dtb_fname)
4424 dtb.Scan()
4425 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4426 'uncomp-size'])
4427 orig = self._decompress(data)
4428 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4429
4430 # Do a sanity check on various fields
4431 image = control.images['image']
4432 entries = image.GetEntries()
4433 self.assertEqual(2, len(entries))
4434
4435 entry = entries['blob']
4436 self.assertEqual(COMPRESS_DATA, entry.data)
4437 self.assertEqual(len(COMPRESS_DATA), entry.size)
4438
4439 entry = entries['u-boot']
4440 self.assertEqual(U_BOOT_DATA, entry.data)
4441 self.assertEqual(len(U_BOOT_DATA), entry.size)
4442
4443 self.assertEqual(len(data), image.size)
4444 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4445 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4446 orig = self._decompress(image.data)
4447 self.assertEqual(orig, image.uncomp_data)
4448
4449 expected = {
4450 'blob:offset': 0,
4451 'blob:size': len(COMPRESS_DATA),
4452 'u-boot:offset': len(COMPRESS_DATA),
4453 'u-boot:size': len(U_BOOT_DATA),
4454 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4455 'offset': 0,
4456 'image-pos': 0,
4457 'size': len(data),
4458 }
4459 self.assertEqual(expected, props)
4460
4461 def testCompressImageLess(self):
4462 """Test compression where compression reduces the image size"""
4463 self._CheckLz4()
4464 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4465 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4466 dtb = fdt.Fdt(out_dtb_fname)
4467 dtb.Scan()
4468 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4469 'uncomp-size'])
4470 orig = self._decompress(data)
4471
4472 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4473
4474 # Do a sanity check on various fields
4475 image = control.images['image']
4476 entries = image.GetEntries()
4477 self.assertEqual(2, len(entries))
4478
4479 entry = entries['blob']
4480 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4481 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4482
4483 entry = entries['u-boot']
4484 self.assertEqual(U_BOOT_DATA, entry.data)
4485 self.assertEqual(len(U_BOOT_DATA), entry.size)
4486
4487 self.assertEqual(len(data), image.size)
4488 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4489 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4490 image.uncomp_size)
4491 orig = self._decompress(image.data)
4492 self.assertEqual(orig, image.uncomp_data)
4493
4494 expected = {
4495 'blob:offset': 0,
4496 'blob:size': len(COMPRESS_DATA_BIG),
4497 'u-boot:offset': len(COMPRESS_DATA_BIG),
4498 'u-boot:size': len(U_BOOT_DATA),
4499 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4500 'offset': 0,
4501 'image-pos': 0,
4502 'size': len(data),
4503 }
4504 self.assertEqual(expected, props)
4505
4506 def testCompressSectionSize(self):
4507 """Test compression of a section with a fixed size"""
4508 self._CheckLz4()
4509 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4510 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4511 dtb = fdt.Fdt(out_dtb_fname)
4512 dtb.Scan()
4513 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4514 'uncomp-size'])
4515 orig = self._decompress(data)
4516 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4517 expected = {
4518 'section/blob:offset': 0,
4519 'section/blob:size': len(COMPRESS_DATA),
4520 'section/u-boot:offset': len(COMPRESS_DATA),
4521 'section/u-boot:size': len(U_BOOT_DATA),
4522 'section:offset': 0,
4523 'section:image-pos': 0,
4524 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4525 'section:size': 0x30,
4526 'offset': 0,
4527 'image-pos': 0,
4528 'size': 0x30,
4529 }
4530 self.assertEqual(expected, props)
4531
4532 def testCompressSection(self):
4533 """Test compression of a section with no fixed size"""
4534 self._CheckLz4()
4535 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4536 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4537 dtb = fdt.Fdt(out_dtb_fname)
4538 dtb.Scan()
4539 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4540 'uncomp-size'])
4541 orig = self._decompress(data)
4542 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4543 expected = {
4544 'section/blob:offset': 0,
4545 'section/blob:size': len(COMPRESS_DATA),
4546 'section/u-boot:offset': len(COMPRESS_DATA),
4547 'section/u-boot:size': len(U_BOOT_DATA),
4548 'section:offset': 0,
4549 'section:image-pos': 0,
4550 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4551 'section:size': len(data),
4552 'offset': 0,
4553 'image-pos': 0,
4554 'size': len(data),
4555 }
4556 self.assertEqual(expected, props)
4557
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004558 def testLz4Missing(self):
4559 """Test that binman still produces an image if lz4 is missing"""
4560 with test_util.capture_sys_output() as (_, stderr):
4561 self._DoTestFile('185_compress_section.dts',
4562 force_missing_bintools='lz4')
4563 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004564 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004565
Simon Glassd92c8362020-10-26 17:40:25 -06004566 def testCompressExtra(self):
4567 """Test compression of a section with no fixed size"""
4568 self._CheckLz4()
4569 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4570 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4571 dtb = fdt.Fdt(out_dtb_fname)
4572 dtb.Scan()
4573 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4574 'uncomp-size'])
4575
4576 base = data[len(U_BOOT_DATA):]
4577 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4578 rest = base[len(U_BOOT_DATA):]
4579
4580 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004581 bintool = self.comp_bintools['lz4']
4582 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004583 data1 = rest[:len(expect1)]
4584 section1 = self._decompress(data1)
4585 self.assertEquals(expect1, data1)
Simon Glassd92c8362020-10-26 17:40:25 -06004586 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4587 rest1 = rest[len(expect1):]
4588
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004589 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004590 data2 = rest1[:len(expect2)]
4591 section2 = self._decompress(data2)
4592 self.assertEquals(expect2, data2)
Simon Glassd92c8362020-10-26 17:40:25 -06004593 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4594 rest2 = rest1[len(expect2):]
4595
4596 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4597 len(expect2) + len(U_BOOT_DATA))
4598 #self.assertEquals(expect_size, len(data))
4599
4600 #self.assertEquals(U_BOOT_DATA, rest2)
4601
4602 self.maxDiff = None
4603 expected = {
4604 'u-boot:offset': 0,
4605 'u-boot:image-pos': 0,
4606 'u-boot:size': len(U_BOOT_DATA),
4607
4608 'base:offset': len(U_BOOT_DATA),
4609 'base:image-pos': len(U_BOOT_DATA),
4610 'base:size': len(data) - len(U_BOOT_DATA),
4611 'base/u-boot:offset': 0,
4612 'base/u-boot:image-pos': len(U_BOOT_DATA),
4613 'base/u-boot:size': len(U_BOOT_DATA),
4614 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4615 len(expect2),
4616 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4617 len(expect2),
4618 'base/u-boot2:size': len(U_BOOT_DATA),
4619
4620 'base/section:offset': len(U_BOOT_DATA),
4621 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4622 'base/section:size': len(expect1),
4623 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4624 'base/section/blob:offset': 0,
4625 'base/section/blob:size': len(COMPRESS_DATA),
4626 'base/section/u-boot:offset': len(COMPRESS_DATA),
4627 'base/section/u-boot:size': len(U_BOOT_DATA),
4628
4629 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4630 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4631 'base/section2:size': len(expect2),
4632 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4633 'base/section2/blob:offset': 0,
4634 'base/section2/blob:size': len(COMPRESS_DATA),
4635 'base/section2/blob2:offset': len(COMPRESS_DATA),
4636 'base/section2/blob2:size': len(COMPRESS_DATA),
4637
4638 'offset': 0,
4639 'image-pos': 0,
4640 'size': len(data),
4641 }
4642 self.assertEqual(expected, props)
4643
Simon Glassecbe4732021-01-06 21:35:15 -07004644 def testSymbolsSubsection(self):
4645 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004646 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004647
Simon Glass3fb25402021-01-06 21:35:16 -07004648 def testReadImageEntryArg(self):
4649 """Test reading an image that would need an entry arg to generate"""
4650 entry_args = {
4651 'cros-ec-rw-path': 'ecrw.bin',
4652 }
4653 data = self.data = self._DoReadFileDtb(
4654 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4655 entry_args=entry_args)
4656
Simon Glass80025522022-01-29 14:14:04 -07004657 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004658 orig_image = control.images['image']
4659
4660 # This should not generate an error about the missing 'cros-ec-rw-path'
4661 # since we are reading the image from a file. Compare with
4662 # testEntryArgsRequired()
4663 image = Image.FromFile(image_fname)
4664 self.assertEqual(orig_image.GetEntries().keys(),
4665 image.GetEntries().keys())
4666
Simon Glassa2af7302021-01-06 21:35:18 -07004667 def testFilesAlign(self):
4668 """Test alignment with files"""
4669 data = self._DoReadFile('190_files_align.dts')
4670
4671 # The first string is 15 bytes so will align to 16
4672 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4673 self.assertEqual(expect, data)
4674
Simon Glassdb84b562021-01-06 21:35:19 -07004675 def testReadImageSkip(self):
4676 """Test reading an image and accessing its FDT map"""
4677 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004678 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004679 orig_image = control.images['image']
4680 image = Image.FromFile(image_fname)
4681 self.assertEqual(orig_image.GetEntries().keys(),
4682 image.GetEntries().keys())
4683
4684 orig_entry = orig_image.GetEntries()['fdtmap']
4685 entry = image.GetEntries()['fdtmap']
4686 self.assertEqual(orig_entry.offset, entry.offset)
4687 self.assertEqual(orig_entry.size, entry.size)
4688 self.assertEqual(16, entry.image_pos)
4689
4690 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4691
4692 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4693
Simon Glassc98de972021-03-18 20:24:57 +13004694 def testTplNoDtb(self):
4695 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004696 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004697 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4698 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4699 data[:len(U_BOOT_TPL_NODTB_DATA)])
4700
Simon Glass63f41d42021-03-18 20:24:58 +13004701 def testTplBssPad(self):
4702 """Test that we can pad TPL's BSS with zeros"""
4703 # ELF file with a '__bss_size' symbol
4704 self._SetupTplElf()
4705 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004706 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004707 data)
4708
4709 def testTplBssPadMissing(self):
4710 """Test that a missing symbol is detected"""
4711 self._SetupTplElf('u_boot_ucode_ptr')
4712 with self.assertRaises(ValueError) as e:
4713 self._DoReadFile('193_tpl_bss_pad.dts')
4714 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4715 str(e.exception))
4716
Simon Glass718b5292021-03-18 20:25:07 +13004717 def checkDtbSizes(self, data, pad_len, start):
4718 """Check the size arguments in a dtb embedded in an image
4719
4720 Args:
4721 data: The image data
4722 pad_len: Length of the pad section in the image, in bytes
4723 start: Start offset of the devicetree to examine, within the image
4724
4725 Returns:
4726 Size of the devicetree in bytes
4727 """
4728 dtb_data = data[start:]
4729 dtb = fdt.Fdt.FromData(dtb_data)
4730 fdt_size = dtb.GetFdtObj().totalsize()
4731 dtb.Scan()
4732 props = self._GetPropTree(dtb, 'size')
4733 self.assertEqual({
4734 'size': len(data),
4735 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4736 'u-boot-spl/u-boot-spl-dtb:size': 801,
4737 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4738 'u-boot-spl:size': 860,
4739 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4740 'u-boot/u-boot-dtb:size': 781,
4741 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4742 'u-boot:size': 827,
4743 }, props)
4744 return fdt_size
4745
4746 def testExpanded(self):
4747 """Test that an expanded entry type is selected when needed"""
4748 self._SetupSplElf()
4749 self._SetupTplElf()
4750
4751 # SPL has a devicetree, TPL does not
4752 entry_args = {
4753 'spl-dtb': '1',
4754 'spl-bss-pad': 'y',
4755 'tpl-dtb': '',
4756 }
4757 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4758 entry_args=entry_args)
4759 image = control.images['image']
4760 entries = image.GetEntries()
4761 self.assertEqual(3, len(entries))
4762
4763 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4764 self.assertIn('u-boot', entries)
4765 entry = entries['u-boot']
4766 self.assertEqual('u-boot-expanded', entry.etype)
4767 subent = entry.GetEntries()
4768 self.assertEqual(2, len(subent))
4769 self.assertIn('u-boot-nodtb', subent)
4770 self.assertIn('u-boot-dtb', subent)
4771
4772 # Second, u-boot-spl, which should be expanded into three parts
4773 self.assertIn('u-boot-spl', entries)
4774 entry = entries['u-boot-spl']
4775 self.assertEqual('u-boot-spl-expanded', entry.etype)
4776 subent = entry.GetEntries()
4777 self.assertEqual(3, len(subent))
4778 self.assertIn('u-boot-spl-nodtb', subent)
4779 self.assertIn('u-boot-spl-bss-pad', subent)
4780 self.assertIn('u-boot-spl-dtb', subent)
4781
4782 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4783 # devicetree
4784 self.assertIn('u-boot-tpl', entries)
4785 entry = entries['u-boot-tpl']
4786 self.assertEqual('u-boot-tpl', entry.etype)
4787 self.assertEqual(None, entry.GetEntries())
4788
4789 def testExpandedTpl(self):
4790 """Test that an expanded entry type is selected for TPL when needed"""
4791 self._SetupTplElf()
4792
4793 entry_args = {
4794 'tpl-bss-pad': 'y',
4795 'tpl-dtb': 'y',
4796 }
4797 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4798 entry_args=entry_args)
4799 image = control.images['image']
4800 entries = image.GetEntries()
4801 self.assertEqual(1, len(entries))
4802
4803 # We only have u-boot-tpl, which be expanded
4804 self.assertIn('u-boot-tpl', entries)
4805 entry = entries['u-boot-tpl']
4806 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4807 subent = entry.GetEntries()
4808 self.assertEqual(3, len(subent))
4809 self.assertIn('u-boot-tpl-nodtb', subent)
4810 self.assertIn('u-boot-tpl-bss-pad', subent)
4811 self.assertIn('u-boot-tpl-dtb', subent)
4812
4813 def testExpandedNoPad(self):
4814 """Test an expanded entry without BSS pad enabled"""
4815 self._SetupSplElf()
4816 self._SetupTplElf()
4817
4818 # SPL has a devicetree, TPL does not
4819 entry_args = {
4820 'spl-dtb': 'something',
4821 'spl-bss-pad': 'n',
4822 'tpl-dtb': '',
4823 }
4824 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4825 entry_args=entry_args)
4826 image = control.images['image']
4827 entries = image.GetEntries()
4828
4829 # Just check u-boot-spl, which should be expanded into two parts
4830 self.assertIn('u-boot-spl', entries)
4831 entry = entries['u-boot-spl']
4832 self.assertEqual('u-boot-spl-expanded', entry.etype)
4833 subent = entry.GetEntries()
4834 self.assertEqual(2, len(subent))
4835 self.assertIn('u-boot-spl-nodtb', subent)
4836 self.assertIn('u-boot-spl-dtb', subent)
4837
4838 def testExpandedTplNoPad(self):
4839 """Test that an expanded entry type with padding disabled in TPL"""
4840 self._SetupTplElf()
4841
4842 entry_args = {
4843 'tpl-bss-pad': '',
4844 'tpl-dtb': 'y',
4845 }
4846 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4847 entry_args=entry_args)
4848 image = control.images['image']
4849 entries = image.GetEntries()
4850 self.assertEqual(1, len(entries))
4851
4852 # We only have u-boot-tpl, which be expanded
4853 self.assertIn('u-boot-tpl', entries)
4854 entry = entries['u-boot-tpl']
4855 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4856 subent = entry.GetEntries()
4857 self.assertEqual(2, len(subent))
4858 self.assertIn('u-boot-tpl-nodtb', subent)
4859 self.assertIn('u-boot-tpl-dtb', subent)
4860
4861 def testFdtInclude(self):
4862 """Test that an Fdt is update within all binaries"""
4863 self._SetupSplElf()
4864 self._SetupTplElf()
4865
4866 # SPL has a devicetree, TPL does not
4867 self.maxDiff = None
4868 entry_args = {
4869 'spl-dtb': '1',
4870 'spl-bss-pad': 'y',
4871 'tpl-dtb': '',
4872 }
4873 # Build the image. It includes two separate devicetree binaries, each
4874 # with their own contents, but all contain the binman definition.
4875 data = self._DoReadFileDtb(
4876 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4877 update_dtb=True, entry_args=entry_args)[0]
4878 pad_len = 10
4879
4880 # Check the U-Boot dtb
4881 start = len(U_BOOT_NODTB_DATA)
4882 fdt_size = self.checkDtbSizes(data, pad_len, start)
4883
4884 # Now check SPL
4885 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4886 fdt_size = self.checkDtbSizes(data, pad_len, start)
4887
4888 # TPL has no devicetree
4889 start += fdt_size + len(U_BOOT_TPL_DATA)
4890 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004891
Simon Glass7098b7f2021-03-21 18:24:30 +13004892 def testSymbolsExpanded(self):
4893 """Test binman can assign symbols in expanded entries"""
4894 entry_args = {
4895 'spl-dtb': '1',
4896 }
4897 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4898 U_BOOT_SPL_DTB_DATA, 0x38,
4899 entry_args=entry_args, use_expanded=True)
4900
Simon Glasse1915782021-03-21 18:24:31 +13004901 def testCollection(self):
4902 """Test a collection"""
4903 data = self._DoReadFile('198_collection.dts')
4904 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004905 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4906 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004907 data)
4908
Simon Glass27a7f772021-03-21 18:24:32 +13004909 def testCollectionSection(self):
4910 """Test a collection where a section must be built first"""
4911 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004912 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004913 # building the contents, producing an error is anything is still
4914 # missing.
4915 data = self._DoReadFile('199_collection_section.dts')
4916 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004917 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4918 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004919 data)
4920
Simon Glassf427c5f2021-03-21 18:24:33 +13004921 def testAlignDefault(self):
4922 """Test that default alignment works on sections"""
4923 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004924 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004925 U_BOOT_DATA)
4926 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004927 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004928 # No alignment within the nested section
4929 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4930 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004931 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004932 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004933
Bin Mengc0b15742021-05-10 20:23:33 +08004934 def testPackOpenSBI(self):
4935 """Test that an image with an OpenSBI binary can be created"""
4936 data = self._DoReadFile('201_opensbi.dts')
4937 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4938
Simon Glass76f496d2021-07-06 10:36:37 -06004939 def testSectionsSingleThread(self):
4940 """Test sections without multithreading"""
4941 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004942 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4943 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4944 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004945 self.assertEqual(expected, data)
4946
4947 def testThreadTimeout(self):
4948 """Test handling a thread that takes too long"""
4949 with self.assertRaises(ValueError) as e:
4950 self._DoTestFile('202_section_timeout.dts',
4951 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004952 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004953
Simon Glass748a1d42021-07-06 10:36:41 -06004954 def testTiming(self):
4955 """Test output of timing information"""
4956 data = self._DoReadFile('055_sections.dts')
4957 with test_util.capture_sys_output() as (stdout, stderr):
4958 state.TimingShow()
4959 self.assertIn('read:', stdout.getvalue())
4960 self.assertIn('compress:', stdout.getvalue())
4961
Simon Glassadfb8492021-11-03 21:09:18 -06004962 def testUpdateFdtInElf(self):
4963 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004964 if not elf.ELF_TOOLS:
4965 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004966 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4967 outfile = os.path.join(self._indir, 'u-boot.out')
4968 begin_sym = 'dtb_embed_begin'
4969 end_sym = 'dtb_embed_end'
4970 retcode = self._DoTestFile(
4971 '060_fdt_update.dts', update_dtb=True,
4972 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4973 self.assertEqual(0, retcode)
4974
4975 # Check that the output file does in fact contact a dtb with the binman
4976 # definition in the correct place
4977 syms = elf.GetSymbolFileOffset(infile,
4978 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004979 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004980 dtb_data = data[syms['dtb_embed_begin'].offset:
4981 syms['dtb_embed_end'].offset]
4982
4983 dtb = fdt.Fdt.FromData(dtb_data)
4984 dtb.Scan()
4985 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4986 self.assertEqual({
4987 'image-pos': 0,
4988 'offset': 0,
4989 '_testing:offset': 32,
4990 '_testing:size': 2,
4991 '_testing:image-pos': 32,
4992 'section@0/u-boot:offset': 0,
4993 'section@0/u-boot:size': len(U_BOOT_DATA),
4994 'section@0/u-boot:image-pos': 0,
4995 'section@0:offset': 0,
4996 'section@0:size': 16,
4997 'section@0:image-pos': 0,
4998
4999 'section@1/u-boot:offset': 0,
5000 'section@1/u-boot:size': len(U_BOOT_DATA),
5001 'section@1/u-boot:image-pos': 16,
5002 'section@1:offset': 16,
5003 'section@1:size': 16,
5004 'section@1:image-pos': 16,
5005 'size': 40
5006 }, props)
5007
5008 def testUpdateFdtInElfInvalid(self):
5009 """Test that invalid args are detected with --update-fdt-in-elf"""
5010 with self.assertRaises(ValueError) as e:
5011 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
5012 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
5013 str(e.exception))
5014
5015 def testUpdateFdtInElfNoSyms(self):
5016 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005017 if not elf.ELF_TOOLS:
5018 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005019 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5020 outfile = ''
5021 begin_sym = 'wrong_begin'
5022 end_sym = 'wrong_end'
5023 with self.assertRaises(ValueError) as e:
5024 self._DoTestFile(
5025 '060_fdt_update.dts',
5026 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5027 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5028 str(e.exception))
5029
5030 def testUpdateFdtInElfTooSmall(self):
5031 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005032 if not elf.ELF_TOOLS:
5033 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005034 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5035 outfile = os.path.join(self._indir, 'u-boot.out')
5036 begin_sym = 'dtb_embed_begin'
5037 end_sym = 'dtb_embed_end'
5038 with self.assertRaises(ValueError) as e:
5039 self._DoTestFile(
5040 '060_fdt_update.dts', update_dtb=True,
5041 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5042 self.assertRegex(
5043 str(e.exception),
5044 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5045
Simon Glass88e04da2021-11-23 11:03:42 -07005046 def testVersion(self):
5047 """Test we can get the binman version"""
5048 version = '(unreleased)'
5049 self.assertEqual(version, state.GetVersion(self._indir))
5050
5051 with self.assertRaises(SystemExit):
5052 with test_util.capture_sys_output() as (_, stderr):
5053 self._DoBinman('-V')
5054 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5055
5056 # Try running the tool too, just to be safe
5057 result = self._RunBinman('-V')
5058 self.assertEqual('Binman %s\n' % version, result.stderr)
5059
5060 # Set up a version file to make sure that works
5061 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005062 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005063 binary=False)
5064 self.assertEqual(version, state.GetVersion(self._indir))
5065
Simon Glass637958f2021-11-23 21:09:50 -07005066 def testAltFormat(self):
5067 """Test that alternative formats can be used to extract"""
5068 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5069
5070 try:
5071 tmpdir, updated_fname = self._SetupImageInTmpdir()
5072 with test_util.capture_sys_output() as (stdout, _):
5073 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5074 self.assertEqual(
5075 '''Flag (-F) Entry type Description
5076fdt fdtmap Extract the devicetree blob from the fdtmap
5077''',
5078 stdout.getvalue())
5079
5080 dtb = os.path.join(tmpdir, 'fdt.dtb')
5081 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5082 dtb, 'fdtmap')
5083
5084 # Check that we can read it and it can be scanning, meaning it does
5085 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005086 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005087 dtb = fdt.Fdt.FromData(data)
5088 dtb.Scan()
5089
5090 # Now check u-boot which has no alt_format
5091 fname = os.path.join(tmpdir, 'fdt.dtb')
5092 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5093 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005094 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005095 self.assertEqual(U_BOOT_DATA, data)
5096
5097 finally:
5098 shutil.rmtree(tmpdir)
5099
Simon Glass0b00ae62021-11-23 21:09:52 -07005100 def testExtblobList(self):
5101 """Test an image with an external blob list"""
5102 data = self._DoReadFile('215_blob_ext_list.dts')
5103 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5104
5105 def testExtblobListMissing(self):
5106 """Test an image with a missing external blob"""
5107 with self.assertRaises(ValueError) as e:
5108 self._DoReadFile('216_blob_ext_list_missing.dts')
5109 self.assertIn("Filename 'missing-file' not found in input path",
5110 str(e.exception))
5111
5112 def testExtblobListMissingOk(self):
5113 """Test an image with an missing external blob that is allowed"""
5114 with test_util.capture_sys_output() as (stdout, stderr):
5115 self._DoTestFile('216_blob_ext_list_missing.dts',
5116 allow_missing=True)
5117 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005118 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005119
Simon Glass3efb2972021-11-23 21:08:59 -07005120 def testFip(self):
5121 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5122 data = self._DoReadFile('203_fip.dts')
5123 hdr, fents = fip_util.decode_fip(data)
5124 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5125 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5126 self.assertEqual(0x123, hdr.flags)
5127
5128 self.assertEqual(2, len(fents))
5129
5130 fent = fents[0]
5131 self.assertEqual(
5132 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5133 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5134 self.assertEqual('soc-fw', fent.fip_type)
5135 self.assertEqual(0x88, fent.offset)
5136 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5137 self.assertEqual(0x123456789abcdef, fent.flags)
5138 self.assertEqual(ATF_BL31_DATA, fent.data)
5139 self.assertEqual(True, fent.valid)
5140
5141 fent = fents[1]
5142 self.assertEqual(
5143 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5144 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5145 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5146 self.assertEqual(0x8c, fent.offset)
5147 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5148 self.assertEqual(0, fent.flags)
5149 self.assertEqual(ATF_BL2U_DATA, fent.data)
5150 self.assertEqual(True, fent.valid)
5151
5152 def testFipOther(self):
5153 """Basic FIP with something that isn't a external blob"""
5154 data = self._DoReadFile('204_fip_other.dts')
5155 hdr, fents = fip_util.decode_fip(data)
5156
5157 self.assertEqual(2, len(fents))
5158 fent = fents[1]
5159 self.assertEqual('rot-cert', fent.fip_type)
5160 self.assertEqual(b'aa', fent.data)
5161
Simon Glass3efb2972021-11-23 21:08:59 -07005162 def testFipNoType(self):
5163 """FIP with an entry of an unknown type"""
5164 with self.assertRaises(ValueError) as e:
5165 self._DoReadFile('205_fip_no_type.dts')
5166 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5167 str(e.exception))
5168
5169 def testFipUuid(self):
5170 """Basic FIP with a manual uuid"""
5171 data = self._DoReadFile('206_fip_uuid.dts')
5172 hdr, fents = fip_util.decode_fip(data)
5173
5174 self.assertEqual(2, len(fents))
5175 fent = fents[1]
5176 self.assertEqual(None, fent.fip_type)
5177 self.assertEqual(
5178 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5179 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5180 fent.uuid)
5181 self.assertEqual(U_BOOT_DATA, fent.data)
5182
5183 def testFipLs(self):
5184 """Test listing a FIP"""
5185 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5186 hdr, fents = fip_util.decode_fip(data)
5187
5188 try:
5189 tmpdir, updated_fname = self._SetupImageInTmpdir()
5190 with test_util.capture_sys_output() as (stdout, stderr):
5191 self._DoBinman('ls', '-i', updated_fname)
5192 finally:
5193 shutil.rmtree(tmpdir)
5194 lines = stdout.getvalue().splitlines()
5195 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005196'Name Image-pos Size Entry-type Offset Uncomp-size',
5197'--------------------------------------------------------------',
5198'image 0 2d3 section 0',
5199' atf-fip 0 90 atf-fip 0',
5200' soc-fw 88 4 blob-ext 88',
5201' u-boot 8c 4 u-boot 8c',
5202' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005203]
5204 self.assertEqual(expected, lines)
5205
5206 image = control.images['image']
5207 entries = image.GetEntries()
5208 fdtmap = entries['fdtmap']
5209
5210 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5211 magic = fdtmap_data[:8]
5212 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005213 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005214
5215 fdt_data = fdtmap_data[16:]
5216 dtb = fdt.Fdt.FromData(fdt_data)
5217 dtb.Scan()
5218 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5219 self.assertEqual({
5220 'atf-fip/soc-fw:image-pos': 136,
5221 'atf-fip/soc-fw:offset': 136,
5222 'atf-fip/soc-fw:size': 4,
5223 'atf-fip/u-boot:image-pos': 140,
5224 'atf-fip/u-boot:offset': 140,
5225 'atf-fip/u-boot:size': 4,
5226 'atf-fip:image-pos': 0,
5227 'atf-fip:offset': 0,
5228 'atf-fip:size': 144,
5229 'image-pos': 0,
5230 'offset': 0,
5231 'fdtmap:image-pos': fdtmap.image_pos,
5232 'fdtmap:offset': fdtmap.offset,
5233 'fdtmap:size': len(fdtmap_data),
5234 'size': len(data),
5235 }, props)
5236
5237 def testFipExtractOneEntry(self):
5238 """Test extracting a single entry fron an FIP"""
5239 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005240 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005241 fname = os.path.join(self._indir, 'output.extact')
5242 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005243 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005244 self.assertEqual(U_BOOT_DATA, data)
5245
5246 def testFipReplace(self):
5247 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005248 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005249 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005250 updated_fname = tools.get_output_filename('image-updated.bin')
5251 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005252 entry_name = 'atf-fip/u-boot'
5253 control.WriteEntry(updated_fname, entry_name, expected,
5254 allow_resize=True)
5255 actual = control.ReadEntry(updated_fname, entry_name)
5256 self.assertEqual(expected, actual)
5257
Simon Glass80025522022-01-29 14:14:04 -07005258 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005259 hdr, fents = fip_util.decode_fip(new_data)
5260
5261 self.assertEqual(2, len(fents))
5262
5263 # Check that the FIP entry is updated
5264 fent = fents[1]
5265 self.assertEqual(0x8c, fent.offset)
5266 self.assertEqual(len(expected), fent.size)
5267 self.assertEqual(0, fent.flags)
5268 self.assertEqual(expected, fent.data)
5269 self.assertEqual(True, fent.valid)
5270
5271 def testFipMissing(self):
5272 with test_util.capture_sys_output() as (stdout, stderr):
5273 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5274 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005275 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005276
5277 def testFipSize(self):
5278 """Test a FIP with a size property"""
5279 data = self._DoReadFile('210_fip_size.dts')
5280 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5281 hdr, fents = fip_util.decode_fip(data)
5282 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5283 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5284
5285 self.assertEqual(1, len(fents))
5286
5287 fent = fents[0]
5288 self.assertEqual('soc-fw', fent.fip_type)
5289 self.assertEqual(0x60, fent.offset)
5290 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5291 self.assertEqual(ATF_BL31_DATA, fent.data)
5292 self.assertEqual(True, fent.valid)
5293
5294 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005295 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005296
5297 def testFipBadAlign(self):
5298 """Test that an invalid alignment value in a FIP is detected"""
5299 with self.assertRaises(ValueError) as e:
5300 self._DoTestFile('211_fip_bad_align.dts')
5301 self.assertIn(
5302 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5303 str(e.exception))
5304
5305 def testFipCollection(self):
5306 """Test using a FIP in a collection"""
5307 data = self._DoReadFile('212_fip_collection.dts')
5308 entry1 = control.images['image'].GetEntries()['collection']
5309 data1 = data[:entry1.size]
5310 hdr1, fents2 = fip_util.decode_fip(data1)
5311
5312 entry2 = control.images['image'].GetEntries()['atf-fip']
5313 data2 = data[entry2.offset:entry2.offset + entry2.size]
5314 hdr1, fents2 = fip_util.decode_fip(data2)
5315
5316 # The 'collection' entry should have U-Boot included at the end
5317 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5318 self.assertEqual(data1, data2 + U_BOOT_DATA)
5319 self.assertEqual(U_BOOT_DATA, data1[-4:])
5320
5321 # There should be a U-Boot after the final FIP
5322 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005323
Simon Glassccae6862022-01-12 13:10:35 -07005324 def testFakeBlob(self):
5325 """Test handling of faking an external blob"""
5326 with test_util.capture_sys_output() as (stdout, stderr):
5327 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5328 allow_fake_blobs=True)
5329 err = stderr.getvalue()
5330 self.assertRegex(
5331 err,
5332 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005333
Simon Glassceb5f912022-01-09 20:13:46 -07005334 def testExtblobListFaked(self):
5335 """Test an extblob with missing external blob that are faked"""
5336 with test_util.capture_sys_output() as (stdout, stderr):
5337 self._DoTestFile('216_blob_ext_list_missing.dts',
5338 allow_fake_blobs=True)
5339 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005340 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005341
Simon Glass162017b2022-01-09 20:13:57 -07005342 def testListBintools(self):
5343 args = ['tool', '--list']
5344 with test_util.capture_sys_output() as (stdout, _):
5345 self._DoBinman(*args)
5346 out = stdout.getvalue().splitlines()
5347 self.assertTrue(len(out) >= 2)
5348
5349 def testFetchBintools(self):
5350 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005351 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005352 raise urllib.error.URLError('my error')
5353
5354 args = ['tool']
5355 with self.assertRaises(ValueError) as e:
5356 self._DoBinman(*args)
5357 self.assertIn("Invalid arguments to 'tool' subcommand",
5358 str(e.exception))
5359
5360 args = ['tool', '--fetch']
5361 with self.assertRaises(ValueError) as e:
5362 self._DoBinman(*args)
5363 self.assertIn('Please specify bintools to fetch', str(e.exception))
5364
5365 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005366 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005367 side_effect=fail_download):
5368 with test_util.capture_sys_output() as (stdout, _):
5369 self._DoBinman(*args)
5370 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5371
Simon Glass620c4462022-01-09 20:14:11 -07005372 def testBintoolDocs(self):
5373 """Test for creation of bintool documentation"""
5374 with test_util.capture_sys_output() as (stdout, stderr):
5375 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5376 self.assertTrue(len(stdout.getvalue()) > 0)
5377
5378 def testBintoolDocsMissing(self):
5379 """Test handling of missing bintool documentation"""
5380 with self.assertRaises(ValueError) as e:
5381 with test_util.capture_sys_output() as (stdout, stderr):
5382 control.write_bintool_docs(
5383 control.bintool.Bintool.get_tool_list(), 'mkimage')
5384 self.assertIn('Documentation is missing for modules: mkimage',
5385 str(e.exception))
5386
Jan Kiszka58c407f2022-01-28 20:37:53 +01005387 def testListWithGenNode(self):
5388 """Check handling of an FDT map when the section cannot be found"""
5389 entry_args = {
5390 'of-list': 'test-fdt1 test-fdt2',
5391 }
5392 data = self._DoReadFileDtb(
5393 '219_fit_gennode.dts',
5394 entry_args=entry_args,
5395 use_real_dtb=True,
5396 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5397
5398 try:
5399 tmpdir, updated_fname = self._SetupImageInTmpdir()
5400 with test_util.capture_sys_output() as (stdout, stderr):
5401 self._RunBinman('ls', '-i', updated_fname)
5402 finally:
5403 shutil.rmtree(tmpdir)
5404
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005405 def testFitSubentryUsesBintool(self):
5406 """Test that binman FIT subentries can use bintools"""
5407 command.test_result = self._HandleGbbCommand
5408 entry_args = {
5409 'keydir': 'devkeys',
5410 'bmpblk': 'bmpblk.bin',
5411 }
5412 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5413 entry_args=entry_args)
5414
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005415 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5416 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005417 self.assertIn(expected, data)
5418
5419 def testFitSubentryMissingBintool(self):
5420 """Test that binman reports missing bintools for FIT subentries"""
5421 entry_args = {
5422 'keydir': 'devkeys',
5423 }
5424 with test_util.capture_sys_output() as (_, stderr):
5425 self._DoTestFile('220_fit_subentry_bintool.dts',
5426 force_missing_bintools='futility', entry_args=entry_args)
5427 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005428 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005429
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005430 def testFitSubentryHashSubnode(self):
5431 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005432 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005433 data, _, _, out_dtb_name = self._DoReadFileDtb(
5434 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5435
5436 mkimage_dtb = fdt.Fdt.FromData(data)
5437 mkimage_dtb.Scan()
5438 binman_dtb = fdt.Fdt(out_dtb_name)
5439 binman_dtb.Scan()
5440
5441 # Check that binman didn't add hash values
5442 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5443 self.assertNotIn('value', fnode.props)
5444
5445 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5446 self.assertNotIn('value', fnode.props)
5447
5448 # Check that mkimage added hash values
5449 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5450 self.assertIn('value', fnode.props)
5451
5452 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5453 self.assertIn('value', fnode.props)
5454
Roger Quadros5cdcea02022-02-19 20:50:04 +02005455 def testPackTeeOs(self):
5456 """Test that an image with an TEE binary can be created"""
5457 data = self._DoReadFile('222_tee_os.dts')
5458 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5459
Neha Malcom Francis59be2552023-12-05 15:12:18 +05305460 def testPackTiDm(self):
5461 """Test that an image with a TI DM binary can be created"""
5462 data = self._DoReadFile('225_ti_dm.dts')
5463 self.assertEqual(TI_DM_DATA, data[:len(TI_DM_DATA)])
5464
Simon Glass912339f2022-02-08 11:50:03 -07005465 def testFitFdtOper(self):
5466 """Check handling of a specified FIT operation"""
5467 entry_args = {
5468 'of-list': 'test-fdt1 test-fdt2',
5469 'default-dt': 'test-fdt2',
5470 }
5471 self._DoReadFileDtb(
5472 '223_fit_fdt_oper.dts',
5473 entry_args=entry_args,
5474 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5475
5476 def testFitFdtBadOper(self):
5477 """Check handling of an FDT map when the section cannot be found"""
5478 with self.assertRaises(ValueError) as exc:
5479 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005480 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005481 str(exc.exception))
5482
Simon Glassdd156a42022-03-05 20:18:59 -07005483 def test_uses_expand_size(self):
5484 """Test that the 'expand-size' property cannot be used anymore"""
5485 with self.assertRaises(ValueError) as e:
5486 data = self._DoReadFile('225_expand_size_bad.dts')
5487 self.assertIn(
5488 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5489 str(e.exception))
5490
Simon Glass5f423422022-03-05 20:19:12 -07005491 def testFitSplitElf(self):
5492 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005493 if not elf.ELF_TOOLS:
5494 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005495 entry_args = {
5496 'of-list': 'test-fdt1 test-fdt2',
5497 'default-dt': 'test-fdt2',
5498 'atf-bl31-path': 'bl31.elf',
5499 'tee-os-path': 'tee.elf',
5500 }
5501 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5502 data = self._DoReadFileDtb(
5503 '226_fit_split_elf.dts',
5504 entry_args=entry_args,
5505 extra_indirs=[test_subdir])[0]
5506
5507 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5508 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5509
5510 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5511 'data', 'load'}
5512 dtb = fdt.Fdt.FromData(fit_data)
5513 dtb.Scan()
5514
5515 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5516 segments, entry = elf.read_loadable_segments(elf_data)
5517
5518 # We assume there are two segments
5519 self.assertEquals(2, len(segments))
5520
5521 atf1 = dtb.GetNode('/images/atf-1')
5522 _, start, data = segments[0]
5523 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5524 self.assertEqual(entry,
5525 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5526 self.assertEqual(start,
5527 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5528 self.assertEqual(data, atf1.props['data'].bytes)
5529
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005530 hash_node = atf1.FindNode('hash')
5531 self.assertIsNotNone(hash_node)
5532 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5533
Simon Glass5f423422022-03-05 20:19:12 -07005534 atf2 = dtb.GetNode('/images/atf-2')
5535 self.assertEqual(base_keys, atf2.props.keys())
5536 _, start, data = segments[1]
5537 self.assertEqual(start,
5538 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5539 self.assertEqual(data, atf2.props['data'].bytes)
5540
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005541 hash_node = atf2.FindNode('hash')
5542 self.assertIsNotNone(hash_node)
5543 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5544
5545 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5546 self.assertIsNotNone(hash_node)
5547 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5548
Simon Glass5f423422022-03-05 20:19:12 -07005549 conf = dtb.GetNode('/configurations')
5550 self.assertEqual({'default'}, conf.props.keys())
5551
5552 for subnode in conf.subnodes:
5553 self.assertEqual({'description', 'fdt', 'loadables'},
5554 subnode.props.keys())
5555 self.assertEqual(
5556 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5557 fdt_util.GetStringList(subnode, 'loadables'))
5558
5559 def _check_bad_fit(self, dts):
5560 """Check a bad FIT
5561
5562 This runs with the given dts and returns the assertion raised
5563
5564 Args:
5565 dts (str): dts filename to use
5566
5567 Returns:
5568 str: Assertion string raised
5569 """
5570 entry_args = {
5571 'of-list': 'test-fdt1 test-fdt2',
5572 'default-dt': 'test-fdt2',
5573 'atf-bl31-path': 'bl31.elf',
5574 'tee-os-path': 'tee.elf',
5575 }
5576 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5577 with self.assertRaises(ValueError) as exc:
5578 self._DoReadFileDtb(dts, entry_args=entry_args,
5579 extra_indirs=[test_subdir])[0]
5580 return str(exc.exception)
5581
5582 def testFitSplitElfBadElf(self):
5583 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005584 if not elf.ELF_TOOLS:
5585 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005586 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5587 entry_args = {
5588 'of-list': 'test-fdt1 test-fdt2',
5589 'default-dt': 'test-fdt2',
5590 'atf-bl31-path': 'bad.elf',
5591 'tee-os-path': 'tee.elf',
5592 }
5593 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5594 with self.assertRaises(ValueError) as exc:
5595 self._DoReadFileDtb(
5596 '226_fit_split_elf.dts',
5597 entry_args=entry_args,
5598 extra_indirs=[test_subdir])[0]
5599 self.assertIn(
5600 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5601 str(exc.exception))
5602
Simon Glass5f423422022-03-05 20:19:12 -07005603 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005604 """Test an split-elf FIT with a missing ELF file
5605
5606 Args:
5607 kwargs (dict of str): Arguments to pass to _DoTestFile()
5608
5609 Returns:
5610 tuple:
5611 str: stdout result
5612 str: stderr result
5613 """
Simon Glass5f423422022-03-05 20:19:12 -07005614 entry_args = {
5615 'of-list': 'test-fdt1 test-fdt2',
5616 'default-dt': 'test-fdt2',
5617 'atf-bl31-path': 'bl31.elf',
5618 'tee-os-path': 'missing.elf',
5619 }
5620 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5621 with test_util.capture_sys_output() as (stdout, stderr):
5622 self._DoTestFile(
5623 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005624 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5625 out = stdout.getvalue()
5626 err = stderr.getvalue()
5627 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005628
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005629 def testFitSplitElfBadDirective(self):
5630 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5631 if not elf.ELF_TOOLS:
5632 self.skipTest('Python elftools not available')
5633 err = self._check_bad_fit('227_fit_bad_dir.dts')
5634 self.assertIn(
5635 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5636 err)
5637
5638 def testFitSplitElfBadDirectiveConfig(self):
5639 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5640 if not elf.ELF_TOOLS:
5641 self.skipTest('Python elftools not available')
5642 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5643 self.assertEqual(
5644 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5645 err)
5646
5647
Simon Glass5f423422022-03-05 20:19:12 -07005648 def testFitSplitElfMissing(self):
5649 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005650 if not elf.ELF_TOOLS:
5651 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005652 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005653 self.assertRegex(
5654 err,
5655 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005656 self.assertNotRegex(out, '.*Faked blob.*')
5657 fname = tools.get_output_filename('binman-fake/missing.elf')
5658 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005659
5660 def testFitSplitElfFaked(self):
5661 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005662 if not elf.ELF_TOOLS:
5663 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005664 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005665 self.assertRegex(
5666 err,
5667 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005668 self.assertRegex(
5669 out,
5670 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5671 fname = tools.get_output_filename('binman-fake/missing.elf')
5672 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005673
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005674 def testMkimageMissingBlob(self):
5675 """Test using mkimage to build an image"""
5676 with test_util.capture_sys_output() as (stdout, stderr):
5677 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5678 allow_fake_blobs=True)
5679 err = stderr.getvalue()
5680 self.assertRegex(
5681 err,
5682 "Image '.*' has faked external blobs and is non-functional: .*")
5683
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005684 def testPreLoad(self):
5685 """Test an image with a pre-load header"""
5686 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005687 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005688 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005689 data = self._DoReadFileDtb(
5690 '230_pre_load.dts', entry_args=entry_args,
5691 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005692 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5693 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5694 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Simon Glasse2dfb962023-07-24 09:19:57 -06005695
5696 def testPreLoadNoKey(self):
5697 """Test an image with a pre-load heade0r with missing key"""
5698 with self.assertRaises(FileNotFoundError) as exc:
5699 self._DoReadFile('230_pre_load.dts')
5700 self.assertIn("No such file or directory: 'dev.key'",
5701 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005702
5703 def testPreLoadPkcs(self):
5704 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005705 entry_args = {
5706 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5707 }
5708 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5709 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005710 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5711 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5712 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5713
5714 def testPreLoadPss(self):
5715 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005716 entry_args = {
5717 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5718 }
5719 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5720 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005721 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5722 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5723 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5724
5725 def testPreLoadInvalidPadding(self):
5726 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005727 entry_args = {
5728 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5729 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005730 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005731 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5732 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005733
5734 def testPreLoadInvalidSha(self):
5735 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005736 entry_args = {
5737 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5738 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005739 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005740 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5741 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005742
5743 def testPreLoadInvalidAlgo(self):
5744 """Test an image with a pre-load header with an invalid algo"""
5745 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005746 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005747
5748 def testPreLoadInvalidKey(self):
5749 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005750 entry_args = {
5751 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5752 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005753 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005754 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5755 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005756
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005757 def _CheckSafeUniqueNames(self, *images):
5758 """Check all entries of given images for unsafe unique names"""
5759 for image in images:
5760 entries = {}
5761 image._CollectEntries(entries, {}, image)
5762 for entry in entries.values():
5763 uniq = entry.GetUniqueName()
5764
5765 # Used as part of a filename, so must not be absolute paths.
5766 self.assertFalse(os.path.isabs(uniq))
5767
5768 def testSafeUniqueNames(self):
5769 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005770 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005771
5772 orig_image = control.images['image']
5773 image_fname = tools.get_output_filename('image.bin')
5774 image = Image.FromFile(image_fname)
5775
5776 self._CheckSafeUniqueNames(orig_image, image)
5777
5778 def testSafeUniqueNamesMulti(self):
5779 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005780 data = self._DoReadFileRealDtb('238_unique_names_multi.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
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005788 def testReplaceCmdWithBintool(self):
5789 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005790 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005791 expected = U_BOOT_DATA + b'aa'
5792 self.assertEqual(expected, data[:len(expected)])
5793
5794 try:
5795 tmpdir, updated_fname = self._SetupImageInTmpdir()
5796 fname = os.path.join(tmpdir, 'update-testing.bin')
5797 tools.write_file(fname, b'zz')
5798 self._DoBinman('replace', '-i', updated_fname,
5799 '_testing', '-f', fname)
5800
5801 data = tools.read_file(updated_fname)
5802 expected = U_BOOT_DATA + b'zz'
5803 self.assertEqual(expected, data[:len(expected)])
5804 finally:
5805 shutil.rmtree(tmpdir)
5806
5807 def testReplaceCmdOtherWithBintool(self):
5808 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005809 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005810 expected = U_BOOT_DATA + b'aa'
5811 self.assertEqual(expected, data[:len(expected)])
5812
5813 try:
5814 tmpdir, updated_fname = self._SetupImageInTmpdir()
5815 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5816 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5817 self._DoBinman('replace', '-i', updated_fname,
5818 'u-boot', '-f', fname)
5819
5820 data = tools.read_file(updated_fname)
5821 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5822 self.assertEqual(expected, data[:len(expected)])
5823 finally:
5824 shutil.rmtree(tmpdir)
5825
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005826 def testReplaceResizeNoRepackSameSize(self):
5827 """Test replacing entries with same-size data without repacking"""
5828 expected = b'x' * len(U_BOOT_DATA)
5829 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5830 self.assertEqual(expected, data)
5831
5832 path, fdtmap = state.GetFdtContents('fdtmap')
5833 self.assertIsNotNone(path)
5834 self.assertEqual(expected_fdtmap, fdtmap)
5835
5836 def testReplaceResizeNoRepackSmallerSize(self):
5837 """Test replacing entries with smaller-size data without repacking"""
5838 new_data = b'x'
5839 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5840 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5841 self.assertEqual(expected, data)
5842
5843 path, fdtmap = state.GetFdtContents('fdtmap')
5844 self.assertIsNotNone(path)
5845 self.assertEqual(expected_fdtmap, fdtmap)
5846
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005847 def testExtractFit(self):
5848 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005849 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005850 image_fname = tools.get_output_filename('image.bin')
5851
5852 fit_data = control.ReadEntry(image_fname, 'fit')
5853 fit = fdt.Fdt.FromData(fit_data)
5854 fit.Scan()
5855
5856 # Check subentry data inside the extracted fit
5857 for node_path, expected in [
5858 ('/images/kernel', U_BOOT_DATA),
5859 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5860 ('/images/scr-1', COMPRESS_DATA),
5861 ]:
5862 node = fit.GetNode(node_path)
5863 data = fit.GetProps(node)['data'].bytes
5864 self.assertEqual(expected, data)
5865
5866 def testExtractFitSubentries(self):
5867 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005868 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005869 image_fname = tools.get_output_filename('image.bin')
5870
5871 for entry_path, expected in [
5872 ('fit/kernel', U_BOOT_DATA),
5873 ('fit/kernel/u-boot', U_BOOT_DATA),
5874 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5875 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5876 ('fit/scr-1', COMPRESS_DATA),
5877 ('fit/scr-1/blob', COMPRESS_DATA),
5878 ]:
5879 data = control.ReadEntry(image_fname, entry_path)
5880 self.assertEqual(expected, data)
5881
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005882 def testReplaceFitSubentryLeafSameSize(self):
5883 """Test replacing a FIT leaf subentry with same-size data"""
5884 new_data = b'x' * len(U_BOOT_DATA)
5885 data, expected_fdtmap, _ = self._RunReplaceCmd(
5886 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005887 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005888 self.assertEqual(new_data, data)
5889
5890 path, fdtmap = state.GetFdtContents('fdtmap')
5891 self.assertIsNotNone(path)
5892 self.assertEqual(expected_fdtmap, fdtmap)
5893
5894 def testReplaceFitSubentryLeafBiggerSize(self):
5895 """Test replacing a FIT leaf subentry with bigger-size data"""
5896 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5897 data, expected_fdtmap, _ = self._RunReplaceCmd(
5898 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005899 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005900 self.assertEqual(new_data, data)
5901
5902 # Will be repacked, so fdtmap must change
5903 path, fdtmap = state.GetFdtContents('fdtmap')
5904 self.assertIsNotNone(path)
5905 self.assertNotEqual(expected_fdtmap, fdtmap)
5906
5907 def testReplaceFitSubentryLeafSmallerSize(self):
5908 """Test replacing a FIT leaf subentry with smaller-size data"""
5909 new_data = b'x'
5910 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5911 data, expected_fdtmap, _ = self._RunReplaceCmd(
5912 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005913 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005914 self.assertEqual(expected, data)
5915
5916 path, fdtmap = state.GetFdtContents('fdtmap')
5917 self.assertIsNotNone(path)
5918 self.assertEqual(expected_fdtmap, fdtmap)
5919
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005920 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005921 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005922 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005923 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5924 new_data, dts='241_replace_section_simple.dts')
5925 self.assertEqual(new_data, data)
5926
5927 entries = image.GetEntries()
5928 self.assertIn('section', entries)
5929 entry = entries['section']
5930 self.assertEqual(len(new_data), entry.size)
5931
5932 def testReplaceSectionLarger(self):
5933 """Test replacing a simple section with larger data"""
5934 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5935 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5936 new_data, dts='241_replace_section_simple.dts')
5937 self.assertEqual(new_data, data)
5938
5939 entries = image.GetEntries()
5940 self.assertIn('section', entries)
5941 entry = entries['section']
5942 self.assertEqual(len(new_data), entry.size)
5943 fentry = entries['fdtmap']
5944 self.assertEqual(entry.offset + entry.size, fentry.offset)
5945
5946 def testReplaceSectionSmaller(self):
5947 """Test replacing a simple section with smaller data"""
5948 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5949 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5950 new_data, dts='241_replace_section_simple.dts')
5951 self.assertEqual(new_data, data)
5952
5953 # The new size is the same as the old, just with a pad byte at the end
5954 entries = image.GetEntries()
5955 self.assertIn('section', entries)
5956 entry = entries['section']
5957 self.assertEqual(len(new_data), entry.size)
5958
5959 def testReplaceSectionSmallerAllow(self):
5960 """Test failing to replace a simple section with smaller data"""
5961 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5962 try:
5963 state.SetAllowEntryContraction(True)
5964 with self.assertRaises(ValueError) as exc:
5965 self._RunReplaceCmd('section', new_data,
5966 dts='241_replace_section_simple.dts')
5967 finally:
5968 state.SetAllowEntryContraction(False)
5969
5970 # Since we have no information about the position of things within the
5971 # section, we cannot adjust the position of /section-u-boot so it ends
5972 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06005973 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07005974 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5975 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06005976 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005977
Simon Glass8fbca772022-08-13 11:40:48 -06005978 def testMkimageImagename(self):
5979 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005980 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005981 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005982
5983 # Check that the data appears in the file somewhere
5984 self.assertIn(U_BOOT_SPL_DATA, data)
5985
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005986 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005987 name = data[0x20:0x40]
5988
5989 # Build the filename that we expect to be placed in there, by virtue of
5990 # the -n paraameter
5991 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5992
5993 # Check that the image name is set to the temporary filename used
5994 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5995
Simon Glassb1669752022-08-13 11:40:49 -06005996 def testMkimageImage(self):
5997 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005998 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005999 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006000
6001 # Check that the data appears in the file somewhere
6002 self.assertIn(U_BOOT_SPL_DATA, data)
6003
Simon Glassbb7d3bb2022-09-06 20:26:52 -06006004 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06006005 name = data[0x20:0x40]
6006
6007 # Build the filename that we expect to be placed in there, by virtue of
6008 # the -n paraameter
6009 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
6010
6011 # Check that the image name is set to the temporary filename used
6012 self.assertEqual(expect.encode('utf-8')[:0x20], name)
6013
6014 # Check the corect data is in the imagename file
6015 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
6016
6017 def testMkimageImageNoContent(self):
6018 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006019 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006020 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006021 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006022 self.assertIn('Could not complete processing of contents',
6023 str(exc.exception))
6024
6025 def testMkimageImageBad(self):
6026 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006027 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06006028 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006029 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06006030 self.assertIn('Cannot use both imagename node and data-to-imagename',
6031 str(exc.exception))
6032
Simon Glassbd5cd882022-08-13 11:40:50 -06006033 def testCollectionOther(self):
6034 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006035 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006036 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6037 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6038 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6039 data)
6040
6041 def testMkimageCollection(self):
6042 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006043 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006044 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006045 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6046 self.assertEqual(expect, data[:len(expect)])
6047
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006048 def testCompressDtbPrependInvalid(self):
6049 """Test that invalid header is detected"""
6050 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006051 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006052 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6053 "'u-boot-dtb': 'invalid'", str(e.exception))
6054
6055 def testCompressDtbPrependLength(self):
6056 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006057 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006058 image = control.images['image']
6059 entries = image.GetEntries()
6060 self.assertIn('u-boot-dtb', entries)
6061 u_boot_dtb = entries['u-boot-dtb']
6062 self.assertIn('fdtmap', entries)
6063 fdtmap = entries['fdtmap']
6064
6065 image_fname = tools.get_output_filename('image.bin')
6066 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6067 dtb = fdt.Fdt.FromData(orig)
6068 dtb.Scan()
6069 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6070 expected = {
6071 'u-boot:size': len(U_BOOT_DATA),
6072 'u-boot-dtb:uncomp-size': len(orig),
6073 'u-boot-dtb:size': u_boot_dtb.size,
6074 'fdtmap:size': fdtmap.size,
6075 'size': len(data),
6076 }
6077 self.assertEqual(expected, props)
6078
6079 # Check implementation
6080 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6081 rest = data[len(U_BOOT_DATA):]
6082 comp_data_len = struct.unpack('<I', rest[:4])[0]
6083 comp_data = rest[4:4 + comp_data_len]
6084 orig2 = self._decompress(comp_data)
6085 self.assertEqual(orig, orig2)
6086
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006087 def testInvalidCompress(self):
6088 """Test that invalid compress algorithm is detected"""
6089 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006090 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006091 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6092
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006093 def testCompUtilCompressions(self):
6094 """Test compression algorithms"""
6095 for bintool in self.comp_bintools.values():
6096 self._CheckBintool(bintool)
6097 data = bintool.compress(COMPRESS_DATA)
6098 self.assertNotEqual(COMPRESS_DATA, data)
6099 orig = bintool.decompress(data)
6100 self.assertEquals(COMPRESS_DATA, orig)
6101
6102 def testCompUtilVersions(self):
6103 """Test tool version of compression algorithms"""
6104 for bintool in self.comp_bintools.values():
6105 self._CheckBintool(bintool)
6106 version = bintool.version()
6107 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6108
6109 def testCompUtilPadding(self):
6110 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006111 # Skip zstd because it doesn't support padding
6112 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006113 self._CheckBintool(bintool)
6114 data = bintool.compress(COMPRESS_DATA)
6115 self.assertNotEqual(COMPRESS_DATA, data)
6116 data += tools.get_bytes(0, 64)
6117 orig = bintool.decompress(data)
6118 self.assertEquals(COMPRESS_DATA, orig)
6119
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006120 def testCompressDtbZstd(self):
6121 """Test that zstd compress of device-tree files failed"""
6122 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006123 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006124 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6125 "requires a length header", str(e.exception))
6126
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006127 def testMkimageMultipleDataFiles(self):
6128 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006129 self._SetupSplElf()
6130 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006131 data = self._DoReadFile('252_mkimage_mult_data.dts')
6132 # Size of files are packed in their 4B big-endian format
6133 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6134 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6135 # Size info is always followed by a 4B zero value.
6136 expect += tools.get_bytes(0, 4)
6137 expect += U_BOOT_TPL_DATA
6138 # All but last files are 4B-aligned
6139 align_pad = len(U_BOOT_TPL_DATA) % 4
6140 if align_pad:
6141 expect += tools.get_bytes(0, align_pad)
6142 expect += U_BOOT_SPL_DATA
6143 self.assertEqual(expect, data[-len(expect):])
6144
Marek Vasutf7413f02023-07-18 07:23:58 -06006145 def testMkimageMultipleExpanded(self):
6146 """Test passing multiple files to mkimage in a mkimage entry"""
6147 self._SetupSplElf()
6148 self._SetupTplElf()
6149 entry_args = {
6150 'spl-bss-pad': 'y',
6151 'spl-dtb': 'y',
6152 }
6153 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6154 use_expanded=True, entry_args=entry_args)[0]
6155 pad_len = 10
6156 tpl_expect = U_BOOT_TPL_DATA
6157 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6158 spl_expect += U_BOOT_SPL_DTB_DATA
6159
6160 content = data[0x40:]
6161 lens = struct.unpack('>III', content[:12])
6162
6163 # Size of files are packed in their 4B big-endian format
6164 # Size info is always followed by a 4B zero value.
6165 self.assertEqual(len(tpl_expect), lens[0])
6166 self.assertEqual(len(spl_expect), lens[1])
6167 self.assertEqual(0, lens[2])
6168
6169 rest = content[12:]
6170 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6171
6172 rest = rest[len(tpl_expect):]
6173 align_pad = len(tpl_expect) % 4
6174 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6175 rest = rest[align_pad:]
6176 self.assertEqual(spl_expect, rest)
6177
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006178 def testMkimageMultipleNoContent(self):
6179 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006180 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006181 with self.assertRaises(ValueError) as exc:
6182 self._DoReadFile('253_mkimage_mult_no_content.dts')
6183 self.assertIn('Could not complete processing of contents',
6184 str(exc.exception))
6185
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006186 def testMkimageFilename(self):
6187 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006188 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006189 retcode = self._DoTestFile('254_mkimage_filename.dts')
6190 self.assertEqual(0, retcode)
6191 fname = tools.get_output_filename('mkimage-test.bin')
6192 self.assertTrue(os.path.exists(fname))
6193
Simon Glass56d05412022-02-28 07:16:54 -07006194 def testVpl(self):
6195 """Test that an image with VPL and its device tree can be created"""
6196 # ELF file with a '__bss_size' symbol
6197 self._SetupVplElf()
6198 data = self._DoReadFile('255_u_boot_vpl.dts')
6199 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6200
6201 def testVplNoDtb(self):
6202 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6203 self._SetupVplElf()
6204 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6205 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6206 data[:len(U_BOOT_VPL_NODTB_DATA)])
6207
6208 def testExpandedVpl(self):
6209 """Test that an expanded entry type is selected for TPL when needed"""
6210 self._SetupVplElf()
6211
6212 entry_args = {
6213 'vpl-bss-pad': 'y',
6214 'vpl-dtb': 'y',
6215 }
6216 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6217 entry_args=entry_args)
6218 image = control.images['image']
6219 entries = image.GetEntries()
6220 self.assertEqual(1, len(entries))
6221
6222 # We only have u-boot-vpl, which be expanded
6223 self.assertIn('u-boot-vpl', entries)
6224 entry = entries['u-boot-vpl']
6225 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6226 subent = entry.GetEntries()
6227 self.assertEqual(3, len(subent))
6228 self.assertIn('u-boot-vpl-nodtb', subent)
6229 self.assertIn('u-boot-vpl-bss-pad', subent)
6230 self.assertIn('u-boot-vpl-dtb', subent)
6231
6232 def testVplBssPadMissing(self):
6233 """Test that a missing symbol is detected"""
6234 self._SetupVplElf('u_boot_ucode_ptr')
6235 with self.assertRaises(ValueError) as e:
6236 self._DoReadFile('258_vpl_bss_pad.dts')
6237 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6238 str(e.exception))
6239
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306240 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306241 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306242 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6243 self.assertEqual(0, retcode)
6244 image = control.images['test_image']
6245 fname = tools.get_output_filename('test_image.bin')
6246 sname = tools.get_output_filename('symlink_to_test.bin')
6247 self.assertTrue(os.path.islink(sname))
6248 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006249
Andrew Davis6b463da2023-07-22 00:14:44 +05306250 def testSymlinkOverwrite(self):
6251 """Test that symlinked images can be overwritten"""
6252 testdir = TestFunctional._MakeInputDir('symlinktest')
6253 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6254 # build the same image again in the same directory so that existing symlink is present
6255 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6256 fname = tools.get_output_filename('test_image.bin')
6257 sname = tools.get_output_filename('symlink_to_test.bin')
6258 self.assertTrue(os.path.islink(sname))
6259 self.assertEqual(os.readlink(sname), fname)
6260
Simon Glass37f85de2022-10-20 18:22:47 -06006261 def testSymbolsElf(self):
6262 """Test binman can assign symbols embedded in an ELF file"""
6263 if not elf.ELF_TOOLS:
6264 self.skipTest('Python elftools not available')
6265 self._SetupTplElf('u_boot_binman_syms')
6266 self._SetupVplElf('u_boot_binman_syms')
6267 self._SetupSplElf('u_boot_binman_syms')
6268 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6269 image_fname = tools.get_output_filename('image.bin')
6270
6271 image = control.images['image']
6272 entries = image.GetEntries()
6273
6274 for entry in entries.values():
6275 # No symbols in u-boot and it has faked contents anyway
6276 if entry.name == 'u-boot':
6277 continue
6278 edata = data[entry.image_pos:entry.image_pos + entry.size]
6279 efname = tools.get_output_filename(f'edata-{entry.name}')
6280 tools.write_file(efname, edata)
6281
6282 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6283 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6284 for name, sym in syms.items():
6285 msg = 'test'
6286 val = elf.GetSymbolValue(sym, edata, msg)
6287 entry_m = re_name.match(name)
6288 if entry_m:
6289 ename, prop = entry_m.group(1), entry_m.group(3)
6290 entry, entry_name, prop_name = image.LookupEntry(entries,
6291 name, msg)
6292 if prop_name == 'offset':
6293 expect_val = entry.offset
6294 elif prop_name == 'image_pos':
6295 expect_val = entry.image_pos
6296 elif prop_name == 'size':
6297 expect_val = entry.size
6298 self.assertEqual(expect_val, val)
6299
6300 def testSymbolsElfBad(self):
6301 """Check error when trying to write symbols without the elftools lib"""
6302 if not elf.ELF_TOOLS:
6303 self.skipTest('Python elftools not available')
6304 self._SetupTplElf('u_boot_binman_syms')
6305 self._SetupVplElf('u_boot_binman_syms')
6306 self._SetupSplElf('u_boot_binman_syms')
6307 try:
6308 elf.ELF_TOOLS = False
6309 with self.assertRaises(ValueError) as exc:
6310 self._DoReadFileDtb('260_symbols_elf.dts')
6311 finally:
6312 elf.ELF_TOOLS = True
6313 self.assertIn(
6314 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6315 'Cannot write symbols to an ELF file without Python elftools',
6316 str(exc.exception))
6317
Simon Glassde244162023-01-07 14:07:08 -07006318 def testSectionFilename(self):
6319 """Check writing of section contents to a file"""
6320 data = self._DoReadFile('261_section_fname.dts')
6321 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6322 tools.get_bytes(ord('!'), 7) +
6323 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6324 self.assertEqual(expected, data)
6325
6326 sect_fname = tools.get_output_filename('outfile.bin')
6327 self.assertTrue(os.path.exists(sect_fname))
6328 sect_data = tools.read_file(sect_fname)
6329 self.assertEqual(U_BOOT_DATA, sect_data)
6330
Simon Glass1e9e61c2023-01-07 14:07:12 -07006331 def testAbsent(self):
6332 """Check handling of absent entries"""
6333 data = self._DoReadFile('262_absent.dts')
6334 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6335
Simon Glassad5cfe12023-01-07 14:07:14 -07006336 def testPackTeeOsOptional(self):
6337 """Test that an image with an optional TEE binary can be created"""
6338 entry_args = {
6339 'tee-os-path': 'tee.elf',
6340 }
6341 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6342 entry_args=entry_args)[0]
6343 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6344
6345 def checkFitTee(self, dts, tee_fname):
6346 """Check that a tee-os entry works and returns data
6347
6348 Args:
6349 dts (str): Device tree filename to use
6350 tee_fname (str): filename containing tee-os
6351
6352 Returns:
6353 bytes: Image contents
6354 """
6355 if not elf.ELF_TOOLS:
6356 self.skipTest('Python elftools not available')
6357 entry_args = {
6358 'of-list': 'test-fdt1 test-fdt2',
6359 'default-dt': 'test-fdt2',
6360 'tee-os-path': tee_fname,
6361 }
6362 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6363 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6364 extra_indirs=[test_subdir])[0]
6365 return data
6366
6367 def testFitTeeOsOptionalFit(self):
6368 """Test an image with a FIT with an optional OP-TEE binary"""
6369 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6370
6371 # There should be only one node, holding the data set up in SetUpClass()
6372 # for tee.bin
6373 dtb = fdt.Fdt.FromData(data)
6374 dtb.Scan()
6375 node = dtb.GetNode('/images/tee-1')
6376 self.assertEqual(TEE_ADDR,
6377 fdt_util.fdt32_to_cpu(node.props['load'].value))
6378 self.assertEqual(TEE_ADDR,
6379 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6380 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6381
Jonas Karlmanb2be3e42023-07-18 20:34:36 +00006382 with test_util.capture_sys_output() as (stdout, stderr):
6383 self.checkFitTee('264_tee_os_opt_fit.dts', '')
6384 err = stderr.getvalue()
6385 self.assertRegex(
6386 err,
6387 "Image '.*' is missing optional external blobs but is still functional: tee-os")
6388
Simon Glassad5cfe12023-01-07 14:07:14 -07006389 def testFitTeeOsOptionalFitBad(self):
6390 """Test an image with a FIT with an optional OP-TEE binary"""
6391 with self.assertRaises(ValueError) as exc:
6392 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6393 self.assertIn(
6394 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6395 str(exc.exception))
6396
6397 def testFitTeeOsBad(self):
6398 """Test an OP-TEE binary with wrong formats"""
6399 self.make_tee_bin('tee.bad1', 123)
6400 with self.assertRaises(ValueError) as exc:
6401 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6402 self.assertIn(
6403 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6404 str(exc.exception))
6405
6406 self.make_tee_bin('tee.bad2', 0, b'extra data')
6407 with self.assertRaises(ValueError) as exc:
6408 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6409 self.assertIn(
6410 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6411 str(exc.exception))
6412
Simon Glass63328f12023-01-07 14:07:15 -07006413 def testExtblobOptional(self):
6414 """Test an image with an external blob that is optional"""
6415 with test_util.capture_sys_output() as (stdout, stderr):
6416 data = self._DoReadFile('266_blob_ext_opt.dts')
6417 self.assertEqual(REFCODE_DATA, data)
6418 err = stderr.getvalue()
6419 self.assertRegex(
6420 err,
Jonas Karlman9f96b812023-07-18 20:34:34 +00006421 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass63328f12023-01-07 14:07:15 -07006422
Simon Glass7447a9d2023-01-11 16:10:12 -07006423 def testSectionInner(self):
6424 """Test an inner section with a size"""
6425 data = self._DoReadFile('267_section_inner.dts')
6426 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6427 self.assertEqual(expected, data)
6428
Simon Glassa4948b22023-01-11 16:10:14 -07006429 def testNull(self):
6430 """Test an image with a null entry"""
6431 data = self._DoReadFile('268_null.dts')
6432 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6433
Simon Glassf1ee03b2023-01-11 16:10:16 -07006434 def testOverlap(self):
6435 """Test an image with a overlapping entry"""
6436 data = self._DoReadFile('269_overlap.dts')
6437 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6438
6439 image = control.images['image']
6440 entries = image.GetEntries()
6441
6442 self.assertIn('inset', entries)
6443 inset = entries['inset']
6444 self.assertEqual(1, inset.offset);
6445 self.assertEqual(1, inset.image_pos);
6446 self.assertEqual(2, inset.size);
6447
6448 def testOverlapNull(self):
6449 """Test an image with a null overlap"""
6450 data = self._DoReadFile('270_overlap_null.dts')
6451 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6452
6453 # Check the FMAP
6454 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6455 self.assertEqual(4, fhdr.nareas)
6456 fiter = iter(fentries)
6457
6458 fentry = next(fiter)
6459 self.assertEqual(b'SECTION', fentry.name)
6460 self.assertEqual(0, fentry.offset)
6461 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6462 self.assertEqual(0, fentry.flags)
6463
6464 fentry = next(fiter)
6465 self.assertEqual(b'U_BOOT', fentry.name)
6466 self.assertEqual(0, fentry.offset)
6467 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6468 self.assertEqual(0, fentry.flags)
6469
6470 # Make sure that the NULL entry appears in the FMAP
6471 fentry = next(fiter)
6472 self.assertEqual(b'NULL', fentry.name)
6473 self.assertEqual(1, fentry.offset)
6474 self.assertEqual(2, fentry.size)
6475 self.assertEqual(0, fentry.flags)
6476
6477 fentry = next(fiter)
6478 self.assertEqual(b'FMAP', fentry.name)
6479 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6480
6481 def testOverlapBad(self):
6482 """Test an image with a bad overlapping entry"""
6483 with self.assertRaises(ValueError) as exc:
6484 self._DoReadFile('271_overlap_bad.dts')
6485 self.assertIn(
6486 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6487 str(exc.exception))
6488
6489 def testOverlapNoOffset(self):
6490 """Test an image with a bad overlapping entry"""
6491 with self.assertRaises(ValueError) as exc:
6492 self._DoReadFile('272_overlap_no_size.dts')
6493 self.assertIn(
6494 "Node '/binman/inset': 'fill' entry is missing properties: size",
6495 str(exc.exception))
6496
Simon Glasse0035c92023-01-11 16:10:17 -07006497 def testBlobSymbol(self):
6498 """Test a blob with symbols read from an ELF file"""
6499 elf_fname = self.ElfTestFile('blob_syms')
6500 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6501 TestFunctional._MakeInputFile('blob_syms.bin',
6502 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6503
6504 data = self._DoReadFile('273_blob_symbol.dts')
6505
6506 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6507 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6508 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6509 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6510 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6511
6512 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6513 expected = sym_values
6514 self.assertEqual(expected, data[:len(expected)])
6515
Simon Glass49e9c002023-01-11 16:10:19 -07006516 def testOffsetFromElf(self):
6517 """Test a blob with symbols read from an ELF file"""
6518 elf_fname = self.ElfTestFile('blob_syms')
6519 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6520 TestFunctional._MakeInputFile('blob_syms.bin',
6521 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6522
6523 data = self._DoReadFile('274_offset_from_elf.dts')
6524
6525 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6526 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6527
6528 image = control.images['image']
6529 entries = image.GetEntries()
6530
6531 self.assertIn('inset', entries)
6532 inset = entries['inset']
6533
6534 self.assertEqual(base + 4, inset.offset);
6535 self.assertEqual(base + 4, inset.image_pos);
6536 self.assertEqual(4, inset.size);
6537
6538 self.assertIn('inset2', entries)
6539 inset = entries['inset2']
6540 self.assertEqual(base + 8, inset.offset);
6541 self.assertEqual(base + 8, inset.image_pos);
6542 self.assertEqual(4, inset.size);
6543
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006544 def testFitAlign(self):
6545 """Test an image with an FIT with aligned external data"""
6546 data = self._DoReadFile('275_fit_align.dts')
6547 self.assertEqual(4096, len(data))
6548
6549 dtb = fdt.Fdt.FromData(data)
6550 dtb.Scan()
6551
6552 props = self._GetPropTree(dtb, ['data-position'])
6553 expected = {
6554 'u-boot:data-position': 1024,
6555 'fdt-1:data-position': 2048,
6556 'fdt-2:data-position': 3072,
6557 }
6558 self.assertEqual(expected, props)
6559
Jonas Karlman490f73c2023-01-21 19:02:12 +00006560 def testFitFirmwareLoadables(self):
6561 """Test an image with an FIT that use fit,firmware"""
6562 if not elf.ELF_TOOLS:
6563 self.skipTest('Python elftools not available')
6564 entry_args = {
6565 'of-list': 'test-fdt1',
6566 'default-dt': 'test-fdt1',
6567 'atf-bl31-path': 'bl31.elf',
6568 'tee-os-path': 'missing.bin',
6569 }
6570 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006571 with test_util.capture_sys_output() as (stdout, stderr):
6572 data = self._DoReadFileDtb(
6573 '276_fit_firmware_loadables.dts',
6574 entry_args=entry_args,
6575 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006576
6577 dtb = fdt.Fdt.FromData(data)
6578 dtb.Scan()
6579
6580 node = dtb.GetNode('/configurations/conf-uboot-1')
6581 self.assertEqual('u-boot', node.props['firmware'].value)
6582 self.assertEqual(['atf-1', 'atf-2'],
6583 fdt_util.GetStringList(node, 'loadables'))
6584
6585 node = dtb.GetNode('/configurations/conf-atf-1')
6586 self.assertEqual('atf-1', node.props['firmware'].value)
6587 self.assertEqual(['u-boot', 'atf-2'],
6588 fdt_util.GetStringList(node, 'loadables'))
6589
6590 node = dtb.GetNode('/configurations/conf-missing-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-missing-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-tee-1')
6601 self.assertEqual('atf-1', node.props['firmware'].value)
6602 self.assertEqual(['u-boot', 'atf-2'],
6603 fdt_util.GetStringList(node, 'loadables'))
6604
Simon Glass9a1c7262023-02-22 12:14:49 -07006605 def testTooldir(self):
6606 """Test that we can specify the tooldir"""
6607 with test_util.capture_sys_output() as (stdout, stderr):
6608 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6609 'tool', '-l'))
6610 self.assertEqual('fred', bintool.Bintool.tooldir)
6611
6612 # Check that the toolpath is updated correctly
6613 self.assertEqual(['fred'], tools.tool_search_paths)
6614
6615 # Try with a few toolpaths; the tooldir should be at the end
6616 with test_util.capture_sys_output() as (stdout, stderr):
6617 self.assertEqual(0, self._DoBinman(
6618 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6619 'tool', '-l'))
6620 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6621
Simon Glass49b77e82023-03-02 17:02:44 -07006622 def testReplaceSectionEntry(self):
6623 """Test replacing an entry in a section"""
6624 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6625 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6626 expect_data, dts='241_replace_section_simple.dts')
6627 self.assertEqual(expect_data, entry_data)
6628
6629 entries = image.GetEntries()
6630 self.assertIn('section', entries)
6631 section = entries['section']
6632
6633 sect_entries = section.GetEntries()
6634 self.assertIn('blob', sect_entries)
6635 entry = sect_entries['blob']
6636 self.assertEqual(len(expect_data), entry.size)
6637
6638 fname = tools.get_output_filename('image-updated.bin')
6639 data = tools.read_file(fname)
6640
6641 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6642 self.assertEqual(expect_data, new_blob_data)
6643
6644 self.assertEqual(U_BOOT_DATA,
6645 data[entry.image_pos + len(expect_data):]
6646 [:len(U_BOOT_DATA)])
6647
6648 def testReplaceSectionDeep(self):
6649 """Test replacing an entry in two levels of sections"""
6650 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6651 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6652 'section/section/blob', expect_data,
6653 dts='278_replace_section_deep.dts')
6654 self.assertEqual(expect_data, entry_data)
6655
6656 entries = image.GetEntries()
6657 self.assertIn('section', entries)
6658 section = entries['section']
6659
6660 subentries = section.GetEntries()
6661 self.assertIn('section', subentries)
6662 section = subentries['section']
6663
6664 sect_entries = section.GetEntries()
6665 self.assertIn('blob', sect_entries)
6666 entry = sect_entries['blob']
6667 self.assertEqual(len(expect_data), entry.size)
6668
6669 fname = tools.get_output_filename('image-updated.bin')
6670 data = tools.read_file(fname)
6671
6672 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6673 self.assertEqual(expect_data, new_blob_data)
6674
6675 self.assertEqual(U_BOOT_DATA,
6676 data[entry.image_pos + len(expect_data):]
6677 [:len(U_BOOT_DATA)])
6678
6679 def testReplaceFitSibling(self):
6680 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006681 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006682 fname = TestFunctional._MakeInputFile('once', b'available once')
6683 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6684 os.remove(fname)
6685
6686 try:
6687 tmpdir, updated_fname = self._SetupImageInTmpdir()
6688
6689 fname = os.path.join(tmpdir, 'update-blob')
6690 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6691 tools.write_file(fname, expected)
6692
6693 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6694 data = tools.read_file(updated_fname)
6695 start = len(U_BOOT_DTB_DATA)
6696 self.assertEqual(expected, data[start:start + len(expected)])
6697 map_fname = os.path.join(tmpdir, 'image-updated.map')
6698 self.assertFalse(os.path.exists(map_fname))
6699 finally:
6700 shutil.rmtree(tmpdir)
6701
Simon Glassc3fe97f2023-03-02 17:02:45 -07006702 def testX509Cert(self):
6703 """Test creating an X509 certificate"""
6704 keyfile = self.TestFile('key.key')
6705 entry_args = {
6706 'keyfile': keyfile,
6707 }
6708 data = self._DoReadFileDtb('279_x509_cert.dts',
6709 entry_args=entry_args)[0]
6710 cert = data[:-4]
6711 self.assertEqual(U_BOOT_DATA, data[-4:])
6712
6713 # TODO: verify the signature
6714
6715 def testX509CertMissing(self):
6716 """Test that binman still produces an image if openssl is missing"""
6717 keyfile = self.TestFile('key.key')
6718 entry_args = {
6719 'keyfile': 'keyfile',
6720 }
6721 with test_util.capture_sys_output() as (_, stderr):
6722 self._DoTestFile('279_x509_cert.dts',
6723 force_missing_bintools='openssl',
6724 entry_args=entry_args)
6725 err = stderr.getvalue()
6726 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6727
Jonas Karlman35305492023-02-25 19:01:33 +00006728 def testPackRockchipTpl(self):
6729 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006730 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman35305492023-02-25 19:01:33 +00006731 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6732
Jonas Karlman1016ec72023-02-25 19:01:35 +00006733 def testMkimageMissingBlobMultiple(self):
6734 """Test missing blob with mkimage entry and multiple-data-files"""
6735 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006736 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006737 err = stderr.getvalue()
6738 self.assertIn("is missing external blobs and is non-functional", err)
6739
6740 with self.assertRaises(ValueError) as e:
Simon Glasse3ef5ed2023-07-24 09:19:58 -06006741 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman1016ec72023-02-25 19:01:35 +00006742 self.assertIn("not found in input path", str(e.exception))
6743
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006744 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6745 """Prepare sign environment
6746
6747 Create private and public keys, add pubkey into dtb.
6748
6749 Returns:
6750 Tuple:
6751 FIT container
6752 Image name
6753 Private key
6754 DTB
6755 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006756 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006757 data = self._DoReadFileRealDtb(dts)
6758 updated_fname = tools.get_output_filename('image-updated.bin')
6759 tools.write_file(updated_fname, data)
6760 dtb = tools.get_output_filename('source.dtb')
6761 private_key = tools.get_output_filename('test_key.key')
6762 public_key = tools.get_output_filename('test_key.crt')
6763 fit = tools.get_output_filename('fit.fit')
6764 key_dir = tools.get_output_dir()
6765
6766 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6767 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6768 private_key, '-out', public_key)
6769 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6770 '-n', 'test_key', '-r', 'conf', dtb)
6771
6772 return fit, updated_fname, private_key, dtb
6773
6774 def testSignSimple(self):
6775 """Test that a FIT container can be signed in image"""
6776 is_signed = False
6777 fit, fname, private_key, dtb = self._PrepareSignEnv()
6778
6779 # do sign with private key
6780 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6781 ['fit'])
6782 is_signed = self._CheckSign(fit, dtb)
6783
6784 self.assertEqual(is_signed, True)
6785
6786 def testSignExactFIT(self):
6787 """Test that a FIT container can be signed and replaced in image"""
6788 is_signed = False
6789 fit, fname, private_key, dtb = self._PrepareSignEnv()
6790
6791 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6792 args = []
6793 if self.toolpath:
6794 for path in self.toolpath:
6795 args += ['--toolpath', path]
6796
6797 # do sign with private key
6798 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6799 'sha256,rsa4096', '-f', fit, 'fit')
6800 is_signed = self._CheckSign(fit, dtb)
6801
6802 self.assertEqual(is_signed, True)
6803
6804 def testSignNonFit(self):
6805 """Test a non-FIT entry cannot be signed"""
6806 is_signed = False
6807 fit, fname, private_key, _ = self._PrepareSignEnv(
6808 '281_sign_non_fit.dts')
6809
6810 # do sign with private key
6811 with self.assertRaises(ValueError) as e:
6812 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6813 'sha256,rsa4096', '-f', fit, 'u-boot')
6814 self.assertIn(
6815 "Node '/u-boot': Updating signatures is not supported with this entry type",
6816 str(e.exception))
6817
6818 def testSignMissingMkimage(self):
6819 """Test that FIT signing handles a missing mkimage tool"""
6820 fit, fname, private_key, _ = self._PrepareSignEnv()
6821
6822 # try to sign with a missing mkimage tool
6823 bintool.Bintool.set_missing_list(['mkimage'])
6824 with self.assertRaises(ValueError) as e:
6825 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6826 ['fit'])
6827 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6828
Simon Glass4abf7842023-07-18 07:23:54 -06006829 def testSymbolNoWrite(self):
6830 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006831 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006832 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6833 no_write_symbols=True)
6834
6835 def testSymbolNoWriteExpanded(self):
6836 """Test disabling of symbol writing in expanded entries"""
6837 entry_args = {
6838 'spl-dtb': '1',
6839 }
6840 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6841 U_BOOT_SPL_DTB_DATA, 0x38,
6842 entry_args=entry_args, use_expanded=True,
6843 no_write_symbols=True)
6844
Marek Vasutf7413f02023-07-18 07:23:58 -06006845 def testMkimageSpecial(self):
6846 """Test mkimage ignores special hash-1 node"""
6847 data = self._DoReadFile('283_mkimage_special.dts')
6848
6849 # Just check that the data appears in the file somewhere
6850 self.assertIn(U_BOOT_DATA, data)
6851
Simon Glass2d94c422023-07-18 07:23:59 -06006852 def testFitFdtList(self):
6853 """Test an image with an FIT with the fit,fdt-list-val option"""
6854 entry_args = {
6855 'default-dt': 'test-fdt2',
6856 }
6857 data = self._DoReadFileDtb(
6858 '284_fit_fdt_list.dts',
6859 entry_args=entry_args,
6860 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6861 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6862 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6863
Simon Glass83b8bfe2023-07-18 07:24:01 -06006864 def testSplEmptyBss(self):
6865 """Test an expanded SPL with a zero-size BSS"""
6866 # ELF file with a '__bss_size' symbol
6867 self._SetupSplElf(src_fname='bss_data_zero')
6868
6869 entry_args = {
6870 'spl-bss-pad': 'y',
6871 'spl-dtb': 'y',
6872 }
6873 data = self._DoReadFileDtb('285_spl_expand.dts',
6874 use_expanded=True, entry_args=entry_args)[0]
6875
Simon Glassfc792842023-07-18 07:24:04 -06006876 def testTemplate(self):
6877 """Test using a template"""
6878 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6879 data = self._DoReadFile('286_template.dts')
6880 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6881 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6882 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6883
Simon Glass09490b02023-07-22 21:43:52 -06006884 dtb_fname1 = tools.get_output_filename('u-boot.dtb.tmpl1')
6885 self.assertTrue(os.path.exists(dtb_fname1))
6886 dtb = fdt.Fdt.FromData(tools.read_file(dtb_fname1))
6887 dtb.Scan()
6888 node1 = dtb.GetNode('/binman/template')
6889 self.assertTrue(node1)
6890 vga = dtb.GetNode('/binman/first/intel-vga')
6891 self.assertTrue(vga)
6892
Simon Glass54825e12023-07-22 21:43:56 -06006893 dtb_fname2 = tools.get_output_filename('u-boot.dtb.tmpl2')
6894 self.assertTrue(os.path.exists(dtb_fname2))
6895 dtb2 = fdt.Fdt.FromData(tools.read_file(dtb_fname2))
6896 dtb2.Scan()
6897 node2 = dtb2.GetNode('/binman/template')
6898 self.assertFalse(node2)
6899
Simon Glass9909c112023-07-18 07:24:05 -06006900 def testTemplateBlobMulti(self):
6901 """Test using a template with 'multiple-images' enabled"""
6902 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6903 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6904 retcode = self._DoTestFile('287_template_multi.dts')
6905
6906 self.assertEqual(0, retcode)
6907 image = control.images['image']
6908 image_fname = tools.get_output_filename('my-image.bin')
6909 data = tools.read_file(image_fname)
6910 self.assertEqual(b'blob@@@@other', data)
6911
Simon Glass5dc511b2023-07-18 07:24:06 -06006912 def testTemplateFit(self):
6913 """Test using a template in a FIT"""
6914 fit_data = self._DoReadFile('288_template_fit.dts')
6915 fname = os.path.join(self._indir, 'fit_data.fit')
6916 tools.write_file(fname, fit_data)
6917 out = tools.run('dumpimage', '-l', fname)
6918
Simon Glassaa6e0552023-07-18 07:24:07 -06006919 def testTemplateSection(self):
6920 """Test using a template in a section (not at top level)"""
6921 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6922 data = self._DoReadFile('289_template_section.dts')
6923 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6924 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6925 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6926
Simon Glassf53a7bc2023-07-18 07:24:08 -06006927 def testMkimageSymbols(self):
6928 """Test using mkimage to build an image with symbols in it"""
6929 self._SetupSplElf('u_boot_binman_syms')
6930 data = self._DoReadFile('290_mkimage_sym.dts')
6931
6932 image = control.images['image']
6933 entries = image.GetEntries()
6934 self.assertIn('u-boot', entries)
6935 u_boot = entries['u-boot']
6936
6937 mkim = entries['mkimage']
6938 mkim_entries = mkim.GetEntries()
6939 self.assertIn('u-boot-spl', mkim_entries)
6940 spl = mkim_entries['u-boot-spl']
6941 self.assertIn('u-boot-spl2', mkim_entries)
6942 spl2 = mkim_entries['u-boot-spl2']
6943
6944 # skip the mkimage header and the area sizes
6945 mk_data = data[mkim.offset + 0x40:]
6946 size, term = struct.unpack('>LL', mk_data[:8])
6947
6948 # There should be only one image, so check that the zero terminator is
6949 # present
6950 self.assertEqual(0, term)
6951
6952 content = mk_data[8:8 + size]
6953
6954 # The image should contain the symbols from u_boot_binman_syms.c
6955 # Note that image_pos is adjusted by the base address of the image,
6956 # which is 0x10 in our test image
6957 spl_data = content[:0x18]
6958 content = content[0x1b:]
6959
6960 # After the header is a table of offsets for each image. There should
6961 # only be one image, then a 0 terminator, so figure out the real start
6962 # of the image data
6963 base = 0x40 + 8
6964
6965 # Check symbols in both u-boot-spl and u-boot-spl2
6966 for i in range(2):
6967 vals = struct.unpack('<LLQLL', spl_data)
6968
6969 # The image should contain the symbols from u_boot_binman_syms.c
6970 # Note that image_pos is adjusted by the base address of the image,
6971 # which is 0x10 in our 'u_boot_binman_syms' test image
6972 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6973 self.assertEqual(base, vals[1])
6974 self.assertEqual(spl2.offset, vals[2])
6975 # figure out the internal positions of its components
6976 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6977
6978 # Check that spl and spl2 are actually at the indicated positions
6979 self.assertEqual(
6980 elf.BINMAN_SYM_MAGIC_VALUE,
6981 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6982 self.assertEqual(
6983 elf.BINMAN_SYM_MAGIC_VALUE,
6984 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6985
6986 self.assertEqual(len(U_BOOT_DATA), vals[4])
6987
6988 # Move to next
6989 spl_data = content[:0x18]
6990
Simon Glass86b3e472023-07-22 21:43:57 -06006991 def testTemplatePhandle(self):
6992 """Test using a template in a node containing a phandle"""
6993 entry_args = {
6994 'atf-bl31-path': 'bl31.elf',
6995 }
Simon Glass76ee0ca2023-08-03 17:23:58 -06006996 data = self._DoReadFileDtb('309_template_phandle.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06006997 entry_args=entry_args)
6998 fname = tools.get_output_filename('image.bin')
6999 out = tools.run('dumpimage', '-l', fname)
7000
7001 # We should see the FIT description and one for each of the two images
7002 lines = out.splitlines()
7003 descs = [line.split()[-1] for line in lines if 'escription' in line]
7004 self.assertEqual(['test-desc', 'atf', 'fdt'], descs)
7005
7006 def testTemplatePhandleDup(self):
7007 """Test using a template in a node containing a phandle"""
7008 entry_args = {
7009 'atf-bl31-path': 'bl31.elf',
7010 }
7011 with self.assertRaises(ValueError) as e:
Simon Glass76ee0ca2023-08-03 17:23:58 -06007012 self._DoReadFileDtb('310_template_phandle_dup.dts',
Simon Glass86b3e472023-07-22 21:43:57 -06007013 entry_args=entry_args)
7014 self.assertIn(
7015 'Duplicate phandle 1 in nodes /binman/image/fit/images/atf/atf-bl31 and /binman/image-2/fit/images/atf/atf-bl31',
7016 str(e.exception))
7017
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307018 def testTIBoardConfig(self):
7019 """Test that a schema validated board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007020 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307021 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
7022
7023 def testTIBoardConfigCombined(self):
7024 """Test that a schema validated combined board config file can be generated"""
Simon Glassf1264ba2023-07-24 09:19:59 -06007025 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307026 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
7027 self.assertGreater(data, configlen_noheader)
7028
7029 def testTIBoardConfigNoDataType(self):
7030 """Test that error is thrown when data type is not supported"""
7031 with self.assertRaises(ValueError) as e:
Simon Glassf1264ba2023-07-24 09:19:59 -06007032 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis3b788942023-07-22 00:14:24 +05307033 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07007034
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307035 def testPackTiSecure(self):
7036 """Test that an image with a TI secured binary can be created"""
7037 keyfile = self.TestFile('key.key')
7038 entry_args = {
7039 'keyfile': keyfile,
7040 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007041 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307042 entry_args=entry_args)[0]
7043 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7044
7045 def testPackTiSecureMissingTool(self):
7046 """Test that an image with a TI secured binary (non-functional) can be created
7047 when openssl is missing"""
7048 keyfile = self.TestFile('key.key')
7049 entry_args = {
7050 'keyfile': keyfile,
7051 }
7052 with test_util.capture_sys_output() as (_, stderr):
Simon Glassf1264ba2023-07-24 09:19:59 -06007053 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307054 force_missing_bintools='openssl',
7055 entry_args=entry_args)
7056 err = stderr.getvalue()
7057 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
7058
7059 def testPackTiSecureROM(self):
7060 """Test that a ROM image with a TI secured binary can be created"""
7061 keyfile = self.TestFile('key.key')
7062 entry_args = {
7063 'keyfile': keyfile,
7064 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007065 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307066 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007067 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307068 entry_args=entry_args)[0]
Simon Glassf1264ba2023-07-24 09:19:59 -06007069 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307070 entry_args=entry_args)[0]
7071 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7072 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7073 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7074
7075 def testPackTiSecureROMCombined(self):
7076 """Test that a ROM image with a TI secured binary can be created"""
7077 keyfile = self.TestFile('key.key')
7078 entry_args = {
7079 'keyfile': keyfile,
7080 }
Simon Glassf1264ba2023-07-24 09:19:59 -06007081 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05307082 entry_args=entry_args)[0]
7083 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7084
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007085 def testEncryptedNoAlgo(self):
7086 """Test encrypted node with missing required properties"""
7087 with self.assertRaises(ValueError) as e:
7088 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7089 self.assertIn(
7090 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7091 str(e.exception))
7092
7093 def testEncryptedInvalidIvfile(self):
7094 """Test encrypted node with invalid iv file"""
7095 with self.assertRaises(ValueError) as e:
7096 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7097 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7098 str(e.exception))
7099
7100 def testEncryptedMissingKey(self):
7101 """Test encrypted node with missing key properties"""
7102 with self.assertRaises(ValueError) as e:
7103 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7104 self.assertIn(
7105 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7106 str(e.exception))
7107
7108 def testEncryptedKeySource(self):
7109 """Test encrypted node with key-source property"""
7110 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7111
7112 dtb = fdt.Fdt.FromData(data)
7113 dtb.Scan()
7114
7115 node = dtb.GetNode('/images/u-boot/cipher')
7116 self.assertEqual('algo-name', node.props['algo'].value)
7117 self.assertEqual('key-source-value', node.props['key-source'].value)
7118 self.assertEqual(ENCRYPTED_IV_DATA,
7119 tools.to_bytes(''.join(node.props['iv'].value)))
7120 self.assertNotIn('key', node.props)
7121
7122 def testEncryptedKeyFile(self):
7123 """Test encrypted node with key-filename property"""
7124 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7125
7126 dtb = fdt.Fdt.FromData(data)
7127 dtb.Scan()
7128
7129 node = dtb.GetNode('/images/u-boot/cipher')
7130 self.assertEqual('algo-name', node.props['algo'].value)
7131 self.assertEqual(ENCRYPTED_IV_DATA,
7132 tools.to_bytes(''.join(node.props['iv'].value)))
7133 self.assertEqual(ENCRYPTED_KEY_DATA,
7134 tools.to_bytes(''.join(node.props['key'].value)))
7135 self.assertNotIn('key-source', node.props)
7136
Lukas Funkee901faf2023-07-18 13:53:13 +02007137
7138 def testSplPubkeyDtb(self):
7139 """Test u_boot_spl_pubkey_dtb etype"""
7140 data = tools.read_file(self.TestFile("key.pem"))
7141 self._MakeInputFile("key.crt", data)
7142 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7143 image = control.images['image']
7144 entries = image.GetEntries()
7145 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7146 dtb_data = dtb_entry.GetData()
7147 dtb = fdt.Fdt.FromData(dtb_data)
7148 dtb.Scan()
7149
7150 signature_node = dtb.GetNode('/signature')
7151 self.assertIsNotNone(signature_node)
7152 key_node = signature_node.FindNode("key-key")
7153 self.assertIsNotNone(key_node)
7154 self.assertEqual(fdt_util.GetString(key_node, "required"),
7155 "conf")
7156 self.assertEqual(fdt_util.GetString(key_node, "algo"),
7157 "sha384,rsa4096")
7158 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"),
7159 "key")
Christian Taedcke62ac29a2023-07-17 09:05:54 +02007160
Lukas Funke712e1062023-08-03 17:22:14 +02007161 def testXilinxBootgenSigning(self):
7162 """Test xilinx-bootgen etype"""
7163 bootgen = bintool.Bintool.create('bootgen')
7164 self._CheckBintool(bootgen)
7165 data = tools.read_file(self.TestFile("key.key"))
7166 self._MakeInputFile("psk.pem", data)
7167 self._MakeInputFile("ssk.pem", data)
7168 self._SetupPmuFwlElf()
7169 self._SetupSplElf()
7170 self._DoReadFileRealDtb('307_xilinx_bootgen_sign.dts')
7171 image_fname = tools.get_output_filename('image.bin')
7172
7173 # Read partition header table and check if authentication is enabled
7174 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7175 "-read", image_fname, "pht").splitlines()
7176 attributes = {"authentication": None,
7177 "core": None,
7178 "encryption": None}
7179
7180 for l in bootgen_out:
7181 for a in attributes.keys():
7182 if a in l:
7183 m = re.match(fr".*{a} \[([^]]+)\]", l)
7184 attributes[a] = m.group(1)
7185
7186 self.assertTrue(attributes['authentication'] == "rsa")
7187 self.assertTrue(attributes['core'] == "a53-0")
7188 self.assertTrue(attributes['encryption'] == "no")
7189
7190 def testXilinxBootgenSigningEncryption(self):
7191 """Test xilinx-bootgen etype"""
7192 bootgen = bintool.Bintool.create('bootgen')
7193 self._CheckBintool(bootgen)
7194 data = tools.read_file(self.TestFile("key.key"))
7195 self._MakeInputFile("psk.pem", data)
7196 self._MakeInputFile("ssk.pem", data)
7197 self._SetupPmuFwlElf()
7198 self._SetupSplElf()
7199 self._DoReadFileRealDtb('308_xilinx_bootgen_sign_enc.dts')
7200 image_fname = tools.get_output_filename('image.bin')
7201
7202 # Read boot header in order to verify encryption source and
7203 # encryption parameter
7204 bootgen_out = bootgen.run_cmd("-arch", "zynqmp",
7205 "-read", image_fname, "bh").splitlines()
7206 attributes = {"auth_only":
7207 {"re": r".*auth_only \[([^]]+)\]", "value": None},
7208 "encryption_keystore":
7209 {"re": r" *encryption_keystore \(0x28\) : (.*)",
7210 "value": None},
7211 }
7212
7213 for l in bootgen_out:
7214 for a in attributes.keys():
7215 if a in l:
7216 m = re.match(attributes[a]['re'], l)
7217 attributes[a] = m.group(1)
7218
7219 # Check if fsbl-attribute is set correctly
7220 self.assertTrue(attributes['auth_only'] == "true")
7221 # Check if key is stored in efuse
7222 self.assertTrue(attributes['encryption_keystore'] == "0xa5c3c5a3")
7223
7224 def testXilinxBootgenMissing(self):
7225 """Test that binman still produces an image if bootgen is missing"""
7226 data = tools.read_file(self.TestFile("key.key"))
7227 self._MakeInputFile("psk.pem", data)
7228 self._MakeInputFile("ssk.pem", data)
7229 self._SetupPmuFwlElf()
7230 self._SetupSplElf()
7231 with test_util.capture_sys_output() as (_, stderr):
7232 self._DoTestFile('307_xilinx_bootgen_sign.dts',
7233 force_missing_bintools='bootgen')
7234 err = stderr.getvalue()
7235 self.assertRegex(err,
7236 "Image 'image'.*missing bintools.*: bootgen")
7237
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307238 def _GetCapsuleHeaders(self, data):
7239 """Get the capsule header contents
7240
7241 Args:
7242 data: Capsule file contents
7243
7244 Returns:
7245 Dict:
7246 key: Capsule Header name (str)
7247 value: Header field value (str)
7248 """
7249 capsule_file = os.path.join(self._indir, 'test.capsule')
7250 tools.write_file(capsule_file, data)
7251
7252 out = tools.run('mkeficapsule', '--dump-capsule', capsule_file)
7253 lines = out.splitlines()
7254
7255 re_line = re.compile(r'^([^:\-\t]*)(?:\t*\s*:\s*(.*))?$')
7256 vals = {}
7257 for line in lines:
7258 mat = re_line.match(line)
7259 if mat:
7260 vals[mat.group(1)] = mat.group(2)
7261
7262 return vals
7263
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307264 def _CheckCapsule(self, data, signed_capsule=False, version_check=False,
7265 capoemflags=False):
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307266 fmp_signature = "3153534D" # 'M', 'S', 'S', '1'
7267 fmp_size = "00000010"
7268 fmp_fw_version = "00000002"
7269 capsule_image_index = "00000001"
7270 oemflag = "00018000"
7271 auth_hdr_revision = "00000200"
7272 auth_hdr_cert_type = "00000EF1"
7273
7274 payload_data_len = len(EFI_CAPSULE_DATA)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307275
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307276 hdr = self._GetCapsuleHeaders(data)
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307277
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307278 self.assertEqual(FW_MGMT_GUID.upper(), hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307279
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307280 self.assertEqual(CAPSULE_IMAGE_GUID.upper(),
7281 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_TYPE_ID'])
7282 self.assertEqual(capsule_image_index,
7283 hdr['FMP_CAPSULE_IMAGE_HDR.UPDATE_IMAGE_INDEX'])
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307284
7285 if capoemflags:
Sughosh Ganu5ffce2b2023-10-10 14:40:57 +05307286 self.assertEqual(oemflag, hdr['EFI_CAPSULE_HDR.FLAGS'])
7287
7288 if signed_capsule:
7289 self.assertEqual(auth_hdr_revision,
7290 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wREVISION'])
7291 self.assertEqual(auth_hdr_cert_type,
7292 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.HDR.wCERTTYPE'])
7293 self.assertEqual(WIN_CERT_TYPE_EFI_GUID.upper(),
7294 hdr['EFI_FIRMWARE_IMAGE_AUTH.AUTH_INFO.CERT_TYPE'])
7295
7296 if version_check:
7297 self.assertEqual(fmp_signature,
7298 hdr['FMP_PAYLOAD_HDR.SIGNATURE'])
7299 self.assertEqual(fmp_size,
7300 hdr['FMP_PAYLOAD_HDR.HEADER_SIZE'])
7301 self.assertEqual(fmp_fw_version,
7302 hdr['FMP_PAYLOAD_HDR.FW_VERSION'])
7303
7304 self.assertEqual(payload_data_len, int(hdr['Payload Image Size']))
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307305
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307306 def _CheckEmptyCapsule(self, data, accept_capsule=False):
7307 if accept_capsule:
7308 capsule_hdr_guid = EMPTY_CAPSULE_ACCEPT_GUID
7309 else:
7310 capsule_hdr_guid = EMPTY_CAPSULE_REVERT_GUID
7311
7312 hdr = self._GetCapsuleHeaders(data)
7313
7314 self.assertEqual(capsule_hdr_guid.upper(),
7315 hdr['EFI_CAPSULE_HDR.CAPSULE_GUID'])
7316
7317 if accept_capsule:
7318 capsule_size = "0000002C"
7319 else:
7320 capsule_size = "0000001C"
7321 self.assertEqual(capsule_size,
7322 hdr['EFI_CAPSULE_HDR.CAPSULE_IMAGE_SIZE'])
7323
7324 if accept_capsule:
7325 self.assertEqual(CAPSULE_IMAGE_GUID.upper(), hdr['ACCEPT_IMAGE_GUID'])
7326
Sughosh Ganu269ee6d2023-08-22 23:09:59 +05307327 def testCapsuleGen(self):
7328 """Test generation of EFI capsule"""
7329 data = self._DoReadFile('311_capsule.dts')
7330
7331 self._CheckCapsule(data)
7332
7333 def testSignedCapsuleGen(self):
7334 """Test generation of EFI capsule"""
7335 data = tools.read_file(self.TestFile("key.key"))
7336 self._MakeInputFile("key.key", data)
7337 data = tools.read_file(self.TestFile("key.pem"))
7338 self._MakeInputFile("key.crt", data)
7339
7340 data = self._DoReadFile('312_capsule_signed.dts')
7341
7342 self._CheckCapsule(data, signed_capsule=True)
7343
7344 def testCapsuleGenVersionSupport(self):
7345 """Test generation of EFI capsule with version support"""
7346 data = self._DoReadFile('313_capsule_version.dts')
7347
7348 self._CheckCapsule(data, version_check=True)
7349
7350 def testCapsuleGenSignedVer(self):
7351 """Test generation of signed EFI capsule with version information"""
7352 data = tools.read_file(self.TestFile("key.key"))
7353 self._MakeInputFile("key.key", data)
7354 data = tools.read_file(self.TestFile("key.pem"))
7355 self._MakeInputFile("key.crt", data)
7356
7357 data = self._DoReadFile('314_capsule_signed_ver.dts')
7358
7359 self._CheckCapsule(data, signed_capsule=True, version_check=True)
7360
7361 def testCapsuleGenCapOemFlags(self):
7362 """Test generation of EFI capsule with OEM Flags set"""
7363 data = self._DoReadFile('315_capsule_oemflags.dts')
7364
7365 self._CheckCapsule(data, capoemflags=True)
7366
7367 def testCapsuleGenKeyMissing(self):
7368 """Test that binman errors out on missing key"""
7369 with self.assertRaises(ValueError) as e:
7370 self._DoReadFile('316_capsule_missing_key.dts')
7371
7372 self.assertIn("Both private key and public key certificate need to be provided",
7373 str(e.exception))
7374
7375 def testCapsuleGenIndexMissing(self):
7376 """Test that binman errors out on missing image index"""
7377 with self.assertRaises(ValueError) as e:
7378 self._DoReadFile('317_capsule_missing_index.dts')
7379
7380 self.assertIn("entry is missing properties: image-index",
7381 str(e.exception))
7382
7383 def testCapsuleGenGuidMissing(self):
7384 """Test that binman errors out on missing image GUID"""
7385 with self.assertRaises(ValueError) as e:
7386 self._DoReadFile('318_capsule_missing_guid.dts')
7387
7388 self.assertIn("entry is missing properties: image-guid",
7389 str(e.exception))
7390
Sughosh Ganu6b2d18a2023-10-10 14:40:59 +05307391 def testCapsuleGenAcceptCapsule(self):
7392 """Test generationg of accept EFI capsule"""
7393 data = self._DoReadFile('319_capsule_accept.dts')
7394
7395 self._CheckEmptyCapsule(data, accept_capsule=True)
7396
7397 def testCapsuleGenRevertCapsule(self):
7398 """Test generationg of revert EFI capsule"""
7399 data = self._DoReadFile('320_capsule_revert.dts')
7400
7401 self._CheckEmptyCapsule(data)
7402
7403 def testCapsuleGenAcceptGuidMissing(self):
7404 """Test that binman errors out on missing image GUID for accept capsule"""
7405 with self.assertRaises(ValueError) as e:
7406 self._DoReadFile('321_capsule_accept_missing_guid.dts')
7407
7408 self.assertIn("Image GUID needed for generating accept capsule",
7409 str(e.exception))
7410
7411 def testCapsuleGenEmptyCapsuleTypeMissing(self):
7412 """Test that capsule-type is specified"""
7413 with self.assertRaises(ValueError) as e:
7414 self._DoReadFile('322_empty_capsule_type_missing.dts')
7415
7416 self.assertIn("entry is missing properties: capsule-type",
7417 str(e.exception))
7418
7419 def testCapsuleGenAcceptOrRevertMissing(self):
7420 """Test that both accept and revert capsule are not specified"""
7421 with self.assertRaises(ValueError) as e:
7422 self._DoReadFile('323_capsule_accept_revert_missing.dts')
7423
Simon Glassac599912017-11-12 21:52:22 -07007424if __name__ == "__main__":
7425 unittest.main()