blob: 36c72bed35f6424113e187d9650b67e0cbf6d532 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass4f443042016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass4f443042016-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 Glassfdc34362020-07-09 18:39:45 -06009import collections
Simon Glass16287932020-04-17 18:09:03 -060010import gzip
Simon Glasse0e5df92018-09-14 04:57:31 -060011import hashlib
Simon Glass4f443042016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glassfdc34362020-07-09 18:39:45 -060014import re
Simon Glass4f443042016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
Simon Glass56ee85e2022-01-09 20:13:57 -070020import unittest.mock
21import urllib.error
Simon Glass4f443042016-11-25 20:15:52 -070022
Simon Glass386c63c2022-01-09 20:13:50 -070023from binman import bintool
Simon Glass16287932020-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 Glass75989722021-11-23 21:08:59 -070029from binman import fip_util
Simon Glass16287932020-04-17 18:09:03 -060030from binman import fmap_util
Simon Glass16287932020-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 Glass07237982020-08-05 13:27:47 -060036from binman.image import Image
Simon Glass4583c002023-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 Glass4f443042016-11-25 20:15:52 -070041
42# Contents of test files, corresponding to different entry types
Simon Glassc6c10e72019-05-17 22:00:46 -060043U_BOOT_DATA = b'1234'
44U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +030045U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
46U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass6ad24522022-02-28 07:16:54 -070047U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glassc6c10e72019-05-17 22:00:46 -060048BLOB_DATA = b'89'
49ME_DATA = b'0abcd'
50VGA_DATA = b'vga'
51U_BOOT_DTB_DATA = b'udtb'
52U_BOOT_SPL_DTB_DATA = b'spldtb'
53U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass6ad24522022-02-28 07:16:54 -070054U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glassc6c10e72019-05-17 22:00:46 -060055X86_START16_DATA = b'start16'
56X86_START16_SPL_DATA = b'start16spl'
57X86_START16_TPL_DATA = b'start16tpl'
Simon Glass2250ee62019-08-24 07:22:48 -060058X86_RESET16_DATA = b'reset16'
59X86_RESET16_SPL_DATA = b'reset16spl'
60X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glassc6c10e72019-05-17 22:00:46 -060061PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
62U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
63U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
64U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Simon Glass6ad24522022-02-28 07:16:54 -070065U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak21353312022-02-08 01:08:04 +030066U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
67U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
68U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glassc6c10e72019-05-17 22:00:46 -060069FSP_DATA = b'fsp'
70CMC_DATA = b'cmc'
71VBT_DATA = b'vbt'
72MRC_DATA = b'mrc'
Simon Glassbb748372018-07-17 13:25:33 -060073TEXT_DATA = 'text'
74TEXT_DATA2 = 'text2'
75TEXT_DATA3 = 'text3'
Simon Glassc6c10e72019-05-17 22:00:46 -060076CROS_EC_RW_DATA = b'ecrw'
77GBB_DATA = b'gbbd'
78BMPBLK_DATA = b'bmp'
79VBLOCK_DATA = b'vblk'
80FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
81 b"sorry you're alive\n")
Simon Glassff5c7e32019-07-08 13:18:42 -060082COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glass8f5ef892020-10-26 17:40:25 -060083COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glassc6c10e72019-05-17 22:00:46 -060084REFCODE_DATA = b'refcode'
Simon Glassea0fff92019-08-24 07:23:07 -060085FSP_M_DATA = b'fsp_m'
Simon Glassbc6a88f2019-10-20 21:31:35 -060086FSP_S_DATA = b'fsp_s'
Simon Glass998d1482019-10-20 21:31:36 -060087FSP_T_DATA = b'fsp_t'
Simon Glassdc2f81a2020-09-01 05:13:58 -060088ATF_BL31_DATA = b'bl31'
Roger Quadros47f420a2022-02-19 20:50:04 +020089TEE_OS_DATA = b'this is some tee OS data'
Simon Glass75989722021-11-23 21:08:59 -070090ATF_BL2U_DATA = b'bl2u'
Bin Meng4c4d6072021-05-10 20:23:33 +080091OPENSBI_DATA = b'opensbi'
Samuel Holland18bd4552020-10-21 21:12:15 -050092SCP_DATA = b'scp'
Jonas Karlman05b978b2023-02-25 19:01:33 +000093ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glass6cf99532020-09-01 05:13:59 -060094TEST_FDT1_DATA = b'fdt1'
95TEST_FDT2_DATA = b'test-fdt2'
Simon Glassfb91d562020-09-06 10:35:33 -060096ENV_DATA = b'var1=1\nvar2="2"'
Christian Taedcke289e6002023-07-17 09:05:54 +020097ENCRYPTED_IV_DATA = b'123456'
98ENCRYPTED_KEY_DATA = b'abcde'
Philippe Reynesb1c50932022-03-28 22:57:04 +020099PRE_LOAD_MAGIC = b'UBSH'
100PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
101PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +0530102TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Neha Malcom Francis78144822023-07-22 00:14:25 +0530103TI_UNSECURE_DATA = b'unsecuredata'
Simon Glass6cf99532020-09-01 05:13:59 -0600104
105# Subdirectory of the input dir to use to put test FDTs
106TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -0600107
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600108# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -0600109EXTRACT_DTB_SIZE = 0x3c9
110
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600111# Properties expected to be in the device tree when update_dtb is used
112BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
113
Simon Glass12bb1a92019-07-20 12:23:51 -0600114# Extra properties expected to be in the device tree when allow-repack is used
115REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
116
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200117# Supported compression bintools
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +0200118COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass4f443042016-11-25 20:15:52 -0700119
Simon Glass2f80c5e2023-01-07 14:07:14 -0700120TEE_ADDR = 0x5678
121
Simon Glass4f443042016-11-25 20:15:52 -0700122class TestFunctional(unittest.TestCase):
123 """Functional tests for binman
124
125 Most of these use a sample .dts file to build an image and then check
126 that it looks correct. The sample files are in the test/ subdirectory
127 and are numbered.
128
129 For each entry type a very small test file is created using fixed
130 string contents. This makes it easy to test that things look right, and
131 debug problems.
132
133 In some cases a 'real' file must be used - these are also supplied in
134 the test/ diurectory.
135 """
136 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600137 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700138 global entry
Simon Glass16287932020-04-17 18:09:03 -0600139 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700140
Simon Glass4f443042016-11-25 20:15:52 -0700141 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600142 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
143 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700144
145 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600146 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700147
148 # Create some test files
149 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
150 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
151 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600152 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700153 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700154 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700155 TestFunctional._MakeInputFile('me.bin', ME_DATA)
156 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600157 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600158
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530159 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600160
Simon Glass5e239182019-08-24 07:22:49 -0600161 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
162 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700163 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600164 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600165 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600166
167 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
168 X86_RESET16_DATA)
169 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
170 X86_RESET16_SPL_DATA)
171 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
172 X86_RESET16_TPL_DATA)
173
Simon Glass4f443042016-11-25 20:15:52 -0700174 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700175 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
176 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600177 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
178 U_BOOT_TPL_NODTB_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700179 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
180 U_BOOT_VPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700181 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
182 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700183 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700184 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600185 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600186 TestFunctional._MakeInputDir('devkeys')
187 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600188 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600189 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600190 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600191 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700192
Simon Glass53e22bf2019-08-24 07:22:53 -0600193 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
194 elf_test.BuildElfTestFiles(cls._elf_testdir)
195
Simon Glasse0ff8552016-11-25 20:15:53 -0700196 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600197 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700198 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700199
200 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600201 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700202
Simon Glassb986b3b2019-08-24 07:22:43 -0600203 shutil.copytree(cls.TestFile('files'),
204 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600205
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +0530206 shutil.copytree(cls.TestFile('yaml'),
207 os.path.join(cls._indir, 'yaml'))
208
Simon Glass83d73c22018-09-14 04:57:26 -0600209 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass8f5ef892020-10-26 17:40:25 -0600210 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600211 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros47f420a2022-02-19 20:50:04 +0200212 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass75989722021-11-23 21:08:59 -0700213 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Meng4c4d6072021-05-10 20:23:33 +0800214 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500215 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman05b978b2023-02-25 19:01:33 +0000216 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis78144822023-07-22 00:14:25 +0530217 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600218
Simon Glass6cf99532020-09-01 05:13:59 -0600219 # Add a few .dtb files for testing
220 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
221 TEST_FDT1_DATA)
222 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
223 TEST_FDT2_DATA)
224
Simon Glassfb91d562020-09-06 10:35:33 -0600225 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
226
Simon Glass40c8bdd2022-03-05 20:19:12 -0700227 # ELF file with two sections in different parts of memory, used for both
228 # ATF and OP_TEE
229 TestFunctional._MakeInputFile('bl31.elf',
230 tools.read_file(cls.ElfTestFile('elf_sections')))
231 TestFunctional._MakeInputFile('tee.elf',
232 tools.read_file(cls.ElfTestFile('elf_sections')))
233
Simon Glass2f80c5e2023-01-07 14:07:14 -0700234 # Newer OP_TEE file in v1 binary format
235 cls.make_tee_bin('tee.bin')
236
Christian Taedcke289e6002023-07-17 09:05:54 +0200237 # test files for encrypted tests
238 TestFunctional._MakeInputFile('encrypted-file.iv', ENCRYPTED_IV_DATA)
239 TestFunctional._MakeInputFile('encrypted-file.key', ENCRYPTED_KEY_DATA)
240
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200241 cls.comp_bintools = {}
242 for name in COMP_BINTOOLS:
243 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glassac62fba2019-07-08 13:18:53 -0600244
Simon Glass4f443042016-11-25 20:15:52 -0700245 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600246 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700247 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600248 if cls.preserve_indir:
249 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600250 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600251 if cls._indir:
252 shutil.rmtree(cls._indir)
253 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700254
Simon Glassd5164a72019-07-08 13:18:49 -0600255 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600256 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600257 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600258 """Accept arguments controlling test execution
259
260 Args:
261 preserve_indir: Preserve the shared input directory used by all
262 tests in this class.
263 preserve_outdir: Preserve the output directories used by tests. Each
264 test has its own, so this is normally only useful when running a
265 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600266 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600267 """
268 cls.preserve_indir = preserve_indir
269 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600270 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600271 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600272
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200273 def _CheckBintool(self, bintool):
274 if not bintool.is_present():
275 self.skipTest('%s not available' % bintool.name)
276
Simon Glassac62fba2019-07-08 13:18:53 -0600277 def _CheckLz4(self):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200278 bintool = self.comp_bintools['lz4']
279 self._CheckBintool(bintool)
Simon Glassac62fba2019-07-08 13:18:53 -0600280
Simon Glassbf574f12019-07-20 12:24:09 -0600281 def _CleanupOutputDir(self):
282 """Remove the temporary output directory"""
283 if self.preserve_outdirs:
284 print('Preserving output dir: %s' % tools.outdir)
285 else:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700286 tools._finalise_for_test()
Simon Glassbf574f12019-07-20 12:24:09 -0600287
Simon Glass4f443042016-11-25 20:15:52 -0700288 def setUp(self):
289 # Enable this to turn on debugging output
Simon Glassf3385a52022-01-29 14:14:15 -0700290 # tout.init(tout.DEBUG)
Simon Glass4f443042016-11-25 20:15:52 -0700291 command.test_result = None
292
293 def tearDown(self):
294 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600295 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700296
Simon Glassf86a7362019-07-20 12:24:10 -0600297 def _SetupImageInTmpdir(self):
298 """Set up the output image in a new temporary directory
299
300 This is used when an image has been generated in the output directory,
301 but we want to run binman again. This will create a new output
302 directory and fail to delete the original one.
303
304 This creates a new temporary directory, copies the image to it (with a
305 new name) and removes the old output directory.
306
307 Returns:
308 Tuple:
309 Temporary directory to use
310 New image filename
311 """
Simon Glassc1aa66e2022-01-29 14:14:04 -0700312 image_fname = tools.get_output_filename('image.bin')
Simon Glassf86a7362019-07-20 12:24:10 -0600313 tmpdir = tempfile.mkdtemp(prefix='binman.')
314 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700315 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf86a7362019-07-20 12:24:10 -0600316 self._CleanupOutputDir()
317 return tmpdir, updated_fname
318
Simon Glassb8ef5b62018-07-17 13:25:48 -0600319 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600320 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600321 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
322 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
323 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700324 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600325
Simon Glass4f443042016-11-25 20:15:52 -0700326 def _RunBinman(self, *args, **kwargs):
327 """Run binman using the command line
328
329 Args:
330 Arguments to pass, as a list of strings
331 kwargs: Arguments to pass to Command.RunPipe()
332 """
Simon Glassd9800692022-01-29 14:14:05 -0700333 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass4f443042016-11-25 20:15:52 -0700334 capture=True, capture_stderr=True, raise_on_error=False)
335 if result.return_code and kwargs.get('raise_on_error', True):
336 raise Exception("Error running '%s': %s" % (' '.join(args),
337 result.stdout + result.stderr))
338 return result
339
Simon Glass53cd5d92019-07-08 14:25:29 -0600340 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700341 """Run binman using directly (in the same process)
342
343 Args:
344 Arguments to pass, as a list of strings
345 Returns:
346 Return value (0 for success)
347 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600348 argv = list(argv)
349 args = cmdline.ParseArgs(argv)
350 args.pager = 'binman-invalid-pager'
351 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700352
353 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600354 # args.verbosity = tout.DEBUG
355 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700356
Simon Glass53af22a2018-07-17 13:25:32 -0600357 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600358 entry_args=None, images=None, use_real_dtb=False,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300359 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thierya89c8f22022-01-06 11:49:41 +0100360 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass4f9ee832022-01-09 20:14:09 -0700361 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis15432ea2023-07-22 00:14:44 +0530362 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass4f443042016-11-25 20:15:52 -0700363 """Run binman with a given test file
364
365 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600366 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600367 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600368 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600369 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600370 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600371 entry_args: Dict of entry args to supply to binman
372 key: arg name
373 value: value of that arg
374 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600375 use_real_dtb: True to use the test file as the contents of
376 the u-boot-dtb entry. Normally this is not needed and the
377 test contents (the U_BOOT_DTB_DATA string) can be used.
378 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300379 use_expanded: True to use expanded entries where available, e.g.
380 'u-boot-expanded' instead of 'u-boot'
Simon Glasse9d336d2020-09-01 05:13:55 -0600381 verbosity: Verbosity level to use (0-3, None=don't set it)
382 allow_missing: Set the '--allow-missing' flag so that missing
383 external binaries just produce a warning instead of an error
Heiko Thierya89c8f22022-01-06 11:49:41 +0100384 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glass6cf99532020-09-01 05:13:59 -0600385 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600386 threads: Number of threads to use (None for default, 0 for
387 single-threaded)
Simon Glass7115f002021-11-03 21:09:17 -0600388 test_section_timeout: True to force the first time to timeout, as
389 used in testThreadTimeout()
Simon Glass0427bed2021-11-03 21:09:18 -0600390 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass4f9ee832022-01-09 20:14:09 -0700391 force_missing_tools (str): comma-separated list of bintools to
392 regard as missing
Andrew Davis15432ea2023-07-22 00:14:44 +0530393 output_dir: Specific output directory to use for image using -O
Simon Glass7115f002021-11-03 21:09:17 -0600394
395 Returns:
396 int return code, 0 on success
Simon Glass4f443042016-11-25 20:15:52 -0700397 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600398 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700399 if debug:
400 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600401 if verbosity is not None:
402 args.append('-v%d' % verbosity)
403 elif self.verbosity:
404 args.append('-v%d' % self.verbosity)
405 if self.toolpath:
406 for path in self.toolpath:
407 args += ['--toolpath', path]
Simon Glassc69d19c2021-07-06 10:36:37 -0600408 if threads is not None:
409 args.append('-T%d' % threads)
410 if test_section_timeout:
411 args.append('--test-section-timeout')
Simon Glass53cd5d92019-07-08 14:25:29 -0600412 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600413 if map:
414 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600415 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600416 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600417 if not use_real_dtb:
418 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300419 if not use_expanded:
420 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600421 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600422 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600423 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600424 if allow_missing:
425 args.append('-M')
Simon Glassb38da152022-11-09 19:14:42 -0700426 if ignore_missing:
427 args.append('-W')
Heiko Thierya89c8f22022-01-06 11:49:41 +0100428 if allow_fake_blobs:
429 args.append('--fake-ext-blobs')
Simon Glass4f9ee832022-01-09 20:14:09 -0700430 if force_missing_bintools:
431 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glass0427bed2021-11-03 21:09:18 -0600432 if update_fdt_in_elf:
433 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass0bfa7b02018-09-14 04:57:12 -0600434 if images:
435 for image in images:
436 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600437 if extra_indirs:
438 for indir in extra_indirs:
439 args += ['-I', indir]
Andrew Davis15432ea2023-07-22 00:14:44 +0530440 if output_dir:
441 args += ['-O', output_dir]
Simon Glass7fe91732017-11-13 18:55:00 -0700442 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700443
444 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700445 """Set up a new test device-tree file
446
447 The given file is compiled and set up as the device tree to be used
448 for ths test.
449
450 Args:
451 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600452 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700453
454 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600455 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700456 """
Simon Glassa004f292019-07-20 12:23:49 -0600457 tmpdir = tempfile.mkdtemp(prefix='binmant.')
458 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600459 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700460 data = fd.read()
461 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600462 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600463 return data
Simon Glass4f443042016-11-25 20:15:52 -0700464
Simon Glass6ad24522022-02-28 07:16:54 -0700465 def _GetDtbContentsForSpls(self, dtb_data, name):
466 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glass6ed45ba2018-09-14 04:57:24 -0600467
468 For testing we don't actually have different versions of the DTB. With
469 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
470 we don't normally have any unwanted nodes.
471
472 We still want the DTBs for SPL and TPL to be different though, since
473 otherwise it is confusing to know which one we are looking at. So add
474 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600475
476 Args:
477 dtb_data: dtb data to modify (this should be a value devicetree)
478 name: Name of a new property to add
479
480 Returns:
481 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600482 """
483 dtb = fdt.Fdt.FromData(dtb_data)
484 dtb.Scan()
485 dtb.GetNode('/binman').AddZeroProp(name)
486 dtb.Sync(auto_resize=True)
487 dtb.Pack()
488 return dtb.GetContents()
489
Simon Glass63aeaeb2021-03-18 20:25:05 +1300490 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
491 map=False, update_dtb=False, entry_args=None,
Simon Glassc69d19c2021-07-06 10:36:37 -0600492 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass4f443042016-11-25 20:15:52 -0700493 """Run binman and return the resulting image
494
495 This runs binman with a given test file and then reads the resulting
496 output file. It is a shortcut function since most tests need to do
497 these steps.
498
499 Raises an assertion failure if binman returns a non-zero exit code.
500
501 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600502 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700503 use_real_dtb: True to use the test file as the contents of
504 the u-boot-dtb entry. Normally this is not needed and the
505 test contents (the U_BOOT_DTB_DATA string) can be used.
506 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300507 use_expanded: True to use expanded entries where available, e.g.
508 'u-boot-expanded' instead of 'u-boot'
Simon Glass3b0c3822018-06-01 09:38:20 -0600509 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600510 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600511 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600512 entry_args: Dict of entry args to supply to binman
513 key: arg name
514 value: value of that arg
515 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
516 function. If reset_dtbs is True, then the original test dtb
517 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600518 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600519 threads: Number of threads to use (None for default, 0 for
520 single-threaded)
Simon Glasse0ff8552016-11-25 20:15:53 -0700521
522 Returns:
523 Tuple:
524 Resulting image contents
525 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600526 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600527 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700528 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700529 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700530 # Use the compiled test file as the u-boot-dtb input
531 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700532 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600533
534 # For testing purposes, make a copy of the DT for SPL and TPL. Add
535 # a node indicating which it is, so aid verification.
Simon Glass6ad24522022-02-28 07:16:54 -0700536 for name in ['spl', 'tpl', 'vpl']:
Simon Glass6ed45ba2018-09-14 04:57:24 -0600537 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
538 outfile = os.path.join(self._indir, dtb_fname)
539 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass6ad24522022-02-28 07:16:54 -0700540 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700541
542 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600543 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600544 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glassc69d19c2021-07-06 10:36:37 -0600545 use_expanded=use_expanded, extra_indirs=extra_indirs,
546 threads=threads)
Simon Glass4f443042016-11-25 20:15:52 -0700547 self.assertEqual(0, retcode)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700548 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700549
550 # Find the (only) image, read it and return its contents
551 image = control.images['image']
Simon Glassc1aa66e2022-01-29 14:14:04 -0700552 image_fname = tools.get_output_filename('image.bin')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600553 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600554 if map:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700555 map_fname = tools.get_output_filename('image.map')
Simon Glass3b0c3822018-06-01 09:38:20 -0600556 with open(map_fname) as fd:
557 map_data = fd.read()
558 else:
559 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600560 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600561 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700562 finally:
563 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600564 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600565 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700566
Simon Glass3c081312019-07-08 14:25:26 -0600567 def _DoReadFileRealDtb(self, fname):
568 """Run binman with a real .dtb file and return the resulting data
569
570 Args:
571 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
572
573 Returns:
574 Resulting image contents
575 """
576 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
577
Simon Glasse0ff8552016-11-25 20:15:53 -0700578 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600579 """Helper function which discards the device-tree binary
580
581 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600582 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600583 use_real_dtb: True to use the test file as the contents of
584 the u-boot-dtb entry. Normally this is not needed and the
585 test contents (the U_BOOT_DTB_DATA string) can be used.
586 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600587
588 Returns:
589 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600590 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700591 return self._DoReadFileDtb(fname, use_real_dtb)[0]
592
Simon Glass4f443042016-11-25 20:15:52 -0700593 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600594 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700595 """Create a new test input file, creating directories as needed
596
597 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600598 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700599 contents: File contents to write in to the file
600 Returns:
601 Full pathname of file created
602 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600603 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700604 dirname = os.path.dirname(pathname)
605 if dirname and not os.path.exists(dirname):
606 os.makedirs(dirname)
607 with open(pathname, 'wb') as fd:
608 fd.write(contents)
609 return pathname
610
611 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600612 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600613 """Create a new test input directory, creating directories as needed
614
615 Args:
616 dirname: Directory name to create
617
618 Returns:
619 Full pathname of directory created
620 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600621 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600622 if not os.path.exists(pathname):
623 os.makedirs(pathname)
624 return pathname
625
626 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600627 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600628 """Set up an ELF file with a '_dt_ucode_base_size' symbol
629
630 Args:
631 Filename of ELF file to use as SPL
632 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600633 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700634 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600635
636 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600637 def _SetupTplElf(cls, src_fname='bss_data'):
638 """Set up an ELF file with a '_dt_ucode_base_size' symbol
639
640 Args:
641 Filename of ELF file to use as TPL
642 """
643 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700644 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass2090f1e2019-08-24 07:23:00 -0600645
646 @classmethod
Simon Glass6ad24522022-02-28 07:16:54 -0700647 def _SetupVplElf(cls, src_fname='bss_data'):
648 """Set up an ELF file with a '_dt_ucode_base_size' symbol
649
650 Args:
651 Filename of ELF file to use as VPL
652 """
653 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
654 tools.read_file(cls.ElfTestFile(src_fname)))
655
656 @classmethod
Lukas Funke8c1fbd12023-07-18 13:53:13 +0200657 def _SetupPmuFwlElf(cls, src_fname='bss_data'):
658 """Set up an ELF file with a '_dt_ucode_base_size' symbol
659
660 Args:
661 Filename of ELF file to use as VPL
662 """
663 TestFunctional._MakeInputFile('pmu-firmware.elf',
664 tools.read_file(cls.ElfTestFile(src_fname)))
665
666 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600667 def _SetupDescriptor(cls):
668 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
669 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
670
671 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600672 def TestFile(cls, fname):
673 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700674
Simon Glass53e22bf2019-08-24 07:22:53 -0600675 @classmethod
676 def ElfTestFile(cls, fname):
677 return os.path.join(cls._elf_testdir, fname)
678
Simon Glass2f80c5e2023-01-07 14:07:14 -0700679 @classmethod
680 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
681 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
682 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
683 dummy, paged_sz) + U_BOOT_DATA
684 data += extra_data
685 TestFunctional._MakeInputFile(fname, data)
686
Simon Glass4f443042016-11-25 20:15:52 -0700687 def AssertInList(self, grep_list, target):
688 """Assert that at least one of a list of things is in a target
689
690 Args:
691 grep_list: List of strings to check
692 target: Target string
693 """
694 for grep in grep_list:
695 if grep in target:
696 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600697 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700698
699 def CheckNoGaps(self, entries):
700 """Check that all entries fit together without gaps
701
702 Args:
703 entries: List of entries to check
704 """
Simon Glass3ab95982018-08-01 15:22:37 -0600705 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700706 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600707 self.assertEqual(offset, entry.offset)
708 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700709
Simon Glasse0ff8552016-11-25 20:15:53 -0700710 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600711 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700712
713 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600714 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700715
716 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600717 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700718 """
719 return struct.unpack('>L', dtb[4:8])[0]
720
Simon Glass086cec92019-07-08 14:25:27 -0600721 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600722 def AddNode(node, path):
723 if node.name != '/':
724 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600725 for prop in node.props.values():
726 if prop.name in prop_names:
727 prop_path = path + ':' + prop.name
728 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
729 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600730 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600731 AddNode(subnode, path)
732
733 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600734 AddNode(dtb.GetRoot(), '')
735 return tree
736
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +0000737 def _CheckSign(self, fit, key):
738 try:
739 tools.run('fit_check_sign', '-k', key, '-f', fit)
740 except:
741 self.fail('Expected signed FIT container')
742 return False
743 return True
744
Simon Glass4f443042016-11-25 20:15:52 -0700745 def testRun(self):
746 """Test a basic run with valid args"""
747 result = self._RunBinman('-h')
748
749 def testFullHelp(self):
750 """Test that the full help is displayed with -H"""
751 result = self._RunBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300752 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-01-16 15:29:50 -0500753 # Remove possible extraneous strings
754 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
755 gothelp = result.stdout.replace(extra, '')
756 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700757 self.assertEqual(0, len(result.stderr))
758 self.assertEqual(0, result.return_code)
759
760 def testFullHelpInternal(self):
761 """Test that the full help is displayed with -H"""
762 try:
763 command.test_result = command.CommandResult()
764 result = self._DoBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300765 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-11-25 20:15:52 -0700766 finally:
767 command.test_result = None
768
769 def testHelp(self):
770 """Test that the basic help is displayed with -h"""
771 result = self._RunBinman('-h')
772 self.assertTrue(len(result.stdout) > 200)
773 self.assertEqual(0, len(result.stderr))
774 self.assertEqual(0, result.return_code)
775
Simon Glass4f443042016-11-25 20:15:52 -0700776 def testBoard(self):
777 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600778 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700779 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300780 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700781 self.assertEqual(0, result)
782
783 def testNeedBoard(self):
784 """Test that we get an error when no board ius supplied"""
785 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600786 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700787 self.assertIn("Must provide a board to process (use -b <board>)",
788 str(e.exception))
789
790 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600791 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700792 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600793 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700794 # We get one error from libfdt, and a different one from fdtget.
795 self.AssertInList(["Couldn't open blob from 'missing_file'",
796 'No such file or directory'], str(e.exception))
797
798 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600799 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700800
801 Since this is a source file it should be compiled and the error
802 will come from the device-tree compiler (dtc).
803 """
804 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600805 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700806 self.assertIn("FATAL ERROR: Unable to parse input tree",
807 str(e.exception))
808
809 def testMissingNode(self):
810 """Test that a device tree without a 'binman' node generates an error"""
811 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600812 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700813 self.assertIn("does not have a 'binman' node", str(e.exception))
814
815 def testEmpty(self):
816 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600817 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700818 self.assertEqual(0, len(result.stderr))
819 self.assertEqual(0, result.return_code)
820
821 def testInvalidEntry(self):
822 """Test that an invalid entry is flagged"""
823 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600824 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600825 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700826 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
827 "'/binman/not-a-valid-type'", str(e.exception))
828
829 def testSimple(self):
830 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600831 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700832 self.assertEqual(U_BOOT_DATA, data)
833
Simon Glass7fe91732017-11-13 18:55:00 -0700834 def testSimpleDebug(self):
835 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600836 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700837
Simon Glass4f443042016-11-25 20:15:52 -0700838 def testDual(self):
839 """Test that we can handle creating two images
840
841 This also tests image padding.
842 """
Simon Glass741f2d62018-10-01 12:22:30 -0600843 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700844 self.assertEqual(0, retcode)
845
846 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600847 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700848 fname = tools.get_output_filename('image1.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700849 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600850 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700851 data = fd.read()
852 self.assertEqual(U_BOOT_DATA, data)
853
854 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600855 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700856 fname = tools.get_output_filename('image2.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700857 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600858 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700859 data = fd.read()
860 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700861 self.assertEqual(tools.get_bytes(0, 3), data[:3])
862 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700863
864 def testBadAlign(self):
865 """Test that an invalid alignment value is detected"""
866 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600867 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700868 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
869 "of two", str(e.exception))
870
871 def testPackSimple(self):
872 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600873 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700874 self.assertEqual(0, retcode)
875 self.assertIn('image', control.images)
876 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600877 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700878 self.assertEqual(5, len(entries))
879
880 # First u-boot
881 self.assertIn('u-boot', entries)
882 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600883 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700884 self.assertEqual(len(U_BOOT_DATA), entry.size)
885
886 # Second u-boot, aligned to 16-byte boundary
887 self.assertIn('u-boot-align', entries)
888 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600889 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700890 self.assertEqual(len(U_BOOT_DATA), entry.size)
891
892 # Third u-boot, size 23 bytes
893 self.assertIn('u-boot-size', entries)
894 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600895 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700896 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
897 self.assertEqual(23, entry.size)
898
899 # Fourth u-boot, placed immediate after the above
900 self.assertIn('u-boot-next', entries)
901 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600902 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700903 self.assertEqual(len(U_BOOT_DATA), entry.size)
904
Simon Glass3ab95982018-08-01 15:22:37 -0600905 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700906 self.assertIn('u-boot-fixed', entries)
907 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600908 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700909 self.assertEqual(len(U_BOOT_DATA), entry.size)
910
Simon Glass8beb11e2019-07-08 14:25:47 -0600911 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700912
913 def testPackExtra(self):
914 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600915 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
916 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700917
Simon Glass4f443042016-11-25 20:15:52 -0700918 self.assertIn('image', control.images)
919 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600920 entries = image.GetEntries()
Samuel Hollandb01ae032023-01-21 17:25:16 -0600921 self.assertEqual(6, len(entries))
Simon Glass4f443042016-11-25 20:15:52 -0700922
Samuel Hollandb01ae032023-01-21 17:25:16 -0600923 # First u-boot with padding before and after (included in minimum size)
Simon Glass4f443042016-11-25 20:15:52 -0700924 self.assertIn('u-boot', entries)
925 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600926 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700927 self.assertEqual(3, entry.pad_before)
928 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600929 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700930 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
931 tools.get_bytes(0, 5), data[:entry.size])
Simon Glassef439ed2020-10-26 17:40:08 -0600932 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700933
934 # Second u-boot has an aligned size, but it has no effect
935 self.assertIn('u-boot-align-size-nop', entries)
936 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600937 self.assertEqual(pos, entry.offset)
938 self.assertEqual(len(U_BOOT_DATA), entry.size)
939 self.assertEqual(U_BOOT_DATA, entry.data)
940 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
941 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700942
943 # Third u-boot has an aligned size too
944 self.assertIn('u-boot-align-size', entries)
945 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600946 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700947 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600948 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700949 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600950 data[pos:pos + entry.size])
951 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700952
953 # Fourth u-boot has an aligned end
954 self.assertIn('u-boot-align-end', entries)
955 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600956 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700957 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600958 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700959 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600960 data[pos:pos + entry.size])
961 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700962
963 # Fifth u-boot immediately afterwards
964 self.assertIn('u-boot-align-both', entries)
965 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600966 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700967 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600968 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700969 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600970 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700971
Samuel Hollandb01ae032023-01-21 17:25:16 -0600972 # Sixth u-boot with both minimum size and aligned size
973 self.assertIn('u-boot-min-size', entries)
974 entry = entries['u-boot-min-size']
975 self.assertEqual(128, entry.offset)
976 self.assertEqual(32, entry.size)
977 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
978 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
979 data[pos:pos + entry.size])
980
Simon Glass4f443042016-11-25 20:15:52 -0700981 self.CheckNoGaps(entries)
Samuel Hollandb01ae032023-01-21 17:25:16 -0600982 self.assertEqual(160, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700983
Simon Glass4eec34c2020-10-26 17:40:10 -0600984 dtb = fdt.Fdt(out_dtb_fname)
985 dtb.Scan()
986 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
987 expected = {
988 'image-pos': 0,
989 'offset': 0,
Samuel Hollandb01ae032023-01-21 17:25:16 -0600990 'size': 160,
Simon Glass4eec34c2020-10-26 17:40:10 -0600991
992 'u-boot:image-pos': 0,
993 'u-boot:offset': 0,
994 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
995
996 'u-boot-align-size-nop:image-pos': 12,
997 'u-boot-align-size-nop:offset': 12,
998 'u-boot-align-size-nop:size': 4,
999
1000 'u-boot-align-size:image-pos': 16,
1001 'u-boot-align-size:offset': 16,
1002 'u-boot-align-size:size': 32,
1003
1004 'u-boot-align-end:image-pos': 48,
1005 'u-boot-align-end:offset': 48,
1006 'u-boot-align-end:size': 16,
1007
1008 'u-boot-align-both:image-pos': 64,
1009 'u-boot-align-both:offset': 64,
1010 'u-boot-align-both:size': 64,
Samuel Hollandb01ae032023-01-21 17:25:16 -06001011
1012 'u-boot-min-size:image-pos': 128,
1013 'u-boot-min-size:offset': 128,
1014 'u-boot-min-size:size': 32,
Simon Glass4eec34c2020-10-26 17:40:10 -06001015 }
1016 self.assertEqual(expected, props)
1017
Simon Glass4f443042016-11-25 20:15:52 -07001018 def testPackAlignPowerOf2(self):
1019 """Test that invalid entry alignment is detected"""
1020 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001021 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001022 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1023 "of two", str(e.exception))
1024
1025 def testPackAlignSizePowerOf2(self):
1026 """Test that invalid entry size alignment is detected"""
1027 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001028 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001029 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1030 "power of two", str(e.exception))
1031
1032 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001033 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -07001034 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001035 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001036 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001037 "align 0x4 (4)", str(e.exception))
1038
1039 def testPackInvalidSizeAlign(self):
1040 """Test that invalid entry size alignment is detected"""
1041 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001042 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001043 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1044 "align-size 0x4 (4)", str(e.exception))
1045
1046 def testPackOverlap(self):
1047 """Test that overlapping regions are detected"""
1048 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001049 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001050 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001051 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1052 str(e.exception))
1053
1054 def testPackEntryOverflow(self):
1055 """Test that entries that overflow their size are detected"""
1056 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001057 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001058 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1059 "but entry size is 0x3 (3)", str(e.exception))
1060
1061 def testPackImageOverflow(self):
1062 """Test that entries which overflow the image size are detected"""
1063 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001064 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001065 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -07001066 "size 0x3 (3)", str(e.exception))
1067
1068 def testPackImageSize(self):
1069 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -06001070 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001071 self.assertEqual(0, retcode)
1072 self.assertIn('image', control.images)
1073 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001074 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -07001075
1076 def testPackImageSizeAlign(self):
1077 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -06001078 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001079 self.assertEqual(0, retcode)
1080 self.assertIn('image', control.images)
1081 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001082 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -07001083
1084 def testPackInvalidImageAlign(self):
1085 """Test that invalid image alignment is detected"""
1086 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001087 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001088 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001089 "align-size 0x8 (8)", str(e.exception))
1090
Simon Glass8d2ef3e2022-02-11 13:23:21 -07001091 def testPackAlignPowerOf2Inv(self):
Simon Glass4f443042016-11-25 20:15:52 -07001092 """Test that invalid image alignment is detected"""
1093 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001094 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001095 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -07001096 "two", str(e.exception))
1097
1098 def testImagePadByte(self):
1099 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001100 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001101 data = self._DoReadFile('021_image_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001102 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001103 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001104
1105 def testImageName(self):
1106 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -06001107 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001108 self.assertEqual(0, retcode)
1109 image = control.images['image1']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001110 fname = tools.get_output_filename('test-name')
Simon Glass4f443042016-11-25 20:15:52 -07001111 self.assertTrue(os.path.exists(fname))
1112
1113 image = control.images['image2']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001114 fname = tools.get_output_filename('test-name.xx')
Simon Glass4f443042016-11-25 20:15:52 -07001115 self.assertTrue(os.path.exists(fname))
1116
1117 def testBlobFilename(self):
1118 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -06001119 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001120 self.assertEqual(BLOB_DATA, data)
1121
1122 def testPackSorted(self):
1123 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001124 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001125 data = self._DoReadFile('024_sorted.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001126 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1127 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001128
Simon Glass3ab95982018-08-01 15:22:37 -06001129 def testPackZeroOffset(self):
1130 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001131 self._SetupSplElf()
Simon Glass4f443042016-11-25 20:15:52 -07001132 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001133 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001134 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001135 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1136 str(e.exception))
1137
1138 def testPackUbootDtb(self):
1139 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001140 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001141 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001142
1143 def testPackX86RomNoSize(self):
1144 """Test that the end-at-4gb property requires a size property"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001145 self._SetupSplElf()
Simon Glasse0ff8552016-11-25 20:15:53 -07001146 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001147 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001148 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001149 "using end-at-4gb", str(e.exception))
1150
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301151 def test4gbAndSkipAtStartTogether(self):
1152 """Test that the end-at-4gb and skip-at-size property can't be used
1153 together"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001154 self._SetupSplElf()
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301155 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001156 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001157 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301158 "'skip-at-start'", str(e.exception))
1159
Simon Glasse0ff8552016-11-25 20:15:53 -07001160 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001161 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001162 self._SetupSplElf()
Simon Glasse0ff8552016-11-25 20:15:53 -07001163 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001164 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001165 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1166 "is outside the section '/binman' starting at "
1167 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001168 str(e.exception))
1169
1170 def testPackX86Rom(self):
1171 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001172 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001173 data = self._DoReadFile('029_x86_rom.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001174 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1175 tools.get_bytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001176
1177 def testPackX86RomMeNoDesc(self):
1178 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001179 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001180 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001181 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001182 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001183 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1184 str(e.exception))
1185 finally:
1186 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001187
1188 def testPackX86RomBadDesc(self):
1189 """Test that the Intel requires a descriptor entry"""
1190 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001191 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001192 self.assertIn("Node '/binman/intel-me': No offset set with "
1193 "offset-unset: should another entry provide this correct "
1194 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001195
1196 def testPackX86RomMe(self):
1197 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001198 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001199 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06001200 if data[:0x1000] != expected_desc:
1201 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001202 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1203
1204 def testPackVga(self):
1205 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001206 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001207 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1208
1209 def testPackStart16(self):
1210 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001211 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001212 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1213
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301214 def testPackPowerpcMpc85xxBootpgResetvec(self):
1215 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1216 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001217 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301218 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1219
Simon Glass736bb0a2018-07-06 10:27:17 -06001220 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001221 """Handle running a test for insertion of microcode
1222
1223 Args:
1224 dts_fname: Name of test .dts file
1225 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001226 ucode_second: True if the microsecond entry is second instead of
1227 third
Simon Glassadc57012018-07-06 10:27:16 -06001228
1229 Returns:
1230 Tuple:
1231 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001232 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001233 in the above (two 4-byte words)
1234 """
Simon Glass6b187df2017-11-12 21:52:27 -07001235 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001236
1237 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001238 if ucode_second:
1239 ucode_content = data[len(nodtb_data):]
1240 ucode_pos = len(nodtb_data)
1241 dtb_with_ucode = ucode_content[16:]
1242 fdt_len = self.GetFdtLen(dtb_with_ucode)
1243 else:
1244 dtb_with_ucode = data[len(nodtb_data):]
1245 fdt_len = self.GetFdtLen(dtb_with_ucode)
1246 ucode_content = dtb_with_ucode[fdt_len:]
1247 ucode_pos = len(nodtb_data) + fdt_len
Simon Glassc1aa66e2022-01-29 14:14:04 -07001248 fname = tools.get_output_filename('test.dtb')
Simon Glasse0ff8552016-11-25 20:15:53 -07001249 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001250 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001251 dtb = fdt.FdtScan(fname)
1252 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001253 self.assertTrue(ucode)
1254 for node in ucode.subnodes:
1255 self.assertFalse(node.props.get('data'))
1256
Simon Glasse0ff8552016-11-25 20:15:53 -07001257 # Check that the microcode appears immediately after the Fdt
1258 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001259 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001260 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1261 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001262 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001263
1264 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001265 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001266 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1267 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001268 u_boot = data[:len(nodtb_data)]
1269 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001270
1271 def testPackUbootMicrocode(self):
1272 """Test that x86 microcode can be handled correctly
1273
1274 We expect to see the following in the image, in order:
1275 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1276 place
1277 u-boot.dtb with the microcode removed
1278 the microcode
1279 """
Simon Glass741f2d62018-10-01 12:22:30 -06001280 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001281 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001282 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1283 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001284
Simon Glass160a7662017-05-27 07:38:26 -06001285 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001286 """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
1292 an empty microcode region
1293 """
1294 # We need the libfdt library to run this test since only that allows
1295 # finding the offset of a property. This is required by
1296 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001297 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001298
1299 second = data[len(U_BOOT_NODTB_DATA):]
1300
1301 fdt_len = self.GetFdtLen(second)
1302 third = second[fdt_len:]
1303 second = second[:fdt_len]
1304
Simon Glass160a7662017-05-27 07:38:26 -06001305 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1306 self.assertIn(ucode_data, second)
1307 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001308
Simon Glass160a7662017-05-27 07:38:26 -06001309 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001310 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001311 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1312 len(ucode_data))
1313 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001314 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1315 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001316
Simon Glass75db0862016-11-25 20:15:55 -07001317 def testPackUbootSingleMicrocode(self):
1318 """Test that x86 microcode can be handled correctly with fdt_normal.
1319 """
Simon Glass160a7662017-05-27 07:38:26 -06001320 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001321
Simon Glassc49deb82016-11-25 20:15:54 -07001322 def testUBootImg(self):
1323 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001324 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001325 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001326
1327 def testNoMicrocode(self):
1328 """Test that a missing microcode region is detected"""
1329 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001330 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001331 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1332 "node found in ", str(e.exception))
1333
1334 def testMicrocodeWithoutNode(self):
1335 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1336 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001337 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001338 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1339 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1340
1341 def testMicrocodeWithoutNode2(self):
1342 """Test that a missing u-boot-ucode node is detected"""
1343 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001344 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001345 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1346 "microcode region u-boot-ucode", str(e.exception))
1347
1348 def testMicrocodeWithoutPtrInElf(self):
1349 """Test that a U-Boot binary without the microcode symbol is detected"""
1350 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001351 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001352 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001353 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001354
1355 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001356 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001357 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1358 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1359
1360 finally:
1361 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001362 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001363 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001364
1365 def testMicrocodeNotInImage(self):
1366 """Test that microcode must be placed within the image"""
1367 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001368 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001369 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1370 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001371 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001372
1373 def testWithoutMicrocode(self):
1374 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001375 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001376 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001377 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001378
1379 # Now check the device tree has no microcode
1380 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1381 second = data[len(U_BOOT_NODTB_DATA):]
1382
1383 fdt_len = self.GetFdtLen(second)
1384 self.assertEqual(dtb, second[:fdt_len])
1385
1386 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1387 third = data[used_len:]
Simon Glassc1aa66e2022-01-29 14:14:04 -07001388 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001389
1390 def testUnknownPosSize(self):
1391 """Test that microcode must be placed within the image"""
1392 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001393 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001394 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001395 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001396
1397 def testPackFsp(self):
1398 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001399 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001400 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1401
1402 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001403 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001404 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001405 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001406
1407 def testPackVbt(self):
1408 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001409 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001410 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001411
Simon Glass56509842017-11-12 21:52:25 -07001412 def testSplBssPad(self):
1413 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001414 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001415 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001416 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001417 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001418 data)
Simon Glass56509842017-11-12 21:52:25 -07001419
Simon Glass86af5112018-10-01 21:12:42 -06001420 def testSplBssPadMissing(self):
1421 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001422 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001423 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001424 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001425 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1426 str(e.exception))
1427
Simon Glass87722132017-11-12 21:52:26 -07001428 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001429 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001430 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001431 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1432
Simon Glass736bb0a2018-07-06 10:27:17 -06001433 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1434 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001435
1436 We expect to see the following in the image, in order:
1437 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1438 correct place
1439 u-boot.dtb with the microcode removed
1440 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001441
1442 Args:
1443 dts: Device tree file to use for test
1444 ucode_second: True if the microsecond entry is second instead of
1445 third
Simon Glass6b187df2017-11-12 21:52:27 -07001446 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001447 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001448 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1449 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001450 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1451 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001452
Simon Glass736bb0a2018-07-06 10:27:17 -06001453 def testPackUbootSplMicrocode(self):
1454 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001455 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001456 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001457
1458 def testPackUbootSplMicrocodeReorder(self):
1459 """Test that order doesn't matter for microcode entries
1460
1461 This is the same as testPackUbootSplMicrocode but when we process the
1462 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1463 entry, so we reply on binman to try later.
1464 """
Simon Glass741f2d62018-10-01 12:22:30 -06001465 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001466 ucode_second=True)
1467
Simon Glassca4f4ff2017-11-12 21:52:28 -07001468 def testPackMrc(self):
1469 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001470 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001471 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1472
Simon Glass47419ea2017-11-13 18:54:55 -07001473 def testSplDtb(self):
1474 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001475 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001476 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001477 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1478
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001479 def testSplNoDtb(self):
1480 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12001481 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001482 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001483 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1484
Simon Glass3d433382021-03-21 18:24:30 +13001485 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4649bea2023-07-18 07:23:54 -06001486 use_expanded=False, no_write_symbols=False):
Simon Glassf5898822021-03-18 20:24:56 +13001487 """Check the image contains the expected symbol values
1488
1489 Args:
1490 dts: Device tree file to use for test
1491 base_data: Data before and after 'u-boot' section
1492 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass3d433382021-03-21 18:24:30 +13001493 entry_args: Dict of entry args to supply to binman
1494 key: arg name
1495 value: value of that arg
1496 use_expanded: True to use expanded entries where available, e.g.
1497 'u-boot-expanded' instead of 'u-boot'
Simon Glassf5898822021-03-18 20:24:56 +13001498 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001499 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001500 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1501 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001502 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glassf5898822021-03-18 20:24:56 +13001503 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001504 addr + 4)
Simon Glass19790632017-11-13 18:55:01 -07001505
Simon Glass11ae93e2018-10-01 21:12:47 -06001506 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001507 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1508 use_expanded=use_expanded)[0]
Simon Glassf5898822021-03-18 20:24:56 +13001509 # The image should contain the symbols from u_boot_binman_syms.c
1510 # Note that image_pos is adjusted by the base address of the image,
1511 # which is 0x10 in our test image
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001512 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1513 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glassf5898822021-03-18 20:24:56 +13001514 0x10 + u_boot_offset, 0x04)
Simon Glass4649bea2023-07-18 07:23:54 -06001515 if no_write_symbols:
1516 expected = (base_data +
1517 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1518 U_BOOT_DATA + base_data)
1519 else:
1520 expected = (sym_values + base_data[24:] +
1521 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1522 base_data[24:])
Simon Glass19790632017-11-13 18:55:01 -07001523 self.assertEqual(expected, data)
1524
Simon Glassf5898822021-03-18 20:24:56 +13001525 def testSymbols(self):
1526 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001527 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassf5898822021-03-18 20:24:56 +13001528
1529 def testSymbolsNoDtb(self):
1530 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001531 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001532 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1533 0x38)
1534
Simon Glassdd57c132018-06-01 09:38:11 -06001535 def testPackUnitAddress(self):
1536 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001537 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001538 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1539
Simon Glass18546952018-06-01 09:38:16 -06001540 def testSections(self):
1541 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001542 data = self._DoReadFile('055_sections.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001543 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1544 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1545 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001546 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001547
Simon Glass3b0c3822018-06-01 09:38:20 -06001548 def testMap(self):
1549 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001550 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001551 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700155200000000 00000000 00000028 image
Simon Glass1be70d22018-07-17 13:25:49 -0600155300000000 00000000 00000010 section@0
155400000000 00000000 00000004 u-boot
155500000010 00000010 00000010 section@1
155600000010 00000000 00000004 u-boot
155700000020 00000020 00000004 section@2
155800000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001559''', map_data)
1560
Simon Glassc8d48ef2018-06-01 09:38:21 -06001561 def testNamePrefix(self):
1562 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001563 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001564 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700156500000000 00000000 00000028 image
Simon Glass1be70d22018-07-17 13:25:49 -0600156600000000 00000000 00000010 section@0
156700000000 00000000 00000004 ro-u-boot
156800000010 00000010 00000010 section@1
156900000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001570''', map_data)
1571
Simon Glass736bb0a2018-07-06 10:27:17 -06001572 def testUnknownContents(self):
1573 """Test that obtaining the contents works as expected"""
1574 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001575 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001576 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001577 "processing of contents: remaining ["
1578 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001579
Simon Glass5c890232018-07-06 10:27:19 -06001580 def testBadChangeSize(self):
1581 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001582 try:
1583 state.SetAllowEntryExpansion(False)
1584 with self.assertRaises(ValueError) as e:
1585 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001586 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001587 str(e.exception))
1588 finally:
1589 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001590
Simon Glass16b8d6b2018-07-06 10:27:42 -06001591 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001592 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001593 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001594 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001595 dtb = fdt.Fdt(out_dtb_fname)
1596 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001597 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001598 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001599 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001600 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001601 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001602 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001603 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001604 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001605 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001606 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001607 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001608 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001609 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001610
Simon Glass3ab95982018-08-01 15:22:37 -06001611 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001612 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001613 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001614 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001615 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001616 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001617 'size': 40
1618 }, props)
1619
1620 def testUpdateFdtBad(self):
1621 """Test that we detect when ProcessFdt never completes"""
1622 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001623 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001624 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001625 '[<binman.etype._testing.Entry__testing',
1626 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001627
Simon Glass53af22a2018-07-17 13:25:32 -06001628 def testEntryArgs(self):
1629 """Test passing arguments to entries from the command line"""
1630 entry_args = {
1631 'test-str-arg': 'test1',
1632 'test-int-arg': '456',
1633 }
Simon Glass741f2d62018-10-01 12:22:30 -06001634 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001635 self.assertIn('image', control.images)
1636 entry = control.images['image'].GetEntries()['_testing']
1637 self.assertEqual('test0', entry.test_str_fdt)
1638 self.assertEqual('test1', entry.test_str_arg)
1639 self.assertEqual(123, entry.test_int_fdt)
1640 self.assertEqual(456, entry.test_int_arg)
1641
1642 def testEntryArgsMissing(self):
1643 """Test missing arguments and properties"""
1644 entry_args = {
1645 'test-int-arg': '456',
1646 }
Simon Glass741f2d62018-10-01 12:22:30 -06001647 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001648 entry = control.images['image'].GetEntries()['_testing']
1649 self.assertEqual('test0', entry.test_str_fdt)
1650 self.assertEqual(None, entry.test_str_arg)
1651 self.assertEqual(None, entry.test_int_fdt)
1652 self.assertEqual(456, entry.test_int_arg)
1653
1654 def testEntryArgsRequired(self):
1655 """Test missing arguments and properties"""
1656 entry_args = {
1657 'test-int-arg': '456',
1658 }
1659 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001660 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001661 self.assertIn("Node '/binman/_testing': "
1662 'Missing required properties/entry args: test-str-arg, '
1663 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001664 str(e.exception))
1665
1666 def testEntryArgsInvalidFormat(self):
1667 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001668 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1669 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001670 with self.assertRaises(ValueError) as e:
1671 self._DoBinman(*args)
1672 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1673
1674 def testEntryArgsInvalidInteger(self):
1675 """Test that an invalid entry-argument integer is detected"""
1676 entry_args = {
1677 'test-int-arg': 'abc',
1678 }
1679 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001680 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001681 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1682 "'test-int-arg' (value 'abc') to integer",
1683 str(e.exception))
1684
1685 def testEntryArgsInvalidDatatype(self):
1686 """Test that an invalid entry-argument datatype is detected
1687
1688 This test could be written in entry_test.py except that it needs
1689 access to control.entry_args, which seems more than that module should
1690 be able to see.
1691 """
1692 entry_args = {
1693 'test-bad-datatype-arg': '12',
1694 }
1695 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001696 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001697 entry_args=entry_args)
1698 self.assertIn('GetArg() internal error: Unknown data type ',
1699 str(e.exception))
1700
Simon Glassbb748372018-07-17 13:25:33 -06001701 def testText(self):
1702 """Test for a text entry type"""
1703 entry_args = {
1704 'test-id': TEXT_DATA,
1705 'test-id2': TEXT_DATA2,
1706 'test-id3': TEXT_DATA3,
1707 }
Simon Glass741f2d62018-10-01 12:22:30 -06001708 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001709 entry_args=entry_args)
Simon Glassc1aa66e2022-01-29 14:14:04 -07001710 expected = (tools.to_bytes(TEXT_DATA) +
1711 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1712 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001713 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001714 self.assertEqual(expected, data)
1715
Simon Glassfd8d1f72018-07-17 13:25:36 -06001716 def testEntryDocs(self):
1717 """Test for creation of entry documentation"""
1718 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001719 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001720 self.assertTrue(len(stdout.getvalue()) > 0)
1721
1722 def testEntryDocsMissing(self):
1723 """Test handling of missing entry documentation"""
1724 with self.assertRaises(ValueError) as e:
1725 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001726 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001727 self.assertIn('Documentation is missing for modules: u_boot',
1728 str(e.exception))
1729
Simon Glass11e36cc2018-07-17 13:25:38 -06001730 def testFmap(self):
1731 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001732 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001733 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07001734 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1735 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001736 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001737 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001738 self.assertEqual(1, fhdr.ver_major)
1739 self.assertEqual(0, fhdr.ver_minor)
1740 self.assertEqual(0, fhdr.base)
Simon Glass17365752021-04-03 11:05:10 +13001741 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glassc7722e82021-04-03 11:05:09 +13001742 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001743 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass17365752021-04-03 11:05:10 +13001744 self.assertEqual(5, fhdr.nareas)
Simon Glassc7722e82021-04-03 11:05:09 +13001745 fiter = iter(fentries)
Simon Glass11e36cc2018-07-17 13:25:38 -06001746
Simon Glassc7722e82021-04-03 11:05:09 +13001747 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001748 self.assertEqual(b'SECTION0', fentry.name)
1749 self.assertEqual(0, fentry.offset)
1750 self.assertEqual(16, fentry.size)
Simon Glass9dbb02b2023-02-12 17:11:15 -07001751 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glass17365752021-04-03 11:05:10 +13001752
1753 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001754 self.assertEqual(b'RO_U_BOOT', fentry.name)
1755 self.assertEqual(0, fentry.offset)
1756 self.assertEqual(4, fentry.size)
1757 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001758
Simon Glassc7722e82021-04-03 11:05:09 +13001759 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001760 self.assertEqual(b'SECTION1', fentry.name)
1761 self.assertEqual(16, fentry.offset)
1762 self.assertEqual(16, fentry.size)
1763 self.assertEqual(0, fentry.flags)
1764
1765 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001766 self.assertEqual(b'RW_U_BOOT', fentry.name)
1767 self.assertEqual(16, fentry.offset)
1768 self.assertEqual(4, fentry.size)
1769 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001770
Simon Glassc7722e82021-04-03 11:05:09 +13001771 fentry = next(fiter)
1772 self.assertEqual(b'FMAP', fentry.name)
1773 self.assertEqual(32, fentry.offset)
1774 self.assertEqual(expect_size, fentry.size)
1775 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001776
Simon Glassec127af2018-07-17 13:25:39 -06001777 def testBlobNamedByArg(self):
1778 """Test we can add a blob with the filename coming from an entry arg"""
1779 entry_args = {
1780 'cros-ec-rw-path': 'ecrw.bin',
1781 }
Simon Glass3decfa32020-09-01 05:13:54 -06001782 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001783
Simon Glass3af8e492018-07-17 13:25:40 -06001784 def testFill(self):
1785 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001786 data = self._DoReadFile('069_fill.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001787 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001788 self.assertEqual(expected, data)
1789
1790 def testFillNoSize(self):
1791 """Test for an fill entry type with no size"""
1792 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001793 self._DoReadFile('070_fill_no_size.dts')
Simon Glasscdadada2022-08-13 11:40:44 -06001794 self.assertIn("'fill' entry is missing properties: size",
Simon Glass3af8e492018-07-17 13:25:40 -06001795 str(e.exception))
1796
Simon Glass0ef87aa2018-07-17 13:25:44 -06001797 def _HandleGbbCommand(self, pipe_list):
1798 """Fake calls to the futility utility"""
Simon Glassfe7e9242023-02-22 12:14:49 -07001799 if 'futility' in pipe_list[0][0]:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001800 fname = pipe_list[0][-1]
1801 # Append our GBB data to the file, which will happen every time the
1802 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001803 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001804 fd.write(GBB_DATA)
1805 return command.CommandResult()
1806
1807 def testGbb(self):
1808 """Test for the Chromium OS Google Binary Block"""
1809 command.test_result = self._HandleGbbCommand
1810 entry_args = {
1811 'keydir': 'devkeys',
1812 'bmpblk': 'bmpblk.bin',
1813 }
Simon Glass741f2d62018-10-01 12:22:30 -06001814 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001815
1816 # Since futility
Simon Glassc1aa66e2022-01-29 14:14:04 -07001817 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1818 tools.get_bytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001819 self.assertEqual(expected, data)
1820
1821 def testGbbTooSmall(self):
1822 """Test for the Chromium OS Google Binary Block being large enough"""
1823 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001824 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001825 self.assertIn("Node '/binman/gbb': GBB is too small",
1826 str(e.exception))
1827
1828 def testGbbNoSize(self):
1829 """Test for the Chromium OS Google Binary Block having a size"""
1830 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001831 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001832 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1833 str(e.exception))
1834
Simon Glass4f9ee832022-01-09 20:14:09 -07001835 def testGbbMissing(self):
1836 """Test that binman still produces an image if futility is missing"""
1837 entry_args = {
1838 'keydir': 'devkeys',
1839 }
1840 with test_util.capture_sys_output() as (_, stderr):
1841 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1842 entry_args=entry_args)
1843 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07001844 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass4f9ee832022-01-09 20:14:09 -07001845
Simon Glass24d0d3c2018-07-17 13:25:47 -06001846 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001847 """Fake calls to the futility utility
1848
1849 The expected pipe is:
1850
1851 [('futility', 'vbutil_firmware', '--vblock',
1852 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1853 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1854 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1855 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1856
1857 This writes to the output file (here, 'vblock.vblock'). If
1858 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1859 of the input data (here, 'input.vblock').
1860 """
Simon Glassfe7e9242023-02-22 12:14:49 -07001861 if 'futility' in pipe_list[0][0]:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001862 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001863 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001864 if self._hash_data:
1865 infile = pipe_list[0][11]
1866 m = hashlib.sha256()
Simon Glassc1aa66e2022-01-29 14:14:04 -07001867 data = tools.read_file(infile)
Simon Glass5af9ebc2021-01-06 21:35:17 -07001868 m.update(data)
1869 fd.write(m.digest())
1870 else:
1871 fd.write(VBLOCK_DATA)
1872
Simon Glass24d0d3c2018-07-17 13:25:47 -06001873 return command.CommandResult()
1874
1875 def testVblock(self):
1876 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001877 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001878 command.test_result = self._HandleVblockCommand
1879 entry_args = {
1880 'keydir': 'devkeys',
1881 }
Simon Glass741f2d62018-10-01 12:22:30 -06001882 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001883 entry_args=entry_args)
1884 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1885 self.assertEqual(expected, data)
1886
1887 def testVblockNoContent(self):
1888 """Test we detect a vblock which has no content to sign"""
1889 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001890 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001891 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001892 'property', str(e.exception))
1893
1894 def testVblockBadPhandle(self):
1895 """Test that we detect a vblock with an invalid phandle in contents"""
1896 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001897 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001898 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1899 '1000', str(e.exception))
1900
1901 def testVblockBadEntry(self):
1902 """Test that we detect an entry that points to a non-entry"""
1903 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001904 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001905 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1906 "'other'", str(e.exception))
1907
Simon Glass5af9ebc2021-01-06 21:35:17 -07001908 def testVblockContent(self):
1909 """Test that the vblock signs the right data"""
1910 self._hash_data = True
1911 command.test_result = self._HandleVblockCommand
1912 entry_args = {
1913 'keydir': 'devkeys',
1914 }
1915 data = self._DoReadFileDtb(
1916 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1917 entry_args=entry_args)[0]
1918 hashlen = 32 # SHA256 hash is 32 bytes
1919 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1920 hashval = data[-hashlen:]
1921 dtb = data[len(U_BOOT_DATA):-hashlen]
1922
1923 expected_data = U_BOOT_DATA + dtb
1924
1925 # The hashval should be a hash of the dtb
1926 m = hashlib.sha256()
1927 m.update(expected_data)
1928 expected_hashval = m.digest()
1929 self.assertEqual(expected_hashval, hashval)
1930
Simon Glass4f9ee832022-01-09 20:14:09 -07001931 def testVblockMissing(self):
1932 """Test that binman still produces an image if futility is missing"""
1933 entry_args = {
1934 'keydir': 'devkeys',
1935 }
1936 with test_util.capture_sys_output() as (_, stderr):
1937 self._DoTestFile('074_vblock.dts',
1938 force_missing_bintools='futility',
1939 entry_args=entry_args)
1940 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07001941 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass4f9ee832022-01-09 20:14:09 -07001942
Simon Glassb8ef5b62018-07-17 13:25:48 -06001943 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001944 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001945 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001946 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001947 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001948 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1949
Simon Glass15a587c2018-07-17 13:25:51 -06001950 def testUsesPos(self):
1951 """Test that the 'pos' property cannot be used anymore"""
1952 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001953 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001954 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1955 "'pos'", str(e.exception))
1956
Simon Glassd178eab2018-09-14 04:57:08 -06001957 def testFillZero(self):
1958 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001959 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001960 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001961
Simon Glass0b489362018-09-14 04:57:09 -06001962 def testTextMissing(self):
1963 """Test for a text entry type where there is no text"""
1964 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001965 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001966 self.assertIn("Node '/binman/text': No value provided for text label "
1967 "'test-id'", str(e.exception))
1968
Simon Glass35b384c2018-09-14 04:57:10 -06001969 def testPackStart16Tpl(self):
1970 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001971 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001972 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1973
Simon Glass0bfa7b02018-09-14 04:57:12 -06001974 def testSelectImage(self):
1975 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001976 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001977
Simon Glasseb833d82019-04-25 21:58:34 -06001978 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001979 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001980 with test_util.capture_sys_output() as (stdout, stderr):
1981 retcode = self._DoTestFile('006_dual_image.dts',
1982 verbosity=verbosity,
1983 images=['image2'])
1984 self.assertEqual(0, retcode)
1985 if verbosity:
1986 self.assertIn(expected, stdout.getvalue())
1987 else:
1988 self.assertNotIn(expected, stdout.getvalue())
1989
Simon Glassc1aa66e2022-01-29 14:14:04 -07001990 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1991 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001992 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001993
Simon Glass6ed45ba2018-09-14 04:57:24 -06001994 def testUpdateFdtAll(self):
1995 """Test that all device trees are updated with offset/size info"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001996 self._SetupSplElf()
1997 self._SetupTplElf()
Simon Glass3c081312019-07-08 14:25:26 -06001998 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001999
2000 base_expected = {
Simon Glass6ed45ba2018-09-14 04:57:24 -06002001 'offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07002002 'image-pos': 0,
2003 'size': 2320,
Simon Glass6ed45ba2018-09-14 04:57:24 -06002004 'section:offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07002005 'section:image-pos': 0,
2006 'section:size': 565,
2007 'section/u-boot-dtb:offset': 0,
2008 'section/u-boot-dtb:image-pos': 0,
2009 'section/u-boot-dtb:size': 565,
2010 'u-boot-spl-dtb:offset': 565,
2011 'u-boot-spl-dtb:image-pos': 565,
2012 'u-boot-spl-dtb:size': 585,
2013 'u-boot-tpl-dtb:offset': 1150,
2014 'u-boot-tpl-dtb:image-pos': 1150,
2015 'u-boot-tpl-dtb:size': 585,
2016 'u-boot-vpl-dtb:image-pos': 1735,
2017 'u-boot-vpl-dtb:offset': 1735,
2018 'u-boot-vpl-dtb:size': 585,
Simon Glass6ed45ba2018-09-14 04:57:24 -06002019 }
2020
2021 # We expect three device-tree files in the output, one after the other.
2022 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2023 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2024 # main U-Boot tree. All three should have the same postions and offset.
2025 start = 0
Simon Glass6ad24522022-02-28 07:16:54 -07002026 self.maxDiff = None
2027 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06002028 dtb = fdt.Fdt.FromData(data[start:])
2029 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06002030 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass6ad24522022-02-28 07:16:54 -07002031 ['spl', 'tpl', 'vpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06002032 expected = dict(base_expected)
2033 if item:
2034 expected[item] = 0
2035 self.assertEqual(expected, props)
2036 start += dtb._fdt_obj.totalsize()
2037
2038 def testUpdateFdtOutput(self):
2039 """Test that output DTB files are updated"""
2040 try:
Simon Glass741f2d62018-10-01 12:22:30 -06002041 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06002042 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2043
2044 # Unfortunately, compiling a source file always results in a file
2045 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06002046 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06002047 # binman as a file called u-boot.dtb. To fix this, copy the file
2048 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06002049 start = 0
2050 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass6ad24522022-02-28 07:16:54 -07002051 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06002052 dtb = fdt.Fdt.FromData(data[start:])
2053 size = dtb._fdt_obj.totalsize()
Simon Glassc1aa66e2022-01-29 14:14:04 -07002054 pathname = tools.get_output_filename(os.path.split(fname)[1])
2055 outdata = tools.read_file(pathname)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002056 name = os.path.split(fname)[0]
2057
2058 if name:
Simon Glass6ad24522022-02-28 07:16:54 -07002059 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002060 else:
2061 orig_indata = dtb_data
2062 self.assertNotEqual(outdata, orig_indata,
2063 "Expected output file '%s' be updated" % pathname)
2064 self.assertEqual(outdata, data[start:start + size],
2065 "Expected output file '%s' to match output image" %
2066 pathname)
2067 start += size
2068 finally:
2069 self._ResetDtbs()
2070
Simon Glass83d73c22018-09-14 04:57:26 -06002071 def _decompress(self, data):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002072 bintool = self.comp_bintools['lz4']
2073 return bintool.decompress(data)
Simon Glass83d73c22018-09-14 04:57:26 -06002074
2075 def testCompress(self):
2076 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06002077 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002078 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06002079 use_real_dtb=True, update_dtb=True)
2080 dtb = fdt.Fdt(out_dtb_fname)
2081 dtb.Scan()
2082 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2083 orig = self._decompress(data)
2084 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06002085
2086 # Do a sanity check on various fields
2087 image = control.images['image']
2088 entries = image.GetEntries()
2089 self.assertEqual(1, len(entries))
2090
2091 entry = entries['blob']
2092 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2093 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2094 orig = self._decompress(entry.data)
2095 self.assertEqual(orig, entry.uncomp_data)
2096
Simon Glass63e7ba62020-10-26 17:40:16 -06002097 self.assertEqual(image.data, entry.data)
2098
Simon Glass83d73c22018-09-14 04:57:26 -06002099 expected = {
2100 'blob:uncomp-size': len(COMPRESS_DATA),
2101 'blob:size': len(data),
2102 'size': len(data),
2103 }
2104 self.assertEqual(expected, props)
2105
Simon Glass0a98b282018-09-14 04:57:28 -06002106 def testFiles(self):
2107 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06002108 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002109 self.assertEqual(FILES_DATA, data)
2110
2111 def testFilesCompress(self):
2112 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06002113 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002114 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002115
2116 image = control.images['image']
2117 entries = image.GetEntries()
2118 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06002119 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06002120
Simon Glassc6c10e72019-05-17 22:00:46 -06002121 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06002122 for i in range(1, 3):
2123 key = '%d.dat' % i
2124 start = entries[key].image_pos
2125 len = entries[key].size
2126 chunk = data[start:start + len]
2127 orig += self._decompress(chunk)
2128
2129 self.assertEqual(FILES_DATA, orig)
2130
2131 def testFilesMissing(self):
2132 """Test missing files"""
2133 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002134 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002135 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2136 'no files', str(e.exception))
2137
2138 def testFilesNoPattern(self):
2139 """Test missing files"""
2140 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002141 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002142 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2143 str(e.exception))
2144
Simon Glass80a66ae2022-03-05 20:18:59 -07002145 def testExtendSize(self):
2146 """Test an extending entry"""
2147 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06002148 map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002149 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2150 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2151 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2152 tools.get_bytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06002153 self.assertEqual(expect, data)
2154 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700215500000000 00000000 00000028 image
Simon Glassba64a0b2018-09-14 04:57:29 -0600215600000000 00000000 00000008 fill
215700000008 00000008 00000004 u-boot
21580000000c 0000000c 00000004 section
21590000000c 00000000 00000003 intel-mrc
216000000010 00000010 00000004 u-boot2
216100000014 00000014 0000000c section2
216200000014 00000000 00000008 fill
21630000001c 00000008 00000004 u-boot
216400000020 00000020 00000008 fill2
2165''', map_data)
2166
Simon Glass80a66ae2022-03-05 20:18:59 -07002167 def testExtendSizeBad(self):
2168 """Test an extending entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06002169 with test_util.capture_sys_output() as (stdout, stderr):
2170 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002171 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002172 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2173 'expanding entry', str(e.exception))
2174
Simon Glasse0e5df92018-09-14 04:57:31 -06002175 def testHash(self):
2176 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002177 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002178 use_real_dtb=True, update_dtb=True)
2179 dtb = fdt.Fdt(out_dtb_fname)
2180 dtb.Scan()
2181 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2182 m = hashlib.sha256()
2183 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002184 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002185
2186 def testHashNoAlgo(self):
2187 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002188 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002189 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2190 'hash node', str(e.exception))
2191
2192 def testHashBadAlgo(self):
2193 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002194 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass8db1f992022-02-08 10:59:44 -07002195 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glasse0e5df92018-09-14 04:57:31 -06002196 str(e.exception))
2197
2198 def testHashSection(self):
2199 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002200 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002201 use_real_dtb=True, update_dtb=True)
2202 dtb = fdt.Fdt(out_dtb_fname)
2203 dtb.Scan()
2204 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2205 m = hashlib.sha256()
2206 m.update(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002207 m.update(tools.get_bytes(ord('a'), 16))
Simon Glassc6c10e72019-05-17 22:00:46 -06002208 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002209
Simon Glassf0253632018-09-14 04:57:32 -06002210 def testPackUBootTplMicrocode(self):
2211 """Test that x86 microcode can be handled correctly in TPL
2212
2213 We expect to see the following in the image, in order:
2214 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2215 place
2216 u-boot-tpl.dtb with the microcode removed
2217 the microcode
2218 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002219 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002220 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002221 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002222 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2223 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002224
Simon Glassf8f8df62018-09-14 04:57:34 -06002225 def testFmapX86(self):
2226 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002227 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002228 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002229 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002230 self.assertEqual(expected, data[:32])
2231 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2232
2233 self.assertEqual(0x100, fhdr.image_size)
2234
2235 self.assertEqual(0, fentries[0].offset)
2236 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002237 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002238
2239 self.assertEqual(4, fentries[1].offset)
2240 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002241 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002242
2243 self.assertEqual(32, fentries[2].offset)
2244 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2245 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002246 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002247
2248 def testFmapX86Section(self):
2249 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002250 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002251 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002252 self.assertEqual(expected, data[:32])
2253 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2254
Simon Glass17365752021-04-03 11:05:10 +13002255 self.assertEqual(0x180, fhdr.image_size)
2256 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002257 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002258
Simon Glassc7722e82021-04-03 11:05:09 +13002259 fentry = next(fiter)
2260 self.assertEqual(b'U_BOOT', fentry.name)
2261 self.assertEqual(0, fentry.offset)
2262 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002263
Simon Glassc7722e82021-04-03 11:05:09 +13002264 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002265 self.assertEqual(b'SECTION', fentry.name)
2266 self.assertEqual(4, fentry.offset)
2267 self.assertEqual(0x20 + expect_size, fentry.size)
2268
2269 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002270 self.assertEqual(b'INTEL_MRC', fentry.name)
2271 self.assertEqual(4, fentry.offset)
2272 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002273
Simon Glassc7722e82021-04-03 11:05:09 +13002274 fentry = next(fiter)
2275 self.assertEqual(b'FMAP', fentry.name)
2276 self.assertEqual(36, fentry.offset)
2277 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002278
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002279 def testElf(self):
2280 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002281 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002282 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002283 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002284 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002285 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002286
Simon Glass093d1682019-07-08 13:18:25 -06002287 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002288 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002289 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002290 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002291 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002292 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002293
Simon Glass163ed6c2018-09-14 04:57:36 -06002294 def testPackOverlapMap(self):
2295 """Test that overlapping regions are detected"""
2296 with test_util.capture_sys_output() as (stdout, stderr):
2297 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002298 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002299 map_fname = tools.get_output_filename('image.map')
Simon Glass163ed6c2018-09-14 04:57:36 -06002300 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2301 stdout.getvalue())
2302
2303 # We should not get an inmage, but there should be a map file
Simon Glassc1aa66e2022-01-29 14:14:04 -07002304 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glass163ed6c2018-09-14 04:57:36 -06002305 self.assertTrue(os.path.exists(map_fname))
Simon Glassc1aa66e2022-01-29 14:14:04 -07002306 map_data = tools.read_file(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002307 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -07002308<none> 00000000 00000008 image
Simon Glass163ed6c2018-09-14 04:57:36 -06002309<none> 00000000 00000004 u-boot
2310<none> 00000003 00000004 u-boot-align
2311''', map_data)
2312
Simon Glass093d1682019-07-08 13:18:25 -06002313 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002314 """Test that an image with an Intel Reference code binary works"""
2315 data = self._DoReadFile('100_intel_refcode.dts')
2316 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2317
Simon Glass9481c802019-04-25 21:58:39 -06002318 def testSectionOffset(self):
2319 """Tests use of a section with an offset"""
2320 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2321 map=True)
2322 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700232300000000 00000000 00000038 image
Simon Glass9481c802019-04-25 21:58:39 -0600232400000004 00000004 00000010 section@0
232500000004 00000000 00000004 u-boot
232600000018 00000018 00000010 section@1
232700000018 00000000 00000004 u-boot
23280000002c 0000002c 00000004 section@2
23290000002c 00000000 00000004 u-boot
2330''', map_data)
2331 self.assertEqual(data,
Simon Glassc1aa66e2022-01-29 14:14:04 -07002332 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2333 tools.get_bytes(0x21, 12) +
2334 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2335 tools.get_bytes(0x61, 12) +
2336 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2337 tools.get_bytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002338
Simon Glassac62fba2019-07-08 13:18:53 -06002339 def testCbfsRaw(self):
2340 """Test base handling of a Coreboot Filesystem (CBFS)
2341
2342 The exact contents of the CBFS is verified by similar tests in
2343 cbfs_util_test.py. The tests here merely check that the files added to
2344 the CBFS can be found in the final image.
2345 """
2346 data = self._DoReadFile('102_cbfs_raw.dts')
2347 size = 0xb0
2348
2349 cbfs = cbfs_util.CbfsReader(data)
2350 self.assertEqual(size, cbfs.rom_size)
2351
2352 self.assertIn('u-boot-dtb', cbfs.files)
2353 cfile = cbfs.files['u-boot-dtb']
2354 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2355
2356 def testCbfsArch(self):
2357 """Test on non-x86 architecture"""
2358 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2359 size = 0x100
2360
2361 cbfs = cbfs_util.CbfsReader(data)
2362 self.assertEqual(size, cbfs.rom_size)
2363
2364 self.assertIn('u-boot-dtb', cbfs.files)
2365 cfile = cbfs.files['u-boot-dtb']
2366 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2367
2368 def testCbfsStage(self):
2369 """Tests handling of a Coreboot Filesystem (CBFS)"""
2370 if not elf.ELF_TOOLS:
2371 self.skipTest('Python elftools not available')
2372 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2373 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2374 size = 0xb0
2375
2376 data = self._DoReadFile('104_cbfs_stage.dts')
2377 cbfs = cbfs_util.CbfsReader(data)
2378 self.assertEqual(size, cbfs.rom_size)
2379
2380 self.assertIn('u-boot', cbfs.files)
2381 cfile = cbfs.files['u-boot']
2382 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2383
2384 def testCbfsRawCompress(self):
2385 """Test handling of compressing raw files"""
2386 self._CheckLz4()
2387 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2388 size = 0x140
2389
2390 cbfs = cbfs_util.CbfsReader(data)
2391 self.assertIn('u-boot', cbfs.files)
2392 cfile = cbfs.files['u-boot']
2393 self.assertEqual(COMPRESS_DATA, cfile.data)
2394
2395 def testCbfsBadArch(self):
2396 """Test handling of a bad architecture"""
2397 with self.assertRaises(ValueError) as e:
2398 self._DoReadFile('106_cbfs_bad_arch.dts')
2399 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2400
2401 def testCbfsNoSize(self):
2402 """Test handling of a missing size property"""
2403 with self.assertRaises(ValueError) as e:
2404 self._DoReadFile('107_cbfs_no_size.dts')
2405 self.assertIn('entry must have a size property', str(e.exception))
2406
Simon Glasse2f04742021-11-23 11:03:54 -07002407 def testCbfsNoContents(self):
Simon Glassac62fba2019-07-08 13:18:53 -06002408 """Test handling of a CBFS entry which does not provide contentsy"""
2409 with self.assertRaises(ValueError) as e:
2410 self._DoReadFile('108_cbfs_no_contents.dts')
2411 self.assertIn('Could not complete processing of contents',
2412 str(e.exception))
2413
2414 def testCbfsBadCompress(self):
2415 """Test handling of a bad architecture"""
2416 with self.assertRaises(ValueError) as e:
2417 self._DoReadFile('109_cbfs_bad_compress.dts')
2418 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2419 str(e.exception))
2420
2421 def testCbfsNamedEntries(self):
2422 """Test handling of named entries"""
2423 data = self._DoReadFile('110_cbfs_name.dts')
2424
2425 cbfs = cbfs_util.CbfsReader(data)
2426 self.assertIn('FRED', cbfs.files)
2427 cfile1 = cbfs.files['FRED']
2428 self.assertEqual(U_BOOT_DATA, cfile1.data)
2429
2430 self.assertIn('hello', cbfs.files)
2431 cfile2 = cbfs.files['hello']
2432 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2433
Simon Glassc5ac1382019-07-08 13:18:54 -06002434 def _SetupIfwi(self, fname):
2435 """Set up to run an IFWI test
2436
2437 Args:
2438 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2439 """
2440 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002441 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002442
2443 # Intel Integrated Firmware Image (IFWI) file
2444 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2445 data = fd.read()
2446 TestFunctional._MakeInputFile(fname,data)
2447
2448 def _CheckIfwi(self, data):
2449 """Check that an image with an IFWI contains the correct output
2450
2451 Args:
2452 data: Conents of output file
2453 """
Simon Glassc1aa66e2022-01-29 14:14:04 -07002454 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06002455 if data[:0x1000] != expected_desc:
2456 self.fail('Expected descriptor binary at start of image')
2457
2458 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glassc1aa66e2022-01-29 14:14:04 -07002459 image_fname = tools.get_output_filename('image.bin')
2460 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass532ae702022-01-09 20:14:01 -07002461 ifwitool = bintool.Bintool.create('ifwitool')
2462 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glassc5ac1382019-07-08 13:18:54 -06002463
Simon Glassc1aa66e2022-01-29 14:14:04 -07002464 tpl_data = tools.read_file(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002465 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002466
2467 def testPackX86RomIfwi(self):
2468 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2469 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002470 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002471 self._CheckIfwi(data)
2472
2473 def testPackX86RomIfwiNoDesc(self):
2474 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2475 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002476 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002477 self._CheckIfwi(data)
2478
2479 def testPackX86RomIfwiNoData(self):
2480 """Test that an x86 ROM with IFWI handles missing data"""
2481 self._SetupIfwi('ifwi.bin')
2482 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002483 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002484 self.assertIn('Could not complete processing of contents',
2485 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002486
Simon Glass4f9ee832022-01-09 20:14:09 -07002487 def testIfwiMissing(self):
2488 """Test that binman still produces an image if ifwitool is missing"""
2489 self._SetupIfwi('fitimage.bin')
2490 with test_util.capture_sys_output() as (_, stderr):
2491 self._DoTestFile('111_x86_rom_ifwi.dts',
2492 force_missing_bintools='ifwitool')
2493 err = stderr.getvalue()
2494 self.assertRegex(err,
Simon Glass193d3db2023-02-07 14:34:18 -07002495 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass4f9ee832022-01-09 20:14:09 -07002496
Simon Glasse073d4e2019-07-08 13:18:56 -06002497 def testCbfsOffset(self):
2498 """Test a CBFS with files at particular offsets
2499
2500 Like all CFBS tests, this is just checking the logic that calls
2501 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2502 """
2503 data = self._DoReadFile('114_cbfs_offset.dts')
2504 size = 0x200
2505
2506 cbfs = cbfs_util.CbfsReader(data)
2507 self.assertEqual(size, cbfs.rom_size)
2508
2509 self.assertIn('u-boot', cbfs.files)
2510 cfile = cbfs.files['u-boot']
2511 self.assertEqual(U_BOOT_DATA, cfile.data)
2512 self.assertEqual(0x40, cfile.cbfs_offset)
2513
2514 self.assertIn('u-boot-dtb', cbfs.files)
2515 cfile2 = cbfs.files['u-boot-dtb']
2516 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2517 self.assertEqual(0x140, cfile2.cbfs_offset)
2518
Simon Glass086cec92019-07-08 14:25:27 -06002519 def testFdtmap(self):
2520 """Test an FDT map can be inserted in the image"""
2521 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2522 fdtmap_data = data[len(U_BOOT_DATA):]
2523 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002524 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002525 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass086cec92019-07-08 14:25:27 -06002526
2527 fdt_data = fdtmap_data[16:]
2528 dtb = fdt.Fdt.FromData(fdt_data)
2529 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002530 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002531 self.assertEqual({
2532 'image-pos': 0,
2533 'offset': 0,
2534 'u-boot:offset': 0,
2535 'u-boot:size': len(U_BOOT_DATA),
2536 'u-boot:image-pos': 0,
2537 'fdtmap:image-pos': 4,
2538 'fdtmap:offset': 4,
2539 'fdtmap:size': len(fdtmap_data),
2540 'size': len(data),
2541 }, props)
2542
2543 def testFdtmapNoMatch(self):
2544 """Check handling of an FDT map when the section cannot be found"""
2545 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2546
2547 # Mangle the section name, which should cause a mismatch between the
2548 # correct FDT path and the one expected by the section
2549 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002550 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002551 entries = image.GetEntries()
2552 fdtmap = entries['fdtmap']
2553 with self.assertRaises(ValueError) as e:
2554 fdtmap._GetFdtmap()
2555 self.assertIn("Cannot locate node for path '/binman-suffix'",
2556 str(e.exception))
2557
Simon Glasscf228942019-07-08 14:25:28 -06002558 def testFdtmapHeader(self):
2559 """Test an FDT map and image header can be inserted in the image"""
2560 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2561 fdtmap_pos = len(U_BOOT_DATA)
2562 fdtmap_data = data[fdtmap_pos:]
2563 fdt_data = fdtmap_data[16:]
2564 dtb = fdt.Fdt.FromData(fdt_data)
2565 fdt_size = dtb.GetFdtObj().totalsize()
2566 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002567 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002568 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2569 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2570
2571 def testFdtmapHeaderStart(self):
2572 """Test an image header can be inserted at the image start"""
2573 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2574 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2575 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002576 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002577 offset = struct.unpack('<I', hdr_data[4:])[0]
2578 self.assertEqual(fdtmap_pos, offset)
2579
2580 def testFdtmapHeaderPos(self):
2581 """Test an image header can be inserted at a chosen position"""
2582 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2583 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2584 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002585 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002586 offset = struct.unpack('<I', hdr_data[4:])[0]
2587 self.assertEqual(fdtmap_pos, offset)
2588
2589 def testHeaderMissingFdtmap(self):
2590 """Test an image header requires an fdtmap"""
2591 with self.assertRaises(ValueError) as e:
2592 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2593 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2594 str(e.exception))
2595
2596 def testHeaderNoLocation(self):
2597 """Test an image header with a no specified location is detected"""
2598 with self.assertRaises(ValueError) as e:
2599 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2600 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2601 str(e.exception))
2602
Simon Glassc52c9e72019-07-08 14:25:37 -06002603 def testEntryExpand(self):
Simon Glass80a66ae2022-03-05 20:18:59 -07002604 """Test extending an entry after it is packed"""
2605 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002606 self.assertEqual(b'aaa', data[:3])
2607 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2608 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002609
Simon Glass80a66ae2022-03-05 20:18:59 -07002610 def testEntryExtendBad(self):
2611 """Test extending an entry after it is packed, twice"""
Simon Glassc52c9e72019-07-08 14:25:37 -06002612 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002613 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002614 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002615 str(e.exception))
2616
Simon Glass80a66ae2022-03-05 20:18:59 -07002617 def testEntryExtendSection(self):
2618 """Test extending an entry within a section after it is packed"""
2619 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass79d3c582019-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 Glassc52c9e72019-07-08 14:25:37 -06002623
Simon Glass6c223fd2019-07-08 14:25:38 -06002624 def testCompressDtb(self):
2625 """Test that compress of device-tree files is supported"""
2626 self._CheckLz4()
2627 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2628 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2629 comp_data = data[len(U_BOOT_DATA):]
2630 orig = self._decompress(comp_data)
2631 dtb = fdt.Fdt.FromData(orig)
2632 dtb.Scan()
2633 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2634 expected = {
2635 'u-boot:size': len(U_BOOT_DATA),
2636 'u-boot-dtb:uncomp-size': len(orig),
2637 'u-boot-dtb:size': len(comp_data),
2638 'size': len(data),
2639 }
2640 self.assertEqual(expected, props)
2641
Simon Glass69f7cb32019-07-08 14:25:41 -06002642 def testCbfsUpdateFdt(self):
2643 """Test that we can update the device tree with CBFS offset/size info"""
2644 self._CheckLz4()
2645 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2646 update_dtb=True)
2647 dtb = fdt.Fdt(out_dtb_fname)
2648 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002649 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002650 del props['cbfs/u-boot:size']
2651 self.assertEqual({
2652 'offset': 0,
2653 'size': len(data),
2654 'image-pos': 0,
2655 'cbfs:offset': 0,
2656 'cbfs:size': len(data),
2657 'cbfs:image-pos': 0,
2658 'cbfs/u-boot:offset': 0x38,
2659 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2660 'cbfs/u-boot:image-pos': 0x38,
2661 'cbfs/u-boot-dtb:offset': 0xb8,
2662 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2663 'cbfs/u-boot-dtb:image-pos': 0xb8,
2664 }, props)
2665
Simon Glass8a1ad062019-07-08 14:25:42 -06002666 def testCbfsBadType(self):
2667 """Test an image header with a no specified location is detected"""
2668 with self.assertRaises(ValueError) as e:
2669 self._DoReadFile('126_cbfs_bad_type.dts')
2670 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2671
Simon Glass41b8ba02019-07-08 14:25:43 -06002672 def testList(self):
2673 """Test listing the files in an image"""
2674 self._CheckLz4()
2675 data = self._DoReadFile('127_list.dts')
2676 image = control.images['image']
2677 entries = image.BuildEntryList()
2678 self.assertEqual(7, len(entries))
2679
2680 ent = entries[0]
2681 self.assertEqual(0, ent.indent)
Simon Glass193d3db2023-02-07 14:34:18 -07002682 self.assertEqual('image', ent.name)
Simon Glass41b8ba02019-07-08 14:25:43 -06002683 self.assertEqual('section', ent.etype)
2684 self.assertEqual(len(data), ent.size)
2685 self.assertEqual(0, ent.image_pos)
2686 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002687 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002688
2689 ent = entries[1]
2690 self.assertEqual(1, ent.indent)
2691 self.assertEqual('u-boot', ent.name)
2692 self.assertEqual('u-boot', ent.etype)
2693 self.assertEqual(len(U_BOOT_DATA), ent.size)
2694 self.assertEqual(0, ent.image_pos)
2695 self.assertEqual(None, ent.uncomp_size)
2696 self.assertEqual(0, ent.offset)
2697
2698 ent = entries[2]
2699 self.assertEqual(1, ent.indent)
2700 self.assertEqual('section', ent.name)
2701 self.assertEqual('section', ent.etype)
2702 section_size = ent.size
2703 self.assertEqual(0x100, ent.image_pos)
2704 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002705 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002706
2707 ent = entries[3]
2708 self.assertEqual(2, ent.indent)
2709 self.assertEqual('cbfs', ent.name)
2710 self.assertEqual('cbfs', ent.etype)
2711 self.assertEqual(0x400, ent.size)
2712 self.assertEqual(0x100, ent.image_pos)
2713 self.assertEqual(None, ent.uncomp_size)
2714 self.assertEqual(0, ent.offset)
2715
2716 ent = entries[4]
2717 self.assertEqual(3, ent.indent)
2718 self.assertEqual('u-boot', ent.name)
2719 self.assertEqual('u-boot', ent.etype)
2720 self.assertEqual(len(U_BOOT_DATA), ent.size)
2721 self.assertEqual(0x138, ent.image_pos)
2722 self.assertEqual(None, ent.uncomp_size)
2723 self.assertEqual(0x38, ent.offset)
2724
2725 ent = entries[5]
2726 self.assertEqual(3, ent.indent)
2727 self.assertEqual('u-boot-dtb', ent.name)
2728 self.assertEqual('text', ent.etype)
2729 self.assertGreater(len(COMPRESS_DATA), ent.size)
2730 self.assertEqual(0x178, ent.image_pos)
2731 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2732 self.assertEqual(0x78, ent.offset)
2733
2734 ent = entries[6]
2735 self.assertEqual(2, ent.indent)
2736 self.assertEqual('u-boot-dtb', ent.name)
2737 self.assertEqual('u-boot-dtb', ent.etype)
2738 self.assertEqual(0x500, ent.image_pos)
2739 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2740 dtb_size = ent.size
2741 # Compressing this data expands it since headers are added
2742 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2743 self.assertEqual(0x400, ent.offset)
2744
2745 self.assertEqual(len(data), 0x100 + section_size)
2746 self.assertEqual(section_size, 0x400 + dtb_size)
2747
Simon Glasse1925fa2019-07-08 14:25:44 -06002748 def testFindFdtmap(self):
2749 """Test locating an FDT map in an image"""
2750 self._CheckLz4()
2751 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2752 image = control.images['image']
2753 entries = image.GetEntries()
2754 entry = entries['fdtmap']
2755 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2756
2757 def testFindFdtmapMissing(self):
2758 """Test failing to locate an FDP map"""
2759 data = self._DoReadFile('005_simple.dts')
2760 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2761
Simon Glass2d260032019-07-08 14:25:45 -06002762 def testFindImageHeader(self):
2763 """Test locating a image header"""
2764 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002765 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002766 image = control.images['image']
2767 entries = image.GetEntries()
2768 entry = entries['fdtmap']
2769 # The header should point to the FDT map
2770 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2771
2772 def testFindImageHeaderStart(self):
2773 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002774 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002775 image = control.images['image']
2776 entries = image.GetEntries()
2777 entry = entries['fdtmap']
2778 # The header should point to the FDT map
2779 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2780
2781 def testFindImageHeaderMissing(self):
2782 """Test failing to locate an image header"""
2783 data = self._DoReadFile('005_simple.dts')
2784 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2785
Simon Glassffded752019-07-08 14:25:46 -06002786 def testReadImage(self):
2787 """Test reading an image and accessing its FDT map"""
2788 self._CheckLz4()
2789 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002790 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002791 orig_image = control.images['image']
2792 image = Image.FromFile(image_fname)
2793 self.assertEqual(orig_image.GetEntries().keys(),
2794 image.GetEntries().keys())
2795
2796 orig_entry = orig_image.GetEntries()['fdtmap']
2797 entry = image.GetEntries()['fdtmap']
2798 self.assertEquals(orig_entry.offset, entry.offset)
2799 self.assertEquals(orig_entry.size, entry.size)
2800 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2801
2802 def testReadImageNoHeader(self):
2803 """Test accessing an image's FDT map without an image header"""
2804 self._CheckLz4()
2805 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002806 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002807 image = Image.FromFile(image_fname)
2808 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002809 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002810
2811 def testReadImageFail(self):
2812 """Test failing to read an image image's FDT map"""
2813 self._DoReadFile('005_simple.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002814 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002815 with self.assertRaises(ValueError) as e:
2816 image = Image.FromFile(image_fname)
2817 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002818
Simon Glass61f564d2019-07-08 14:25:48 -06002819 def testListCmd(self):
2820 """Test listing the files in an image using an Fdtmap"""
2821 self._CheckLz4()
2822 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2823
2824 # lz4 compression size differs depending on the version
2825 image = control.images['image']
2826 entries = image.GetEntries()
2827 section_size = entries['section'].size
2828 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2829 fdtmap_offset = entries['fdtmap'].offset
2830
Simon Glassf86a7362019-07-20 12:24:10 -06002831 try:
2832 tmpdir, updated_fname = self._SetupImageInTmpdir()
2833 with test_util.capture_sys_output() as (stdout, stderr):
2834 self._DoBinman('ls', '-i', updated_fname)
2835 finally:
2836 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002837 lines = stdout.getvalue().splitlines()
2838 expected = [
2839'Name Image-pos Size Entry-type Offset Uncomp-size',
2840'----------------------------------------------------------------------',
Simon Glass193d3db2023-02-07 14:34:18 -07002841'image 0 c00 section 0',
Simon Glass61f564d2019-07-08 14:25:48 -06002842' u-boot 0 4 u-boot 0',
2843' section 100 %x section 100' % section_size,
2844' cbfs 100 400 cbfs 0',
2845' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002846' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002847' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002848' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002849 (fdtmap_offset, fdtmap_offset),
2850' image-header bf8 8 image-header bf8',
2851 ]
2852 self.assertEqual(expected, lines)
2853
2854 def testListCmdFail(self):
2855 """Test failing to list an image"""
2856 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002857 try:
2858 tmpdir, updated_fname = self._SetupImageInTmpdir()
2859 with self.assertRaises(ValueError) as e:
2860 self._DoBinman('ls', '-i', updated_fname)
2861 finally:
2862 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002863 self.assertIn("Cannot find FDT map in image", str(e.exception))
2864
2865 def _RunListCmd(self, paths, expected):
2866 """List out entries and check the result
2867
2868 Args:
2869 paths: List of paths to pass to the list command
2870 expected: Expected list of filenames to be returned, in order
2871 """
2872 self._CheckLz4()
2873 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002874 image_fname = tools.get_output_filename('image.bin')
Simon Glass61f564d2019-07-08 14:25:48 -06002875 image = Image.FromFile(image_fname)
2876 lines = image.GetListEntries(paths)[1]
2877 files = [line[0].strip() for line in lines[1:]]
2878 self.assertEqual(expected, files)
2879
2880 def testListCmdSection(self):
2881 """Test listing the files in a section"""
2882 self._RunListCmd(['section'],
2883 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2884
2885 def testListCmdFile(self):
2886 """Test listing a particular file"""
2887 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2888
2889 def testListCmdWildcard(self):
2890 """Test listing a wildcarded file"""
2891 self._RunListCmd(['*boot*'],
2892 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2893
2894 def testListCmdWildcardMulti(self):
2895 """Test listing a wildcarded file"""
2896 self._RunListCmd(['*cb*', '*head*'],
2897 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2898
2899 def testListCmdEmpty(self):
2900 """Test listing a wildcarded file"""
2901 self._RunListCmd(['nothing'], [])
2902
2903 def testListCmdPath(self):
2904 """Test listing the files in a sub-entry of a section"""
2905 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2906
Simon Glassf667e452019-07-08 14:25:50 -06002907 def _RunExtractCmd(self, entry_name, decomp=True):
2908 """Extract an entry from an image
2909
2910 Args:
2911 entry_name: Entry name to extract
2912 decomp: True to decompress the data if compressed, False to leave
2913 it in its raw uncompressed format
2914
2915 Returns:
2916 data from entry
2917 """
2918 self._CheckLz4()
2919 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002920 image_fname = tools.get_output_filename('image.bin')
Simon Glassf667e452019-07-08 14:25:50 -06002921 return control.ReadEntry(image_fname, entry_name, decomp)
2922
2923 def testExtractSimple(self):
2924 """Test extracting a single file"""
2925 data = self._RunExtractCmd('u-boot')
2926 self.assertEqual(U_BOOT_DATA, data)
2927
Simon Glass71ce0ba2019-07-08 14:25:52 -06002928 def testExtractSection(self):
2929 """Test extracting the files in a section"""
2930 data = self._RunExtractCmd('section')
2931 cbfs_data = data[:0x400]
2932 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002933 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002934 dtb_data = data[0x400:]
2935 dtb = self._decompress(dtb_data)
2936 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2937
2938 def testExtractCompressed(self):
2939 """Test extracting compressed data"""
2940 data = self._RunExtractCmd('section/u-boot-dtb')
2941 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2942
2943 def testExtractRaw(self):
2944 """Test extracting compressed data without decompressing it"""
2945 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2946 dtb = self._decompress(data)
2947 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2948
2949 def testExtractCbfs(self):
2950 """Test extracting CBFS data"""
2951 data = self._RunExtractCmd('section/cbfs/u-boot')
2952 self.assertEqual(U_BOOT_DATA, data)
2953
2954 def testExtractCbfsCompressed(self):
2955 """Test extracting CBFS compressed data"""
2956 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2957 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2958
2959 def testExtractCbfsRaw(self):
2960 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002961 bintool = self.comp_bintools['lzma_alone']
2962 self._CheckBintool(bintool)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002963 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002964 dtb = bintool.decompress(data)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002965 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2966
Simon Glassf667e452019-07-08 14:25:50 -06002967 def testExtractBadEntry(self):
2968 """Test extracting a bad section path"""
2969 with self.assertRaises(ValueError) as e:
2970 self._RunExtractCmd('section/does-not-exist')
2971 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2972 str(e.exception))
2973
2974 def testExtractMissingFile(self):
2975 """Test extracting file that does not exist"""
2976 with self.assertRaises(IOError) as e:
2977 control.ReadEntry('missing-file', 'name')
2978
2979 def testExtractBadFile(self):
2980 """Test extracting an invalid file"""
2981 fname = os.path.join(self._indir, 'badfile')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002982 tools.write_file(fname, b'')
Simon Glassf667e452019-07-08 14:25:50 -06002983 with self.assertRaises(ValueError) as e:
2984 control.ReadEntry(fname, 'name')
2985
Simon Glass71ce0ba2019-07-08 14:25:52 -06002986 def testExtractCmd(self):
2987 """Test extracting a file fron an image on the command line"""
2988 self._CheckLz4()
2989 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002990 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002991 try:
2992 tmpdir, updated_fname = self._SetupImageInTmpdir()
2993 with test_util.capture_sys_output() as (stdout, stderr):
2994 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2995 '-f', fname)
2996 finally:
2997 shutil.rmtree(tmpdir)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002998 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002999 self.assertEqual(U_BOOT_DATA, data)
3000
3001 def testExtractOneEntry(self):
3002 """Test extracting a single entry fron an image """
3003 self._CheckLz4()
3004 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003005 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003006 fname = os.path.join(self._indir, 'output.extact')
3007 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07003008 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003009 self.assertEqual(U_BOOT_DATA, data)
3010
3011 def _CheckExtractOutput(self, decomp):
3012 """Helper to test file output with and without decompression
3013
3014 Args:
3015 decomp: True to decompress entry data, False to output it raw
3016 """
3017 def _CheckPresent(entry_path, expect_data, expect_size=None):
3018 """Check and remove expected file
3019
3020 This checks the data/size of a file and removes the file both from
3021 the outfiles set and from the output directory. Once all files are
3022 processed, both the set and directory should be empty.
3023
3024 Args:
3025 entry_path: Entry path
3026 expect_data: Data to expect in file, or None to skip check
3027 expect_size: Size of data to expect in file, or None to skip
3028 """
3029 path = os.path.join(outdir, entry_path)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003030 data = tools.read_file(path)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003031 os.remove(path)
3032 if expect_data:
3033 self.assertEqual(expect_data, data)
3034 elif expect_size:
3035 self.assertEqual(expect_size, len(data))
3036 outfiles.remove(path)
3037
3038 def _CheckDirPresent(name):
3039 """Remove expected directory
3040
3041 This gives an error if the directory does not exist as expected
3042
3043 Args:
3044 name: Name of directory to remove
3045 """
3046 path = os.path.join(outdir, name)
3047 os.rmdir(path)
3048
3049 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003050 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003051 outdir = os.path.join(self._indir, 'extract')
3052 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3053
3054 # Create a set of all file that were output (should be 9)
3055 outfiles = set()
3056 for root, dirs, files in os.walk(outdir):
3057 outfiles |= set([os.path.join(root, fname) for fname in files])
3058 self.assertEqual(9, len(outfiles))
3059 self.assertEqual(9, len(einfos))
3060
3061 image = control.images['image']
3062 entries = image.GetEntries()
3063
3064 # Check the 9 files in various ways
3065 section = entries['section']
3066 section_entries = section.GetEntries()
3067 cbfs_entries = section_entries['cbfs'].GetEntries()
3068 _CheckPresent('u-boot', U_BOOT_DATA)
3069 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3070 dtb_len = EXTRACT_DTB_SIZE
3071 if not decomp:
3072 dtb_len = cbfs_entries['u-boot-dtb'].size
3073 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3074 if not decomp:
3075 dtb_len = section_entries['u-boot-dtb'].size
3076 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3077
3078 fdtmap = entries['fdtmap']
3079 _CheckPresent('fdtmap', fdtmap.data)
3080 hdr = entries['image-header']
3081 _CheckPresent('image-header', hdr.data)
3082
3083 _CheckPresent('section/root', section.data)
3084 cbfs = section_entries['cbfs']
3085 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003086 data = tools.read_file(image_fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003087 _CheckPresent('root', data)
3088
3089 # There should be no files left. Remove all the directories to check.
3090 # If there are any files/dirs remaining, one of these checks will fail.
3091 self.assertEqual(0, len(outfiles))
3092 _CheckDirPresent('section/cbfs')
3093 _CheckDirPresent('section')
3094 _CheckDirPresent('')
3095 self.assertFalse(os.path.exists(outdir))
3096
3097 def testExtractAllEntries(self):
3098 """Test extracting all entries"""
3099 self._CheckLz4()
3100 self._CheckExtractOutput(decomp=True)
3101
3102 def testExtractAllEntriesRaw(self):
3103 """Test extracting all entries without decompressing them"""
3104 self._CheckLz4()
3105 self._CheckExtractOutput(decomp=False)
3106
3107 def testExtractSelectedEntries(self):
3108 """Test extracting some entries"""
3109 self._CheckLz4()
3110 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003111 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003112 outdir = os.path.join(self._indir, 'extract')
3113 einfos = control.ExtractEntries(image_fname, None, outdir,
3114 ['*cb*', '*head*'])
3115
3116 # File output is tested by testExtractAllEntries(), so just check that
3117 # the expected entries are selected
3118 names = [einfo.name for einfo in einfos]
3119 self.assertEqual(names,
3120 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3121
3122 def testExtractNoEntryPaths(self):
3123 """Test extracting some entries"""
3124 self._CheckLz4()
3125 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003126 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003127 with self.assertRaises(ValueError) as e:
3128 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06003129 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003130 str(e.exception))
3131
3132 def testExtractTooManyEntryPaths(self):
3133 """Test extracting some entries"""
3134 self._CheckLz4()
3135 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003136 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003137 with self.assertRaises(ValueError) as e:
3138 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06003139 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003140 str(e.exception))
3141
Simon Glasse2705fa2019-07-08 14:25:53 -06003142 def testPackAlignSection(self):
3143 """Test that sections can have alignment"""
3144 self._DoReadFile('131_pack_align_section.dts')
3145
3146 self.assertIn('image', control.images)
3147 image = control.images['image']
3148 entries = image.GetEntries()
3149 self.assertEqual(3, len(entries))
3150
3151 # First u-boot
3152 self.assertIn('u-boot', entries)
3153 entry = entries['u-boot']
3154 self.assertEqual(0, entry.offset)
3155 self.assertEqual(0, entry.image_pos)
3156 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3157 self.assertEqual(len(U_BOOT_DATA), entry.size)
3158
3159 # Section0
3160 self.assertIn('section0', entries)
3161 section0 = entries['section0']
3162 self.assertEqual(0x10, section0.offset)
3163 self.assertEqual(0x10, section0.image_pos)
3164 self.assertEqual(len(U_BOOT_DATA), section0.size)
3165
3166 # Second u-boot
3167 section_entries = section0.GetEntries()
3168 self.assertIn('u-boot', section_entries)
3169 entry = section_entries['u-boot']
3170 self.assertEqual(0, entry.offset)
3171 self.assertEqual(0x10, entry.image_pos)
3172 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3173 self.assertEqual(len(U_BOOT_DATA), entry.size)
3174
3175 # Section1
3176 self.assertIn('section1', entries)
3177 section1 = entries['section1']
3178 self.assertEqual(0x14, section1.offset)
3179 self.assertEqual(0x14, section1.image_pos)
3180 self.assertEqual(0x20, section1.size)
3181
3182 # Second u-boot
3183 section_entries = section1.GetEntries()
3184 self.assertIn('u-boot', section_entries)
3185 entry = section_entries['u-boot']
3186 self.assertEqual(0, entry.offset)
3187 self.assertEqual(0x14, entry.image_pos)
3188 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3189 self.assertEqual(len(U_BOOT_DATA), entry.size)
3190
3191 # Section2
3192 self.assertIn('section2', section_entries)
3193 section2 = section_entries['section2']
3194 self.assertEqual(0x4, section2.offset)
3195 self.assertEqual(0x18, section2.image_pos)
3196 self.assertEqual(4, section2.size)
3197
3198 # Third u-boot
3199 section_entries = section2.GetEntries()
3200 self.assertIn('u-boot', section_entries)
3201 entry = section_entries['u-boot']
3202 self.assertEqual(0, entry.offset)
3203 self.assertEqual(0x18, entry.image_pos)
3204 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3205 self.assertEqual(len(U_BOOT_DATA), entry.size)
3206
Simon Glass51014aa2019-07-20 12:23:56 -06003207 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3208 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003209 """Replace an entry in an image
3210
3211 This writes the entry data to update it, then opens the updated file and
3212 returns the value that it now finds there.
3213
3214 Args:
3215 entry_name: Entry name to replace
3216 data: Data to replace it with
3217 decomp: True to compress the data if needed, False if data is
3218 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003219 allow_resize: True to allow entries to change size, False to raise
3220 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003221
3222 Returns:
3223 Tuple:
3224 data from entry
3225 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003226 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003227 """
Simon Glass51014aa2019-07-20 12:23:56 -06003228 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003229 update_dtb=True)[1]
3230
3231 self.assertIn('image', control.images)
3232 image = control.images['image']
3233 entries = image.GetEntries()
3234 orig_dtb_data = entries['u-boot-dtb'].data
3235 orig_fdtmap_data = entries['fdtmap'].data
3236
Simon Glassc1aa66e2022-01-29 14:14:04 -07003237 image_fname = tools.get_output_filename('image.bin')
3238 updated_fname = tools.get_output_filename('image-updated.bin')
3239 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003240 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3241 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003242 data = control.ReadEntry(updated_fname, entry_name, decomp)
3243
Simon Glass51014aa2019-07-20 12:23:56 -06003244 # The DT data should not change unless resized:
3245 if not allow_resize:
3246 new_dtb_data = entries['u-boot-dtb'].data
3247 self.assertEqual(new_dtb_data, orig_dtb_data)
3248 new_fdtmap_data = entries['fdtmap'].data
3249 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003250
Simon Glass51014aa2019-07-20 12:23:56 -06003251 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003252
3253 def testReplaceSimple(self):
3254 """Test replacing a single file"""
3255 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003256 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3257 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003258 self.assertEqual(expected, data)
3259
3260 # Test that the state looks right. There should be an FDT for the fdtmap
3261 # that we jsut read back in, and it should match what we find in the
3262 # 'control' tables. Checking for an FDT that does not exist should
3263 # return None.
3264 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003265 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003266 self.assertEqual(expected_fdtmap, fdtmap)
3267
3268 dtb = state.GetFdtForEtype('fdtmap')
3269 self.assertEqual(dtb.GetContents(), fdtmap)
3270
3271 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3272 self.assertIsNone(missing_path)
3273 self.assertIsNone(missing_fdtmap)
3274
3275 missing_dtb = state.GetFdtForEtype('missing')
3276 self.assertIsNone(missing_dtb)
3277
3278 self.assertEqual('/binman', state.fdt_path_prefix)
3279
3280 def testReplaceResizeFail(self):
3281 """Test replacing a file by something larger"""
3282 expected = U_BOOT_DATA + b'x'
3283 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003284 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3285 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003286 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3287 str(e.exception))
3288
3289 def testReplaceMulti(self):
3290 """Test replacing entry data where multiple images are generated"""
3291 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3292 update_dtb=True)[0]
3293 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003294 updated_fname = tools.get_output_filename('image-updated.bin')
3295 tools.write_file(updated_fname, data)
Simon Glass10f9d002019-07-20 12:23:50 -06003296 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003297 control.WriteEntry(updated_fname, entry_name, expected,
3298 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003299 data = control.ReadEntry(updated_fname, entry_name)
3300 self.assertEqual(expected, data)
3301
3302 # Check the state looks right.
3303 self.assertEqual('/binman/image', state.fdt_path_prefix)
3304
3305 # Now check we can write the first image
Simon Glassc1aa66e2022-01-29 14:14:04 -07003306 image_fname = tools.get_output_filename('first-image.bin')
3307 updated_fname = tools.get_output_filename('first-updated.bin')
3308 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass10f9d002019-07-20 12:23:50 -06003309 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003310 control.WriteEntry(updated_fname, entry_name, expected,
3311 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003312 data = control.ReadEntry(updated_fname, entry_name)
3313 self.assertEqual(expected, data)
3314
3315 # Check the state looks right.
3316 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003317
Simon Glass12bb1a92019-07-20 12:23:51 -06003318 def testUpdateFdtAllRepack(self):
3319 """Test that all device trees are updated with offset/size info"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003320 self._SetupSplElf()
3321 self._SetupTplElf()
Simon Glass12bb1a92019-07-20 12:23:51 -06003322 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3323 SECTION_SIZE = 0x300
3324 DTB_SIZE = 602
3325 FDTMAP_SIZE = 608
3326 base_expected = {
3327 'offset': 0,
3328 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3329 'image-pos': 0,
3330 'section:offset': 0,
3331 'section:size': SECTION_SIZE,
3332 'section:image-pos': 0,
3333 'section/u-boot-dtb:offset': 4,
3334 'section/u-boot-dtb:size': 636,
3335 'section/u-boot-dtb:image-pos': 4,
3336 'u-boot-spl-dtb:offset': SECTION_SIZE,
3337 'u-boot-spl-dtb:size': DTB_SIZE,
3338 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3339 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3340 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3341 'u-boot-tpl-dtb:size': DTB_SIZE,
3342 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3343 'fdtmap:size': FDTMAP_SIZE,
3344 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3345 }
3346 main_expected = {
3347 'section:orig-size': SECTION_SIZE,
3348 'section/u-boot-dtb:orig-offset': 4,
3349 }
3350
3351 # We expect three device-tree files in the output, with the first one
3352 # within a fixed-size section.
3353 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3354 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3355 # main U-Boot tree. All three should have the same positions and offset
3356 # except that the main tree should include the main_expected properties
3357 start = 4
3358 for item in ['', 'spl', 'tpl', None]:
3359 if item is None:
3360 start += 16 # Move past fdtmap header
3361 dtb = fdt.Fdt.FromData(data[start:])
3362 dtb.Scan()
3363 props = self._GetPropTree(dtb,
3364 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3365 prefix='/' if item is None else '/binman/')
3366 expected = dict(base_expected)
3367 if item:
3368 expected[item] = 0
3369 else:
3370 # Main DTB and fdtdec should include the 'orig-' properties
3371 expected.update(main_expected)
3372 # Helpful for debugging:
3373 #for prop in sorted(props):
3374 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3375 self.assertEqual(expected, props)
3376 if item == '':
3377 start = SECTION_SIZE
3378 else:
3379 start += dtb._fdt_obj.totalsize()
3380
Simon Glasseba1f0c2019-07-20 12:23:55 -06003381 def testFdtmapHeaderMiddle(self):
3382 """Test an FDT map in the middle of an image when it should be at end"""
3383 with self.assertRaises(ValueError) as e:
3384 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3385 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3386 str(e.exception))
3387
3388 def testFdtmapHeaderStartBad(self):
3389 """Test an FDT map in middle of an image when it should be at start"""
3390 with self.assertRaises(ValueError) as e:
3391 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3392 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3393 str(e.exception))
3394
3395 def testFdtmapHeaderEndBad(self):
3396 """Test an FDT map at the start of an image when it should be at end"""
3397 with self.assertRaises(ValueError) as e:
3398 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3399 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3400 str(e.exception))
3401
3402 def testFdtmapHeaderNoSize(self):
3403 """Test an image header at the end of an image with undefined size"""
3404 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3405
Simon Glass51014aa2019-07-20 12:23:56 -06003406 def testReplaceResize(self):
3407 """Test replacing a single file in an entry with a larger file"""
3408 expected = U_BOOT_DATA + b'x'
3409 data, _, image = self._RunReplaceCmd('u-boot', expected,
3410 dts='139_replace_repack.dts')
3411 self.assertEqual(expected, data)
3412
3413 entries = image.GetEntries()
3414 dtb_data = entries['u-boot-dtb'].data
3415 dtb = fdt.Fdt.FromData(dtb_data)
3416 dtb.Scan()
3417
3418 # The u-boot section should now be larger in the dtb
3419 node = dtb.GetNode('/binman/u-boot')
3420 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3421
3422 # Same for the fdtmap
3423 fdata = entries['fdtmap'].data
3424 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3425 fdtb.Scan()
3426 fnode = fdtb.GetNode('/u-boot')
3427 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3428
3429 def testReplaceResizeNoRepack(self):
3430 """Test replacing an entry with a larger file when not allowed"""
3431 expected = U_BOOT_DATA + b'x'
3432 with self.assertRaises(ValueError) as e:
3433 self._RunReplaceCmd('u-boot', expected)
3434 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3435 str(e.exception))
3436
Simon Glass61ec04f2019-07-20 12:23:58 -06003437 def testEntryShrink(self):
3438 """Test contracting an entry after it is packed"""
3439 try:
3440 state.SetAllowEntryContraction(True)
3441 data = self._DoReadFileDtb('140_entry_shrink.dts',
3442 update_dtb=True)[0]
3443 finally:
3444 state.SetAllowEntryContraction(False)
3445 self.assertEqual(b'a', data[:1])
3446 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3447 self.assertEqual(b'a', data[-1:])
3448
3449 def testEntryShrinkFail(self):
3450 """Test not being allowed to contract an entry after it is packed"""
3451 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3452
3453 # In this case there is a spare byte at the end of the data. The size of
3454 # the contents is only 1 byte but we still have the size before it
3455 # shrunk.
3456 self.assertEqual(b'a\0', data[:2])
3457 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3458 self.assertEqual(b'a\0', data[-2:])
3459
Simon Glass27145fd2019-07-20 12:24:01 -06003460 def testDescriptorOffset(self):
3461 """Test that the Intel descriptor is always placed at at the start"""
3462 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3463 image = control.images['image']
3464 entries = image.GetEntries()
3465 desc = entries['intel-descriptor']
3466 self.assertEqual(0xff800000, desc.offset);
3467 self.assertEqual(0xff800000, desc.image_pos);
3468
Simon Glasseb0f4a42019-07-20 12:24:06 -06003469 def testReplaceCbfs(self):
3470 """Test replacing a single file in CBFS without changing the size"""
3471 self._CheckLz4()
3472 expected = b'x' * len(U_BOOT_DATA)
3473 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003474 updated_fname = tools.get_output_filename('image-updated.bin')
3475 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003476 entry_name = 'section/cbfs/u-boot'
3477 control.WriteEntry(updated_fname, entry_name, expected,
3478 allow_resize=True)
3479 data = control.ReadEntry(updated_fname, entry_name)
3480 self.assertEqual(expected, data)
3481
3482 def testReplaceResizeCbfs(self):
3483 """Test replacing a single file in CBFS with one of a different size"""
3484 self._CheckLz4()
3485 expected = U_BOOT_DATA + b'x'
3486 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003487 updated_fname = tools.get_output_filename('image-updated.bin')
3488 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003489 entry_name = 'section/cbfs/u-boot'
3490 control.WriteEntry(updated_fname, entry_name, expected,
3491 allow_resize=True)
3492 data = control.ReadEntry(updated_fname, entry_name)
3493 self.assertEqual(expected, data)
3494
Simon Glassa6cb9952019-07-20 12:24:15 -06003495 def _SetupForReplace(self):
3496 """Set up some files to use to replace entries
3497
3498 This generates an image, copies it to a new file, extracts all the files
3499 in it and updates some of them
3500
3501 Returns:
3502 List
3503 Image filename
3504 Output directory
3505 Expected values for updated entries, each a string
3506 """
3507 data = self._DoReadFileRealDtb('143_replace_all.dts')
3508
Simon Glassc1aa66e2022-01-29 14:14:04 -07003509 updated_fname = tools.get_output_filename('image-updated.bin')
3510 tools.write_file(updated_fname, data)
Simon Glassa6cb9952019-07-20 12:24:15 -06003511
3512 outdir = os.path.join(self._indir, 'extract')
3513 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3514
3515 expected1 = b'x' + U_BOOT_DATA + b'y'
3516 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003517 tools.write_file(u_boot_fname1, expected1)
Simon Glassa6cb9952019-07-20 12:24:15 -06003518
3519 expected2 = b'a' + U_BOOT_DATA + b'b'
3520 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003521 tools.write_file(u_boot_fname2, expected2)
Simon Glassa6cb9952019-07-20 12:24:15 -06003522
3523 expected_text = b'not the same text'
3524 text_fname = os.path.join(outdir, 'text')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003525 tools.write_file(text_fname, expected_text)
Simon Glassa6cb9952019-07-20 12:24:15 -06003526
3527 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3528 dtb = fdt.FdtScan(dtb_fname)
3529 node = dtb.GetNode('/binman/text')
3530 node.AddString('my-property', 'the value')
3531 dtb.Sync(auto_resize=True)
3532 dtb.Flush()
3533
3534 return updated_fname, outdir, expected1, expected2, expected_text
3535
3536 def _CheckReplaceMultiple(self, entry_paths):
3537 """Handle replacing the contents of multiple entries
3538
3539 Args:
3540 entry_paths: List of entry paths to replace
3541
3542 Returns:
3543 List
3544 Dict of entries in the image:
3545 key: Entry name
3546 Value: Entry object
3547 Expected values for updated entries, each a string
3548 """
3549 updated_fname, outdir, expected1, expected2, expected_text = (
3550 self._SetupForReplace())
3551 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3552
3553 image = Image.FromFile(updated_fname)
3554 image.LoadData()
3555 return image.GetEntries(), expected1, expected2, expected_text
3556
3557 def testReplaceAll(self):
3558 """Test replacing the contents of all entries"""
3559 entries, expected1, expected2, expected_text = (
3560 self._CheckReplaceMultiple([]))
3561 data = entries['u-boot'].data
3562 self.assertEqual(expected1, data)
3563
3564 data = entries['u-boot2'].data
3565 self.assertEqual(expected2, data)
3566
3567 data = entries['text'].data
3568 self.assertEqual(expected_text, data)
3569
3570 # Check that the device tree is updated
3571 data = entries['u-boot-dtb'].data
3572 dtb = fdt.Fdt.FromData(data)
3573 dtb.Scan()
3574 node = dtb.GetNode('/binman/text')
3575 self.assertEqual('the value', node.props['my-property'].value)
3576
3577 def testReplaceSome(self):
3578 """Test replacing the contents of a few entries"""
3579 entries, expected1, expected2, expected_text = (
3580 self._CheckReplaceMultiple(['u-boot2', 'text']))
3581
3582 # This one should not change
3583 data = entries['u-boot'].data
3584 self.assertEqual(U_BOOT_DATA, data)
3585
3586 data = entries['u-boot2'].data
3587 self.assertEqual(expected2, data)
3588
3589 data = entries['text'].data
3590 self.assertEqual(expected_text, data)
3591
3592 def testReplaceCmd(self):
3593 """Test replacing a file fron an image on the command line"""
3594 self._DoReadFileRealDtb('143_replace_all.dts')
3595
3596 try:
3597 tmpdir, updated_fname = self._SetupImageInTmpdir()
3598
3599 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3600 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003601 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003602
3603 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003604 data = tools.read_file(updated_fname)
Simon Glassa6cb9952019-07-20 12:24:15 -06003605 self.assertEqual(expected, data[:len(expected)])
3606 map_fname = os.path.join(tmpdir, 'image-updated.map')
3607 self.assertFalse(os.path.exists(map_fname))
3608 finally:
3609 shutil.rmtree(tmpdir)
3610
3611 def testReplaceCmdSome(self):
3612 """Test replacing some files fron an image on the command line"""
3613 updated_fname, outdir, expected1, expected2, expected_text = (
3614 self._SetupForReplace())
3615
3616 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3617 'u-boot2', 'text')
3618
Simon Glassc1aa66e2022-01-29 14:14:04 -07003619 tools.prepare_output_dir(None)
Simon Glassa6cb9952019-07-20 12:24:15 -06003620 image = Image.FromFile(updated_fname)
3621 image.LoadData()
3622 entries = image.GetEntries()
3623
3624 # This one should not change
3625 data = entries['u-boot'].data
3626 self.assertEqual(U_BOOT_DATA, data)
3627
3628 data = entries['u-boot2'].data
3629 self.assertEqual(expected2, data)
3630
3631 data = entries['text'].data
3632 self.assertEqual(expected_text, data)
3633
3634 def testReplaceMissing(self):
3635 """Test replacing entries where the file is missing"""
3636 updated_fname, outdir, expected1, expected2, expected_text = (
3637 self._SetupForReplace())
3638
3639 # Remove one of the files, to generate a warning
3640 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3641 os.remove(u_boot_fname1)
3642
3643 with test_util.capture_sys_output() as (stdout, stderr):
3644 control.ReplaceEntries(updated_fname, None, outdir, [])
3645 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003646 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003647
3648 def testReplaceCmdMap(self):
3649 """Test replacing a file fron an image on the command line"""
3650 self._DoReadFileRealDtb('143_replace_all.dts')
3651
3652 try:
3653 tmpdir, updated_fname = self._SetupImageInTmpdir()
3654
3655 fname = os.path.join(self._indir, 'update-u-boot.bin')
3656 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003657 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003658
3659 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3660 '-f', fname, '-m')
3661 map_fname = os.path.join(tmpdir, 'image-updated.map')
3662 self.assertTrue(os.path.exists(map_fname))
3663 finally:
3664 shutil.rmtree(tmpdir)
3665
3666 def testReplaceNoEntryPaths(self):
3667 """Test replacing an entry without an entry path"""
3668 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003669 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003670 with self.assertRaises(ValueError) as e:
3671 control.ReplaceEntries(image_fname, 'fname', None, [])
3672 self.assertIn('Must specify an entry path to read with -f',
3673 str(e.exception))
3674
3675 def testReplaceTooManyEntryPaths(self):
3676 """Test extracting some entries"""
3677 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003678 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003679 with self.assertRaises(ValueError) as e:
3680 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3681 self.assertIn('Must specify exactly one entry path to write with -f',
3682 str(e.exception))
3683
Simon Glass2250ee62019-08-24 07:22:48 -06003684 def testPackReset16(self):
3685 """Test that an image with an x86 reset16 region can be created"""
3686 data = self._DoReadFile('144_x86_reset16.dts')
3687 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3688
3689 def testPackReset16Spl(self):
3690 """Test that an image with an x86 reset16-spl region can be created"""
3691 data = self._DoReadFile('145_x86_reset16_spl.dts')
3692 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3693
3694 def testPackReset16Tpl(self):
3695 """Test that an image with an x86 reset16-tpl region can be created"""
3696 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3697 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3698
Simon Glass5af12072019-08-24 07:22:50 -06003699 def testPackIntelFit(self):
3700 """Test that an image with an Intel FIT and pointer can be created"""
3701 data = self._DoReadFile('147_intel_fit.dts')
3702 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3703 fit = data[16:32];
3704 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3705 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3706
3707 image = control.images['image']
3708 entries = image.GetEntries()
3709 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3710 self.assertEqual(expected_ptr, ptr)
3711
3712 def testPackIntelFitMissing(self):
3713 """Test detection of a FIT pointer with not FIT region"""
3714 with self.assertRaises(ValueError) as e:
3715 self._DoReadFile('148_intel_fit_missing.dts')
3716 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3717 str(e.exception))
3718
Simon Glass7c150132019-11-06 17:22:44 -07003719 def _CheckSymbolsTplSection(self, dts, expected_vals):
3720 data = self._DoReadFile(dts)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003721 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003722 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003723 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003724 self.assertEqual(expected1, data[:upto1])
3725
3726 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003727 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003728 self.assertEqual(expected2, data[upto1:upto2])
3729
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003730 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003731 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003732 self.assertEqual(expected3, data[upto2:upto3])
3733
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003734 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass7c150132019-11-06 17:22:44 -07003735 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3736
3737 def testSymbolsTplSection(self):
3738 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3739 self._SetupSplElf('u_boot_binman_syms')
3740 self._SetupTplElf('u_boot_binman_syms')
3741 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003742 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass7c150132019-11-06 17:22:44 -07003743
3744 def testSymbolsTplSectionX86(self):
3745 """Test binman can assign symbols in a section with end-at-4gb"""
3746 self._SetupSplElf('u_boot_binman_syms_x86')
3747 self._SetupTplElf('u_boot_binman_syms_x86')
3748 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003749 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass7c150132019-11-06 17:22:44 -07003750 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003751
Simon Glassbf4d0e22019-08-24 07:23:03 -06003752 def testPackX86RomIfwiSectiom(self):
3753 """Test that a section can be placed in an IFWI region"""
3754 self._SetupIfwi('fitimage.bin')
3755 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3756 self._CheckIfwi(data)
3757
Simon Glassea0fff92019-08-24 07:23:07 -06003758 def testPackFspM(self):
3759 """Test that an image with a FSP memory-init binary can be created"""
3760 data = self._DoReadFile('152_intel_fsp_m.dts')
3761 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3762
Simon Glassbc6a88f2019-10-20 21:31:35 -06003763 def testPackFspS(self):
3764 """Test that an image with a FSP silicon-init binary can be created"""
3765 data = self._DoReadFile('153_intel_fsp_s.dts')
3766 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003767
Simon Glass998d1482019-10-20 21:31:36 -06003768 def testPackFspT(self):
3769 """Test that an image with a FSP temp-ram-init binary can be created"""
3770 data = self._DoReadFile('154_intel_fsp_t.dts')
3771 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3772
Simon Glass0dc706f2020-07-09 18:39:31 -06003773 def testMkimage(self):
3774 """Test using mkimage to build an image"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003775 self._SetupSplElf()
Simon Glass0dc706f2020-07-09 18:39:31 -06003776 data = self._DoReadFile('156_mkimage.dts')
3777
3778 # Just check that the data appears in the file somewhere
3779 self.assertIn(U_BOOT_SPL_DATA, data)
3780
Simon Glass4f9ee832022-01-09 20:14:09 -07003781 def testMkimageMissing(self):
3782 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003783 self._SetupSplElf()
Simon Glass4f9ee832022-01-09 20:14:09 -07003784 with test_util.capture_sys_output() as (_, stderr):
3785 self._DoTestFile('156_mkimage.dts',
3786 force_missing_bintools='mkimage')
3787 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003788 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass4f9ee832022-01-09 20:14:09 -07003789
Simon Glassce867ad2020-07-09 18:39:36 -06003790 def testExtblob(self):
3791 """Test an image with an external blob"""
3792 data = self._DoReadFile('157_blob_ext.dts')
3793 self.assertEqual(REFCODE_DATA, data)
3794
3795 def testExtblobMissing(self):
3796 """Test an image with a missing external blob"""
3797 with self.assertRaises(ValueError) as e:
3798 self._DoReadFile('158_blob_ext_missing.dts')
3799 self.assertIn("Filename 'missing-file' not found in input path",
3800 str(e.exception))
3801
Simon Glass4f9f1052020-07-09 18:39:38 -06003802 def testExtblobMissingOk(self):
3803 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003804 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glassb38da152022-11-09 19:14:42 -07003805 ret = self._DoTestFile('158_blob_ext_missing.dts',
3806 allow_missing=True)
3807 self.assertEqual(103, ret)
Simon Glassb1cca952020-07-09 18:39:40 -06003808 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003809 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glassb38da152022-11-09 19:14:42 -07003810 self.assertIn('Some images are invalid', err)
3811
3812 def testExtblobMissingOkFlag(self):
3813 """Test an image with an missing external blob allowed with -W"""
3814 with test_util.capture_sys_output() as (stdout, stderr):
3815 ret = self._DoTestFile('158_blob_ext_missing.dts',
3816 allow_missing=True, ignore_missing=True)
3817 self.assertEqual(0, ret)
3818 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003819 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glassb38da152022-11-09 19:14:42 -07003820 self.assertIn('Some images are invalid', err)
Simon Glassb1cca952020-07-09 18:39:40 -06003821
3822 def testExtblobMissingOkSect(self):
3823 """Test an image with an missing external blob that is allowed"""
3824 with test_util.capture_sys_output() as (stdout, stderr):
3825 self._DoTestFile('159_blob_ext_missing_sect.dts',
3826 allow_missing=True)
3827 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003828 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003829
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003830 def testPackX86RomMeMissingDesc(self):
3831 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003832 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003833 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003834 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003835 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003836
3837 def testPackX86RomMissingIfwi(self):
3838 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3839 self._SetupIfwi('fitimage.bin')
3840 pathname = os.path.join(self._indir, 'fitimage.bin')
3841 os.remove(pathname)
3842 with test_util.capture_sys_output() as (stdout, stderr):
3843 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3844 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003845 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003846
Simon Glass8d2ef3e2022-02-11 13:23:21 -07003847 def testPackOverlapZero(self):
Simon Glassb3295fd2020-07-09 18:39:42 -06003848 """Test that zero-size overlapping regions are ignored"""
3849 self._DoTestFile('160_pack_overlap_zero.dts')
3850
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003851 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glassfdc34362020-07-09 18:39:45 -06003852 # The data should be inside the FIT
3853 dtb = fdt.Fdt.FromData(fit_data)
3854 dtb.Scan()
3855 fnode = dtb.GetNode('/images/kernel')
3856 self.assertIn('data', fnode.props)
3857
3858 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003859 tools.write_file(fname, fit_data)
3860 out = tools.run('dumpimage', '-l', fname)
Simon Glassfdc34362020-07-09 18:39:45 -06003861
3862 # Check a few features to make sure the plumbing works. We don't need
3863 # to test the operation of mkimage or dumpimage here. First convert the
3864 # output into a dict where the keys are the fields printed by dumpimage
3865 # and the values are a list of values for each field
3866 lines = out.splitlines()
3867
3868 # Converts "Compression: gzip compressed" into two groups:
3869 # 'Compression' and 'gzip compressed'
3870 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3871 vals = collections.defaultdict(list)
3872 for line in lines:
3873 mat = re_line.match(line)
3874 vals[mat.group(1)].append(mat.group(2))
3875
3876 self.assertEquals('FIT description: test-desc', lines[0])
3877 self.assertIn('Created:', lines[1])
3878 self.assertIn('Image 0 (kernel)', vals)
3879 self.assertIn('Hash value', vals)
3880 data_sizes = vals.get('Data Size')
3881 self.assertIsNotNone(data_sizes)
3882 self.assertEqual(2, len(data_sizes))
3883 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003884 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3885 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3886
Alper Nebi Yasake7368782022-03-27 18:31:47 +03003887 # Check if entry listing correctly omits /images/
3888 image = control.images['image']
3889 fit_entry = image.GetEntries()['fit']
3890 subentries = list(fit_entry.GetEntries().keys())
3891 expected = ['kernel', 'fdt-1']
3892 self.assertEqual(expected, subentries)
3893
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003894 def testSimpleFit(self):
3895 """Test an image with a FIT inside"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003896 self._SetupSplElf()
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003897 data = self._DoReadFile('161_fit.dts')
3898 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3899 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3900 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3901
3902 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3903
3904 def testSimpleFitExpandsSubentries(self):
3905 """Test that FIT images expand their subentries"""
3906 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3907 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3908 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3909 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3910
3911 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glassfdc34362020-07-09 18:39:45 -06003912
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003913 def testSimpleFitImagePos(self):
3914 """Test that we have correct image-pos for FIT subentries"""
3915 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3916 update_dtb=True)
3917 dtb = fdt.Fdt(out_dtb_fname)
3918 dtb.Scan()
3919 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3920
Simon Glass38397d02022-03-05 20:19:01 -07003921 self.maxDiff = None
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003922 self.assertEqual({
3923 'image-pos': 0,
3924 'offset': 0,
3925 'size': 1890,
3926
3927 'u-boot:image-pos': 0,
3928 'u-boot:offset': 0,
3929 'u-boot:size': 4,
3930
3931 'fit:image-pos': 4,
3932 'fit:offset': 4,
3933 'fit:size': 1840,
3934
Simon Glass38397d02022-03-05 20:19:01 -07003935 'fit/images/kernel:image-pos': 304,
3936 'fit/images/kernel:offset': 300,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003937 'fit/images/kernel:size': 4,
3938
Simon Glass38397d02022-03-05 20:19:01 -07003939 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003940 'fit/images/kernel/u-boot:offset': 0,
3941 'fit/images/kernel/u-boot:size': 4,
3942
Simon Glass38397d02022-03-05 20:19:01 -07003943 'fit/images/fdt-1:image-pos': 552,
3944 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003945 'fit/images/fdt-1:size': 6,
3946
Simon Glass38397d02022-03-05 20:19:01 -07003947 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003948 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3949 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3950
3951 'u-boot-nodtb:image-pos': 1844,
3952 'u-boot-nodtb:offset': 1844,
3953 'u-boot-nodtb:size': 46,
3954 }, props)
3955
3956 # Actually check the data is where we think it is
3957 for node, expected in [
3958 ("u-boot", U_BOOT_DATA),
3959 ("fit/images/kernel", U_BOOT_DATA),
3960 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3961 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3962 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3963 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3964 ]:
3965 image_pos = props[f"{node}:image-pos"]
3966 size = props[f"{node}:size"]
3967 self.assertEqual(len(expected), size)
3968 self.assertEqual(expected, data[image_pos:image_pos+size])
3969
Simon Glassfdc34362020-07-09 18:39:45 -06003970 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003971 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003972 data = self._DoReadFile('162_fit_external.dts')
3973 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3974
Simon Glass8bc78b72022-01-09 20:13:39 -07003975 # Size of the external-data region as set up by mkimage
3976 external_data_size = len(U_BOOT_DATA) + 2
3977 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glassc1aa66e2022-01-29 14:14:04 -07003978 tools.align(external_data_size, 4) +
Simon Glass8bc78b72022-01-09 20:13:39 -07003979 len(U_BOOT_NODTB_DATA))
3980
Simon Glassfdc34362020-07-09 18:39:45 -06003981 # The data should be outside the FIT
3982 dtb = fdt.Fdt.FromData(fit_data)
3983 dtb.Scan()
3984 fnode = dtb.GetNode('/images/kernel')
3985 self.assertNotIn('data', fnode.props)
Simon Glass8bc78b72022-01-09 20:13:39 -07003986 self.assertEqual(len(U_BOOT_DATA),
3987 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3988 fit_pos = 0x400;
3989 self.assertEqual(
3990 fit_pos,
3991 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3992
3993 self.assertEquals(expected_size, len(data))
3994 actual_pos = len(U_BOOT_DATA) + fit_pos
3995 self.assertEqual(U_BOOT_DATA + b'aa',
3996 data[actual_pos:actual_pos + external_data_size])
Simon Glass12bb1a92019-07-20 12:23:51 -06003997
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003998 def testFitExternalImagePos(self):
3999 """Test that we have correct image-pos for external FIT subentries"""
4000 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
4001 update_dtb=True)
4002 dtb = fdt.Fdt(out_dtb_fname)
4003 dtb.Scan()
4004 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4005
4006 self.assertEqual({
4007 'image-pos': 0,
4008 'offset': 0,
4009 'size': 1082,
4010
4011 'u-boot:image-pos': 0,
4012 'u-boot:offset': 0,
4013 'u-boot:size': 4,
4014
4015 'fit:size': 1032,
4016 'fit:offset': 4,
4017 'fit:image-pos': 4,
4018
4019 'fit/images/kernel:size': 4,
4020 'fit/images/kernel:offset': 1024,
4021 'fit/images/kernel:image-pos': 1028,
4022
4023 'fit/images/kernel/u-boot:size': 4,
4024 'fit/images/kernel/u-boot:offset': 0,
4025 'fit/images/kernel/u-boot:image-pos': 1028,
4026
4027 'fit/images/fdt-1:size': 2,
4028 'fit/images/fdt-1:offset': 1028,
4029 'fit/images/fdt-1:image-pos': 1032,
4030
4031 'fit/images/fdt-1/_testing:size': 2,
4032 'fit/images/fdt-1/_testing:offset': 0,
4033 'fit/images/fdt-1/_testing:image-pos': 1032,
4034
4035 'u-boot-nodtb:image-pos': 1036,
4036 'u-boot-nodtb:offset': 1036,
4037 'u-boot-nodtb:size': 46,
4038 }, props)
4039
4040 # Actually check the data is where we think it is
4041 for node, expected in [
4042 ("u-boot", U_BOOT_DATA),
4043 ("fit/images/kernel", U_BOOT_DATA),
4044 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4045 ("fit/images/fdt-1", b'aa'),
4046 ("fit/images/fdt-1/_testing", b'aa'),
4047 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4048 ]:
4049 image_pos = props[f"{node}:image-pos"]
4050 size = props[f"{node}:size"]
4051 self.assertEqual(len(expected), size)
4052 self.assertEqual(expected, data[image_pos:image_pos+size])
4053
Simon Glass4f9ee832022-01-09 20:14:09 -07004054 def testFitMissing(self):
Simon Glass033828c2023-03-02 17:02:43 -07004055 """Test that binman complains if mkimage is missing"""
4056 with self.assertRaises(ValueError) as e:
4057 self._DoTestFile('162_fit_external.dts',
4058 force_missing_bintools='mkimage')
4059 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4060 str(e.exception))
4061
4062 def testFitMissingOK(self):
Simon Glass4f9ee832022-01-09 20:14:09 -07004063 """Test that binman still produces a FIT image if mkimage is missing"""
4064 with test_util.capture_sys_output() as (_, stderr):
Simon Glass033828c2023-03-02 17:02:43 -07004065 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass4f9ee832022-01-09 20:14:09 -07004066 force_missing_bintools='mkimage')
4067 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004068 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass4f9ee832022-01-09 20:14:09 -07004069
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03004070 def testSectionIgnoreHashSignature(self):
4071 """Test that sections ignore hash, signature nodes for its data"""
4072 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4073 expected = (U_BOOT_DATA + U_BOOT_DATA)
4074 self.assertEqual(expected, data)
4075
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004076 def testPadInSections(self):
4077 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06004078 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4079 '166_pad_in_sections.dts', update_dtb=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004080 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4081 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004082 U_BOOT_DATA)
4083 self.assertEqual(expected, data)
4084
Simon Glassf90d9062020-10-26 17:40:09 -06004085 dtb = fdt.Fdt(out_dtb_fname)
4086 dtb.Scan()
4087 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4088 expected = {
4089 'image-pos': 0,
4090 'offset': 0,
4091 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4092
4093 'section:image-pos': 0,
4094 'section:offset': 0,
4095 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4096
4097 'section/before:image-pos': 0,
4098 'section/before:offset': 0,
4099 'section/before:size': len(U_BOOT_DATA),
4100
4101 'section/u-boot:image-pos': 4,
4102 'section/u-boot:offset': 4,
4103 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4104
4105 'section/after:image-pos': 26,
4106 'section/after:offset': 26,
4107 'section/after:size': len(U_BOOT_DATA),
4108 }
4109 self.assertEqual(expected, props)
4110
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004111 def testFitImageSubentryAlignment(self):
4112 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03004113 self._SetupSplElf()
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004114 entry_args = {
4115 'test-id': TEXT_DATA,
4116 }
4117 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4118 entry_args=entry_args)
4119 dtb = fdt.Fdt.FromData(data)
4120 dtb.Scan()
4121
4122 node = dtb.GetNode('/images/kernel')
4123 data = dtb.GetProps(node)["data"].bytes
4124 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004125 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4126 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004127 self.assertEqual(expected, data)
4128
4129 node = dtb.GetNode('/images/fdt-1')
4130 data = dtb.GetProps(node)["data"].bytes
Simon Glassc1aa66e2022-01-29 14:14:04 -07004131 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4132 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004133 U_BOOT_DTB_DATA)
4134 self.assertEqual(expected, data)
4135
4136 def testFitExtblobMissingOk(self):
4137 """Test a FIT with a missing external blob that is allowed"""
4138 with test_util.capture_sys_output() as (stdout, stderr):
4139 self._DoTestFile('168_fit_missing_blob.dts',
4140 allow_missing=True)
4141 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004142 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004143
Simon Glass3decfa32020-09-01 05:13:54 -06004144 def testBlobNamedByArgMissing(self):
4145 """Test handling of a missing entry arg"""
4146 with self.assertRaises(ValueError) as e:
4147 self._DoReadFile('068_blob_named_by_arg.dts')
4148 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4149 str(e.exception))
4150
Simon Glassdc2f81a2020-09-01 05:13:58 -06004151 def testPackBl31(self):
4152 """Test that an image with an ATF BL31 binary can be created"""
4153 data = self._DoReadFile('169_atf_bl31.dts')
4154 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4155
Samuel Holland18bd4552020-10-21 21:12:15 -05004156 def testPackScp(self):
4157 """Test that an image with an SCP binary can be created"""
4158 data = self._DoReadFile('172_scp.dts')
4159 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4160
Simon Glass6cf99532020-09-01 05:13:59 -06004161 def testFitFdt(self):
4162 """Test an image with an FIT with multiple FDT images"""
4163 def _CheckFdt(seq, expected_data):
4164 """Check the FDT nodes
4165
4166 Args:
4167 seq: Sequence number to check (0 or 1)
4168 expected_data: Expected contents of 'data' property
4169 """
4170 name = 'fdt-%d' % seq
4171 fnode = dtb.GetNode('/images/%s' % name)
4172 self.assertIsNotNone(fnode)
4173 self.assertEqual({'description','type', 'compression', 'data'},
4174 set(fnode.props.keys()))
4175 self.assertEqual(expected_data, fnode.props['data'].bytes)
4176 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4177 fnode.props['description'].value)
Jan Kiszkab2106612022-02-28 17:06:20 +01004178 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glass6cf99532020-09-01 05:13:59 -06004179
4180 def _CheckConfig(seq, expected_data):
4181 """Check the configuration nodes
4182
4183 Args:
4184 seq: Sequence number to check (0 or 1)
4185 expected_data: Expected contents of 'data' property
4186 """
4187 cnode = dtb.GetNode('/configurations')
4188 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004189 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06004190
4191 name = 'config-%d' % seq
4192 fnode = dtb.GetNode('/configurations/%s' % name)
4193 self.assertIsNotNone(fnode)
4194 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4195 set(fnode.props.keys()))
4196 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4197 fnode.props['description'].value)
4198 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4199
4200 entry_args = {
4201 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004202 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06004203 }
4204 data = self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004205 '170_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06004206 entry_args=entry_args,
4207 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4208 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4209 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4210
4211 dtb = fdt.Fdt.FromData(fit_data)
4212 dtb.Scan()
4213 fnode = dtb.GetNode('/images/kernel')
4214 self.assertIn('data', fnode.props)
4215
4216 # Check all the properties in fdt-1 and fdt-2
4217 _CheckFdt(1, TEST_FDT1_DATA)
4218 _CheckFdt(2, TEST_FDT2_DATA)
4219
4220 # Check configurations
4221 _CheckConfig(1, TEST_FDT1_DATA)
4222 _CheckConfig(2, TEST_FDT2_DATA)
4223
4224 def testFitFdtMissingList(self):
4225 """Test handling of a missing 'of-list' entry arg"""
4226 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08004227 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06004228 self.assertIn("Generator node requires 'of-list' entry argument",
4229 str(e.exception))
4230
4231 def testFitFdtEmptyList(self):
4232 """Test handling of an empty 'of-list' entry arg"""
4233 entry_args = {
4234 'of-list': '',
4235 }
4236 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4237
4238 def testFitFdtMissingProp(self):
4239 """Test handling of a missing 'fit,fdt-list' property"""
4240 with self.assertRaises(ValueError) as e:
4241 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4242 self.assertIn("Generator node requires 'fit,fdt-list' property",
4243 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06004244
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004245 def testFitFdtMissing(self):
4246 """Test handling of a missing 'default-dt' entry arg"""
4247 entry_args = {
4248 'of-list': 'test-fdt1 test-fdt2',
4249 }
4250 with self.assertRaises(ValueError) as e:
4251 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004252 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004253 entry_args=entry_args,
4254 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4255 self.assertIn("Generated 'default' node requires default-dt entry argument",
4256 str(e.exception))
4257
4258 def testFitFdtNotInList(self):
4259 """Test handling of a default-dt that is not in the of-list"""
4260 entry_args = {
4261 'of-list': 'test-fdt1 test-fdt2',
4262 'default-dt': 'test-fdt3',
4263 }
4264 with self.assertRaises(ValueError) as e:
4265 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004266 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004267 entry_args=entry_args,
4268 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4269 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4270 str(e.exception))
4271
Simon Glassb2381432020-09-06 10:39:09 -06004272 def testFitExtblobMissingHelp(self):
4273 """Test display of help messages when an external blob is missing"""
4274 control.missing_blob_help = control._ReadMissingBlobHelp()
4275 control.missing_blob_help['wibble'] = 'Wibble test'
4276 control.missing_blob_help['another'] = 'Another test'
4277 with test_util.capture_sys_output() as (stdout, stderr):
4278 self._DoTestFile('168_fit_missing_blob.dts',
4279 allow_missing=True)
4280 err = stderr.getvalue()
4281
4282 # We can get the tag from the name, the type or the missing-msg
4283 # property. Check all three.
4284 self.assertIn('You may need to build ARM Trusted', err)
4285 self.assertIn('Wibble test', err)
4286 self.assertIn('Another test', err)
4287
Simon Glass204aa782020-09-06 10:35:32 -06004288 def testMissingBlob(self):
4289 """Test handling of a blob containing a missing file"""
4290 with self.assertRaises(ValueError) as e:
4291 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4292 self.assertIn("Filename 'missing' not found in input path",
4293 str(e.exception))
4294
Simon Glassfb91d562020-09-06 10:35:33 -06004295 def testEnvironment(self):
4296 """Test adding a U-Boot environment"""
4297 data = self._DoReadFile('174_env.dts')
4298 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4299 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4300 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4301 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4302 env)
4303
4304 def testEnvironmentNoSize(self):
4305 """Test that a missing 'size' property is detected"""
4306 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004307 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004308 self.assertIn("'u-boot-env' entry must have a size property",
4309 str(e.exception))
4310
4311 def testEnvironmentTooSmall(self):
4312 """Test handling of an environment that does not fit"""
4313 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004314 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004315
4316 # checksum, start byte, environment with \0 terminator, final \0
4317 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4318 short = need - 0x8
4319 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4320 str(e.exception))
4321
Simon Glassf2c0dd82020-10-26 17:40:01 -06004322 def testSkipAtStart(self):
4323 """Test handling of skip-at-start section"""
4324 data = self._DoReadFile('177_skip_at_start.dts')
4325 self.assertEqual(U_BOOT_DATA, data)
4326
4327 image = control.images['image']
4328 entries = image.GetEntries()
4329 section = entries['section']
4330 self.assertEqual(0, section.offset)
4331 self.assertEqual(len(U_BOOT_DATA), section.size)
4332 self.assertEqual(U_BOOT_DATA, section.GetData())
4333
4334 entry = section.GetEntries()['u-boot']
4335 self.assertEqual(16, entry.offset)
4336 self.assertEqual(len(U_BOOT_DATA), entry.size)
4337 self.assertEqual(U_BOOT_DATA, entry.data)
4338
4339 def testSkipAtStartPad(self):
4340 """Test handling of skip-at-start section with padded entry"""
4341 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004342 before = tools.get_bytes(0, 8)
4343 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004344 all = before + U_BOOT_DATA + after
4345 self.assertEqual(all, data)
4346
4347 image = control.images['image']
4348 entries = image.GetEntries()
4349 section = entries['section']
4350 self.assertEqual(0, section.offset)
4351 self.assertEqual(len(all), section.size)
4352 self.assertEqual(all, section.GetData())
4353
4354 entry = section.GetEntries()['u-boot']
4355 self.assertEqual(16, entry.offset)
4356 self.assertEqual(len(all), entry.size)
4357 self.assertEqual(U_BOOT_DATA, entry.data)
4358
4359 def testSkipAtStartSectionPad(self):
4360 """Test handling of skip-at-start section with padding"""
4361 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004362 before = tools.get_bytes(0, 8)
4363 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004364 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06004365 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004366
4367 image = control.images['image']
4368 entries = image.GetEntries()
4369 section = entries['section']
4370 self.assertEqual(0, section.offset)
4371 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004372 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004373 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004374
4375 entry = section.GetEntries()['u-boot']
4376 self.assertEqual(16, entry.offset)
4377 self.assertEqual(len(U_BOOT_DATA), entry.size)
4378 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004379
Simon Glass7d398bb2020-10-26 17:40:14 -06004380 def testSectionPad(self):
4381 """Testing padding with sections"""
4382 data = self._DoReadFile('180_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004383 expected = (tools.get_bytes(ord('&'), 3) +
4384 tools.get_bytes(ord('!'), 5) +
Simon Glass7d398bb2020-10-26 17:40:14 -06004385 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004386 tools.get_bytes(ord('!'), 1) +
4387 tools.get_bytes(ord('&'), 2))
Simon Glass7d398bb2020-10-26 17:40:14 -06004388 self.assertEqual(expected, data)
4389
4390 def testSectionAlign(self):
4391 """Testing alignment with sections"""
4392 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4393 expected = (b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004394 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glass7d398bb2020-10-26 17:40:14 -06004395 b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004396 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glass7d398bb2020-10-26 17:40:14 -06004397 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004398 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4399 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glass7d398bb2020-10-26 17:40:14 -06004400 self.assertEqual(expected, data)
4401
Simon Glass8f5ef892020-10-26 17:40:25 -06004402 def testCompressImage(self):
4403 """Test compression of the entire image"""
4404 self._CheckLz4()
4405 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4406 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4407 dtb = fdt.Fdt(out_dtb_fname)
4408 dtb.Scan()
4409 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4410 'uncomp-size'])
4411 orig = self._decompress(data)
4412 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4413
4414 # Do a sanity check on various fields
4415 image = control.images['image']
4416 entries = image.GetEntries()
4417 self.assertEqual(2, len(entries))
4418
4419 entry = entries['blob']
4420 self.assertEqual(COMPRESS_DATA, entry.data)
4421 self.assertEqual(len(COMPRESS_DATA), entry.size)
4422
4423 entry = entries['u-boot']
4424 self.assertEqual(U_BOOT_DATA, entry.data)
4425 self.assertEqual(len(U_BOOT_DATA), entry.size)
4426
4427 self.assertEqual(len(data), image.size)
4428 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4429 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4430 orig = self._decompress(image.data)
4431 self.assertEqual(orig, image.uncomp_data)
4432
4433 expected = {
4434 'blob:offset': 0,
4435 'blob:size': len(COMPRESS_DATA),
4436 'u-boot:offset': len(COMPRESS_DATA),
4437 'u-boot:size': len(U_BOOT_DATA),
4438 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4439 'offset': 0,
4440 'image-pos': 0,
4441 'size': len(data),
4442 }
4443 self.assertEqual(expected, props)
4444
4445 def testCompressImageLess(self):
4446 """Test compression where compression reduces the image size"""
4447 self._CheckLz4()
4448 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4449 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4450 dtb = fdt.Fdt(out_dtb_fname)
4451 dtb.Scan()
4452 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4453 'uncomp-size'])
4454 orig = self._decompress(data)
4455
4456 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4457
4458 # Do a sanity check on various fields
4459 image = control.images['image']
4460 entries = image.GetEntries()
4461 self.assertEqual(2, len(entries))
4462
4463 entry = entries['blob']
4464 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4465 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4466
4467 entry = entries['u-boot']
4468 self.assertEqual(U_BOOT_DATA, entry.data)
4469 self.assertEqual(len(U_BOOT_DATA), entry.size)
4470
4471 self.assertEqual(len(data), image.size)
4472 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4473 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4474 image.uncomp_size)
4475 orig = self._decompress(image.data)
4476 self.assertEqual(orig, image.uncomp_data)
4477
4478 expected = {
4479 'blob:offset': 0,
4480 'blob:size': len(COMPRESS_DATA_BIG),
4481 'u-boot:offset': len(COMPRESS_DATA_BIG),
4482 'u-boot:size': len(U_BOOT_DATA),
4483 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4484 'offset': 0,
4485 'image-pos': 0,
4486 'size': len(data),
4487 }
4488 self.assertEqual(expected, props)
4489
4490 def testCompressSectionSize(self):
4491 """Test compression of a section with a fixed size"""
4492 self._CheckLz4()
4493 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4494 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4495 dtb = fdt.Fdt(out_dtb_fname)
4496 dtb.Scan()
4497 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4498 'uncomp-size'])
4499 orig = self._decompress(data)
4500 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4501 expected = {
4502 'section/blob:offset': 0,
4503 'section/blob:size': len(COMPRESS_DATA),
4504 'section/u-boot:offset': len(COMPRESS_DATA),
4505 'section/u-boot:size': len(U_BOOT_DATA),
4506 'section:offset': 0,
4507 'section:image-pos': 0,
4508 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4509 'section:size': 0x30,
4510 'offset': 0,
4511 'image-pos': 0,
4512 'size': 0x30,
4513 }
4514 self.assertEqual(expected, props)
4515
4516 def testCompressSection(self):
4517 """Test compression of a section with no fixed size"""
4518 self._CheckLz4()
4519 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4520 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4521 dtb = fdt.Fdt(out_dtb_fname)
4522 dtb.Scan()
4523 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4524 'uncomp-size'])
4525 orig = self._decompress(data)
4526 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4527 expected = {
4528 'section/blob:offset': 0,
4529 'section/blob:size': len(COMPRESS_DATA),
4530 'section/u-boot:offset': len(COMPRESS_DATA),
4531 'section/u-boot:size': len(U_BOOT_DATA),
4532 'section:offset': 0,
4533 'section:image-pos': 0,
4534 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4535 'section:size': len(data),
4536 'offset': 0,
4537 'image-pos': 0,
4538 'size': len(data),
4539 }
4540 self.assertEqual(expected, props)
4541
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004542 def testLz4Missing(self):
4543 """Test that binman still produces an image if lz4 is missing"""
4544 with test_util.capture_sys_output() as (_, stderr):
4545 self._DoTestFile('185_compress_section.dts',
4546 force_missing_bintools='lz4')
4547 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004548 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004549
Simon Glass8f5ef892020-10-26 17:40:25 -06004550 def testCompressExtra(self):
4551 """Test compression of a section with no fixed size"""
4552 self._CheckLz4()
4553 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4554 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4555 dtb = fdt.Fdt(out_dtb_fname)
4556 dtb.Scan()
4557 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4558 'uncomp-size'])
4559
4560 base = data[len(U_BOOT_DATA):]
4561 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4562 rest = base[len(U_BOOT_DATA):]
4563
4564 # Check compressed data
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004565 bintool = self.comp_bintools['lz4']
4566 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004567 data1 = rest[:len(expect1)]
4568 section1 = self._decompress(data1)
4569 self.assertEquals(expect1, data1)
Simon Glass8f5ef892020-10-26 17:40:25 -06004570 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4571 rest1 = rest[len(expect1):]
4572
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004573 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004574 data2 = rest1[:len(expect2)]
4575 section2 = self._decompress(data2)
4576 self.assertEquals(expect2, data2)
Simon Glass8f5ef892020-10-26 17:40:25 -06004577 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4578 rest2 = rest1[len(expect2):]
4579
4580 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4581 len(expect2) + len(U_BOOT_DATA))
4582 #self.assertEquals(expect_size, len(data))
4583
4584 #self.assertEquals(U_BOOT_DATA, rest2)
4585
4586 self.maxDiff = None
4587 expected = {
4588 'u-boot:offset': 0,
4589 'u-boot:image-pos': 0,
4590 'u-boot:size': len(U_BOOT_DATA),
4591
4592 'base:offset': len(U_BOOT_DATA),
4593 'base:image-pos': len(U_BOOT_DATA),
4594 'base:size': len(data) - len(U_BOOT_DATA),
4595 'base/u-boot:offset': 0,
4596 'base/u-boot:image-pos': len(U_BOOT_DATA),
4597 'base/u-boot:size': len(U_BOOT_DATA),
4598 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4599 len(expect2),
4600 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4601 len(expect2),
4602 'base/u-boot2:size': len(U_BOOT_DATA),
4603
4604 'base/section:offset': len(U_BOOT_DATA),
4605 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4606 'base/section:size': len(expect1),
4607 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4608 'base/section/blob:offset': 0,
4609 'base/section/blob:size': len(COMPRESS_DATA),
4610 'base/section/u-boot:offset': len(COMPRESS_DATA),
4611 'base/section/u-boot:size': len(U_BOOT_DATA),
4612
4613 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4614 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4615 'base/section2:size': len(expect2),
4616 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4617 'base/section2/blob:offset': 0,
4618 'base/section2/blob:size': len(COMPRESS_DATA),
4619 'base/section2/blob2:offset': len(COMPRESS_DATA),
4620 'base/section2/blob2:size': len(COMPRESS_DATA),
4621
4622 'offset': 0,
4623 'image-pos': 0,
4624 'size': len(data),
4625 }
4626 self.assertEqual(expected, props)
4627
Simon Glass870a9ea2021-01-06 21:35:15 -07004628 def testSymbolsSubsection(self):
4629 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03004630 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass870a9ea2021-01-06 21:35:15 -07004631
Simon Glass939d1062021-01-06 21:35:16 -07004632 def testReadImageEntryArg(self):
4633 """Test reading an image that would need an entry arg to generate"""
4634 entry_args = {
4635 'cros-ec-rw-path': 'ecrw.bin',
4636 }
4637 data = self.data = self._DoReadFileDtb(
4638 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4639 entry_args=entry_args)
4640
Simon Glassc1aa66e2022-01-29 14:14:04 -07004641 image_fname = tools.get_output_filename('image.bin')
Simon Glass939d1062021-01-06 21:35:16 -07004642 orig_image = control.images['image']
4643
4644 # This should not generate an error about the missing 'cros-ec-rw-path'
4645 # since we are reading the image from a file. Compare with
4646 # testEntryArgsRequired()
4647 image = Image.FromFile(image_fname)
4648 self.assertEqual(orig_image.GetEntries().keys(),
4649 image.GetEntries().keys())
4650
Simon Glass6eb99322021-01-06 21:35:18 -07004651 def testFilesAlign(self):
4652 """Test alignment with files"""
4653 data = self._DoReadFile('190_files_align.dts')
4654
4655 # The first string is 15 bytes so will align to 16
4656 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4657 self.assertEqual(expect, data)
4658
Simon Glass5c6ba712021-01-06 21:35:19 -07004659 def testReadImageSkip(self):
4660 """Test reading an image and accessing its FDT map"""
4661 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004662 image_fname = tools.get_output_filename('image.bin')
Simon Glass5c6ba712021-01-06 21:35:19 -07004663 orig_image = control.images['image']
4664 image = Image.FromFile(image_fname)
4665 self.assertEqual(orig_image.GetEntries().keys(),
4666 image.GetEntries().keys())
4667
4668 orig_entry = orig_image.GetEntries()['fdtmap']
4669 entry = image.GetEntries()['fdtmap']
4670 self.assertEqual(orig_entry.offset, entry.offset)
4671 self.assertEqual(orig_entry.size, entry.size)
4672 self.assertEqual(16, entry.image_pos)
4673
4674 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4675
4676 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4677
Simon Glass77a64e02021-03-18 20:24:57 +13004678 def testTplNoDtb(self):
4679 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004680 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004681 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4682 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4683 data[:len(U_BOOT_TPL_NODTB_DATA)])
4684
Simon Glassd26efc82021-03-18 20:24:58 +13004685 def testTplBssPad(self):
4686 """Test that we can pad TPL's BSS with zeros"""
4687 # ELF file with a '__bss_size' symbol
4688 self._SetupTplElf()
4689 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004690 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassd26efc82021-03-18 20:24:58 +13004691 data)
4692
4693 def testTplBssPadMissing(self):
4694 """Test that a missing symbol is detected"""
4695 self._SetupTplElf('u_boot_ucode_ptr')
4696 with self.assertRaises(ValueError) as e:
4697 self._DoReadFile('193_tpl_bss_pad.dts')
4698 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4699 str(e.exception))
4700
Simon Glass06684922021-03-18 20:25:07 +13004701 def checkDtbSizes(self, data, pad_len, start):
4702 """Check the size arguments in a dtb embedded in an image
4703
4704 Args:
4705 data: The image data
4706 pad_len: Length of the pad section in the image, in bytes
4707 start: Start offset of the devicetree to examine, within the image
4708
4709 Returns:
4710 Size of the devicetree in bytes
4711 """
4712 dtb_data = data[start:]
4713 dtb = fdt.Fdt.FromData(dtb_data)
4714 fdt_size = dtb.GetFdtObj().totalsize()
4715 dtb.Scan()
4716 props = self._GetPropTree(dtb, 'size')
4717 self.assertEqual({
4718 'size': len(data),
4719 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4720 'u-boot-spl/u-boot-spl-dtb:size': 801,
4721 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4722 'u-boot-spl:size': 860,
4723 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4724 'u-boot/u-boot-dtb:size': 781,
4725 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4726 'u-boot:size': 827,
4727 }, props)
4728 return fdt_size
4729
4730 def testExpanded(self):
4731 """Test that an expanded entry type is selected when needed"""
4732 self._SetupSplElf()
4733 self._SetupTplElf()
4734
4735 # SPL has a devicetree, TPL does not
4736 entry_args = {
4737 'spl-dtb': '1',
4738 'spl-bss-pad': 'y',
4739 'tpl-dtb': '',
4740 }
4741 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4742 entry_args=entry_args)
4743 image = control.images['image']
4744 entries = image.GetEntries()
4745 self.assertEqual(3, len(entries))
4746
4747 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4748 self.assertIn('u-boot', entries)
4749 entry = entries['u-boot']
4750 self.assertEqual('u-boot-expanded', entry.etype)
4751 subent = entry.GetEntries()
4752 self.assertEqual(2, len(subent))
4753 self.assertIn('u-boot-nodtb', subent)
4754 self.assertIn('u-boot-dtb', subent)
4755
4756 # Second, u-boot-spl, which should be expanded into three parts
4757 self.assertIn('u-boot-spl', entries)
4758 entry = entries['u-boot-spl']
4759 self.assertEqual('u-boot-spl-expanded', entry.etype)
4760 subent = entry.GetEntries()
4761 self.assertEqual(3, len(subent))
4762 self.assertIn('u-boot-spl-nodtb', subent)
4763 self.assertIn('u-boot-spl-bss-pad', subent)
4764 self.assertIn('u-boot-spl-dtb', subent)
4765
4766 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4767 # devicetree
4768 self.assertIn('u-boot-tpl', entries)
4769 entry = entries['u-boot-tpl']
4770 self.assertEqual('u-boot-tpl', entry.etype)
4771 self.assertEqual(None, entry.GetEntries())
4772
4773 def testExpandedTpl(self):
4774 """Test that an expanded entry type is selected for TPL when needed"""
4775 self._SetupTplElf()
4776
4777 entry_args = {
4778 'tpl-bss-pad': 'y',
4779 'tpl-dtb': 'y',
4780 }
4781 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4782 entry_args=entry_args)
4783 image = control.images['image']
4784 entries = image.GetEntries()
4785 self.assertEqual(1, len(entries))
4786
4787 # We only have u-boot-tpl, which be expanded
4788 self.assertIn('u-boot-tpl', entries)
4789 entry = entries['u-boot-tpl']
4790 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4791 subent = entry.GetEntries()
4792 self.assertEqual(3, len(subent))
4793 self.assertIn('u-boot-tpl-nodtb', subent)
4794 self.assertIn('u-boot-tpl-bss-pad', subent)
4795 self.assertIn('u-boot-tpl-dtb', subent)
4796
4797 def testExpandedNoPad(self):
4798 """Test an expanded entry without BSS pad enabled"""
4799 self._SetupSplElf()
4800 self._SetupTplElf()
4801
4802 # SPL has a devicetree, TPL does not
4803 entry_args = {
4804 'spl-dtb': 'something',
4805 'spl-bss-pad': 'n',
4806 'tpl-dtb': '',
4807 }
4808 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4809 entry_args=entry_args)
4810 image = control.images['image']
4811 entries = image.GetEntries()
4812
4813 # Just check u-boot-spl, which should be expanded into two parts
4814 self.assertIn('u-boot-spl', entries)
4815 entry = entries['u-boot-spl']
4816 self.assertEqual('u-boot-spl-expanded', entry.etype)
4817 subent = entry.GetEntries()
4818 self.assertEqual(2, len(subent))
4819 self.assertIn('u-boot-spl-nodtb', subent)
4820 self.assertIn('u-boot-spl-dtb', subent)
4821
4822 def testExpandedTplNoPad(self):
4823 """Test that an expanded entry type with padding disabled in TPL"""
4824 self._SetupTplElf()
4825
4826 entry_args = {
4827 'tpl-bss-pad': '',
4828 'tpl-dtb': 'y',
4829 }
4830 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4831 entry_args=entry_args)
4832 image = control.images['image']
4833 entries = image.GetEntries()
4834 self.assertEqual(1, len(entries))
4835
4836 # We only have u-boot-tpl, which be expanded
4837 self.assertIn('u-boot-tpl', entries)
4838 entry = entries['u-boot-tpl']
4839 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4840 subent = entry.GetEntries()
4841 self.assertEqual(2, len(subent))
4842 self.assertIn('u-boot-tpl-nodtb', subent)
4843 self.assertIn('u-boot-tpl-dtb', subent)
4844
4845 def testFdtInclude(self):
4846 """Test that an Fdt is update within all binaries"""
4847 self._SetupSplElf()
4848 self._SetupTplElf()
4849
4850 # SPL has a devicetree, TPL does not
4851 self.maxDiff = None
4852 entry_args = {
4853 'spl-dtb': '1',
4854 'spl-bss-pad': 'y',
4855 'tpl-dtb': '',
4856 }
4857 # Build the image. It includes two separate devicetree binaries, each
4858 # with their own contents, but all contain the binman definition.
4859 data = self._DoReadFileDtb(
4860 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4861 update_dtb=True, entry_args=entry_args)[0]
4862 pad_len = 10
4863
4864 # Check the U-Boot dtb
4865 start = len(U_BOOT_NODTB_DATA)
4866 fdt_size = self.checkDtbSizes(data, pad_len, start)
4867
4868 # Now check SPL
4869 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4870 fdt_size = self.checkDtbSizes(data, pad_len, start)
4871
4872 # TPL has no devicetree
4873 start += fdt_size + len(U_BOOT_TPL_DATA)
4874 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004875
Simon Glass3d433382021-03-21 18:24:30 +13004876 def testSymbolsExpanded(self):
4877 """Test binman can assign symbols in expanded entries"""
4878 entry_args = {
4879 'spl-dtb': '1',
4880 }
4881 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4882 U_BOOT_SPL_DTB_DATA, 0x38,
4883 entry_args=entry_args, use_expanded=True)
4884
Simon Glass189f2912021-03-21 18:24:31 +13004885 def testCollection(self):
4886 """Test a collection"""
4887 data = self._DoReadFile('198_collection.dts')
4888 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004889 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4890 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glass189f2912021-03-21 18:24:31 +13004891 data)
4892
Simon Glass631f7522021-03-21 18:24:32 +13004893 def testCollectionSection(self):
4894 """Test a collection where a section must be built first"""
4895 # Sections never have their contents when GetData() is called, but when
Simon Glassd34bcdd2021-11-23 11:03:47 -07004896 # BuildSectionData() is called with required=True, a section will force
Simon Glass631f7522021-03-21 18:24:32 +13004897 # building the contents, producing an error is anything is still
4898 # missing.
4899 data = self._DoReadFile('199_collection_section.dts')
4900 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glassc1aa66e2022-01-29 14:14:04 -07004901 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4902 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass631f7522021-03-21 18:24:32 +13004903 data)
4904
Simon Glass5ff9fed2021-03-21 18:24:33 +13004905 def testAlignDefault(self):
4906 """Test that default alignment works on sections"""
4907 data = self._DoReadFile('200_align_default.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004908 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glass5ff9fed2021-03-21 18:24:33 +13004909 U_BOOT_DATA)
4910 # Special alignment for section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004911 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glass5ff9fed2021-03-21 18:24:33 +13004912 # No alignment within the nested section
4913 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4914 # Now the final piece, which should be default-aligned
Simon Glassc1aa66e2022-01-29 14:14:04 -07004915 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glass5ff9fed2021-03-21 18:24:33 +13004916 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004917
Bin Meng4c4d6072021-05-10 20:23:33 +08004918 def testPackOpenSBI(self):
4919 """Test that an image with an OpenSBI binary can be created"""
4920 data = self._DoReadFile('201_opensbi.dts')
4921 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4922
Simon Glassc69d19c2021-07-06 10:36:37 -06004923 def testSectionsSingleThread(self):
4924 """Test sections without multithreading"""
4925 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glassc1aa66e2022-01-29 14:14:04 -07004926 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4927 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4928 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassc69d19c2021-07-06 10:36:37 -06004929 self.assertEqual(expected, data)
4930
4931 def testThreadTimeout(self):
4932 """Test handling a thread that takes too long"""
4933 with self.assertRaises(ValueError) as e:
4934 self._DoTestFile('202_section_timeout.dts',
4935 test_section_timeout=True)
Simon Glassb2dfe832021-10-18 12:13:15 -06004936 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glassc69d19c2021-07-06 10:36:37 -06004937
Simon Glass03ebc202021-07-06 10:36:41 -06004938 def testTiming(self):
4939 """Test output of timing information"""
4940 data = self._DoReadFile('055_sections.dts')
4941 with test_util.capture_sys_output() as (stdout, stderr):
4942 state.TimingShow()
4943 self.assertIn('read:', stdout.getvalue())
4944 self.assertIn('compress:', stdout.getvalue())
4945
Simon Glass0427bed2021-11-03 21:09:18 -06004946 def testUpdateFdtInElf(self):
4947 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004948 if not elf.ELF_TOOLS:
4949 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004950 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4951 outfile = os.path.join(self._indir, 'u-boot.out')
4952 begin_sym = 'dtb_embed_begin'
4953 end_sym = 'dtb_embed_end'
4954 retcode = self._DoTestFile(
4955 '060_fdt_update.dts', update_dtb=True,
4956 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4957 self.assertEqual(0, retcode)
4958
4959 # Check that the output file does in fact contact a dtb with the binman
4960 # definition in the correct place
4961 syms = elf.GetSymbolFileOffset(infile,
4962 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07004963 data = tools.read_file(outfile)
Simon Glass0427bed2021-11-03 21:09:18 -06004964 dtb_data = data[syms['dtb_embed_begin'].offset:
4965 syms['dtb_embed_end'].offset]
4966
4967 dtb = fdt.Fdt.FromData(dtb_data)
4968 dtb.Scan()
4969 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4970 self.assertEqual({
4971 'image-pos': 0,
4972 'offset': 0,
4973 '_testing:offset': 32,
4974 '_testing:size': 2,
4975 '_testing:image-pos': 32,
4976 'section@0/u-boot:offset': 0,
4977 'section@0/u-boot:size': len(U_BOOT_DATA),
4978 'section@0/u-boot:image-pos': 0,
4979 'section@0:offset': 0,
4980 'section@0:size': 16,
4981 'section@0:image-pos': 0,
4982
4983 'section@1/u-boot:offset': 0,
4984 'section@1/u-boot:size': len(U_BOOT_DATA),
4985 'section@1/u-boot:image-pos': 16,
4986 'section@1:offset': 16,
4987 'section@1:size': 16,
4988 'section@1:image-pos': 16,
4989 'size': 40
4990 }, props)
4991
4992 def testUpdateFdtInElfInvalid(self):
4993 """Test that invalid args are detected with --update-fdt-in-elf"""
4994 with self.assertRaises(ValueError) as e:
4995 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4996 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4997 str(e.exception))
4998
4999 def testUpdateFdtInElfNoSyms(self):
5000 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005001 if not elf.ELF_TOOLS:
5002 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06005003 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
5004 outfile = ''
5005 begin_sym = 'wrong_begin'
5006 end_sym = 'wrong_end'
5007 with self.assertRaises(ValueError) as e:
5008 self._DoTestFile(
5009 '060_fdt_update.dts',
5010 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5011 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
5012 str(e.exception))
5013
5014 def testUpdateFdtInElfTooSmall(self):
5015 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005016 if not elf.ELF_TOOLS:
5017 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06005018 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5019 outfile = os.path.join(self._indir, 'u-boot.out')
5020 begin_sym = 'dtb_embed_begin'
5021 end_sym = 'dtb_embed_end'
5022 with self.assertRaises(ValueError) as e:
5023 self._DoTestFile(
5024 '060_fdt_update.dts', update_dtb=True,
5025 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5026 self.assertRegex(
5027 str(e.exception),
5028 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5029
Simon Glassc475dec2021-11-23 11:03:42 -07005030 def testVersion(self):
5031 """Test we can get the binman version"""
5032 version = '(unreleased)'
5033 self.assertEqual(version, state.GetVersion(self._indir))
5034
5035 with self.assertRaises(SystemExit):
5036 with test_util.capture_sys_output() as (_, stderr):
5037 self._DoBinman('-V')
5038 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5039
5040 # Try running the tool too, just to be safe
5041 result = self._RunBinman('-V')
5042 self.assertEqual('Binman %s\n' % version, result.stderr)
5043
5044 # Set up a version file to make sure that works
5045 version = 'v2025.01-rc2'
Simon Glassc1aa66e2022-01-29 14:14:04 -07005046 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glassc475dec2021-11-23 11:03:42 -07005047 binary=False)
5048 self.assertEqual(version, state.GetVersion(self._indir))
5049
Simon Glass943bf782021-11-23 21:09:50 -07005050 def testAltFormat(self):
5051 """Test that alternative formats can be used to extract"""
5052 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5053
5054 try:
5055 tmpdir, updated_fname = self._SetupImageInTmpdir()
5056 with test_util.capture_sys_output() as (stdout, _):
5057 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5058 self.assertEqual(
5059 '''Flag (-F) Entry type Description
5060fdt fdtmap Extract the devicetree blob from the fdtmap
5061''',
5062 stdout.getvalue())
5063
5064 dtb = os.path.join(tmpdir, 'fdt.dtb')
5065 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5066 dtb, 'fdtmap')
5067
5068 # Check that we can read it and it can be scanning, meaning it does
5069 # not have a 16-byte fdtmap header
Simon Glassc1aa66e2022-01-29 14:14:04 -07005070 data = tools.read_file(dtb)
Simon Glass943bf782021-11-23 21:09:50 -07005071 dtb = fdt.Fdt.FromData(data)
5072 dtb.Scan()
5073
5074 # Now check u-boot which has no alt_format
5075 fname = os.path.join(tmpdir, 'fdt.dtb')
5076 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5077 '-f', fname, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005078 data = tools.read_file(fname)
Simon Glass943bf782021-11-23 21:09:50 -07005079 self.assertEqual(U_BOOT_DATA, data)
5080
5081 finally:
5082 shutil.rmtree(tmpdir)
5083
Simon Glasscc2c5002021-11-23 21:09:52 -07005084 def testExtblobList(self):
5085 """Test an image with an external blob list"""
5086 data = self._DoReadFile('215_blob_ext_list.dts')
5087 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5088
5089 def testExtblobListMissing(self):
5090 """Test an image with a missing external blob"""
5091 with self.assertRaises(ValueError) as e:
5092 self._DoReadFile('216_blob_ext_list_missing.dts')
5093 self.assertIn("Filename 'missing-file' not found in input path",
5094 str(e.exception))
5095
5096 def testExtblobListMissingOk(self):
5097 """Test an image with an missing external blob that is allowed"""
5098 with test_util.capture_sys_output() as (stdout, stderr):
5099 self._DoTestFile('216_blob_ext_list_missing.dts',
5100 allow_missing=True)
5101 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005102 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glasscc2c5002021-11-23 21:09:52 -07005103
Simon Glass75989722021-11-23 21:08:59 -07005104 def testFip(self):
5105 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5106 data = self._DoReadFile('203_fip.dts')
5107 hdr, fents = fip_util.decode_fip(data)
5108 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5109 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5110 self.assertEqual(0x123, hdr.flags)
5111
5112 self.assertEqual(2, len(fents))
5113
5114 fent = fents[0]
5115 self.assertEqual(
5116 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5117 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5118 self.assertEqual('soc-fw', fent.fip_type)
5119 self.assertEqual(0x88, fent.offset)
5120 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5121 self.assertEqual(0x123456789abcdef, fent.flags)
5122 self.assertEqual(ATF_BL31_DATA, fent.data)
5123 self.assertEqual(True, fent.valid)
5124
5125 fent = fents[1]
5126 self.assertEqual(
5127 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5128 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5129 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5130 self.assertEqual(0x8c, fent.offset)
5131 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5132 self.assertEqual(0, fent.flags)
5133 self.assertEqual(ATF_BL2U_DATA, fent.data)
5134 self.assertEqual(True, fent.valid)
5135
5136 def testFipOther(self):
5137 """Basic FIP with something that isn't a external blob"""
5138 data = self._DoReadFile('204_fip_other.dts')
5139 hdr, fents = fip_util.decode_fip(data)
5140
5141 self.assertEqual(2, len(fents))
5142 fent = fents[1]
5143 self.assertEqual('rot-cert', fent.fip_type)
5144 self.assertEqual(b'aa', fent.data)
5145
Simon Glass75989722021-11-23 21:08:59 -07005146 def testFipNoType(self):
5147 """FIP with an entry of an unknown type"""
5148 with self.assertRaises(ValueError) as e:
5149 self._DoReadFile('205_fip_no_type.dts')
5150 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5151 str(e.exception))
5152
5153 def testFipUuid(self):
5154 """Basic FIP with a manual uuid"""
5155 data = self._DoReadFile('206_fip_uuid.dts')
5156 hdr, fents = fip_util.decode_fip(data)
5157
5158 self.assertEqual(2, len(fents))
5159 fent = fents[1]
5160 self.assertEqual(None, fent.fip_type)
5161 self.assertEqual(
5162 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5163 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5164 fent.uuid)
5165 self.assertEqual(U_BOOT_DATA, fent.data)
5166
5167 def testFipLs(self):
5168 """Test listing a FIP"""
5169 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5170 hdr, fents = fip_util.decode_fip(data)
5171
5172 try:
5173 tmpdir, updated_fname = self._SetupImageInTmpdir()
5174 with test_util.capture_sys_output() as (stdout, stderr):
5175 self._DoBinman('ls', '-i', updated_fname)
5176 finally:
5177 shutil.rmtree(tmpdir)
5178 lines = stdout.getvalue().splitlines()
5179 expected = [
Simon Glass193d3db2023-02-07 14:34:18 -07005180'Name Image-pos Size Entry-type Offset Uncomp-size',
5181'--------------------------------------------------------------',
5182'image 0 2d3 section 0',
5183' atf-fip 0 90 atf-fip 0',
5184' soc-fw 88 4 blob-ext 88',
5185' u-boot 8c 4 u-boot 8c',
5186' fdtmap 90 243 fdtmap 90',
Simon Glass75989722021-11-23 21:08:59 -07005187]
5188 self.assertEqual(expected, lines)
5189
5190 image = control.images['image']
5191 entries = image.GetEntries()
5192 fdtmap = entries['fdtmap']
5193
5194 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5195 magic = fdtmap_data[:8]
5196 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07005197 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass75989722021-11-23 21:08:59 -07005198
5199 fdt_data = fdtmap_data[16:]
5200 dtb = fdt.Fdt.FromData(fdt_data)
5201 dtb.Scan()
5202 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5203 self.assertEqual({
5204 'atf-fip/soc-fw:image-pos': 136,
5205 'atf-fip/soc-fw:offset': 136,
5206 'atf-fip/soc-fw:size': 4,
5207 'atf-fip/u-boot:image-pos': 140,
5208 'atf-fip/u-boot:offset': 140,
5209 'atf-fip/u-boot:size': 4,
5210 'atf-fip:image-pos': 0,
5211 'atf-fip:offset': 0,
5212 'atf-fip:size': 144,
5213 'image-pos': 0,
5214 'offset': 0,
5215 'fdtmap:image-pos': fdtmap.image_pos,
5216 'fdtmap:offset': fdtmap.offset,
5217 'fdtmap:size': len(fdtmap_data),
5218 'size': len(data),
5219 }, props)
5220
5221 def testFipExtractOneEntry(self):
5222 """Test extracting a single entry fron an FIP"""
5223 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005224 image_fname = tools.get_output_filename('image.bin')
Simon Glass75989722021-11-23 21:08:59 -07005225 fname = os.path.join(self._indir, 'output.extact')
5226 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07005227 data = tools.read_file(fname)
Simon Glass75989722021-11-23 21:08:59 -07005228 self.assertEqual(U_BOOT_DATA, data)
5229
5230 def testFipReplace(self):
5231 """Test replacing a single file in a FIP"""
Simon Glassc1aa66e2022-01-29 14:14:04 -07005232 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass75989722021-11-23 21:08:59 -07005233 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005234 updated_fname = tools.get_output_filename('image-updated.bin')
5235 tools.write_file(updated_fname, data)
Simon Glass75989722021-11-23 21:08:59 -07005236 entry_name = 'atf-fip/u-boot'
5237 control.WriteEntry(updated_fname, entry_name, expected,
5238 allow_resize=True)
5239 actual = control.ReadEntry(updated_fname, entry_name)
5240 self.assertEqual(expected, actual)
5241
Simon Glassc1aa66e2022-01-29 14:14:04 -07005242 new_data = tools.read_file(updated_fname)
Simon Glass75989722021-11-23 21:08:59 -07005243 hdr, fents = fip_util.decode_fip(new_data)
5244
5245 self.assertEqual(2, len(fents))
5246
5247 # Check that the FIP entry is updated
5248 fent = fents[1]
5249 self.assertEqual(0x8c, fent.offset)
5250 self.assertEqual(len(expected), fent.size)
5251 self.assertEqual(0, fent.flags)
5252 self.assertEqual(expected, fent.data)
5253 self.assertEqual(True, fent.valid)
5254
5255 def testFipMissing(self):
5256 with test_util.capture_sys_output() as (stdout, stderr):
5257 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5258 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005259 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass75989722021-11-23 21:08:59 -07005260
5261 def testFipSize(self):
5262 """Test a FIP with a size property"""
5263 data = self._DoReadFile('210_fip_size.dts')
5264 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5265 hdr, fents = fip_util.decode_fip(data)
5266 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5267 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5268
5269 self.assertEqual(1, len(fents))
5270
5271 fent = fents[0]
5272 self.assertEqual('soc-fw', fent.fip_type)
5273 self.assertEqual(0x60, fent.offset)
5274 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5275 self.assertEqual(ATF_BL31_DATA, fent.data)
5276 self.assertEqual(True, fent.valid)
5277
5278 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glassc1aa66e2022-01-29 14:14:04 -07005279 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass75989722021-11-23 21:08:59 -07005280
5281 def testFipBadAlign(self):
5282 """Test that an invalid alignment value in a FIP is detected"""
5283 with self.assertRaises(ValueError) as e:
5284 self._DoTestFile('211_fip_bad_align.dts')
5285 self.assertIn(
5286 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5287 str(e.exception))
5288
5289 def testFipCollection(self):
5290 """Test using a FIP in a collection"""
5291 data = self._DoReadFile('212_fip_collection.dts')
5292 entry1 = control.images['image'].GetEntries()['collection']
5293 data1 = data[:entry1.size]
5294 hdr1, fents2 = fip_util.decode_fip(data1)
5295
5296 entry2 = control.images['image'].GetEntries()['atf-fip']
5297 data2 = data[entry2.offset:entry2.offset + entry2.size]
5298 hdr1, fents2 = fip_util.decode_fip(data2)
5299
5300 # The 'collection' entry should have U-Boot included at the end
5301 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5302 self.assertEqual(data1, data2 + U_BOOT_DATA)
5303 self.assertEqual(U_BOOT_DATA, data1[-4:])
5304
5305 # There should be a U-Boot after the final FIP
5306 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glassc69d19c2021-07-06 10:36:37 -06005307
Simon Glass32d4f102022-01-12 13:10:35 -07005308 def testFakeBlob(self):
5309 """Test handling of faking an external blob"""
5310 with test_util.capture_sys_output() as (stdout, stderr):
5311 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5312 allow_fake_blobs=True)
5313 err = stderr.getvalue()
5314 self.assertRegex(
5315 err,
5316 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glass32d4f102022-01-12 13:10:35 -07005317
Simon Glassf4590e02022-01-09 20:13:46 -07005318 def testExtblobListFaked(self):
5319 """Test an extblob with missing external blob that are faked"""
5320 with test_util.capture_sys_output() as (stdout, stderr):
5321 self._DoTestFile('216_blob_ext_list_missing.dts',
5322 allow_fake_blobs=True)
5323 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005324 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassf4590e02022-01-09 20:13:46 -07005325
Simon Glass56ee85e2022-01-09 20:13:57 -07005326 def testListBintools(self):
5327 args = ['tool', '--list']
5328 with test_util.capture_sys_output() as (stdout, _):
5329 self._DoBinman(*args)
5330 out = stdout.getvalue().splitlines()
5331 self.assertTrue(len(out) >= 2)
5332
5333 def testFetchBintools(self):
5334 def fail_download(url):
Simon Glassc1aa66e2022-01-29 14:14:04 -07005335 """Take the tools.download() function by raising an exception"""
Simon Glass56ee85e2022-01-09 20:13:57 -07005336 raise urllib.error.URLError('my error')
5337
5338 args = ['tool']
5339 with self.assertRaises(ValueError) as e:
5340 self._DoBinman(*args)
5341 self.assertIn("Invalid arguments to 'tool' subcommand",
5342 str(e.exception))
5343
5344 args = ['tool', '--fetch']
5345 with self.assertRaises(ValueError) as e:
5346 self._DoBinman(*args)
5347 self.assertIn('Please specify bintools to fetch', str(e.exception))
5348
5349 args = ['tool', '--fetch', '_testing']
Simon Glassc1aa66e2022-01-29 14:14:04 -07005350 with unittest.mock.patch.object(tools, 'download',
Simon Glass56ee85e2022-01-09 20:13:57 -07005351 side_effect=fail_download):
5352 with test_util.capture_sys_output() as (stdout, _):
5353 self._DoBinman(*args)
5354 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5355
Simon Glassbc570642022-01-09 20:14:11 -07005356 def testBintoolDocs(self):
5357 """Test for creation of bintool documentation"""
5358 with test_util.capture_sys_output() as (stdout, stderr):
5359 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5360 self.assertTrue(len(stdout.getvalue()) > 0)
5361
5362 def testBintoolDocsMissing(self):
5363 """Test handling of missing bintool documentation"""
5364 with self.assertRaises(ValueError) as e:
5365 with test_util.capture_sys_output() as (stdout, stderr):
5366 control.write_bintool_docs(
5367 control.bintool.Bintool.get_tool_list(), 'mkimage')
5368 self.assertIn('Documentation is missing for modules: mkimage',
5369 str(e.exception))
5370
Jan Kiszkafcc87ef2022-01-28 20:37:53 +01005371 def testListWithGenNode(self):
5372 """Check handling of an FDT map when the section cannot be found"""
5373 entry_args = {
5374 'of-list': 'test-fdt1 test-fdt2',
5375 }
5376 data = self._DoReadFileDtb(
5377 '219_fit_gennode.dts',
5378 entry_args=entry_args,
5379 use_real_dtb=True,
5380 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5381
5382 try:
5383 tmpdir, updated_fname = self._SetupImageInTmpdir()
5384 with test_util.capture_sys_output() as (stdout, stderr):
5385 self._RunBinman('ls', '-i', updated_fname)
5386 finally:
5387 shutil.rmtree(tmpdir)
5388
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005389 def testFitSubentryUsesBintool(self):
5390 """Test that binman FIT subentries can use bintools"""
5391 command.test_result = self._HandleGbbCommand
5392 entry_args = {
5393 'keydir': 'devkeys',
5394 'bmpblk': 'bmpblk.bin',
5395 }
5396 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5397 entry_args=entry_args)
5398
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03005399 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5400 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005401 self.assertIn(expected, data)
5402
5403 def testFitSubentryMissingBintool(self):
5404 """Test that binman reports missing bintools for FIT subentries"""
5405 entry_args = {
5406 'keydir': 'devkeys',
5407 }
5408 with test_util.capture_sys_output() as (_, stderr):
5409 self._DoTestFile('220_fit_subentry_bintool.dts',
5410 force_missing_bintools='futility', entry_args=entry_args)
5411 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005412 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass32d4f102022-01-12 13:10:35 -07005413
Alper Nebi Yasakee813c82022-02-09 22:02:35 +03005414 def testFitSubentryHashSubnode(self):
5415 """Test an image with a FIT inside"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005416 self._SetupSplElf()
Alper Nebi Yasakee813c82022-02-09 22:02:35 +03005417 data, _, _, out_dtb_name = self._DoReadFileDtb(
5418 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5419
5420 mkimage_dtb = fdt.Fdt.FromData(data)
5421 mkimage_dtb.Scan()
5422 binman_dtb = fdt.Fdt(out_dtb_name)
5423 binman_dtb.Scan()
5424
5425 # Check that binman didn't add hash values
5426 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5427 self.assertNotIn('value', fnode.props)
5428
5429 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5430 self.assertNotIn('value', fnode.props)
5431
5432 # Check that mkimage added hash values
5433 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5434 self.assertIn('value', fnode.props)
5435
5436 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5437 self.assertIn('value', fnode.props)
5438
Roger Quadros47f420a2022-02-19 20:50:04 +02005439 def testPackTeeOs(self):
5440 """Test that an image with an TEE binary can be created"""
5441 data = self._DoReadFile('222_tee_os.dts')
5442 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5443
Simon Glass6a0b5f82022-02-08 11:50:03 -07005444 def testFitFdtOper(self):
5445 """Check handling of a specified FIT operation"""
5446 entry_args = {
5447 'of-list': 'test-fdt1 test-fdt2',
5448 'default-dt': 'test-fdt2',
5449 }
5450 self._DoReadFileDtb(
5451 '223_fit_fdt_oper.dts',
5452 entry_args=entry_args,
5453 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5454
5455 def testFitFdtBadOper(self):
5456 """Check handling of an FDT map when the section cannot be found"""
5457 with self.assertRaises(ValueError) as exc:
5458 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glassce4e4022022-03-05 20:19:09 -07005459 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass6a0b5f82022-02-08 11:50:03 -07005460 str(exc.exception))
5461
Simon Glass80a66ae2022-03-05 20:18:59 -07005462 def test_uses_expand_size(self):
5463 """Test that the 'expand-size' property cannot be used anymore"""
5464 with self.assertRaises(ValueError) as e:
5465 data = self._DoReadFile('225_expand_size_bad.dts')
5466 self.assertIn(
5467 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5468 str(e.exception))
5469
Simon Glass40c8bdd2022-03-05 20:19:12 -07005470 def testFitSplitElf(self):
5471 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005472 if not elf.ELF_TOOLS:
5473 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005474 entry_args = {
5475 'of-list': 'test-fdt1 test-fdt2',
5476 'default-dt': 'test-fdt2',
5477 'atf-bl31-path': 'bl31.elf',
5478 'tee-os-path': 'tee.elf',
5479 }
5480 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5481 data = self._DoReadFileDtb(
5482 '226_fit_split_elf.dts',
5483 entry_args=entry_args,
5484 extra_indirs=[test_subdir])[0]
5485
5486 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5487 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5488
5489 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5490 'data', 'load'}
5491 dtb = fdt.Fdt.FromData(fit_data)
5492 dtb.Scan()
5493
5494 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5495 segments, entry = elf.read_loadable_segments(elf_data)
5496
5497 # We assume there are two segments
5498 self.assertEquals(2, len(segments))
5499
5500 atf1 = dtb.GetNode('/images/atf-1')
5501 _, start, data = segments[0]
5502 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5503 self.assertEqual(entry,
5504 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5505 self.assertEqual(start,
5506 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5507 self.assertEqual(data, atf1.props['data'].bytes)
5508
Jonas Karlman00b3d532023-01-21 19:01:48 +00005509 hash_node = atf1.FindNode('hash')
5510 self.assertIsNotNone(hash_node)
5511 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5512
Simon Glass40c8bdd2022-03-05 20:19:12 -07005513 atf2 = dtb.GetNode('/images/atf-2')
5514 self.assertEqual(base_keys, atf2.props.keys())
5515 _, start, data = segments[1]
5516 self.assertEqual(start,
5517 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5518 self.assertEqual(data, atf2.props['data'].bytes)
5519
Jonas Karlman00b3d532023-01-21 19:01:48 +00005520 hash_node = atf2.FindNode('hash')
5521 self.assertIsNotNone(hash_node)
5522 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5523
5524 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5525 self.assertIsNotNone(hash_node)
5526 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5527
Simon Glass40c8bdd2022-03-05 20:19:12 -07005528 conf = dtb.GetNode('/configurations')
5529 self.assertEqual({'default'}, conf.props.keys())
5530
5531 for subnode in conf.subnodes:
5532 self.assertEqual({'description', 'fdt', 'loadables'},
5533 subnode.props.keys())
5534 self.assertEqual(
5535 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5536 fdt_util.GetStringList(subnode, 'loadables'))
5537
5538 def _check_bad_fit(self, dts):
5539 """Check a bad FIT
5540
5541 This runs with the given dts and returns the assertion raised
5542
5543 Args:
5544 dts (str): dts filename to use
5545
5546 Returns:
5547 str: Assertion string raised
5548 """
5549 entry_args = {
5550 'of-list': 'test-fdt1 test-fdt2',
5551 'default-dt': 'test-fdt2',
5552 'atf-bl31-path': 'bl31.elf',
5553 'tee-os-path': 'tee.elf',
5554 }
5555 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5556 with self.assertRaises(ValueError) as exc:
5557 self._DoReadFileDtb(dts, entry_args=entry_args,
5558 extra_indirs=[test_subdir])[0]
5559 return str(exc.exception)
5560
5561 def testFitSplitElfBadElf(self):
5562 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005563 if not elf.ELF_TOOLS:
5564 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005565 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5566 entry_args = {
5567 'of-list': 'test-fdt1 test-fdt2',
5568 'default-dt': 'test-fdt2',
5569 'atf-bl31-path': 'bad.elf',
5570 'tee-os-path': 'tee.elf',
5571 }
5572 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5573 with self.assertRaises(ValueError) as exc:
5574 self._DoReadFileDtb(
5575 '226_fit_split_elf.dts',
5576 entry_args=entry_args,
5577 extra_indirs=[test_subdir])[0]
5578 self.assertIn(
5579 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5580 str(exc.exception))
5581
Simon Glass40c8bdd2022-03-05 20:19:12 -07005582 def checkFitSplitElf(self, **kwargs):
Simon Glass7960a0a2022-08-07 09:46:46 -06005583 """Test an split-elf FIT with a missing ELF file
5584
5585 Args:
5586 kwargs (dict of str): Arguments to pass to _DoTestFile()
5587
5588 Returns:
5589 tuple:
5590 str: stdout result
5591 str: stderr result
5592 """
Simon Glass40c8bdd2022-03-05 20:19:12 -07005593 entry_args = {
5594 'of-list': 'test-fdt1 test-fdt2',
5595 'default-dt': 'test-fdt2',
5596 'atf-bl31-path': 'bl31.elf',
5597 'tee-os-path': 'missing.elf',
5598 }
5599 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5600 with test_util.capture_sys_output() as (stdout, stderr):
5601 self._DoTestFile(
5602 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7960a0a2022-08-07 09:46:46 -06005603 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5604 out = stdout.getvalue()
5605 err = stderr.getvalue()
5606 return out, err
Simon Glass40c8bdd2022-03-05 20:19:12 -07005607
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005608 def testFitSplitElfBadDirective(self):
5609 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5610 if not elf.ELF_TOOLS:
5611 self.skipTest('Python elftools not available')
5612 err = self._check_bad_fit('227_fit_bad_dir.dts')
5613 self.assertIn(
5614 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5615 err)
5616
5617 def testFitSplitElfBadDirectiveConfig(self):
5618 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5619 if not elf.ELF_TOOLS:
5620 self.skipTest('Python elftools not available')
5621 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5622 self.assertEqual(
5623 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5624 err)
5625
5626
Simon Glass40c8bdd2022-03-05 20:19:12 -07005627 def testFitSplitElfMissing(self):
5628 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005629 if not elf.ELF_TOOLS:
5630 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005631 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005632 self.assertRegex(
5633 err,
5634 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005635 self.assertNotRegex(out, '.*Faked blob.*')
5636 fname = tools.get_output_filename('binman-fake/missing.elf')
5637 self.assertFalse(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005638
5639 def testFitSplitElfFaked(self):
5640 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005641 if not elf.ELF_TOOLS:
5642 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005643 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005644 self.assertRegex(
5645 err,
5646 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005647 self.assertRegex(
5648 out,
5649 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5650 fname = tools.get_output_filename('binman-fake/missing.elf')
5651 self.assertTrue(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005652
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005653 def testMkimageMissingBlob(self):
5654 """Test using mkimage to build an image"""
5655 with test_util.capture_sys_output() as (stdout, stderr):
5656 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5657 allow_fake_blobs=True)
5658 err = stderr.getvalue()
5659 self.assertRegex(
5660 err,
5661 "Image '.*' has faked external blobs and is non-functional: .*")
5662
Philippe Reynesb1c50932022-03-28 22:57:04 +02005663 def testPreLoad(self):
5664 """Test an image with a pre-load header"""
5665 entry_args = {
Simon Glassefda8ab2023-07-24 09:19:57 -06005666 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesb1c50932022-03-28 22:57:04 +02005667 }
Simon Glassefda8ab2023-07-24 09:19:57 -06005668 data = self._DoReadFileDtb(
5669 '230_pre_load.dts', entry_args=entry_args,
5670 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesb1c50932022-03-28 22:57:04 +02005671 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5672 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5673 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5674
Simon Glassefda8ab2023-07-24 09:19:57 -06005675 def testPreLoadNoKey(self):
5676 """Test an image with a pre-load heade0r with missing key"""
5677 with self.assertRaises(FileNotFoundError) as exc:
5678 self._DoReadFile('230_pre_load.dts')
5679 self.assertIn("No such file or directory: 'dev.key'",
5680 str(exc.exception))
5681
Philippe Reynesb1c50932022-03-28 22:57:04 +02005682 def testPreLoadPkcs(self):
5683 """Test an image with a pre-load header with padding pkcs"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005684 entry_args = {
5685 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5686 }
5687 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5688 entry_args=entry_args)[0]
Philippe Reynesb1c50932022-03-28 22:57:04 +02005689 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5690 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5691 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5692
5693 def testPreLoadPss(self):
5694 """Test an image with a pre-load header with padding pss"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005695 entry_args = {
5696 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5697 }
5698 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5699 entry_args=entry_args)[0]
Philippe Reynesb1c50932022-03-28 22:57:04 +02005700 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5701 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5702 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5703
5704 def testPreLoadInvalidPadding(self):
5705 """Test an image with a pre-load header with an invalid padding"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005706 entry_args = {
5707 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5708 }
Philippe Reynesb1c50932022-03-28 22:57:04 +02005709 with self.assertRaises(ValueError) as e:
Simon Glassefda8ab2023-07-24 09:19:57 -06005710 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5711 entry_args=entry_args)
Philippe Reynesb1c50932022-03-28 22:57:04 +02005712
5713 def testPreLoadInvalidSha(self):
5714 """Test an image with a pre-load header with an invalid hash"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005715 entry_args = {
5716 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5717 }
Philippe Reynesb1c50932022-03-28 22:57:04 +02005718 with self.assertRaises(ValueError) as e:
Simon Glassefda8ab2023-07-24 09:19:57 -06005719 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5720 entry_args=entry_args)
Philippe Reynesb1c50932022-03-28 22:57:04 +02005721
5722 def testPreLoadInvalidAlgo(self):
5723 """Test an image with a pre-load header with an invalid algo"""
5724 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005725 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesb1c50932022-03-28 22:57:04 +02005726
5727 def testPreLoadInvalidKey(self):
5728 """Test an image with a pre-load header with an invalid key"""
Simon Glassefda8ab2023-07-24 09:19:57 -06005729 entry_args = {
5730 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5731 }
Philippe Reynesb1c50932022-03-28 22:57:04 +02005732 with self.assertRaises(ValueError) as e:
Simon Glassefda8ab2023-07-24 09:19:57 -06005733 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5734 entry_args=entry_args)
Roger Quadros47f420a2022-02-19 20:50:04 +02005735
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005736 def _CheckSafeUniqueNames(self, *images):
5737 """Check all entries of given images for unsafe unique names"""
5738 for image in images:
5739 entries = {}
5740 image._CollectEntries(entries, {}, image)
5741 for entry in entries.values():
5742 uniq = entry.GetUniqueName()
5743
5744 # Used as part of a filename, so must not be absolute paths.
5745 self.assertFalse(os.path.isabs(uniq))
5746
5747 def testSafeUniqueNames(self):
5748 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005749 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005750
5751 orig_image = control.images['image']
5752 image_fname = tools.get_output_filename('image.bin')
5753 image = Image.FromFile(image_fname)
5754
5755 self._CheckSafeUniqueNames(orig_image, image)
5756
5757 def testSafeUniqueNamesMulti(self):
5758 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005759 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005760
5761 orig_image = control.images['image']
5762 image_fname = tools.get_output_filename('image.bin')
5763 image = Image.FromFile(image_fname)
5764
5765 self._CheckSafeUniqueNames(orig_image, image)
5766
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005767 def testReplaceCmdWithBintool(self):
5768 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005769 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005770 expected = U_BOOT_DATA + b'aa'
5771 self.assertEqual(expected, data[:len(expected)])
5772
5773 try:
5774 tmpdir, updated_fname = self._SetupImageInTmpdir()
5775 fname = os.path.join(tmpdir, 'update-testing.bin')
5776 tools.write_file(fname, b'zz')
5777 self._DoBinman('replace', '-i', updated_fname,
5778 '_testing', '-f', fname)
5779
5780 data = tools.read_file(updated_fname)
5781 expected = U_BOOT_DATA + b'zz'
5782 self.assertEqual(expected, data[:len(expected)])
5783 finally:
5784 shutil.rmtree(tmpdir)
5785
5786 def testReplaceCmdOtherWithBintool(self):
5787 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005788 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005789 expected = U_BOOT_DATA + b'aa'
5790 self.assertEqual(expected, data[:len(expected)])
5791
5792 try:
5793 tmpdir, updated_fname = self._SetupImageInTmpdir()
5794 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5795 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5796 self._DoBinman('replace', '-i', updated_fname,
5797 'u-boot', '-f', fname)
5798
5799 data = tools.read_file(updated_fname)
5800 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5801 self.assertEqual(expected, data[:len(expected)])
5802 finally:
5803 shutil.rmtree(tmpdir)
5804
Alper Nebi Yasake2ce4fb2022-03-27 18:31:46 +03005805 def testReplaceResizeNoRepackSameSize(self):
5806 """Test replacing entries with same-size data without repacking"""
5807 expected = b'x' * len(U_BOOT_DATA)
5808 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5809 self.assertEqual(expected, data)
5810
5811 path, fdtmap = state.GetFdtContents('fdtmap')
5812 self.assertIsNotNone(path)
5813 self.assertEqual(expected_fdtmap, fdtmap)
5814
5815 def testReplaceResizeNoRepackSmallerSize(self):
5816 """Test replacing entries with smaller-size data without repacking"""
5817 new_data = b'x'
5818 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5819 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5820 self.assertEqual(expected, data)
5821
5822 path, fdtmap = state.GetFdtContents('fdtmap')
5823 self.assertIsNotNone(path)
5824 self.assertEqual(expected_fdtmap, fdtmap)
5825
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005826 def testExtractFit(self):
5827 """Test extracting a FIT section"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005828 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005829 image_fname = tools.get_output_filename('image.bin')
5830
5831 fit_data = control.ReadEntry(image_fname, 'fit')
5832 fit = fdt.Fdt.FromData(fit_data)
5833 fit.Scan()
5834
5835 # Check subentry data inside the extracted fit
5836 for node_path, expected in [
5837 ('/images/kernel', U_BOOT_DATA),
5838 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5839 ('/images/scr-1', COMPRESS_DATA),
5840 ]:
5841 node = fit.GetNode(node_path)
5842 data = fit.GetProps(node)['data'].bytes
5843 self.assertEqual(expected, data)
5844
5845 def testExtractFitSubentries(self):
5846 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005847 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005848 image_fname = tools.get_output_filename('image.bin')
5849
5850 for entry_path, expected in [
5851 ('fit/kernel', U_BOOT_DATA),
5852 ('fit/kernel/u-boot', U_BOOT_DATA),
5853 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5854 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5855 ('fit/scr-1', COMPRESS_DATA),
5856 ('fit/scr-1/blob', COMPRESS_DATA),
5857 ]:
5858 data = control.ReadEntry(image_fname, entry_path)
5859 self.assertEqual(expected, data)
5860
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005861 def testReplaceFitSubentryLeafSameSize(self):
5862 """Test replacing a FIT leaf subentry with same-size data"""
5863 new_data = b'x' * len(U_BOOT_DATA)
5864 data, expected_fdtmap, _ = self._RunReplaceCmd(
5865 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005866 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005867 self.assertEqual(new_data, data)
5868
5869 path, fdtmap = state.GetFdtContents('fdtmap')
5870 self.assertIsNotNone(path)
5871 self.assertEqual(expected_fdtmap, fdtmap)
5872
5873 def testReplaceFitSubentryLeafBiggerSize(self):
5874 """Test replacing a FIT leaf subentry with bigger-size data"""
5875 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5876 data, expected_fdtmap, _ = self._RunReplaceCmd(
5877 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005878 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005879 self.assertEqual(new_data, data)
5880
5881 # Will be repacked, so fdtmap must change
5882 path, fdtmap = state.GetFdtContents('fdtmap')
5883 self.assertIsNotNone(path)
5884 self.assertNotEqual(expected_fdtmap, fdtmap)
5885
5886 def testReplaceFitSubentryLeafSmallerSize(self):
5887 """Test replacing a FIT leaf subentry with smaller-size data"""
5888 new_data = b'x'
5889 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5890 data, expected_fdtmap, _ = self._RunReplaceCmd(
5891 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005892 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005893 self.assertEqual(expected, data)
5894
5895 path, fdtmap = state.GetFdtContents('fdtmap')
5896 self.assertIsNotNone(path)
5897 self.assertEqual(expected_fdtmap, fdtmap)
5898
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005899 def testReplaceSectionSimple(self):
Simon Glass7caa3722023-03-02 17:02:44 -07005900 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005901 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass7caa3722023-03-02 17:02:44 -07005902 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5903 new_data, dts='241_replace_section_simple.dts')
5904 self.assertEqual(new_data, data)
5905
5906 entries = image.GetEntries()
5907 self.assertIn('section', entries)
5908 entry = entries['section']
5909 self.assertEqual(len(new_data), entry.size)
5910
5911 def testReplaceSectionLarger(self):
5912 """Test replacing a simple section with larger data"""
5913 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5914 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5915 new_data, dts='241_replace_section_simple.dts')
5916 self.assertEqual(new_data, data)
5917
5918 entries = image.GetEntries()
5919 self.assertIn('section', entries)
5920 entry = entries['section']
5921 self.assertEqual(len(new_data), entry.size)
5922 fentry = entries['fdtmap']
5923 self.assertEqual(entry.offset + entry.size, fentry.offset)
5924
5925 def testReplaceSectionSmaller(self):
5926 """Test replacing a simple section with smaller data"""
5927 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5928 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5929 new_data, dts='241_replace_section_simple.dts')
5930 self.assertEqual(new_data, data)
5931
5932 # The new size is the same as the old, just with a pad byte at the end
5933 entries = image.GetEntries()
5934 self.assertIn('section', entries)
5935 entry = entries['section']
5936 self.assertEqual(len(new_data), entry.size)
5937
5938 def testReplaceSectionSmallerAllow(self):
5939 """Test failing to replace a simple section with smaller data"""
5940 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5941 try:
5942 state.SetAllowEntryContraction(True)
5943 with self.assertRaises(ValueError) as exc:
5944 self._RunReplaceCmd('section', new_data,
5945 dts='241_replace_section_simple.dts')
5946 finally:
5947 state.SetAllowEntryContraction(False)
5948
5949 # Since we have no information about the position of things within the
5950 # section, we cannot adjust the position of /section-u-boot so it ends
5951 # up outside the section
Simon Glass73593e42022-08-13 11:40:46 -06005952 self.assertIn(
Simon Glass7caa3722023-03-02 17:02:44 -07005953 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5954 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glass73593e42022-08-13 11:40:46 -06005955 str(exc.exception))
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005956
Simon Glassdfe1db42022-08-13 11:40:48 -06005957 def testMkimageImagename(self):
5958 """Test using mkimage with -n holding the data too"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005959 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005960 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glassdfe1db42022-08-13 11:40:48 -06005961
5962 # Check that the data appears in the file somewhere
5963 self.assertIn(U_BOOT_SPL_DATA, data)
5964
Simon Glassf3543e62022-09-06 20:26:52 -06005965 # Get struct legacy_img_hdr -> ih_name
Simon Glassdfe1db42022-08-13 11:40:48 -06005966 name = data[0x20:0x40]
5967
5968 # Build the filename that we expect to be placed in there, by virtue of
5969 # the -n paraameter
5970 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5971
5972 # Check that the image name is set to the temporary filename used
5973 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5974
Simon Glass9db9e932022-08-13 11:40:49 -06005975 def testMkimageImage(self):
5976 """Test using mkimage with -n holding the data too"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005977 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005978 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06005979
5980 # Check that the data appears in the file somewhere
5981 self.assertIn(U_BOOT_SPL_DATA, data)
5982
Simon Glassf3543e62022-09-06 20:26:52 -06005983 # Get struct legacy_img_hdr -> ih_name
Simon Glass9db9e932022-08-13 11:40:49 -06005984 name = data[0x20:0x40]
5985
5986 # Build the filename that we expect to be placed in there, by virtue of
5987 # the -n paraameter
5988 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5989
5990 # Check that the image name is set to the temporary filename used
5991 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5992
5993 # Check the corect data is in the imagename file
5994 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5995
5996 def testMkimageImageNoContent(self):
5997 """Test using mkimage with -n and no data"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005998 self._SetupSplElf()
Simon Glass9db9e932022-08-13 11:40:49 -06005999 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006000 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06006001 self.assertIn('Could not complete processing of contents',
6002 str(exc.exception))
6003
6004 def testMkimageImageBad(self):
6005 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006006 self._SetupSplElf()
Simon Glass9db9e932022-08-13 11:40:49 -06006007 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006008 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06006009 self.assertIn('Cannot use both imagename node and data-to-imagename',
6010 str(exc.exception))
6011
Simon Glassd626e822022-08-13 11:40:50 -06006012 def testCollectionOther(self):
6013 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006014 data = self._DoReadFile('246_collection_other.dts')
Simon Glassd626e822022-08-13 11:40:50 -06006015 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6016 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6017 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6018 data)
6019
6020 def testMkimageCollection(self):
6021 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006022 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006023 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassd626e822022-08-13 11:40:50 -06006024 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6025 self.assertEqual(expect, data[:len(expect)])
6026
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02006027 def testCompressDtbPrependInvalid(self):
6028 """Test that invalid header is detected"""
6029 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006030 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02006031 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6032 "'u-boot-dtb': 'invalid'", str(e.exception))
6033
6034 def testCompressDtbPrependLength(self):
6035 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006036 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02006037 image = control.images['image']
6038 entries = image.GetEntries()
6039 self.assertIn('u-boot-dtb', entries)
6040 u_boot_dtb = entries['u-boot-dtb']
6041 self.assertIn('fdtmap', entries)
6042 fdtmap = entries['fdtmap']
6043
6044 image_fname = tools.get_output_filename('image.bin')
6045 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6046 dtb = fdt.Fdt.FromData(orig)
6047 dtb.Scan()
6048 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6049 expected = {
6050 'u-boot:size': len(U_BOOT_DATA),
6051 'u-boot-dtb:uncomp-size': len(orig),
6052 'u-boot-dtb:size': u_boot_dtb.size,
6053 'fdtmap:size': fdtmap.size,
6054 'size': len(data),
6055 }
6056 self.assertEqual(expected, props)
6057
6058 # Check implementation
6059 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6060 rest = data[len(U_BOOT_DATA):]
6061 comp_data_len = struct.unpack('<I', rest[:4])[0]
6062 comp_data = rest[4:4 + comp_data_len]
6063 orig2 = self._decompress(comp_data)
6064 self.assertEqual(orig, orig2)
6065
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02006066 def testInvalidCompress(self):
6067 """Test that invalid compress algorithm is detected"""
6068 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006069 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02006070 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6071
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02006072 def testCompUtilCompressions(self):
6073 """Test compression algorithms"""
6074 for bintool in self.comp_bintools.values():
6075 self._CheckBintool(bintool)
6076 data = bintool.compress(COMPRESS_DATA)
6077 self.assertNotEqual(COMPRESS_DATA, data)
6078 orig = bintool.decompress(data)
6079 self.assertEquals(COMPRESS_DATA, orig)
6080
6081 def testCompUtilVersions(self):
6082 """Test tool version of compression algorithms"""
6083 for bintool in self.comp_bintools.values():
6084 self._CheckBintool(bintool)
6085 version = bintool.version()
6086 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6087
6088 def testCompUtilPadding(self):
6089 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006090 # Skip zstd because it doesn't support padding
6091 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02006092 self._CheckBintool(bintool)
6093 data = bintool.compress(COMPRESS_DATA)
6094 self.assertNotEqual(COMPRESS_DATA, data)
6095 data += tools.get_bytes(0, 64)
6096 orig = bintool.decompress(data)
6097 self.assertEquals(COMPRESS_DATA, orig)
6098
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006099 def testCompressDtbZstd(self):
6100 """Test that zstd compress of device-tree files failed"""
6101 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006102 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006103 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6104 "requires a length header", str(e.exception))
6105
Quentin Schulz4d91df02022-09-02 15:10:48 +02006106 def testMkimageMultipleDataFiles(self):
6107 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006108 self._SetupSplElf()
6109 self._SetupTplElf()
Quentin Schulz4d91df02022-09-02 15:10:48 +02006110 data = self._DoReadFile('252_mkimage_mult_data.dts')
6111 # Size of files are packed in their 4B big-endian format
6112 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6113 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6114 # Size info is always followed by a 4B zero value.
6115 expect += tools.get_bytes(0, 4)
6116 expect += U_BOOT_TPL_DATA
6117 # All but last files are 4B-aligned
6118 align_pad = len(U_BOOT_TPL_DATA) % 4
6119 if align_pad:
6120 expect += tools.get_bytes(0, align_pad)
6121 expect += U_BOOT_SPL_DATA
6122 self.assertEqual(expect, data[-len(expect):])
6123
Marek Vasutfadad3a2023-07-18 07:23:58 -06006124 def testMkimageMultipleExpanded(self):
6125 """Test passing multiple files to mkimage in a mkimage entry"""
6126 self._SetupSplElf()
6127 self._SetupTplElf()
6128 entry_args = {
6129 'spl-bss-pad': 'y',
6130 'spl-dtb': 'y',
6131 }
6132 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6133 use_expanded=True, entry_args=entry_args)[0]
6134 pad_len = 10
6135 tpl_expect = U_BOOT_TPL_DATA
6136 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6137 spl_expect += U_BOOT_SPL_DTB_DATA
6138
6139 content = data[0x40:]
6140 lens = struct.unpack('>III', content[:12])
6141
6142 # Size of files are packed in their 4B big-endian format
6143 # Size info is always followed by a 4B zero value.
6144 self.assertEqual(len(tpl_expect), lens[0])
6145 self.assertEqual(len(spl_expect), lens[1])
6146 self.assertEqual(0, lens[2])
6147
6148 rest = content[12:]
6149 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6150
6151 rest = rest[len(tpl_expect):]
6152 align_pad = len(tpl_expect) % 4
6153 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6154 rest = rest[align_pad:]
6155 self.assertEqual(spl_expect, rest)
6156
Quentin Schulz4d91df02022-09-02 15:10:48 +02006157 def testMkimageMultipleNoContent(self):
6158 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006159 self._SetupSplElf()
Quentin Schulz4d91df02022-09-02 15:10:48 +02006160 with self.assertRaises(ValueError) as exc:
6161 self._DoReadFile('253_mkimage_mult_no_content.dts')
6162 self.assertIn('Could not complete processing of contents',
6163 str(exc.exception))
6164
Quentin Schulz6cc29dc2022-09-02 15:10:49 +02006165 def testMkimageFilename(self):
6166 """Test using mkimage to build a binary with a filename"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006167 self._SetupSplElf()
Quentin Schulz6cc29dc2022-09-02 15:10:49 +02006168 retcode = self._DoTestFile('254_mkimage_filename.dts')
6169 self.assertEqual(0, retcode)
6170 fname = tools.get_output_filename('mkimage-test.bin')
6171 self.assertTrue(os.path.exists(fname))
6172
Simon Glass6ad24522022-02-28 07:16:54 -07006173 def testVpl(self):
6174 """Test that an image with VPL and its device tree can be created"""
6175 # ELF file with a '__bss_size' symbol
6176 self._SetupVplElf()
6177 data = self._DoReadFile('255_u_boot_vpl.dts')
6178 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6179
6180 def testVplNoDtb(self):
6181 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6182 self._SetupVplElf()
6183 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6184 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6185 data[:len(U_BOOT_VPL_NODTB_DATA)])
6186
6187 def testExpandedVpl(self):
6188 """Test that an expanded entry type is selected for TPL when needed"""
6189 self._SetupVplElf()
6190
6191 entry_args = {
6192 'vpl-bss-pad': 'y',
6193 'vpl-dtb': 'y',
6194 }
6195 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6196 entry_args=entry_args)
6197 image = control.images['image']
6198 entries = image.GetEntries()
6199 self.assertEqual(1, len(entries))
6200
6201 # We only have u-boot-vpl, which be expanded
6202 self.assertIn('u-boot-vpl', entries)
6203 entry = entries['u-boot-vpl']
6204 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6205 subent = entry.GetEntries()
6206 self.assertEqual(3, len(subent))
6207 self.assertIn('u-boot-vpl-nodtb', subent)
6208 self.assertIn('u-boot-vpl-bss-pad', subent)
6209 self.assertIn('u-boot-vpl-dtb', subent)
6210
6211 def testVplBssPadMissing(self):
6212 """Test that a missing symbol is detected"""
6213 self._SetupVplElf('u_boot_ucode_ptr')
6214 with self.assertRaises(ValueError) as e:
6215 self._DoReadFile('258_vpl_bss_pad.dts')
6216 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6217 str(e.exception))
6218
Neha Malcom Francis3545e852022-10-17 16:36:25 +05306219 def testSymlink(self):
Andrew Davis15432ea2023-07-22 00:14:44 +05306220 """Test that image files can be symlinked"""
Neha Malcom Francis3545e852022-10-17 16:36:25 +05306221 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6222 self.assertEqual(0, retcode)
6223 image = control.images['test_image']
6224 fname = tools.get_output_filename('test_image.bin')
6225 sname = tools.get_output_filename('symlink_to_test.bin')
6226 self.assertTrue(os.path.islink(sname))
6227 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03006228
Andrew Davis15432ea2023-07-22 00:14:44 +05306229 def testSymlinkOverwrite(self):
6230 """Test that symlinked images can be overwritten"""
6231 testdir = TestFunctional._MakeInputDir('symlinktest')
6232 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6233 # build the same image again in the same directory so that existing symlink is present
6234 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6235 fname = tools.get_output_filename('test_image.bin')
6236 sname = tools.get_output_filename('symlink_to_test.bin')
6237 self.assertTrue(os.path.islink(sname))
6238 self.assertEqual(os.readlink(sname), fname)
6239
Simon Glassd2afb9e2022-10-20 18:22:47 -06006240 def testSymbolsElf(self):
6241 """Test binman can assign symbols embedded in an ELF file"""
6242 if not elf.ELF_TOOLS:
6243 self.skipTest('Python elftools not available')
6244 self._SetupTplElf('u_boot_binman_syms')
6245 self._SetupVplElf('u_boot_binman_syms')
6246 self._SetupSplElf('u_boot_binman_syms')
6247 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6248 image_fname = tools.get_output_filename('image.bin')
6249
6250 image = control.images['image']
6251 entries = image.GetEntries()
6252
6253 for entry in entries.values():
6254 # No symbols in u-boot and it has faked contents anyway
6255 if entry.name == 'u-boot':
6256 continue
6257 edata = data[entry.image_pos:entry.image_pos + entry.size]
6258 efname = tools.get_output_filename(f'edata-{entry.name}')
6259 tools.write_file(efname, edata)
6260
6261 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6262 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6263 for name, sym in syms.items():
6264 msg = 'test'
6265 val = elf.GetSymbolValue(sym, edata, msg)
6266 entry_m = re_name.match(name)
6267 if entry_m:
6268 ename, prop = entry_m.group(1), entry_m.group(3)
6269 entry, entry_name, prop_name = image.LookupEntry(entries,
6270 name, msg)
6271 if prop_name == 'offset':
6272 expect_val = entry.offset
6273 elif prop_name == 'image_pos':
6274 expect_val = entry.image_pos
6275 elif prop_name == 'size':
6276 expect_val = entry.size
6277 self.assertEqual(expect_val, val)
6278
6279 def testSymbolsElfBad(self):
6280 """Check error when trying to write symbols without the elftools lib"""
6281 if not elf.ELF_TOOLS:
6282 self.skipTest('Python elftools not available')
6283 self._SetupTplElf('u_boot_binman_syms')
6284 self._SetupVplElf('u_boot_binman_syms')
6285 self._SetupSplElf('u_boot_binman_syms')
6286 try:
6287 elf.ELF_TOOLS = False
6288 with self.assertRaises(ValueError) as exc:
6289 self._DoReadFileDtb('260_symbols_elf.dts')
6290 finally:
6291 elf.ELF_TOOLS = True
6292 self.assertIn(
6293 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6294 'Cannot write symbols to an ELF file without Python elftools',
6295 str(exc.exception))
6296
Simon Glassefddab62023-01-07 14:07:08 -07006297 def testSectionFilename(self):
6298 """Check writing of section contents to a file"""
6299 data = self._DoReadFile('261_section_fname.dts')
6300 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6301 tools.get_bytes(ord('!'), 7) +
6302 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6303 self.assertEqual(expected, data)
6304
6305 sect_fname = tools.get_output_filename('outfile.bin')
6306 self.assertTrue(os.path.exists(sect_fname))
6307 sect_data = tools.read_file(sect_fname)
6308 self.assertEqual(U_BOOT_DATA, sect_data)
6309
Simon Glassc8c9f312023-01-07 14:07:12 -07006310 def testAbsent(self):
6311 """Check handling of absent entries"""
6312 data = self._DoReadFile('262_absent.dts')
6313 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6314
Simon Glass2f80c5e2023-01-07 14:07:14 -07006315 def testPackTeeOsOptional(self):
6316 """Test that an image with an optional TEE binary can be created"""
6317 entry_args = {
6318 'tee-os-path': 'tee.elf',
6319 }
6320 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6321 entry_args=entry_args)[0]
6322 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6323
6324 def checkFitTee(self, dts, tee_fname):
6325 """Check that a tee-os entry works and returns data
6326
6327 Args:
6328 dts (str): Device tree filename to use
6329 tee_fname (str): filename containing tee-os
6330
6331 Returns:
6332 bytes: Image contents
6333 """
6334 if not elf.ELF_TOOLS:
6335 self.skipTest('Python elftools not available')
6336 entry_args = {
6337 'of-list': 'test-fdt1 test-fdt2',
6338 'default-dt': 'test-fdt2',
6339 'tee-os-path': tee_fname,
6340 }
6341 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6342 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6343 extra_indirs=[test_subdir])[0]
6344 return data
6345
6346 def testFitTeeOsOptionalFit(self):
6347 """Test an image with a FIT with an optional OP-TEE binary"""
6348 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6349
6350 # There should be only one node, holding the data set up in SetUpClass()
6351 # for tee.bin
6352 dtb = fdt.Fdt.FromData(data)
6353 dtb.Scan()
6354 node = dtb.GetNode('/images/tee-1')
6355 self.assertEqual(TEE_ADDR,
6356 fdt_util.fdt32_to_cpu(node.props['load'].value))
6357 self.assertEqual(TEE_ADDR,
6358 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6359 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6360
6361 def testFitTeeOsOptionalFitBad(self):
6362 """Test an image with a FIT with an optional OP-TEE binary"""
6363 with self.assertRaises(ValueError) as exc:
6364 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6365 self.assertIn(
6366 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6367 str(exc.exception))
6368
6369 def testFitTeeOsBad(self):
6370 """Test an OP-TEE binary with wrong formats"""
6371 self.make_tee_bin('tee.bad1', 123)
6372 with self.assertRaises(ValueError) as exc:
6373 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6374 self.assertIn(
6375 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6376 str(exc.exception))
6377
6378 self.make_tee_bin('tee.bad2', 0, b'extra data')
6379 with self.assertRaises(ValueError) as exc:
6380 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6381 self.assertIn(
6382 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6383 str(exc.exception))
6384
Simon Glass67a05012023-01-07 14:07:15 -07006385 def testExtblobOptional(self):
6386 """Test an image with an external blob that is optional"""
6387 with test_util.capture_sys_output() as (stdout, stderr):
6388 data = self._DoReadFile('266_blob_ext_opt.dts')
6389 self.assertEqual(REFCODE_DATA, data)
6390 err = stderr.getvalue()
6391 self.assertRegex(
6392 err,
Jonas Karlman05dec372023-07-18 20:34:34 +00006393 "Image '.*' is missing optional external blobs but is still functional: missing")
Simon Glass67a05012023-01-07 14:07:15 -07006394
Simon Glass0b079fc2023-01-11 16:10:12 -07006395 def testSectionInner(self):
6396 """Test an inner section with a size"""
6397 data = self._DoReadFile('267_section_inner.dts')
6398 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6399 self.assertEqual(expected, data)
6400
Simon Glass62ef2f72023-01-11 16:10:14 -07006401 def testNull(self):
6402 """Test an image with a null entry"""
6403 data = self._DoReadFile('268_null.dts')
6404 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6405
Simon Glass9766f692023-01-11 16:10:16 -07006406 def testOverlap(self):
6407 """Test an image with a overlapping entry"""
6408 data = self._DoReadFile('269_overlap.dts')
6409 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6410
6411 image = control.images['image']
6412 entries = image.GetEntries()
6413
6414 self.assertIn('inset', entries)
6415 inset = entries['inset']
6416 self.assertEqual(1, inset.offset);
6417 self.assertEqual(1, inset.image_pos);
6418 self.assertEqual(2, inset.size);
6419
6420 def testOverlapNull(self):
6421 """Test an image with a null overlap"""
6422 data = self._DoReadFile('270_overlap_null.dts')
6423 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6424
6425 # Check the FMAP
6426 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6427 self.assertEqual(4, fhdr.nareas)
6428 fiter = iter(fentries)
6429
6430 fentry = next(fiter)
6431 self.assertEqual(b'SECTION', fentry.name)
6432 self.assertEqual(0, fentry.offset)
6433 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6434 self.assertEqual(0, fentry.flags)
6435
6436 fentry = next(fiter)
6437 self.assertEqual(b'U_BOOT', fentry.name)
6438 self.assertEqual(0, fentry.offset)
6439 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6440 self.assertEqual(0, fentry.flags)
6441
6442 # Make sure that the NULL entry appears in the FMAP
6443 fentry = next(fiter)
6444 self.assertEqual(b'NULL', fentry.name)
6445 self.assertEqual(1, fentry.offset)
6446 self.assertEqual(2, fentry.size)
6447 self.assertEqual(0, fentry.flags)
6448
6449 fentry = next(fiter)
6450 self.assertEqual(b'FMAP', fentry.name)
6451 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6452
6453 def testOverlapBad(self):
6454 """Test an image with a bad overlapping entry"""
6455 with self.assertRaises(ValueError) as exc:
6456 self._DoReadFile('271_overlap_bad.dts')
6457 self.assertIn(
6458 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6459 str(exc.exception))
6460
6461 def testOverlapNoOffset(self):
6462 """Test an image with a bad overlapping entry"""
6463 with self.assertRaises(ValueError) as exc:
6464 self._DoReadFile('272_overlap_no_size.dts')
6465 self.assertIn(
6466 "Node '/binman/inset': 'fill' entry is missing properties: size",
6467 str(exc.exception))
6468
Simon Glassc1157862023-01-11 16:10:17 -07006469 def testBlobSymbol(self):
6470 """Test a blob with symbols read from an ELF file"""
6471 elf_fname = self.ElfTestFile('blob_syms')
6472 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6473 TestFunctional._MakeInputFile('blob_syms.bin',
6474 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6475
6476 data = self._DoReadFile('273_blob_symbol.dts')
6477
6478 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6479 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6480 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6481 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6482 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6483
6484 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6485 expected = sym_values
6486 self.assertEqual(expected, data[:len(expected)])
6487
Simon Glass571bc4e2023-01-11 16:10:19 -07006488 def testOffsetFromElf(self):
6489 """Test a blob with symbols read from an ELF file"""
6490 elf_fname = self.ElfTestFile('blob_syms')
6491 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6492 TestFunctional._MakeInputFile('blob_syms.bin',
6493 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6494
6495 data = self._DoReadFile('274_offset_from_elf.dts')
6496
6497 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6498 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6499
6500 image = control.images['image']
6501 entries = image.GetEntries()
6502
6503 self.assertIn('inset', entries)
6504 inset = entries['inset']
6505
6506 self.assertEqual(base + 4, inset.offset);
6507 self.assertEqual(base + 4, inset.image_pos);
6508 self.assertEqual(4, inset.size);
6509
6510 self.assertIn('inset2', entries)
6511 inset = entries['inset2']
6512 self.assertEqual(base + 8, inset.offset);
6513 self.assertEqual(base + 8, inset.image_pos);
6514 self.assertEqual(4, inset.size);
6515
Jonas Karlman9b2fd2d2023-01-21 19:01:39 +00006516 def testFitAlign(self):
6517 """Test an image with an FIT with aligned external data"""
6518 data = self._DoReadFile('275_fit_align.dts')
6519 self.assertEqual(4096, len(data))
6520
6521 dtb = fdt.Fdt.FromData(data)
6522 dtb.Scan()
6523
6524 props = self._GetPropTree(dtb, ['data-position'])
6525 expected = {
6526 'u-boot:data-position': 1024,
6527 'fdt-1:data-position': 2048,
6528 'fdt-2:data-position': 3072,
6529 }
6530 self.assertEqual(expected, props)
6531
Jonas Karlmanf584d442023-01-21 19:02:12 +00006532 def testFitFirmwareLoadables(self):
6533 """Test an image with an FIT that use fit,firmware"""
6534 if not elf.ELF_TOOLS:
6535 self.skipTest('Python elftools not available')
6536 entry_args = {
6537 'of-list': 'test-fdt1',
6538 'default-dt': 'test-fdt1',
6539 'atf-bl31-path': 'bl31.elf',
6540 'tee-os-path': 'missing.bin',
6541 }
6542 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass7c4027a2023-02-23 18:18:01 -07006543 with test_util.capture_sys_output() as (stdout, stderr):
6544 data = self._DoReadFileDtb(
6545 '276_fit_firmware_loadables.dts',
6546 entry_args=entry_args,
6547 extra_indirs=[test_subdir])[0]
Jonas Karlmanf584d442023-01-21 19:02:12 +00006548
6549 dtb = fdt.Fdt.FromData(data)
6550 dtb.Scan()
6551
6552 node = dtb.GetNode('/configurations/conf-uboot-1')
6553 self.assertEqual('u-boot', node.props['firmware'].value)
6554 self.assertEqual(['atf-1', 'atf-2'],
6555 fdt_util.GetStringList(node, 'loadables'))
6556
6557 node = dtb.GetNode('/configurations/conf-atf-1')
6558 self.assertEqual('atf-1', node.props['firmware'].value)
6559 self.assertEqual(['u-boot', 'atf-2'],
6560 fdt_util.GetStringList(node, 'loadables'))
6561
6562 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6563 self.assertEqual('u-boot', node.props['firmware'].value)
6564 self.assertEqual(['atf-1', 'atf-2'],
6565 fdt_util.GetStringList(node, 'loadables'))
6566
6567 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6568 self.assertEqual('atf-1', node.props['firmware'].value)
6569 self.assertEqual(['u-boot', 'atf-2'],
6570 fdt_util.GetStringList(node, 'loadables'))
6571
6572 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6573 self.assertEqual('atf-1', node.props['firmware'].value)
6574 self.assertEqual(['u-boot', 'atf-2'],
6575 fdt_util.GetStringList(node, 'loadables'))
6576
Simon Glassfe7e9242023-02-22 12:14:49 -07006577 def testTooldir(self):
6578 """Test that we can specify the tooldir"""
6579 with test_util.capture_sys_output() as (stdout, stderr):
6580 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6581 'tool', '-l'))
6582 self.assertEqual('fred', bintool.Bintool.tooldir)
6583
6584 # Check that the toolpath is updated correctly
6585 self.assertEqual(['fred'], tools.tool_search_paths)
6586
6587 # Try with a few toolpaths; the tooldir should be at the end
6588 with test_util.capture_sys_output() as (stdout, stderr):
6589 self.assertEqual(0, self._DoBinman(
6590 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6591 'tool', '-l'))
6592 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6593
Simon Glass7caa3722023-03-02 17:02:44 -07006594 def testReplaceSectionEntry(self):
6595 """Test replacing an entry in a section"""
6596 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6597 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6598 expect_data, dts='241_replace_section_simple.dts')
6599 self.assertEqual(expect_data, entry_data)
6600
6601 entries = image.GetEntries()
6602 self.assertIn('section', entries)
6603 section = entries['section']
6604
6605 sect_entries = section.GetEntries()
6606 self.assertIn('blob', sect_entries)
6607 entry = sect_entries['blob']
6608 self.assertEqual(len(expect_data), entry.size)
6609
6610 fname = tools.get_output_filename('image-updated.bin')
6611 data = tools.read_file(fname)
6612
6613 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6614 self.assertEqual(expect_data, new_blob_data)
6615
6616 self.assertEqual(U_BOOT_DATA,
6617 data[entry.image_pos + len(expect_data):]
6618 [:len(U_BOOT_DATA)])
6619
6620 def testReplaceSectionDeep(self):
6621 """Test replacing an entry in two levels of sections"""
6622 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6623 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6624 'section/section/blob', expect_data,
6625 dts='278_replace_section_deep.dts')
6626 self.assertEqual(expect_data, entry_data)
6627
6628 entries = image.GetEntries()
6629 self.assertIn('section', entries)
6630 section = entries['section']
6631
6632 subentries = section.GetEntries()
6633 self.assertIn('section', subentries)
6634 section = subentries['section']
6635
6636 sect_entries = section.GetEntries()
6637 self.assertIn('blob', sect_entries)
6638 entry = sect_entries['blob']
6639 self.assertEqual(len(expect_data), entry.size)
6640
6641 fname = tools.get_output_filename('image-updated.bin')
6642 data = tools.read_file(fname)
6643
6644 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6645 self.assertEqual(expect_data, new_blob_data)
6646
6647 self.assertEqual(U_BOOT_DATA,
6648 data[entry.image_pos + len(expect_data):]
6649 [:len(U_BOOT_DATA)])
6650
6651 def testReplaceFitSibling(self):
6652 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006653 self._SetupSplElf()
Simon Glass7caa3722023-03-02 17:02:44 -07006654 fname = TestFunctional._MakeInputFile('once', b'available once')
6655 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6656 os.remove(fname)
6657
6658 try:
6659 tmpdir, updated_fname = self._SetupImageInTmpdir()
6660
6661 fname = os.path.join(tmpdir, 'update-blob')
6662 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6663 tools.write_file(fname, expected)
6664
6665 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6666 data = tools.read_file(updated_fname)
6667 start = len(U_BOOT_DTB_DATA)
6668 self.assertEqual(expected, data[start:start + len(expected)])
6669 map_fname = os.path.join(tmpdir, 'image-updated.map')
6670 self.assertFalse(os.path.exists(map_fname))
6671 finally:
6672 shutil.rmtree(tmpdir)
6673
Simon Glass953d4172023-03-02 17:02:45 -07006674 def testX509Cert(self):
6675 """Test creating an X509 certificate"""
6676 keyfile = self.TestFile('key.key')
6677 entry_args = {
6678 'keyfile': keyfile,
6679 }
6680 data = self._DoReadFileDtb('279_x509_cert.dts',
6681 entry_args=entry_args)[0]
6682 cert = data[:-4]
6683 self.assertEqual(U_BOOT_DATA, data[-4:])
6684
6685 # TODO: verify the signature
6686
6687 def testX509CertMissing(self):
6688 """Test that binman still produces an image if openssl is missing"""
6689 keyfile = self.TestFile('key.key')
6690 entry_args = {
6691 'keyfile': 'keyfile',
6692 }
6693 with test_util.capture_sys_output() as (_, stderr):
6694 self._DoTestFile('279_x509_cert.dts',
6695 force_missing_bintools='openssl',
6696 entry_args=entry_args)
6697 err = stderr.getvalue()
6698 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6699
Jonas Karlman05b978b2023-02-25 19:01:33 +00006700 def testPackRockchipTpl(self):
6701 """Test that an image with a Rockchip TPL binary can be created"""
Simon Glass176f1f62023-07-24 09:19:58 -06006702 data = self._DoReadFile('291_rockchip_tpl.dts')
Jonas Karlman05b978b2023-02-25 19:01:33 +00006703 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6704
Jonas Karlman40389c22023-02-25 19:01:35 +00006705 def testMkimageMissingBlobMultiple(self):
6706 """Test missing blob with mkimage entry and multiple-data-files"""
6707 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass176f1f62023-07-24 09:19:58 -06006708 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=True)
Jonas Karlman40389c22023-02-25 19:01:35 +00006709 err = stderr.getvalue()
6710 self.assertIn("is missing external blobs and is non-functional", err)
6711
6712 with self.assertRaises(ValueError) as e:
Simon Glass176f1f62023-07-24 09:19:58 -06006713 self._DoTestFile('292_mkimage_missing_multiple.dts', allow_missing=False)
Jonas Karlman40389c22023-02-25 19:01:35 +00006714 self.assertIn("not found in input path", str(e.exception))
6715
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +00006716 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6717 """Prepare sign environment
6718
6719 Create private and public keys, add pubkey into dtb.
6720
6721 Returns:
6722 Tuple:
6723 FIT container
6724 Image name
6725 Private key
6726 DTB
6727 """
Marek Vasutfadad3a2023-07-18 07:23:58 -06006728 self._SetupSplElf()
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +00006729 data = self._DoReadFileRealDtb(dts)
6730 updated_fname = tools.get_output_filename('image-updated.bin')
6731 tools.write_file(updated_fname, data)
6732 dtb = tools.get_output_filename('source.dtb')
6733 private_key = tools.get_output_filename('test_key.key')
6734 public_key = tools.get_output_filename('test_key.crt')
6735 fit = tools.get_output_filename('fit.fit')
6736 key_dir = tools.get_output_dir()
6737
6738 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6739 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6740 private_key, '-out', public_key)
6741 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6742 '-n', 'test_key', '-r', 'conf', dtb)
6743
6744 return fit, updated_fname, private_key, dtb
6745
6746 def testSignSimple(self):
6747 """Test that a FIT container can be signed in image"""
6748 is_signed = False
6749 fit, fname, private_key, dtb = self._PrepareSignEnv()
6750
6751 # do sign with private key
6752 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6753 ['fit'])
6754 is_signed = self._CheckSign(fit, dtb)
6755
6756 self.assertEqual(is_signed, True)
6757
6758 def testSignExactFIT(self):
6759 """Test that a FIT container can be signed and replaced in image"""
6760 is_signed = False
6761 fit, fname, private_key, dtb = self._PrepareSignEnv()
6762
6763 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6764 args = []
6765 if self.toolpath:
6766 for path in self.toolpath:
6767 args += ['--toolpath', path]
6768
6769 # do sign with private key
6770 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6771 'sha256,rsa4096', '-f', fit, 'fit')
6772 is_signed = self._CheckSign(fit, dtb)
6773
6774 self.assertEqual(is_signed, True)
6775
6776 def testSignNonFit(self):
6777 """Test a non-FIT entry cannot be signed"""
6778 is_signed = False
6779 fit, fname, private_key, _ = self._PrepareSignEnv(
6780 '281_sign_non_fit.dts')
6781
6782 # do sign with private key
6783 with self.assertRaises(ValueError) as e:
6784 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6785 'sha256,rsa4096', '-f', fit, 'u-boot')
6786 self.assertIn(
6787 "Node '/u-boot': Updating signatures is not supported with this entry type",
6788 str(e.exception))
6789
6790 def testSignMissingMkimage(self):
6791 """Test that FIT signing handles a missing mkimage tool"""
6792 fit, fname, private_key, _ = self._PrepareSignEnv()
6793
6794 # try to sign with a missing mkimage tool
6795 bintool.Bintool.set_missing_list(['mkimage'])
6796 with self.assertRaises(ValueError) as e:
6797 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6798 ['fit'])
6799 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6800
Simon Glass4649bea2023-07-18 07:23:54 -06006801 def testSymbolNoWrite(self):
6802 """Test disabling of symbol writing"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006803 self._SetupSplElf()
Simon Glass4649bea2023-07-18 07:23:54 -06006804 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6805 no_write_symbols=True)
6806
6807 def testSymbolNoWriteExpanded(self):
6808 """Test disabling of symbol writing in expanded entries"""
6809 entry_args = {
6810 'spl-dtb': '1',
6811 }
6812 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6813 U_BOOT_SPL_DTB_DATA, 0x38,
6814 entry_args=entry_args, use_expanded=True,
6815 no_write_symbols=True)
6816
Marek Vasutfadad3a2023-07-18 07:23:58 -06006817 def testMkimageSpecial(self):
6818 """Test mkimage ignores special hash-1 node"""
6819 data = self._DoReadFile('283_mkimage_special.dts')
6820
6821 # Just check that the data appears in the file somewhere
6822 self.assertIn(U_BOOT_DATA, data)
6823
Simon Glassb1e40ee2023-07-18 07:23:59 -06006824 def testFitFdtList(self):
6825 """Test an image with an FIT with the fit,fdt-list-val option"""
6826 entry_args = {
6827 'default-dt': 'test-fdt2',
6828 }
6829 data = self._DoReadFileDtb(
6830 '284_fit_fdt_list.dts',
6831 entry_args=entry_args,
6832 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6833 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6834 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6835
Simon Glasse1ad57e2023-07-18 07:24:01 -06006836 def testSplEmptyBss(self):
6837 """Test an expanded SPL with a zero-size BSS"""
6838 # ELF file with a '__bss_size' symbol
6839 self._SetupSplElf(src_fname='bss_data_zero')
6840
6841 entry_args = {
6842 'spl-bss-pad': 'y',
6843 'spl-dtb': 'y',
6844 }
6845 data = self._DoReadFileDtb('285_spl_expand.dts',
6846 use_expanded=True, entry_args=entry_args)[0]
6847
Simon Glassf6abd522023-07-18 07:24:04 -06006848 def testTemplate(self):
6849 """Test using a template"""
6850 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6851 data = self._DoReadFile('286_template.dts')
6852 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6853 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6854 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6855
Simon Glass35f72fb2023-07-18 07:24:05 -06006856 def testTemplateBlobMulti(self):
6857 """Test using a template with 'multiple-images' enabled"""
6858 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6859 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6860 retcode = self._DoTestFile('287_template_multi.dts')
6861
6862 self.assertEqual(0, retcode)
6863 image = control.images['image']
6864 image_fname = tools.get_output_filename('my-image.bin')
6865 data = tools.read_file(image_fname)
6866 self.assertEqual(b'blob@@@@other', data)
6867
Simon Glassdb0e3f12023-07-18 07:24:06 -06006868 def testTemplateFit(self):
6869 """Test using a template in a FIT"""
6870 fit_data = self._DoReadFile('288_template_fit.dts')
6871 fname = os.path.join(self._indir, 'fit_data.fit')
6872 tools.write_file(fname, fit_data)
6873 out = tools.run('dumpimage', '-l', fname)
6874
Simon Glass696f2b72023-07-18 07:24:07 -06006875 def testTemplateSection(self):
6876 """Test using a template in a section (not at top level)"""
6877 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6878 data = self._DoReadFile('289_template_section.dts')
6879 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6880 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6881 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6882
Simon Glass23b96e92023-07-18 07:24:08 -06006883 def testMkimageSymbols(self):
6884 """Test using mkimage to build an image with symbols in it"""
6885 self._SetupSplElf('u_boot_binman_syms')
6886 data = self._DoReadFile('290_mkimage_sym.dts')
6887
6888 image = control.images['image']
6889 entries = image.GetEntries()
6890 self.assertIn('u-boot', entries)
6891 u_boot = entries['u-boot']
6892
6893 mkim = entries['mkimage']
6894 mkim_entries = mkim.GetEntries()
6895 self.assertIn('u-boot-spl', mkim_entries)
6896 spl = mkim_entries['u-boot-spl']
6897 self.assertIn('u-boot-spl2', mkim_entries)
6898 spl2 = mkim_entries['u-boot-spl2']
6899
6900 # skip the mkimage header and the area sizes
6901 mk_data = data[mkim.offset + 0x40:]
6902 size, term = struct.unpack('>LL', mk_data[:8])
6903
6904 # There should be only one image, so check that the zero terminator is
6905 # present
6906 self.assertEqual(0, term)
6907
6908 content = mk_data[8:8 + size]
6909
6910 # The image should contain the symbols from u_boot_binman_syms.c
6911 # Note that image_pos is adjusted by the base address of the image,
6912 # which is 0x10 in our test image
6913 spl_data = content[:0x18]
6914 content = content[0x1b:]
6915
6916 # After the header is a table of offsets for each image. There should
6917 # only be one image, then a 0 terminator, so figure out the real start
6918 # of the image data
6919 base = 0x40 + 8
6920
6921 # Check symbols in both u-boot-spl and u-boot-spl2
6922 for i in range(2):
6923 vals = struct.unpack('<LLQLL', spl_data)
6924
6925 # The image should contain the symbols from u_boot_binman_syms.c
6926 # Note that image_pos is adjusted by the base address of the image,
6927 # which is 0x10 in our 'u_boot_binman_syms' test image
6928 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6929 self.assertEqual(base, vals[1])
6930 self.assertEqual(spl2.offset, vals[2])
6931 # figure out the internal positions of its components
6932 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6933
6934 # Check that spl and spl2 are actually at the indicated positions
6935 self.assertEqual(
6936 elf.BINMAN_SYM_MAGIC_VALUE,
6937 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6938 self.assertEqual(
6939 elf.BINMAN_SYM_MAGIC_VALUE,
6940 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6941
6942 self.assertEqual(len(U_BOOT_DATA), vals[4])
6943
6944 # Move to next
6945 spl_data = content[:0x18]
6946
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05306947 def testTIBoardConfig(self):
6948 """Test that a schema validated board config file can be generated"""
Simon Glassa6b44ac2023-07-24 09:19:59 -06006949 data = self._DoReadFile('293_ti_board_cfg.dts')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05306950 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
6951
6952 def testTIBoardConfigCombined(self):
6953 """Test that a schema validated combined board config file can be generated"""
Simon Glassa6b44ac2023-07-24 09:19:59 -06006954 data = self._DoReadFile('294_ti_board_cfg_combined.dts')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05306955 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
6956 self.assertGreater(data, configlen_noheader)
6957
6958 def testTIBoardConfigNoDataType(self):
6959 """Test that error is thrown when data type is not supported"""
6960 with self.assertRaises(ValueError) as e:
Simon Glassa6b44ac2023-07-24 09:19:59 -06006961 data = self._DoReadFile('295_ti_board_cfg_no_type.dts')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05306962 self.assertIn("Schema validation error", str(e.exception))
Simon Glassefddab62023-01-07 14:07:08 -07006963
Neha Malcom Francis78144822023-07-22 00:14:25 +05306964 def testPackTiSecure(self):
6965 """Test that an image with a TI secured binary can be created"""
6966 keyfile = self.TestFile('key.key')
6967 entry_args = {
6968 'keyfile': keyfile,
6969 }
Simon Glassa6b44ac2023-07-24 09:19:59 -06006970 data = self._DoReadFileDtb('296_ti_secure.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05306971 entry_args=entry_args)[0]
6972 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
6973
6974 def testPackTiSecureMissingTool(self):
6975 """Test that an image with a TI secured binary (non-functional) can be created
6976 when openssl is missing"""
6977 keyfile = self.TestFile('key.key')
6978 entry_args = {
6979 'keyfile': keyfile,
6980 }
6981 with test_util.capture_sys_output() as (_, stderr):
Simon Glassa6b44ac2023-07-24 09:19:59 -06006982 self._DoTestFile('296_ti_secure.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05306983 force_missing_bintools='openssl',
6984 entry_args=entry_args)
6985 err = stderr.getvalue()
6986 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6987
6988 def testPackTiSecureROM(self):
6989 """Test that a ROM image with a TI secured binary can be created"""
6990 keyfile = self.TestFile('key.key')
6991 entry_args = {
6992 'keyfile': keyfile,
6993 }
Simon Glassa6b44ac2023-07-24 09:19:59 -06006994 data = self._DoReadFileDtb('297_ti_secure_rom.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05306995 entry_args=entry_args)[0]
Simon Glassa6b44ac2023-07-24 09:19:59 -06006996 data_a = self._DoReadFileDtb('299_ti_secure_rom_a.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05306997 entry_args=entry_args)[0]
Simon Glassa6b44ac2023-07-24 09:19:59 -06006998 data_b = self._DoReadFileDtb('300_ti_secure_rom_b.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05306999 entry_args=entry_args)[0]
7000 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7001 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
7002 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
7003
7004 def testPackTiSecureROMCombined(self):
7005 """Test that a ROM image with a TI secured binary can be created"""
7006 keyfile = self.TestFile('key.key')
7007 entry_args = {
7008 'keyfile': keyfile,
7009 }
Simon Glassa6b44ac2023-07-24 09:19:59 -06007010 data = self._DoReadFileDtb('298_ti_secure_rom_combined.dts',
Neha Malcom Francis78144822023-07-22 00:14:25 +05307011 entry_args=entry_args)[0]
7012 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
7013
Christian Taedcke289e6002023-07-17 09:05:54 +02007014 def testEncryptedNoAlgo(self):
7015 """Test encrypted node with missing required properties"""
7016 with self.assertRaises(ValueError) as e:
7017 self._DoReadFileDtb('301_encrypted_no_algo.dts')
7018 self.assertIn(
7019 "Node '/binman/fit/images/u-boot/encrypted': 'encrypted' entry is missing properties: algo iv-filename",
7020 str(e.exception))
7021
7022 def testEncryptedInvalidIvfile(self):
7023 """Test encrypted node with invalid iv file"""
7024 with self.assertRaises(ValueError) as e:
7025 self._DoReadFileDtb('302_encrypted_invalid_iv_file.dts')
7026 self.assertIn("Filename 'invalid-iv-file' not found in input path",
7027 str(e.exception))
7028
7029 def testEncryptedMissingKey(self):
7030 """Test encrypted node with missing key properties"""
7031 with self.assertRaises(ValueError) as e:
7032 self._DoReadFileDtb('303_encrypted_missing_key.dts')
7033 self.assertIn(
7034 "Node '/binman/fit/images/u-boot/encrypted': Provide either 'key-filename' or 'key-source'",
7035 str(e.exception))
7036
7037 def testEncryptedKeySource(self):
7038 """Test encrypted node with key-source property"""
7039 data = self._DoReadFileDtb('304_encrypted_key_source.dts')[0]
7040
7041 dtb = fdt.Fdt.FromData(data)
7042 dtb.Scan()
7043
7044 node = dtb.GetNode('/images/u-boot/cipher')
7045 self.assertEqual('algo-name', node.props['algo'].value)
7046 self.assertEqual('key-source-value', node.props['key-source'].value)
7047 self.assertEqual(ENCRYPTED_IV_DATA,
7048 tools.to_bytes(''.join(node.props['iv'].value)))
7049 self.assertNotIn('key', node.props)
7050
7051 def testEncryptedKeyFile(self):
7052 """Test encrypted node with key-filename property"""
7053 data = self._DoReadFileDtb('305_encrypted_key_file.dts')[0]
7054
7055 dtb = fdt.Fdt.FromData(data)
7056 dtb.Scan()
7057
7058 node = dtb.GetNode('/images/u-boot/cipher')
7059 self.assertEqual('algo-name', node.props['algo'].value)
7060 self.assertEqual(ENCRYPTED_IV_DATA,
7061 tools.to_bytes(''.join(node.props['iv'].value)))
7062 self.assertEqual(ENCRYPTED_KEY_DATA,
7063 tools.to_bytes(''.join(node.props['key'].value)))
7064 self.assertNotIn('key-source', node.props)
7065
7066
Lukas Funke8c1fbd12023-07-18 13:53:13 +02007067 def testSplPubkeyDtb(self):
7068 """Test u_boot_spl_pubkey_dtb etype"""
7069 data = tools.read_file(self.TestFile("key.pem"))
7070 self._MakeInputFile("key.crt", data)
7071 self._DoReadFileRealDtb('306_spl_pubkey_dtb.dts')
7072 image = control.images['image']
7073 entries = image.GetEntries()
7074 dtb_entry = entries['u-boot-spl-pubkey-dtb']
7075 dtb_data = dtb_entry.GetData()
7076 dtb = fdt.Fdt.FromData(dtb_data)
7077 dtb.Scan()
7078
7079 signature_node = dtb.GetNode('/signature')
7080 self.assertIsNotNone(signature_node)
7081 key_node = signature_node.FindNode("key-key")
7082 self.assertIsNotNone(key_node)
7083 self.assertEqual(fdt_util.GetString(key_node, "required"),
7084 "conf")
7085 self.assertEqual(fdt_util.GetString(key_node, "algo"),
7086 "sha384,rsa4096")
7087 self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"),
7088 "key")
7089
Simon Glass9fc60b42017-11-12 21:52:22 -07007090if __name__ == "__main__":
7091 unittest.main()