blob: 5a3226e3cb08cbcef065311be07d6d43b9b246cf [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"'
Philippe Reynesb1c50932022-03-28 22:57:04 +020097PRE_LOAD_MAGIC = b'UBSH'
98PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
99PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +0530100TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Simon Glass6cf99532020-09-01 05:13:59 -0600101
102# Subdirectory of the input dir to use to put test FDTs
103TEST_FDT_SUBDIR = 'fdts'
Simon Glassec127af2018-07-17 13:25:39 -0600104
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600105# The expected size for the device tree in some tests
Simon Glassf667e452019-07-08 14:25:50 -0600106EXTRACT_DTB_SIZE = 0x3c9
107
Simon Glass6ccbfcd2019-07-20 12:23:47 -0600108# Properties expected to be in the device tree when update_dtb is used
109BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
110
Simon Glass12bb1a92019-07-20 12:23:51 -0600111# Extra properties expected to be in the device tree when allow-repack is used
112REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
113
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200114# Supported compression bintools
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +0200115COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass4f443042016-11-25 20:15:52 -0700116
Simon Glass2f80c5e2023-01-07 14:07:14 -0700117TEE_ADDR = 0x5678
118
Simon Glass4f443042016-11-25 20:15:52 -0700119class TestFunctional(unittest.TestCase):
120 """Functional tests for binman
121
122 Most of these use a sample .dts file to build an image and then check
123 that it looks correct. The sample files are in the test/ subdirectory
124 and are numbered.
125
126 For each entry type a very small test file is created using fixed
127 string contents. This makes it easy to test that things look right, and
128 debug problems.
129
130 In some cases a 'real' file must be used - these are also supplied in
131 the test/ diurectory.
132 """
133 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600134 def setUpClass(cls):
Simon Glass4d5994f2017-11-12 21:52:20 -0700135 global entry
Simon Glass16287932020-04-17 18:09:03 -0600136 from binman import entry
Simon Glass4d5994f2017-11-12 21:52:20 -0700137
Simon Glass4f443042016-11-25 20:15:52 -0700138 # Handle the case where argv[0] is 'python'
Simon Glassb986b3b2019-08-24 07:22:43 -0600139 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
140 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass4f443042016-11-25 20:15:52 -0700141
142 # Create a temporary directory for input files
Simon Glassb986b3b2019-08-24 07:22:43 -0600143 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass4f443042016-11-25 20:15:52 -0700144
145 # Create some test files
146 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
147 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
148 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600149 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700150 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700151 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -0700152 TestFunctional._MakeInputFile('me.bin', ME_DATA)
153 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glassb986b3b2019-08-24 07:22:43 -0600154 cls._ResetDtbs()
Simon Glass2250ee62019-08-24 07:22:48 -0600155
Jagdish Gediya9d368f32018-09-03 21:35:08 +0530156 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600157
Simon Glass5e239182019-08-24 07:22:49 -0600158 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
159 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glass87722132017-11-12 21:52:26 -0700160 X86_START16_SPL_DATA)
Simon Glass5e239182019-08-24 07:22:49 -0600161 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glass35b384c2018-09-14 04:57:10 -0600162 X86_START16_TPL_DATA)
Simon Glass2250ee62019-08-24 07:22:48 -0600163
164 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
165 X86_RESET16_DATA)
166 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
167 X86_RESET16_SPL_DATA)
168 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
169 X86_RESET16_TPL_DATA)
170
Simon Glass4f443042016-11-25 20:15:52 -0700171 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass6b187df2017-11-12 21:52:27 -0700172 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
173 U_BOOT_SPL_NODTB_DATA)
Simon Glassf0253632018-09-14 04:57:32 -0600174 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
175 U_BOOT_TPL_NODTB_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700176 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
177 U_BOOT_VPL_NODTB_DATA)
Simon Glassda229092016-11-25 20:15:56 -0700178 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
179 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Meng59ea8c22017-08-15 22:41:54 -0700180 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassca4f4ff2017-11-12 21:52:28 -0700181 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassec127af2018-07-17 13:25:39 -0600182 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600183 TestFunctional._MakeInputDir('devkeys')
184 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass3ae192c2018-10-01 12:22:31 -0600185 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassea0fff92019-08-24 07:23:07 -0600186 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glassbc6a88f2019-10-20 21:31:35 -0600187 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass998d1482019-10-20 21:31:36 -0600188 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass4f443042016-11-25 20:15:52 -0700189
Simon Glass53e22bf2019-08-24 07:22:53 -0600190 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
191 elf_test.BuildElfTestFiles(cls._elf_testdir)
192
Simon Glasse0ff8552016-11-25 20:15:53 -0700193 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glassf514d8f2019-08-24 07:22:54 -0600194 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700195 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glasse0ff8552016-11-25 20:15:53 -0700196
197 # Intel flash descriptor file
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600198 cls._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -0700199
Simon Glassb986b3b2019-08-24 07:22:43 -0600200 shutil.copytree(cls.TestFile('files'),
201 os.path.join(cls._indir, 'files'))
Simon Glass0a98b282018-09-14 04:57:28 -0600202
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +0530203 shutil.copytree(cls.TestFile('yaml'),
204 os.path.join(cls._indir, 'yaml'))
205
Simon Glass83d73c22018-09-14 04:57:26 -0600206 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glass8f5ef892020-10-26 17:40:25 -0600207 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glassdc2f81a2020-09-01 05:13:58 -0600208 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros47f420a2022-02-19 20:50:04 +0200209 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass75989722021-11-23 21:08:59 -0700210 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Meng4c4d6072021-05-10 20:23:33 +0800211 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland18bd4552020-10-21 21:12:15 -0500212 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman05b978b2023-02-25 19:01:33 +0000213 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Simon Glass83d73c22018-09-14 04:57:26 -0600214
Simon Glass6cf99532020-09-01 05:13:59 -0600215 # Add a few .dtb files for testing
216 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
217 TEST_FDT1_DATA)
218 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
219 TEST_FDT2_DATA)
220
Simon Glassfb91d562020-09-06 10:35:33 -0600221 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
222
Simon Glass40c8bdd2022-03-05 20:19:12 -0700223 # ELF file with two sections in different parts of memory, used for both
224 # ATF and OP_TEE
225 TestFunctional._MakeInputFile('bl31.elf',
226 tools.read_file(cls.ElfTestFile('elf_sections')))
227 TestFunctional._MakeInputFile('tee.elf',
228 tools.read_file(cls.ElfTestFile('elf_sections')))
229
Simon Glass2f80c5e2023-01-07 14:07:14 -0700230 # Newer OP_TEE file in v1 binary format
231 cls.make_tee_bin('tee.bin')
232
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200233 cls.comp_bintools = {}
234 for name in COMP_BINTOOLS:
235 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glassac62fba2019-07-08 13:18:53 -0600236
Simon Glass4f443042016-11-25 20:15:52 -0700237 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600238 def tearDownClass(cls):
Simon Glass4f443042016-11-25 20:15:52 -0700239 """Remove the temporary input directory and its contents"""
Simon Glassb986b3b2019-08-24 07:22:43 -0600240 if cls.preserve_indir:
241 print('Preserving input dir: %s' % cls._indir)
Simon Glassd5164a72019-07-08 13:18:49 -0600242 else:
Simon Glassb986b3b2019-08-24 07:22:43 -0600243 if cls._indir:
244 shutil.rmtree(cls._indir)
245 cls._indir = None
Simon Glass4f443042016-11-25 20:15:52 -0700246
Simon Glassd5164a72019-07-08 13:18:49 -0600247 @classmethod
Simon Glass8acce602019-07-08 13:18:50 -0600248 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glass53cd5d92019-07-08 14:25:29 -0600249 toolpath=None, verbosity=None):
Simon Glassd5164a72019-07-08 13:18:49 -0600250 """Accept arguments controlling test execution
251
252 Args:
253 preserve_indir: Preserve the shared input directory used by all
254 tests in this class.
255 preserve_outdir: Preserve the output directories used by tests. Each
256 test has its own, so this is normally only useful when running a
257 single test.
Simon Glass8acce602019-07-08 13:18:50 -0600258 toolpath: ist of paths to use for tools
Simon Glassd5164a72019-07-08 13:18:49 -0600259 """
260 cls.preserve_indir = preserve_indir
261 cls.preserve_outdirs = preserve_outdirs
Simon Glass8acce602019-07-08 13:18:50 -0600262 cls.toolpath = toolpath
Simon Glass53cd5d92019-07-08 14:25:29 -0600263 cls.verbosity = verbosity
Simon Glassd5164a72019-07-08 13:18:49 -0600264
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200265 def _CheckBintool(self, bintool):
266 if not bintool.is_present():
267 self.skipTest('%s not available' % bintool.name)
268
Simon Glassac62fba2019-07-08 13:18:53 -0600269 def _CheckLz4(self):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +0200270 bintool = self.comp_bintools['lz4']
271 self._CheckBintool(bintool)
Simon Glassac62fba2019-07-08 13:18:53 -0600272
Simon Glassbf574f12019-07-20 12:24:09 -0600273 def _CleanupOutputDir(self):
274 """Remove the temporary output directory"""
275 if self.preserve_outdirs:
276 print('Preserving output dir: %s' % tools.outdir)
277 else:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700278 tools._finalise_for_test()
Simon Glassbf574f12019-07-20 12:24:09 -0600279
Simon Glass4f443042016-11-25 20:15:52 -0700280 def setUp(self):
281 # Enable this to turn on debugging output
Simon Glassf3385a52022-01-29 14:14:15 -0700282 # tout.init(tout.DEBUG)
Simon Glass4f443042016-11-25 20:15:52 -0700283 command.test_result = None
284
285 def tearDown(self):
286 """Remove the temporary output directory"""
Simon Glassbf574f12019-07-20 12:24:09 -0600287 self._CleanupOutputDir()
Simon Glass4f443042016-11-25 20:15:52 -0700288
Simon Glassf86a7362019-07-20 12:24:10 -0600289 def _SetupImageInTmpdir(self):
290 """Set up the output image in a new temporary directory
291
292 This is used when an image has been generated in the output directory,
293 but we want to run binman again. This will create a new output
294 directory and fail to delete the original one.
295
296 This creates a new temporary directory, copies the image to it (with a
297 new name) and removes the old output directory.
298
299 Returns:
300 Tuple:
301 Temporary directory to use
302 New image filename
303 """
Simon Glassc1aa66e2022-01-29 14:14:04 -0700304 image_fname = tools.get_output_filename('image.bin')
Simon Glassf86a7362019-07-20 12:24:10 -0600305 tmpdir = tempfile.mkdtemp(prefix='binman.')
306 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glassc1aa66e2022-01-29 14:14:04 -0700307 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf86a7362019-07-20 12:24:10 -0600308 self._CleanupOutputDir()
309 return tmpdir, updated_fname
310
Simon Glassb8ef5b62018-07-17 13:25:48 -0600311 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600312 def _ResetDtbs(cls):
Simon Glassb8ef5b62018-07-17 13:25:48 -0600313 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
314 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
315 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass6ad24522022-02-28 07:16:54 -0700316 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glassb8ef5b62018-07-17 13:25:48 -0600317
Simon Glass4f443042016-11-25 20:15:52 -0700318 def _RunBinman(self, *args, **kwargs):
319 """Run binman using the command line
320
321 Args:
322 Arguments to pass, as a list of strings
323 kwargs: Arguments to pass to Command.RunPipe()
324 """
Simon Glassd9800692022-01-29 14:14:05 -0700325 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass4f443042016-11-25 20:15:52 -0700326 capture=True, capture_stderr=True, raise_on_error=False)
327 if result.return_code and kwargs.get('raise_on_error', True):
328 raise Exception("Error running '%s': %s" % (' '.join(args),
329 result.stdout + result.stderr))
330 return result
331
Simon Glass53cd5d92019-07-08 14:25:29 -0600332 def _DoBinman(self, *argv):
Simon Glass4f443042016-11-25 20:15:52 -0700333 """Run binman using directly (in the same process)
334
335 Args:
336 Arguments to pass, as a list of strings
337 Returns:
338 Return value (0 for success)
339 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600340 argv = list(argv)
341 args = cmdline.ParseArgs(argv)
342 args.pager = 'binman-invalid-pager'
343 args.build_dir = self._indir
Simon Glass4f443042016-11-25 20:15:52 -0700344
345 # For testing, you can force an increase in verbosity here
Simon Glass53cd5d92019-07-08 14:25:29 -0600346 # args.verbosity = tout.DEBUG
347 return control.Binman(args)
Simon Glass4f443042016-11-25 20:15:52 -0700348
Simon Glass53af22a2018-07-17 13:25:32 -0600349 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glasseb833d82019-04-25 21:58:34 -0600350 entry_args=None, images=None, use_real_dtb=False,
Simon Glass63aeaeb2021-03-18 20:25:05 +1300351 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thierya89c8f22022-01-06 11:49:41 +0100352 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass4f9ee832022-01-09 20:14:09 -0700353 test_section_timeout=False, update_fdt_in_elf=None,
Simon Glassb38da152022-11-09 19:14:42 -0700354 force_missing_bintools='', ignore_missing=False):
Simon Glass4f443042016-11-25 20:15:52 -0700355 """Run binman with a given test file
356
357 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600358 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600359 debug: True to enable debugging output
Simon Glass3b0c3822018-06-01 09:38:20 -0600360 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600361 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600362 tree before packing it into the image
Simon Glass0bfa7b02018-09-14 04:57:12 -0600363 entry_args: Dict of entry args to supply to binman
364 key: arg name
365 value: value of that arg
366 images: List of image names to build
Simon Glasse9d336d2020-09-01 05:13:55 -0600367 use_real_dtb: True to use the test file as the contents of
368 the u-boot-dtb entry. Normally this is not needed and the
369 test contents (the U_BOOT_DTB_DATA string) can be used.
370 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300371 use_expanded: True to use expanded entries where available, e.g.
372 'u-boot-expanded' instead of 'u-boot'
Simon Glasse9d336d2020-09-01 05:13:55 -0600373 verbosity: Verbosity level to use (0-3, None=don't set it)
374 allow_missing: Set the '--allow-missing' flag so that missing
375 external binaries just produce a warning instead of an error
Heiko Thierya89c8f22022-01-06 11:49:41 +0100376 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glass6cf99532020-09-01 05:13:59 -0600377 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600378 threads: Number of threads to use (None for default, 0 for
379 single-threaded)
Simon Glass7115f002021-11-03 21:09:17 -0600380 test_section_timeout: True to force the first time to timeout, as
381 used in testThreadTimeout()
Simon Glass0427bed2021-11-03 21:09:18 -0600382 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass4f9ee832022-01-09 20:14:09 -0700383 force_missing_tools (str): comma-separated list of bintools to
384 regard as missing
Simon Glass7115f002021-11-03 21:09:17 -0600385
386 Returns:
387 int return code, 0 on success
Simon Glass4f443042016-11-25 20:15:52 -0700388 """
Simon Glass53cd5d92019-07-08 14:25:29 -0600389 args = []
Simon Glass7fe91732017-11-13 18:55:00 -0700390 if debug:
391 args.append('-D')
Simon Glass53cd5d92019-07-08 14:25:29 -0600392 if verbosity is not None:
393 args.append('-v%d' % verbosity)
394 elif self.verbosity:
395 args.append('-v%d' % self.verbosity)
396 if self.toolpath:
397 for path in self.toolpath:
398 args += ['--toolpath', path]
Simon Glassc69d19c2021-07-06 10:36:37 -0600399 if threads is not None:
400 args.append('-T%d' % threads)
401 if test_section_timeout:
402 args.append('--test-section-timeout')
Simon Glass53cd5d92019-07-08 14:25:29 -0600403 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass3b0c3822018-06-01 09:38:20 -0600404 if map:
405 args.append('-m')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600406 if update_dtb:
Simon Glass2569e102019-07-08 13:18:47 -0600407 args.append('-u')
Simon Glass93d17412018-09-14 04:57:23 -0600408 if not use_real_dtb:
409 args.append('--fake-dtb')
Simon Glass63aeaeb2021-03-18 20:25:05 +1300410 if not use_expanded:
411 args.append('--no-expanded')
Simon Glass53af22a2018-07-17 13:25:32 -0600412 if entry_args:
Simon Glass50979152019-05-14 15:53:41 -0600413 for arg, value in entry_args.items():
Simon Glass53af22a2018-07-17 13:25:32 -0600414 args.append('-a%s=%s' % (arg, value))
Simon Glass4f9f1052020-07-09 18:39:38 -0600415 if allow_missing:
416 args.append('-M')
Simon Glassb38da152022-11-09 19:14:42 -0700417 if ignore_missing:
418 args.append('-W')
Heiko Thierya89c8f22022-01-06 11:49:41 +0100419 if allow_fake_blobs:
420 args.append('--fake-ext-blobs')
Simon Glass4f9ee832022-01-09 20:14:09 -0700421 if force_missing_bintools:
422 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glass0427bed2021-11-03 21:09:18 -0600423 if update_fdt_in_elf:
424 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass0bfa7b02018-09-14 04:57:12 -0600425 if images:
426 for image in images:
427 args += ['-i', image]
Simon Glass6cf99532020-09-01 05:13:59 -0600428 if extra_indirs:
429 for indir in extra_indirs:
430 args += ['-I', indir]
Simon Glass7fe91732017-11-13 18:55:00 -0700431 return self._DoBinman(*args)
Simon Glass4f443042016-11-25 20:15:52 -0700432
433 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glasse0ff8552016-11-25 20:15:53 -0700434 """Set up a new test device-tree file
435
436 The given file is compiled and set up as the device tree to be used
437 for ths test.
438
439 Args:
440 fname: Filename of .dts file to read
Simon Glass7ae5f312018-06-01 09:38:19 -0600441 outfile: Output filename for compiled device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700442
443 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600444 Contents of device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700445 """
Simon Glassa004f292019-07-20 12:23:49 -0600446 tmpdir = tempfile.mkdtemp(prefix='binmant.')
447 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass1d0ebf72019-05-14 15:53:42 -0600448 with open(dtb, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700449 data = fd.read()
450 TestFunctional._MakeInputFile(outfile, data)
Simon Glassa004f292019-07-20 12:23:49 -0600451 shutil.rmtree(tmpdir)
Simon Glasse0e62752018-10-01 21:12:41 -0600452 return data
Simon Glass4f443042016-11-25 20:15:52 -0700453
Simon Glass6ad24522022-02-28 07:16:54 -0700454 def _GetDtbContentsForSpls(self, dtb_data, name):
455 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glass6ed45ba2018-09-14 04:57:24 -0600456
457 For testing we don't actually have different versions of the DTB. With
458 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
459 we don't normally have any unwanted nodes.
460
461 We still want the DTBs for SPL and TPL to be different though, since
462 otherwise it is confusing to know which one we are looking at. So add
463 an 'spl' or 'tpl' property to the top-level node.
Simon Glasse9d336d2020-09-01 05:13:55 -0600464
465 Args:
466 dtb_data: dtb data to modify (this should be a value devicetree)
467 name: Name of a new property to add
468
469 Returns:
470 New dtb data with the property added
Simon Glass6ed45ba2018-09-14 04:57:24 -0600471 """
472 dtb = fdt.Fdt.FromData(dtb_data)
473 dtb.Scan()
474 dtb.GetNode('/binman').AddZeroProp(name)
475 dtb.Sync(auto_resize=True)
476 dtb.Pack()
477 return dtb.GetContents()
478
Simon Glass63aeaeb2021-03-18 20:25:05 +1300479 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
480 map=False, update_dtb=False, entry_args=None,
Simon Glassc69d19c2021-07-06 10:36:37 -0600481 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass4f443042016-11-25 20:15:52 -0700482 """Run binman and return the resulting image
483
484 This runs binman with a given test file and then reads the resulting
485 output file. It is a shortcut function since most tests need to do
486 these steps.
487
488 Raises an assertion failure if binman returns a non-zero exit code.
489
490 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600491 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass4f443042016-11-25 20:15:52 -0700492 use_real_dtb: True to use the test file as the contents of
493 the u-boot-dtb entry. Normally this is not needed and the
494 test contents (the U_BOOT_DTB_DATA string) can be used.
495 But in some test we need the real contents.
Simon Glass63aeaeb2021-03-18 20:25:05 +1300496 use_expanded: True to use expanded entries where available, e.g.
497 'u-boot-expanded' instead of 'u-boot'
Simon Glass3b0c3822018-06-01 09:38:20 -0600498 map: True to output map files for the images
Simon Glass3ab95982018-08-01 15:22:37 -0600499 update_dtb: Update the offset and size of each entry in the device
Simon Glass16b8d6b2018-07-06 10:27:42 -0600500 tree before packing it into the image
Simon Glasse9d336d2020-09-01 05:13:55 -0600501 entry_args: Dict of entry args to supply to binman
502 key: arg name
503 value: value of that arg
504 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
505 function. If reset_dtbs is True, then the original test dtb
506 is written back before this function finishes
Simon Glass6cf99532020-09-01 05:13:59 -0600507 extra_indirs: Extra input directories to add using -I
Simon Glassc69d19c2021-07-06 10:36:37 -0600508 threads: Number of threads to use (None for default, 0 for
509 single-threaded)
Simon Glasse0ff8552016-11-25 20:15:53 -0700510
511 Returns:
512 Tuple:
513 Resulting image contents
514 Device tree contents
Simon Glass3b0c3822018-06-01 09:38:20 -0600515 Map data showing contents of image (or None if none)
Simon Glassea6922e2018-07-17 13:25:27 -0600516 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass4f443042016-11-25 20:15:52 -0700517 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700518 dtb_data = None
Simon Glass4f443042016-11-25 20:15:52 -0700519 # Use the compiled test file as the u-boot-dtb input
520 if use_real_dtb:
Simon Glasse0ff8552016-11-25 20:15:53 -0700521 dtb_data = self._SetupDtb(fname)
Simon Glass6ed45ba2018-09-14 04:57:24 -0600522
523 # For testing purposes, make a copy of the DT for SPL and TPL. Add
524 # a node indicating which it is, so aid verification.
Simon Glass6ad24522022-02-28 07:16:54 -0700525 for name in ['spl', 'tpl', 'vpl']:
Simon Glass6ed45ba2018-09-14 04:57:24 -0600526 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
527 outfile = os.path.join(self._indir, dtb_fname)
528 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass6ad24522022-02-28 07:16:54 -0700529 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass4f443042016-11-25 20:15:52 -0700530
531 try:
Simon Glass53af22a2018-07-17 13:25:32 -0600532 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glass6cf99532020-09-01 05:13:59 -0600533 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glassc69d19c2021-07-06 10:36:37 -0600534 use_expanded=use_expanded, extra_indirs=extra_indirs,
535 threads=threads)
Simon Glass4f443042016-11-25 20:15:52 -0700536 self.assertEqual(0, retcode)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700537 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass4f443042016-11-25 20:15:52 -0700538
539 # Find the (only) image, read it and return its contents
540 image = control.images['image']
Simon Glassc1aa66e2022-01-29 14:14:04 -0700541 image_fname = tools.get_output_filename('image.bin')
Simon Glass16b8d6b2018-07-06 10:27:42 -0600542 self.assertTrue(os.path.exists(image_fname))
Simon Glass3b0c3822018-06-01 09:38:20 -0600543 if map:
Simon Glassc1aa66e2022-01-29 14:14:04 -0700544 map_fname = tools.get_output_filename('image.map')
Simon Glass3b0c3822018-06-01 09:38:20 -0600545 with open(map_fname) as fd:
546 map_data = fd.read()
547 else:
548 map_data = None
Simon Glass1d0ebf72019-05-14 15:53:42 -0600549 with open(image_fname, 'rb') as fd:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600550 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass4f443042016-11-25 20:15:52 -0700551 finally:
552 # Put the test file back
Simon Glass6ed45ba2018-09-14 04:57:24 -0600553 if reset_dtbs and use_real_dtb:
Simon Glassb8ef5b62018-07-17 13:25:48 -0600554 self._ResetDtbs()
Simon Glass4f443042016-11-25 20:15:52 -0700555
Simon Glass3c081312019-07-08 14:25:26 -0600556 def _DoReadFileRealDtb(self, fname):
557 """Run binman with a real .dtb file and return the resulting data
558
559 Args:
560 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
561
562 Returns:
563 Resulting image contents
564 """
565 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
566
Simon Glasse0ff8552016-11-25 20:15:53 -0700567 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass7ae5f312018-06-01 09:38:19 -0600568 """Helper function which discards the device-tree binary
569
570 Args:
Simon Glass741f2d62018-10-01 12:22:30 -0600571 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass7ae5f312018-06-01 09:38:19 -0600572 use_real_dtb: True to use the test file as the contents of
573 the u-boot-dtb entry. Normally this is not needed and the
574 test contents (the U_BOOT_DTB_DATA string) can be used.
575 But in some test we need the real contents.
Simon Glassea6922e2018-07-17 13:25:27 -0600576
577 Returns:
578 Resulting image contents
Simon Glass7ae5f312018-06-01 09:38:19 -0600579 """
Simon Glasse0ff8552016-11-25 20:15:53 -0700580 return self._DoReadFileDtb(fname, use_real_dtb)[0]
581
Simon Glass4f443042016-11-25 20:15:52 -0700582 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600583 def _MakeInputFile(cls, fname, contents):
Simon Glass4f443042016-11-25 20:15:52 -0700584 """Create a new test input file, creating directories as needed
585
586 Args:
Simon Glass3ab95982018-08-01 15:22:37 -0600587 fname: Filename to create
Simon Glass4f443042016-11-25 20:15:52 -0700588 contents: File contents to write in to the file
589 Returns:
590 Full pathname of file created
591 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600592 pathname = os.path.join(cls._indir, fname)
Simon Glass4f443042016-11-25 20:15:52 -0700593 dirname = os.path.dirname(pathname)
594 if dirname and not os.path.exists(dirname):
595 os.makedirs(dirname)
596 with open(pathname, 'wb') as fd:
597 fd.write(contents)
598 return pathname
599
600 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600601 def _MakeInputDir(cls, dirname):
Simon Glass0ef87aa2018-07-17 13:25:44 -0600602 """Create a new test input directory, creating directories as needed
603
604 Args:
605 dirname: Directory name to create
606
607 Returns:
608 Full pathname of directory created
609 """
Simon Glassb986b3b2019-08-24 07:22:43 -0600610 pathname = os.path.join(cls._indir, dirname)
Simon Glass0ef87aa2018-07-17 13:25:44 -0600611 if not os.path.exists(pathname):
612 os.makedirs(pathname)
613 return pathname
614
615 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600616 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass11ae93e2018-10-01 21:12:47 -0600617 """Set up an ELF file with a '_dt_ucode_base_size' symbol
618
619 Args:
620 Filename of ELF file to use as SPL
621 """
Simon Glassc9a0b272019-08-24 07:22:59 -0600622 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700623 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass11ae93e2018-10-01 21:12:47 -0600624
625 @classmethod
Simon Glass2090f1e2019-08-24 07:23:00 -0600626 def _SetupTplElf(cls, src_fname='bss_data'):
627 """Set up an ELF file with a '_dt_ucode_base_size' symbol
628
629 Args:
630 Filename of ELF file to use as TPL
631 """
632 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glassc1aa66e2022-01-29 14:14:04 -0700633 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass2090f1e2019-08-24 07:23:00 -0600634
635 @classmethod
Simon Glass6ad24522022-02-28 07:16:54 -0700636 def _SetupVplElf(cls, src_fname='bss_data'):
637 """Set up an ELF file with a '_dt_ucode_base_size' symbol
638
639 Args:
640 Filename of ELF file to use as VPL
641 """
642 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
643 tools.read_file(cls.ElfTestFile(src_fname)))
644
645 @classmethod
Simon Glass0ba4b3d2020-07-09 18:39:41 -0600646 def _SetupDescriptor(cls):
647 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
648 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
649
650 @classmethod
Simon Glassb986b3b2019-08-24 07:22:43 -0600651 def TestFile(cls, fname):
652 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass4f443042016-11-25 20:15:52 -0700653
Simon Glass53e22bf2019-08-24 07:22:53 -0600654 @classmethod
655 def ElfTestFile(cls, fname):
656 return os.path.join(cls._elf_testdir, fname)
657
Simon Glass2f80c5e2023-01-07 14:07:14 -0700658 @classmethod
659 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
660 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
661 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
662 dummy, paged_sz) + U_BOOT_DATA
663 data += extra_data
664 TestFunctional._MakeInputFile(fname, data)
665
Simon Glass4f443042016-11-25 20:15:52 -0700666 def AssertInList(self, grep_list, target):
667 """Assert that at least one of a list of things is in a target
668
669 Args:
670 grep_list: List of strings to check
671 target: Target string
672 """
673 for grep in grep_list:
674 if grep in target:
675 return
Simon Glass1fc62de2019-05-17 22:00:50 -0600676 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass4f443042016-11-25 20:15:52 -0700677
678 def CheckNoGaps(self, entries):
679 """Check that all entries fit together without gaps
680
681 Args:
682 entries: List of entries to check
683 """
Simon Glass3ab95982018-08-01 15:22:37 -0600684 offset = 0
Simon Glass4f443042016-11-25 20:15:52 -0700685 for entry in entries.values():
Simon Glass3ab95982018-08-01 15:22:37 -0600686 self.assertEqual(offset, entry.offset)
687 offset += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700688
Simon Glasse0ff8552016-11-25 20:15:53 -0700689 def GetFdtLen(self, dtb):
Simon Glass7ae5f312018-06-01 09:38:19 -0600690 """Get the totalsize field from a device-tree binary
Simon Glasse0ff8552016-11-25 20:15:53 -0700691
692 Args:
Simon Glass7ae5f312018-06-01 09:38:19 -0600693 dtb: Device-tree binary contents
Simon Glasse0ff8552016-11-25 20:15:53 -0700694
695 Returns:
Simon Glass7ae5f312018-06-01 09:38:19 -0600696 Total size of device-tree binary, from the header
Simon Glasse0ff8552016-11-25 20:15:53 -0700697 """
698 return struct.unpack('>L', dtb[4:8])[0]
699
Simon Glass086cec92019-07-08 14:25:27 -0600700 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glass16b8d6b2018-07-06 10:27:42 -0600701 def AddNode(node, path):
702 if node.name != '/':
703 path += '/' + node.name
Simon Glass086cec92019-07-08 14:25:27 -0600704 for prop in node.props.values():
705 if prop.name in prop_names:
706 prop_path = path + ':' + prop.name
707 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
708 prop.value)
Simon Glass16b8d6b2018-07-06 10:27:42 -0600709 for subnode in node.subnodes:
Simon Glass16b8d6b2018-07-06 10:27:42 -0600710 AddNode(subnode, path)
711
712 tree = {}
Simon Glass16b8d6b2018-07-06 10:27:42 -0600713 AddNode(dtb.GetRoot(), '')
714 return tree
715
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +0000716 def _CheckSign(self, fit, key):
717 try:
718 tools.run('fit_check_sign', '-k', key, '-f', fit)
719 except:
720 self.fail('Expected signed FIT container')
721 return False
722 return True
723
Simon Glass4f443042016-11-25 20:15:52 -0700724 def testRun(self):
725 """Test a basic run with valid args"""
726 result = self._RunBinman('-h')
727
728 def testFullHelp(self):
729 """Test that the full help is displayed with -H"""
730 result = self._RunBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300731 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rini3759df02018-01-16 15:29:50 -0500732 # Remove possible extraneous strings
733 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
734 gothelp = result.stdout.replace(extra, '')
735 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass4f443042016-11-25 20:15:52 -0700736 self.assertEqual(0, len(result.stderr))
737 self.assertEqual(0, result.return_code)
738
739 def testFullHelpInternal(self):
740 """Test that the full help is displayed with -H"""
741 try:
742 command.test_result = command.CommandResult()
743 result = self._DoBinman('-H')
Simon Glass61adb2d2021-03-18 20:25:13 +1300744 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass4f443042016-11-25 20:15:52 -0700745 finally:
746 command.test_result = None
747
748 def testHelp(self):
749 """Test that the basic help is displayed with -h"""
750 result = self._RunBinman('-h')
751 self.assertTrue(len(result.stdout) > 200)
752 self.assertEqual(0, len(result.stderr))
753 self.assertEqual(0, result.return_code)
754
Simon Glass4f443042016-11-25 20:15:52 -0700755 def testBoard(self):
756 """Test that we can run it with a specific board"""
Simon Glass741f2d62018-10-01 12:22:30 -0600757 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass4f443042016-11-25 20:15:52 -0700758 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glass63aeaeb2021-03-18 20:25:05 +1300759 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass4f443042016-11-25 20:15:52 -0700760 self.assertEqual(0, result)
761
762 def testNeedBoard(self):
763 """Test that we get an error when no board ius supplied"""
764 with self.assertRaises(ValueError) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600765 result = self._DoBinman('build')
Simon Glass4f443042016-11-25 20:15:52 -0700766 self.assertIn("Must provide a board to process (use -b <board>)",
767 str(e.exception))
768
769 def testMissingDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600770 """Test that an invalid device-tree file generates an error"""
Simon Glass4f443042016-11-25 20:15:52 -0700771 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600772 self._RunBinman('build', '-d', 'missing_file')
Simon Glass4f443042016-11-25 20:15:52 -0700773 # We get one error from libfdt, and a different one from fdtget.
774 self.AssertInList(["Couldn't open blob from 'missing_file'",
775 'No such file or directory'], str(e.exception))
776
777 def testBrokenDt(self):
Simon Glass7ae5f312018-06-01 09:38:19 -0600778 """Test that an invalid device-tree source file generates an error
Simon Glass4f443042016-11-25 20:15:52 -0700779
780 Since this is a source file it should be compiled and the error
781 will come from the device-tree compiler (dtc).
782 """
783 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600784 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700785 self.assertIn("FATAL ERROR: Unable to parse input tree",
786 str(e.exception))
787
788 def testMissingNode(self):
789 """Test that a device tree without a 'binman' node generates an error"""
790 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600791 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700792 self.assertIn("does not have a 'binman' node", str(e.exception))
793
794 def testEmpty(self):
795 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glass53cd5d92019-07-08 14:25:29 -0600796 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700797 self.assertEqual(0, len(result.stderr))
798 self.assertEqual(0, result.return_code)
799
800 def testInvalidEntry(self):
801 """Test that an invalid entry is flagged"""
802 with self.assertRaises(Exception) as e:
Simon Glass53cd5d92019-07-08 14:25:29 -0600803 result = self._RunBinman('build', '-d',
Simon Glass741f2d62018-10-01 12:22:30 -0600804 self.TestFile('004_invalid_entry.dts'))
Simon Glass4f443042016-11-25 20:15:52 -0700805 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
806 "'/binman/not-a-valid-type'", str(e.exception))
807
808 def testSimple(self):
809 """Test a simple binman with a single file"""
Simon Glass741f2d62018-10-01 12:22:30 -0600810 data = self._DoReadFile('005_simple.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700811 self.assertEqual(U_BOOT_DATA, data)
812
Simon Glass7fe91732017-11-13 18:55:00 -0700813 def testSimpleDebug(self):
814 """Test a simple binman run with debugging enabled"""
Simon Glasse2705fa2019-07-08 14:25:53 -0600815 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass7fe91732017-11-13 18:55:00 -0700816
Simon Glass4f443042016-11-25 20:15:52 -0700817 def testDual(self):
818 """Test that we can handle creating two images
819
820 This also tests image padding.
821 """
Simon Glass741f2d62018-10-01 12:22:30 -0600822 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700823 self.assertEqual(0, retcode)
824
825 image = control.images['image1']
Simon Glass8beb11e2019-07-08 14:25:47 -0600826 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700827 fname = tools.get_output_filename('image1.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700828 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600829 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700830 data = fd.read()
831 self.assertEqual(U_BOOT_DATA, data)
832
833 image = control.images['image2']
Simon Glass8beb11e2019-07-08 14:25:47 -0600834 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700835 fname = tools.get_output_filename('image2.bin')
Simon Glass4f443042016-11-25 20:15:52 -0700836 self.assertTrue(os.path.exists(fname))
Simon Glass1d0ebf72019-05-14 15:53:42 -0600837 with open(fname, 'rb') as fd:
Simon Glass4f443042016-11-25 20:15:52 -0700838 data = fd.read()
839 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700840 self.assertEqual(tools.get_bytes(0, 3), data[:3])
841 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass4f443042016-11-25 20:15:52 -0700842
843 def testBadAlign(self):
844 """Test that an invalid alignment value is detected"""
845 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -0600846 self._DoTestFile('007_bad_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700847 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
848 "of two", str(e.exception))
849
850 def testPackSimple(self):
851 """Test that packing works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -0600852 retcode = self._DoTestFile('008_pack.dts')
Simon Glass4f443042016-11-25 20:15:52 -0700853 self.assertEqual(0, retcode)
854 self.assertIn('image', control.images)
855 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600856 entries = image.GetEntries()
Simon Glass4f443042016-11-25 20:15:52 -0700857 self.assertEqual(5, len(entries))
858
859 # First u-boot
860 self.assertIn('u-boot', entries)
861 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600862 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700863 self.assertEqual(len(U_BOOT_DATA), entry.size)
864
865 # Second u-boot, aligned to 16-byte boundary
866 self.assertIn('u-boot-align', entries)
867 entry = entries['u-boot-align']
Simon Glass3ab95982018-08-01 15:22:37 -0600868 self.assertEqual(16, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700869 self.assertEqual(len(U_BOOT_DATA), entry.size)
870
871 # Third u-boot, size 23 bytes
872 self.assertIn('u-boot-size', entries)
873 entry = entries['u-boot-size']
Simon Glass3ab95982018-08-01 15:22:37 -0600874 self.assertEqual(20, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700875 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
876 self.assertEqual(23, entry.size)
877
878 # Fourth u-boot, placed immediate after the above
879 self.assertIn('u-boot-next', entries)
880 entry = entries['u-boot-next']
Simon Glass3ab95982018-08-01 15:22:37 -0600881 self.assertEqual(43, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700882 self.assertEqual(len(U_BOOT_DATA), entry.size)
883
Simon Glass3ab95982018-08-01 15:22:37 -0600884 # Fifth u-boot, placed at a fixed offset
Simon Glass4f443042016-11-25 20:15:52 -0700885 self.assertIn('u-boot-fixed', entries)
886 entry = entries['u-boot-fixed']
Simon Glass3ab95982018-08-01 15:22:37 -0600887 self.assertEqual(61, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700888 self.assertEqual(len(U_BOOT_DATA), entry.size)
889
Simon Glass8beb11e2019-07-08 14:25:47 -0600890 self.assertEqual(65, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700891
892 def testPackExtra(self):
893 """Test that extra packing feature works as expected"""
Simon Glass4eec34c2020-10-26 17:40:10 -0600894 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
895 update_dtb=True)
Simon Glass4f443042016-11-25 20:15:52 -0700896
Simon Glass4f443042016-11-25 20:15:52 -0700897 self.assertIn('image', control.images)
898 image = control.images['image']
Simon Glass8f1da502018-06-01 09:38:12 -0600899 entries = image.GetEntries()
Samuel Hollandb01ae032023-01-21 17:25:16 -0600900 self.assertEqual(6, len(entries))
Simon Glass4f443042016-11-25 20:15:52 -0700901
Samuel Hollandb01ae032023-01-21 17:25:16 -0600902 # First u-boot with padding before and after (included in minimum size)
Simon Glass4f443042016-11-25 20:15:52 -0700903 self.assertIn('u-boot', entries)
904 entry = entries['u-boot']
Simon Glass3ab95982018-08-01 15:22:37 -0600905 self.assertEqual(0, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700906 self.assertEqual(3, entry.pad_before)
907 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600908 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700909 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
910 tools.get_bytes(0, 5), data[:entry.size])
Simon Glassef439ed2020-10-26 17:40:08 -0600911 pos = entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700912
913 # Second u-boot has an aligned size, but it has no effect
914 self.assertIn('u-boot-align-size-nop', entries)
915 entry = entries['u-boot-align-size-nop']
Simon Glassef439ed2020-10-26 17:40:08 -0600916 self.assertEqual(pos, entry.offset)
917 self.assertEqual(len(U_BOOT_DATA), entry.size)
918 self.assertEqual(U_BOOT_DATA, entry.data)
919 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
920 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700921
922 # Third u-boot has an aligned size too
923 self.assertIn('u-boot-align-size', entries)
924 entry = entries['u-boot-align-size']
Simon Glassef439ed2020-10-26 17:40:08 -0600925 self.assertEqual(pos, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700926 self.assertEqual(32, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600927 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -0700928 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600929 data[pos:pos + entry.size])
930 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700931
932 # Fourth u-boot has an aligned end
933 self.assertIn('u-boot-align-end', entries)
934 entry = entries['u-boot-align-end']
Simon Glass3ab95982018-08-01 15:22:37 -0600935 self.assertEqual(48, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700936 self.assertEqual(16, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600937 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700938 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600939 data[pos:pos + entry.size])
940 pos += entry.size
Simon Glass4f443042016-11-25 20:15:52 -0700941
942 # Fifth u-boot immediately afterwards
943 self.assertIn('u-boot-align-both', entries)
944 entry = entries['u-boot-align-both']
Simon Glass3ab95982018-08-01 15:22:37 -0600945 self.assertEqual(64, entry.offset)
Simon Glass4f443042016-11-25 20:15:52 -0700946 self.assertEqual(64, entry.size)
Simon Glassef439ed2020-10-26 17:40:08 -0600947 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glassc1aa66e2022-01-29 14:14:04 -0700948 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glassef439ed2020-10-26 17:40:08 -0600949 data[pos:pos + entry.size])
Simon Glass4f443042016-11-25 20:15:52 -0700950
Samuel Hollandb01ae032023-01-21 17:25:16 -0600951 # Sixth u-boot with both minimum size and aligned size
952 self.assertIn('u-boot-min-size', entries)
953 entry = entries['u-boot-min-size']
954 self.assertEqual(128, entry.offset)
955 self.assertEqual(32, entry.size)
956 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
957 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
958 data[pos:pos + entry.size])
959
Simon Glass4f443042016-11-25 20:15:52 -0700960 self.CheckNoGaps(entries)
Samuel Hollandb01ae032023-01-21 17:25:16 -0600961 self.assertEqual(160, image.size)
Simon Glass4f443042016-11-25 20:15:52 -0700962
Simon Glass4eec34c2020-10-26 17:40:10 -0600963 dtb = fdt.Fdt(out_dtb_fname)
964 dtb.Scan()
965 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
966 expected = {
967 'image-pos': 0,
968 'offset': 0,
Samuel Hollandb01ae032023-01-21 17:25:16 -0600969 'size': 160,
Simon Glass4eec34c2020-10-26 17:40:10 -0600970
971 'u-boot:image-pos': 0,
972 'u-boot:offset': 0,
973 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
974
975 'u-boot-align-size-nop:image-pos': 12,
976 'u-boot-align-size-nop:offset': 12,
977 'u-boot-align-size-nop:size': 4,
978
979 'u-boot-align-size:image-pos': 16,
980 'u-boot-align-size:offset': 16,
981 'u-boot-align-size:size': 32,
982
983 'u-boot-align-end:image-pos': 48,
984 'u-boot-align-end:offset': 48,
985 'u-boot-align-end:size': 16,
986
987 'u-boot-align-both:image-pos': 64,
988 'u-boot-align-both:offset': 64,
989 'u-boot-align-both:size': 64,
Samuel Hollandb01ae032023-01-21 17:25:16 -0600990
991 'u-boot-min-size:image-pos': 128,
992 'u-boot-min-size:offset': 128,
993 'u-boot-min-size:size': 32,
Simon Glass4eec34c2020-10-26 17:40:10 -0600994 }
995 self.assertEqual(expected, props)
996
Simon Glass4f443042016-11-25 20:15:52 -0700997 def testPackAlignPowerOf2(self):
998 """Test that invalid entry alignment is detected"""
999 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001000 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001001 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1002 "of two", str(e.exception))
1003
1004 def testPackAlignSizePowerOf2(self):
1005 """Test that invalid entry size alignment is detected"""
1006 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001007 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001008 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1009 "power of two", str(e.exception))
1010
1011 def testPackInvalidAlign(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001012 """Test detection of an offset that does not match its alignment"""
Simon Glass4f443042016-11-25 20:15:52 -07001013 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001014 self._DoTestFile('012_pack_inv_align.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001015 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001016 "align 0x4 (4)", str(e.exception))
1017
1018 def testPackInvalidSizeAlign(self):
1019 """Test that invalid entry size alignment is detected"""
1020 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001021 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001022 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1023 "align-size 0x4 (4)", str(e.exception))
1024
1025 def testPackOverlap(self):
1026 """Test that overlapping regions are detected"""
1027 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001028 self._DoTestFile('014_pack_overlap.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001029 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001030 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1031 str(e.exception))
1032
1033 def testPackEntryOverflow(self):
1034 """Test that entries that overflow their size are detected"""
1035 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001036 self._DoTestFile('015_pack_overflow.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001037 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1038 "but entry size is 0x3 (3)", str(e.exception))
1039
1040 def testPackImageOverflow(self):
1041 """Test that entries which overflow the image size are detected"""
1042 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001043 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001044 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass4f443042016-11-25 20:15:52 -07001045 "size 0x3 (3)", str(e.exception))
1046
1047 def testPackImageSize(self):
1048 """Test that the image size can be set"""
Simon Glass741f2d62018-10-01 12:22:30 -06001049 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001050 self.assertEqual(0, retcode)
1051 self.assertIn('image', control.images)
1052 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001053 self.assertEqual(7, image.size)
Simon Glass4f443042016-11-25 20:15:52 -07001054
1055 def testPackImageSizeAlign(self):
1056 """Test that image size alignemnt works as expected"""
Simon Glass741f2d62018-10-01 12:22:30 -06001057 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001058 self.assertEqual(0, retcode)
1059 self.assertIn('image', control.images)
1060 image = control.images['image']
Simon Glass8beb11e2019-07-08 14:25:47 -06001061 self.assertEqual(16, image.size)
Simon Glass4f443042016-11-25 20:15:52 -07001062
1063 def testPackInvalidImageAlign(self):
1064 """Test that invalid image alignment is detected"""
1065 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001066 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glass8f1da502018-06-01 09:38:12 -06001067 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass4f443042016-11-25 20:15:52 -07001068 "align-size 0x8 (8)", str(e.exception))
1069
Simon Glass8d2ef3e2022-02-11 13:23:21 -07001070 def testPackAlignPowerOf2Inv(self):
Simon Glass4f443042016-11-25 20:15:52 -07001071 """Test that invalid image alignment is detected"""
1072 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001073 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001074 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass4f443042016-11-25 20:15:52 -07001075 "two", str(e.exception))
1076
1077 def testImagePadByte(self):
1078 """Test that the image pad byte can be specified"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001079 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001080 data = self._DoReadFile('021_image_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001081 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glasse6d85ff2019-05-14 15:53:47 -06001082 U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001083
1084 def testImageName(self):
1085 """Test that image files can be named"""
Simon Glass741f2d62018-10-01 12:22:30 -06001086 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001087 self.assertEqual(0, retcode)
1088 image = control.images['image1']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001089 fname = tools.get_output_filename('test-name')
Simon Glass4f443042016-11-25 20:15:52 -07001090 self.assertTrue(os.path.exists(fname))
1091
1092 image = control.images['image2']
Simon Glassc1aa66e2022-01-29 14:14:04 -07001093 fname = tools.get_output_filename('test-name.xx')
Simon Glass4f443042016-11-25 20:15:52 -07001094 self.assertTrue(os.path.exists(fname))
1095
1096 def testBlobFilename(self):
1097 """Test that generic blobs can be provided by filename"""
Simon Glass741f2d62018-10-01 12:22:30 -06001098 data = self._DoReadFile('023_blob.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001099 self.assertEqual(BLOB_DATA, data)
1100
1101 def testPackSorted(self):
1102 """Test that entries can be sorted"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001103 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001104 data = self._DoReadFile('024_sorted.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001105 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1106 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass4f443042016-11-25 20:15:52 -07001107
Simon Glass3ab95982018-08-01 15:22:37 -06001108 def testPackZeroOffset(self):
1109 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001110 self._SetupSplElf()
Simon Glass4f443042016-11-25 20:15:52 -07001111 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001112 self._DoTestFile('025_pack_zero_size.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001113 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass4f443042016-11-25 20:15:52 -07001114 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1115 str(e.exception))
1116
1117 def testPackUbootDtb(self):
1118 """Test that a device tree can be added to U-Boot"""
Simon Glass741f2d62018-10-01 12:22:30 -06001119 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass4f443042016-11-25 20:15:52 -07001120 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001121
1122 def testPackX86RomNoSize(self):
1123 """Test that the end-at-4gb property requires a size property"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001124 self._SetupSplElf()
Simon Glasse0ff8552016-11-25 20:15:53 -07001125 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001126 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001127 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glasse0ff8552016-11-25 20:15:53 -07001128 "using end-at-4gb", str(e.exception))
1129
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301130 def test4gbAndSkipAtStartTogether(self):
1131 """Test that the end-at-4gb and skip-at-size property can't be used
1132 together"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001133 self._SetupSplElf()
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301134 with self.assertRaises(ValueError) as e:
Simon Glassdfdd2b62019-08-24 07:23:02 -06001135 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass8beb11e2019-07-08 14:25:47 -06001136 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya94b57db2018-09-03 21:35:07 +05301137 "'skip-at-start'", str(e.exception))
1138
Simon Glasse0ff8552016-11-25 20:15:53 -07001139 def testPackX86RomOutside(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001140 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001141 self._SetupSplElf()
Simon Glasse0ff8552016-11-25 20:15:53 -07001142 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001143 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glasse6bed4f2020-10-26 17:40:05 -06001144 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1145 "is outside the section '/binman' starting at "
1146 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glasse0ff8552016-11-25 20:15:53 -07001147 str(e.exception))
1148
1149 def testPackX86Rom(self):
1150 """Test that a basic x86 ROM can be created"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001151 self._SetupSplElf()
Simon Glass9255f3c2019-08-24 07:23:01 -06001152 data = self._DoReadFile('029_x86_rom.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001153 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1154 tools.get_bytes(0, 2), data)
Simon Glasse0ff8552016-11-25 20:15:53 -07001155
1156 def testPackX86RomMeNoDesc(self):
1157 """Test that an invalid Intel descriptor entry is detected"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001158 try:
Simon Glass52b10dd2020-07-25 15:11:19 -06001159 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001160 with self.assertRaises(ValueError) as e:
Simon Glass52b10dd2020-07-25 15:11:19 -06001161 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glass0ba4b3d2020-07-09 18:39:41 -06001162 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1163 str(e.exception))
1164 finally:
1165 self._SetupDescriptor()
Simon Glasse0ff8552016-11-25 20:15:53 -07001166
1167 def testPackX86RomBadDesc(self):
1168 """Test that the Intel requires a descriptor entry"""
1169 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06001170 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glass3ab95982018-08-01 15:22:37 -06001171 self.assertIn("Node '/binman/intel-me': No offset set with "
1172 "offset-unset: should another entry provide this correct "
1173 "offset?", str(e.exception))
Simon Glasse0ff8552016-11-25 20:15:53 -07001174
1175 def testPackX86RomMe(self):
1176 """Test that an x86 ROM with an ME region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001177 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001178 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06001179 if data[:0x1000] != expected_desc:
1180 self.fail('Expected descriptor binary at start of image')
Simon Glasse0ff8552016-11-25 20:15:53 -07001181 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1182
1183 def testPackVga(self):
1184 """Test that an image with a VGA binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001185 data = self._DoReadFile('032_intel_vga.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001186 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1187
1188 def testPackStart16(self):
1189 """Test that an image with an x86 start16 region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001190 data = self._DoReadFile('033_x86_start16.dts')
Simon Glasse0ff8552016-11-25 20:15:53 -07001191 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1192
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301193 def testPackPowerpcMpc85xxBootpgResetvec(self):
1194 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1195 created"""
Simon Glassdfdd2b62019-08-24 07:23:02 -06001196 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya9d368f32018-09-03 21:35:08 +05301197 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1198
Simon Glass736bb0a2018-07-06 10:27:17 -06001199 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glassadc57012018-07-06 10:27:16 -06001200 """Handle running a test for insertion of microcode
1201
1202 Args:
1203 dts_fname: Name of test .dts file
1204 nodtb_data: Data that we expect in the first section
Simon Glass736bb0a2018-07-06 10:27:17 -06001205 ucode_second: True if the microsecond entry is second instead of
1206 third
Simon Glassadc57012018-07-06 10:27:16 -06001207
1208 Returns:
1209 Tuple:
1210 Contents of first region (U-Boot or SPL)
Simon Glass3ab95982018-08-01 15:22:37 -06001211 Offset and size components of microcode pointer, as inserted
Simon Glassadc57012018-07-06 10:27:16 -06001212 in the above (two 4-byte words)
1213 """
Simon Glass6b187df2017-11-12 21:52:27 -07001214 data = self._DoReadFile(dts_fname, True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001215
1216 # Now check the device tree has no microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001217 if ucode_second:
1218 ucode_content = data[len(nodtb_data):]
1219 ucode_pos = len(nodtb_data)
1220 dtb_with_ucode = ucode_content[16:]
1221 fdt_len = self.GetFdtLen(dtb_with_ucode)
1222 else:
1223 dtb_with_ucode = data[len(nodtb_data):]
1224 fdt_len = self.GetFdtLen(dtb_with_ucode)
1225 ucode_content = dtb_with_ucode[fdt_len:]
1226 ucode_pos = len(nodtb_data) + fdt_len
Simon Glassc1aa66e2022-01-29 14:14:04 -07001227 fname = tools.get_output_filename('test.dtb')
Simon Glasse0ff8552016-11-25 20:15:53 -07001228 with open(fname, 'wb') as fd:
Simon Glassadc57012018-07-06 10:27:16 -06001229 fd.write(dtb_with_ucode)
Simon Glassec3f3782017-05-27 07:38:29 -06001230 dtb = fdt.FdtScan(fname)
1231 ucode = dtb.GetNode('/microcode')
Simon Glasse0ff8552016-11-25 20:15:53 -07001232 self.assertTrue(ucode)
1233 for node in ucode.subnodes:
1234 self.assertFalse(node.props.get('data'))
1235
Simon Glasse0ff8552016-11-25 20:15:53 -07001236 # Check that the microcode appears immediately after the Fdt
1237 # This matches the concatenation of the data properties in
Simon Glass87722132017-11-12 21:52:26 -07001238 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glasse0ff8552016-11-25 20:15:53 -07001239 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1240 0x78235609)
Simon Glassadc57012018-07-06 10:27:16 -06001241 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glasse0ff8552016-11-25 20:15:53 -07001242
1243 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001244 # expected offset and size
Simon Glasse0ff8552016-11-25 20:15:53 -07001245 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1246 len(ucode_data))
Simon Glass736bb0a2018-07-06 10:27:17 -06001247 u_boot = data[:len(nodtb_data)]
1248 return u_boot, pos_and_size
Simon Glass6b187df2017-11-12 21:52:27 -07001249
1250 def testPackUbootMicrocode(self):
1251 """Test that x86 microcode can be handled correctly
1252
1253 We expect to see the following in the image, in order:
1254 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1255 place
1256 u-boot.dtb with the microcode removed
1257 the microcode
1258 """
Simon Glass741f2d62018-10-01 12:22:30 -06001259 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass6b187df2017-11-12 21:52:27 -07001260 U_BOOT_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06001261 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1262 b' somewhere in here', first)
Simon Glasse0ff8552016-11-25 20:15:53 -07001263
Simon Glass160a7662017-05-27 07:38:26 -06001264 def _RunPackUbootSingleMicrocode(self):
Simon Glasse0ff8552016-11-25 20:15:53 -07001265 """Test that x86 microcode can be handled correctly
1266
1267 We expect to see the following in the image, in order:
1268 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1269 place
1270 u-boot.dtb with the microcode
1271 an empty microcode region
1272 """
1273 # We need the libfdt library to run this test since only that allows
1274 # finding the offset of a property. This is required by
1275 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass741f2d62018-10-01 12:22:30 -06001276 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glasse0ff8552016-11-25 20:15:53 -07001277
1278 second = data[len(U_BOOT_NODTB_DATA):]
1279
1280 fdt_len = self.GetFdtLen(second)
1281 third = second[fdt_len:]
1282 second = second[:fdt_len]
1283
Simon Glass160a7662017-05-27 07:38:26 -06001284 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1285 self.assertIn(ucode_data, second)
1286 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glasse0ff8552016-11-25 20:15:53 -07001287
Simon Glass160a7662017-05-27 07:38:26 -06001288 # Check that the microcode pointer was inserted. It should match the
Simon Glass3ab95982018-08-01 15:22:37 -06001289 # expected offset and size
Simon Glass160a7662017-05-27 07:38:26 -06001290 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1291 len(ucode_data))
1292 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glassc6c10e72019-05-17 22:00:46 -06001293 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1294 b' somewhere in here', first)
Simon Glassc49deb82016-11-25 20:15:54 -07001295
Simon Glass75db0862016-11-25 20:15:55 -07001296 def testPackUbootSingleMicrocode(self):
1297 """Test that x86 microcode can be handled correctly with fdt_normal.
1298 """
Simon Glass160a7662017-05-27 07:38:26 -06001299 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001300
Simon Glassc49deb82016-11-25 20:15:54 -07001301 def testUBootImg(self):
1302 """Test that u-boot.img can be put in a file"""
Simon Glass741f2d62018-10-01 12:22:30 -06001303 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glassc49deb82016-11-25 20:15:54 -07001304 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glass75db0862016-11-25 20:15:55 -07001305
1306 def testNoMicrocode(self):
1307 """Test that a missing microcode region is detected"""
1308 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001309 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001310 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1311 "node found in ", str(e.exception))
1312
1313 def testMicrocodeWithoutNode(self):
1314 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1315 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001316 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001317 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1318 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1319
1320 def testMicrocodeWithoutNode2(self):
1321 """Test that a missing u-boot-ucode node is detected"""
1322 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001323 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001324 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1325 "microcode region u-boot-ucode", str(e.exception))
1326
1327 def testMicrocodeWithoutPtrInElf(self):
1328 """Test that a U-Boot binary without the microcode symbol is detected"""
1329 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glass75db0862016-11-25 20:15:55 -07001330 try:
Simon Glassbccd91d2019-08-24 07:22:55 -06001331 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001332 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001333
1334 with self.assertRaises(ValueError) as e:
Simon Glass160a7662017-05-27 07:38:26 -06001335 self._RunPackUbootSingleMicrocode()
Simon Glass75db0862016-11-25 20:15:55 -07001336 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1337 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1338
1339 finally:
1340 # Put the original file back
Simon Glassf514d8f2019-08-24 07:22:54 -06001341 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001342 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass75db0862016-11-25 20:15:55 -07001343
1344 def testMicrocodeNotInImage(self):
1345 """Test that microcode must be placed within the image"""
1346 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001347 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001348 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1349 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glass25ac0e62018-06-01 09:38:14 -06001350 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glass75db0862016-11-25 20:15:55 -07001351
1352 def testWithoutMicrocode(self):
1353 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassbccd91d2019-08-24 07:22:55 -06001354 TestFunctional._MakeInputFile('u-boot',
Simon Glassc1aa66e2022-01-29 14:14:04 -07001355 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass741f2d62018-10-01 12:22:30 -06001356 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glass75db0862016-11-25 20:15:55 -07001357
1358 # Now check the device tree has no microcode
1359 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1360 second = data[len(U_BOOT_NODTB_DATA):]
1361
1362 fdt_len = self.GetFdtLen(second)
1363 self.assertEqual(dtb, second[:fdt_len])
1364
1365 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1366 third = data[used_len:]
Simon Glassc1aa66e2022-01-29 14:14:04 -07001367 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glass75db0862016-11-25 20:15:55 -07001368
1369 def testUnknownPosSize(self):
1370 """Test that microcode must be placed within the image"""
1371 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001372 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glass3ab95982018-08-01 15:22:37 -06001373 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glass75db0862016-11-25 20:15:55 -07001374 "entry 'invalid-entry'", str(e.exception))
Simon Glassda229092016-11-25 20:15:56 -07001375
1376 def testPackFsp(self):
1377 """Test that an image with a FSP binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001378 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassda229092016-11-25 20:15:56 -07001379 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1380
1381 def testPackCmc(self):
Bin Meng59ea8c22017-08-15 22:41:54 -07001382 """Test that an image with a CMC binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001383 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassda229092016-11-25 20:15:56 -07001384 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Meng59ea8c22017-08-15 22:41:54 -07001385
1386 def testPackVbt(self):
1387 """Test that an image with a VBT binary can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001388 data = self._DoReadFile('046_intel_vbt.dts')
Bin Meng59ea8c22017-08-15 22:41:54 -07001389 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glass9fc60b42017-11-12 21:52:22 -07001390
Simon Glass56509842017-11-12 21:52:25 -07001391 def testSplBssPad(self):
1392 """Test that we can pad SPL's BSS with zeros"""
Simon Glass6b187df2017-11-12 21:52:27 -07001393 # ELF file with a '__bss_size' symbol
Simon Glass11ae93e2018-10-01 21:12:47 -06001394 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001395 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001396 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glasse6d85ff2019-05-14 15:53:47 -06001397 data)
Simon Glass56509842017-11-12 21:52:25 -07001398
Simon Glass86af5112018-10-01 21:12:42 -06001399 def testSplBssPadMissing(self):
1400 """Test that a missing symbol is detected"""
Simon Glass11ae93e2018-10-01 21:12:47 -06001401 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -07001402 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001403 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glassb50e5612017-11-13 18:54:54 -07001404 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1405 str(e.exception))
1406
Simon Glass87722132017-11-12 21:52:26 -07001407 def testPackStart16Spl(self):
Simon Glass35b384c2018-09-14 04:57:10 -06001408 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001409 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glass87722132017-11-12 21:52:26 -07001410 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1411
Simon Glass736bb0a2018-07-06 10:27:17 -06001412 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1413 """Helper function for microcode tests
Simon Glass6b187df2017-11-12 21:52:27 -07001414
1415 We expect to see the following in the image, in order:
1416 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1417 correct place
1418 u-boot.dtb with the microcode removed
1419 the microcode
Simon Glass736bb0a2018-07-06 10:27:17 -06001420
1421 Args:
1422 dts: Device tree file to use for test
1423 ucode_second: True if the microsecond entry is second instead of
1424 third
Simon Glass6b187df2017-11-12 21:52:27 -07001425 """
Simon Glass11ae93e2018-10-01 21:12:47 -06001426 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass736bb0a2018-07-06 10:27:17 -06001427 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1428 ucode_second=ucode_second)
Simon Glassc6c10e72019-05-17 22:00:46 -06001429 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1430 b'ter somewhere in here', first)
Simon Glass6b187df2017-11-12 21:52:27 -07001431
Simon Glass736bb0a2018-07-06 10:27:17 -06001432 def testPackUbootSplMicrocode(self):
1433 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001434 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001435 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass736bb0a2018-07-06 10:27:17 -06001436
1437 def testPackUbootSplMicrocodeReorder(self):
1438 """Test that order doesn't matter for microcode entries
1439
1440 This is the same as testPackUbootSplMicrocode but when we process the
1441 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1442 entry, so we reply on binman to try later.
1443 """
Simon Glass741f2d62018-10-01 12:22:30 -06001444 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass736bb0a2018-07-06 10:27:17 -06001445 ucode_second=True)
1446
Simon Glassca4f4ff2017-11-12 21:52:28 -07001447 def testPackMrc(self):
1448 """Test that an image with an MRC binary can be created"""
Simon Glass741f2d62018-10-01 12:22:30 -06001449 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassca4f4ff2017-11-12 21:52:28 -07001450 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1451
Simon Glass47419ea2017-11-13 18:54:55 -07001452 def testSplDtb(self):
1453 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001454 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001455 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass47419ea2017-11-13 18:54:55 -07001456 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1457
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001458 def testSplNoDtb(self):
1459 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12001460 self._SetupSplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001461 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass4e6fdbe2017-11-13 18:54:56 -07001462 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1463
Simon Glass3d433382021-03-21 18:24:30 +13001464 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4649bea2023-07-18 07:23:54 -06001465 use_expanded=False, no_write_symbols=False):
Simon Glassf5898822021-03-18 20:24:56 +13001466 """Check the image contains the expected symbol values
1467
1468 Args:
1469 dts: Device tree file to use for test
1470 base_data: Data before and after 'u-boot' section
1471 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass3d433382021-03-21 18:24:30 +13001472 entry_args: Dict of entry args to supply to binman
1473 key: arg name
1474 value: value of that arg
1475 use_expanded: True to use expanded entries where available, e.g.
1476 'u-boot-expanded' instead of 'u-boot'
Simon Glassf5898822021-03-18 20:24:56 +13001477 """
Simon Glass1542c8b2019-08-24 07:22:56 -06001478 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass19790632017-11-13 18:55:01 -07001479 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1480 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001481 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glassf5898822021-03-18 20:24:56 +13001482 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001483 addr + 4)
Simon Glass19790632017-11-13 18:55:01 -07001484
Simon Glass11ae93e2018-10-01 21:12:47 -06001485 self._SetupSplElf('u_boot_binman_syms')
Simon Glass3d433382021-03-21 18:24:30 +13001486 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1487 use_expanded=use_expanded)[0]
Simon Glassf5898822021-03-18 20:24:56 +13001488 # The image should contain the symbols from u_boot_binman_syms.c
1489 # Note that image_pos is adjusted by the base address of the image,
1490 # which is 0x10 in our test image
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001491 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1492 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glassf5898822021-03-18 20:24:56 +13001493 0x10 + u_boot_offset, 0x04)
Simon Glass4649bea2023-07-18 07:23:54 -06001494 if no_write_symbols:
1495 expected = (base_data +
1496 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1497 U_BOOT_DATA + base_data)
1498 else:
1499 expected = (sym_values + base_data[24:] +
1500 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1501 base_data[24:])
Simon Glass19790632017-11-13 18:55:01 -07001502 self.assertEqual(expected, data)
1503
Simon Glassf5898822021-03-18 20:24:56 +13001504 def testSymbols(self):
1505 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03001506 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassf5898822021-03-18 20:24:56 +13001507
1508 def testSymbolsNoDtb(self):
1509 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glasse9e0db82021-03-21 18:24:29 +13001510 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glassf5898822021-03-18 20:24:56 +13001511 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1512 0x38)
1513
Simon Glassdd57c132018-06-01 09:38:11 -06001514 def testPackUnitAddress(self):
1515 """Test that we support multiple binaries with the same name"""
Simon Glass741f2d62018-10-01 12:22:30 -06001516 data = self._DoReadFile('054_unit_address.dts')
Simon Glassdd57c132018-06-01 09:38:11 -06001517 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1518
Simon Glass18546952018-06-01 09:38:16 -06001519 def testSections(self):
1520 """Basic test of sections"""
Simon Glass741f2d62018-10-01 12:22:30 -06001521 data = self._DoReadFile('055_sections.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001522 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1523 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1524 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass18546952018-06-01 09:38:16 -06001525 self.assertEqual(expected, data)
Simon Glass9fc60b42017-11-12 21:52:22 -07001526
Simon Glass3b0c3822018-06-01 09:38:20 -06001527 def testMap(self):
1528 """Tests outputting a map of the images"""
Simon Glass741f2d62018-10-01 12:22:30 -06001529 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001530 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700153100000000 00000000 00000028 image
Simon Glass1be70d22018-07-17 13:25:49 -0600153200000000 00000000 00000010 section@0
153300000000 00000000 00000004 u-boot
153400000010 00000010 00000010 section@1
153500000010 00000000 00000004 u-boot
153600000020 00000020 00000004 section@2
153700000020 00000000 00000004 u-boot
Simon Glass3b0c3822018-06-01 09:38:20 -06001538''', map_data)
1539
Simon Glassc8d48ef2018-06-01 09:38:21 -06001540 def testNamePrefix(self):
1541 """Tests that name prefixes are used"""
Simon Glass741f2d62018-10-01 12:22:30 -06001542 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass1be70d22018-07-17 13:25:49 -06001543 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700154400000000 00000000 00000028 image
Simon Glass1be70d22018-07-17 13:25:49 -0600154500000000 00000000 00000010 section@0
154600000000 00000000 00000004 ro-u-boot
154700000010 00000010 00000010 section@1
154800000010 00000000 00000004 rw-u-boot
Simon Glassc8d48ef2018-06-01 09:38:21 -06001549''', map_data)
1550
Simon Glass736bb0a2018-07-06 10:27:17 -06001551 def testUnknownContents(self):
1552 """Test that obtaining the contents works as expected"""
1553 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001554 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass8beb11e2019-07-08 14:25:47 -06001555 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glass16287932020-04-17 18:09:03 -06001556 "processing of contents: remaining ["
1557 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass736bb0a2018-07-06 10:27:17 -06001558
Simon Glass5c890232018-07-06 10:27:19 -06001559 def testBadChangeSize(self):
1560 """Test that trying to change the size of an entry fails"""
Simon Glassc52c9e72019-07-08 14:25:37 -06001561 try:
1562 state.SetAllowEntryExpansion(False)
1563 with self.assertRaises(ValueError) as e:
1564 self._DoReadFile('059_change_size.dts', True)
Simon Glass79d3c582019-07-20 12:23:57 -06001565 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glassc52c9e72019-07-08 14:25:37 -06001566 str(e.exception))
1567 finally:
1568 state.SetAllowEntryExpansion(True)
Simon Glass5c890232018-07-06 10:27:19 -06001569
Simon Glass16b8d6b2018-07-06 10:27:42 -06001570 def testUpdateFdt(self):
Simon Glass3ab95982018-08-01 15:22:37 -06001571 """Test that we can update the device tree with offset/size info"""
Simon Glass741f2d62018-10-01 12:22:30 -06001572 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glass16b8d6b2018-07-06 10:27:42 -06001573 update_dtb=True)
Simon Glasscee02e62018-07-17 13:25:52 -06001574 dtb = fdt.Fdt(out_dtb_fname)
1575 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06001576 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001577 self.assertEqual({
Simon Glassdbf6be92018-08-01 15:22:42 -06001578 'image-pos': 0,
Simon Glass8122f392018-07-17 13:25:28 -06001579 'offset': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001580 '_testing:offset': 32,
Simon Glass79d3c582019-07-20 12:23:57 -06001581 '_testing:size': 2,
Simon Glassdbf6be92018-08-01 15:22:42 -06001582 '_testing:image-pos': 32,
Simon Glass3ab95982018-08-01 15:22:37 -06001583 'section@0/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001584 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001585 'section@0/u-boot:image-pos': 0,
Simon Glass3ab95982018-08-01 15:22:37 -06001586 'section@0:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001587 'section@0:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001588 'section@0:image-pos': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001589
Simon Glass3ab95982018-08-01 15:22:37 -06001590 'section@1/u-boot:offset': 0,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001591 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glassdbf6be92018-08-01 15:22:42 -06001592 'section@1/u-boot:image-pos': 16,
Simon Glass3ab95982018-08-01 15:22:37 -06001593 'section@1:offset': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001594 'section@1:size': 16,
Simon Glassdbf6be92018-08-01 15:22:42 -06001595 'section@1:image-pos': 16,
Simon Glass16b8d6b2018-07-06 10:27:42 -06001596 'size': 40
1597 }, props)
1598
1599 def testUpdateFdtBad(self):
1600 """Test that we detect when ProcessFdt never completes"""
1601 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001602 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glass16b8d6b2018-07-06 10:27:42 -06001603 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glass16287932020-04-17 18:09:03 -06001604 '[<binman.etype._testing.Entry__testing',
1605 str(e.exception))
Simon Glass5c890232018-07-06 10:27:19 -06001606
Simon Glass53af22a2018-07-17 13:25:32 -06001607 def testEntryArgs(self):
1608 """Test passing arguments to entries from the command line"""
1609 entry_args = {
1610 'test-str-arg': 'test1',
1611 'test-int-arg': '456',
1612 }
Simon Glass741f2d62018-10-01 12:22:30 -06001613 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001614 self.assertIn('image', control.images)
1615 entry = control.images['image'].GetEntries()['_testing']
1616 self.assertEqual('test0', entry.test_str_fdt)
1617 self.assertEqual('test1', entry.test_str_arg)
1618 self.assertEqual(123, entry.test_int_fdt)
1619 self.assertEqual(456, entry.test_int_arg)
1620
1621 def testEntryArgsMissing(self):
1622 """Test missing arguments and properties"""
1623 entry_args = {
1624 'test-int-arg': '456',
1625 }
Simon Glass741f2d62018-10-01 12:22:30 -06001626 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001627 entry = control.images['image'].GetEntries()['_testing']
1628 self.assertEqual('test0', entry.test_str_fdt)
1629 self.assertEqual(None, entry.test_str_arg)
1630 self.assertEqual(None, entry.test_int_fdt)
1631 self.assertEqual(456, entry.test_int_arg)
1632
1633 def testEntryArgsRequired(self):
1634 """Test missing arguments and properties"""
1635 entry_args = {
1636 'test-int-arg': '456',
1637 }
1638 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001639 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass3decfa32020-09-01 05:13:54 -06001640 self.assertIn("Node '/binman/_testing': "
1641 'Missing required properties/entry args: test-str-arg, '
1642 'test-int-fdt, test-int-arg',
Simon Glass53af22a2018-07-17 13:25:32 -06001643 str(e.exception))
1644
1645 def testEntryArgsInvalidFormat(self):
1646 """Test that an invalid entry-argument format is detected"""
Simon Glass53cd5d92019-07-08 14:25:29 -06001647 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1648 '-ano-value']
Simon Glass53af22a2018-07-17 13:25:32 -06001649 with self.assertRaises(ValueError) as e:
1650 self._DoBinman(*args)
1651 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1652
1653 def testEntryArgsInvalidInteger(self):
1654 """Test that an invalid entry-argument integer is detected"""
1655 entry_args = {
1656 'test-int-arg': 'abc',
1657 }
1658 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001659 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass53af22a2018-07-17 13:25:32 -06001660 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1661 "'test-int-arg' (value 'abc') to integer",
1662 str(e.exception))
1663
1664 def testEntryArgsInvalidDatatype(self):
1665 """Test that an invalid entry-argument datatype is detected
1666
1667 This test could be written in entry_test.py except that it needs
1668 access to control.entry_args, which seems more than that module should
1669 be able to see.
1670 """
1671 entry_args = {
1672 'test-bad-datatype-arg': '12',
1673 }
1674 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001675 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass53af22a2018-07-17 13:25:32 -06001676 entry_args=entry_args)
1677 self.assertIn('GetArg() internal error: Unknown data type ',
1678 str(e.exception))
1679
Simon Glassbb748372018-07-17 13:25:33 -06001680 def testText(self):
1681 """Test for a text entry type"""
1682 entry_args = {
1683 'test-id': TEXT_DATA,
1684 'test-id2': TEXT_DATA2,
1685 'test-id3': TEXT_DATA3,
1686 }
Simon Glass741f2d62018-10-01 12:22:30 -06001687 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glassbb748372018-07-17 13:25:33 -06001688 entry_args=entry_args)
Simon Glassc1aa66e2022-01-29 14:14:04 -07001689 expected = (tools.to_bytes(TEXT_DATA) +
1690 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1691 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glassaa88b502019-07-08 13:18:40 -06001692 b'some text' + b'more text')
Simon Glassbb748372018-07-17 13:25:33 -06001693 self.assertEqual(expected, data)
1694
Simon Glassfd8d1f72018-07-17 13:25:36 -06001695 def testEntryDocs(self):
1696 """Test for creation of entry documentation"""
1697 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001698 control.WriteEntryDocs(control.GetEntryModules())
Simon Glassfd8d1f72018-07-17 13:25:36 -06001699 self.assertTrue(len(stdout.getvalue()) > 0)
1700
1701 def testEntryDocsMissing(self):
1702 """Test handling of missing entry documentation"""
1703 with self.assertRaises(ValueError) as e:
1704 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass87d43322020-08-05 13:27:46 -06001705 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glassfd8d1f72018-07-17 13:25:36 -06001706 self.assertIn('Documentation is missing for modules: u_boot',
1707 str(e.exception))
1708
Simon Glass11e36cc2018-07-17 13:25:38 -06001709 def testFmap(self):
1710 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06001711 data = self._DoReadFile('067_fmap.dts')
Simon Glass11e36cc2018-07-17 13:25:38 -06001712 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07001713 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1714 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass11e36cc2018-07-17 13:25:38 -06001715 self.assertEqual(expected, data[:32])
Simon Glassc6c10e72019-05-17 22:00:46 -06001716 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass11e36cc2018-07-17 13:25:38 -06001717 self.assertEqual(1, fhdr.ver_major)
1718 self.assertEqual(0, fhdr.ver_minor)
1719 self.assertEqual(0, fhdr.base)
Simon Glass17365752021-04-03 11:05:10 +13001720 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glassc7722e82021-04-03 11:05:09 +13001721 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glassc6c10e72019-05-17 22:00:46 -06001722 self.assertEqual(b'FMAP', fhdr.name)
Simon Glass17365752021-04-03 11:05:10 +13001723 self.assertEqual(5, fhdr.nareas)
Simon Glassc7722e82021-04-03 11:05:09 +13001724 fiter = iter(fentries)
Simon Glass11e36cc2018-07-17 13:25:38 -06001725
Simon Glassc7722e82021-04-03 11:05:09 +13001726 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001727 self.assertEqual(b'SECTION0', fentry.name)
1728 self.assertEqual(0, fentry.offset)
1729 self.assertEqual(16, fentry.size)
Simon Glass9dbb02b2023-02-12 17:11:15 -07001730 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glass17365752021-04-03 11:05:10 +13001731
1732 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001733 self.assertEqual(b'RO_U_BOOT', fentry.name)
1734 self.assertEqual(0, fentry.offset)
1735 self.assertEqual(4, fentry.size)
1736 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001737
Simon Glassc7722e82021-04-03 11:05:09 +13001738 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13001739 self.assertEqual(b'SECTION1', fentry.name)
1740 self.assertEqual(16, fentry.offset)
1741 self.assertEqual(16, fentry.size)
1742 self.assertEqual(0, fentry.flags)
1743
1744 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13001745 self.assertEqual(b'RW_U_BOOT', fentry.name)
1746 self.assertEqual(16, fentry.offset)
1747 self.assertEqual(4, fentry.size)
1748 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001749
Simon Glassc7722e82021-04-03 11:05:09 +13001750 fentry = next(fiter)
1751 self.assertEqual(b'FMAP', fentry.name)
1752 self.assertEqual(32, fentry.offset)
1753 self.assertEqual(expect_size, fentry.size)
1754 self.assertEqual(0, fentry.flags)
Simon Glass11e36cc2018-07-17 13:25:38 -06001755
Simon Glassec127af2018-07-17 13:25:39 -06001756 def testBlobNamedByArg(self):
1757 """Test we can add a blob with the filename coming from an entry arg"""
1758 entry_args = {
1759 'cros-ec-rw-path': 'ecrw.bin',
1760 }
Simon Glass3decfa32020-09-01 05:13:54 -06001761 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassec127af2018-07-17 13:25:39 -06001762
Simon Glass3af8e492018-07-17 13:25:40 -06001763 def testFill(self):
1764 """Test for an fill entry type"""
Simon Glass741f2d62018-10-01 12:22:30 -06001765 data = self._DoReadFile('069_fill.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001766 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass3af8e492018-07-17 13:25:40 -06001767 self.assertEqual(expected, data)
1768
1769 def testFillNoSize(self):
1770 """Test for an fill entry type with no size"""
1771 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001772 self._DoReadFile('070_fill_no_size.dts')
Simon Glasscdadada2022-08-13 11:40:44 -06001773 self.assertIn("'fill' entry is missing properties: size",
Simon Glass3af8e492018-07-17 13:25:40 -06001774 str(e.exception))
1775
Simon Glass0ef87aa2018-07-17 13:25:44 -06001776 def _HandleGbbCommand(self, pipe_list):
1777 """Fake calls to the futility utility"""
Simon Glassfe7e9242023-02-22 12:14:49 -07001778 if 'futility' in pipe_list[0][0]:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001779 fname = pipe_list[0][-1]
1780 # Append our GBB data to the file, which will happen every time the
1781 # futility command is called.
Simon Glass1d0ebf72019-05-14 15:53:42 -06001782 with open(fname, 'ab') as fd:
Simon Glass0ef87aa2018-07-17 13:25:44 -06001783 fd.write(GBB_DATA)
1784 return command.CommandResult()
1785
1786 def testGbb(self):
1787 """Test for the Chromium OS Google Binary Block"""
1788 command.test_result = self._HandleGbbCommand
1789 entry_args = {
1790 'keydir': 'devkeys',
1791 'bmpblk': 'bmpblk.bin',
1792 }
Simon Glass741f2d62018-10-01 12:22:30 -06001793 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glass0ef87aa2018-07-17 13:25:44 -06001794
1795 # Since futility
Simon Glassc1aa66e2022-01-29 14:14:04 -07001796 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1797 tools.get_bytes(0, 0x2180 - 16))
Simon Glass0ef87aa2018-07-17 13:25:44 -06001798 self.assertEqual(expected, data)
1799
1800 def testGbbTooSmall(self):
1801 """Test for the Chromium OS Google Binary Block being large enough"""
1802 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001803 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001804 self.assertIn("Node '/binman/gbb': GBB is too small",
1805 str(e.exception))
1806
1807 def testGbbNoSize(self):
1808 """Test for the Chromium OS Google Binary Block having a size"""
1809 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001810 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glass0ef87aa2018-07-17 13:25:44 -06001811 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1812 str(e.exception))
1813
Simon Glass4f9ee832022-01-09 20:14:09 -07001814 def testGbbMissing(self):
1815 """Test that binman still produces an image if futility is missing"""
1816 entry_args = {
1817 'keydir': 'devkeys',
1818 }
1819 with test_util.capture_sys_output() as (_, stderr):
1820 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1821 entry_args=entry_args)
1822 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07001823 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass4f9ee832022-01-09 20:14:09 -07001824
Simon Glass24d0d3c2018-07-17 13:25:47 -06001825 def _HandleVblockCommand(self, pipe_list):
Simon Glass5af9ebc2021-01-06 21:35:17 -07001826 """Fake calls to the futility utility
1827
1828 The expected pipe is:
1829
1830 [('futility', 'vbutil_firmware', '--vblock',
1831 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1832 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1833 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1834 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1835
1836 This writes to the output file (here, 'vblock.vblock'). If
1837 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1838 of the input data (here, 'input.vblock').
1839 """
Simon Glassfe7e9242023-02-22 12:14:49 -07001840 if 'futility' in pipe_list[0][0]:
Simon Glass24d0d3c2018-07-17 13:25:47 -06001841 fname = pipe_list[0][3]
Simon Glassa326b492018-09-14 04:57:11 -06001842 with open(fname, 'wb') as fd:
Simon Glass5af9ebc2021-01-06 21:35:17 -07001843 if self._hash_data:
1844 infile = pipe_list[0][11]
1845 m = hashlib.sha256()
Simon Glassc1aa66e2022-01-29 14:14:04 -07001846 data = tools.read_file(infile)
Simon Glass5af9ebc2021-01-06 21:35:17 -07001847 m.update(data)
1848 fd.write(m.digest())
1849 else:
1850 fd.write(VBLOCK_DATA)
1851
Simon Glass24d0d3c2018-07-17 13:25:47 -06001852 return command.CommandResult()
1853
1854 def testVblock(self):
1855 """Test for the Chromium OS Verified Boot Block"""
Simon Glass5af9ebc2021-01-06 21:35:17 -07001856 self._hash_data = False
Simon Glass24d0d3c2018-07-17 13:25:47 -06001857 command.test_result = self._HandleVblockCommand
1858 entry_args = {
1859 'keydir': 'devkeys',
1860 }
Simon Glass741f2d62018-10-01 12:22:30 -06001861 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass24d0d3c2018-07-17 13:25:47 -06001862 entry_args=entry_args)
1863 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1864 self.assertEqual(expected, data)
1865
1866 def testVblockNoContent(self):
1867 """Test we detect a vblock which has no content to sign"""
1868 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001869 self._DoReadFile('075_vblock_no_content.dts')
Simon Glass189f2912021-03-21 18:24:31 +13001870 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass24d0d3c2018-07-17 13:25:47 -06001871 'property', str(e.exception))
1872
1873 def testVblockBadPhandle(self):
1874 """Test that we detect a vblock with an invalid phandle in contents"""
1875 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001876 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001877 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1878 '1000', str(e.exception))
1879
1880 def testVblockBadEntry(self):
1881 """Test that we detect an entry that points to a non-entry"""
1882 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001883 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass24d0d3c2018-07-17 13:25:47 -06001884 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1885 "'other'", str(e.exception))
1886
Simon Glass5af9ebc2021-01-06 21:35:17 -07001887 def testVblockContent(self):
1888 """Test that the vblock signs the right data"""
1889 self._hash_data = True
1890 command.test_result = self._HandleVblockCommand
1891 entry_args = {
1892 'keydir': 'devkeys',
1893 }
1894 data = self._DoReadFileDtb(
1895 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1896 entry_args=entry_args)[0]
1897 hashlen = 32 # SHA256 hash is 32 bytes
1898 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1899 hashval = data[-hashlen:]
1900 dtb = data[len(U_BOOT_DATA):-hashlen]
1901
1902 expected_data = U_BOOT_DATA + dtb
1903
1904 # The hashval should be a hash of the dtb
1905 m = hashlib.sha256()
1906 m.update(expected_data)
1907 expected_hashval = m.digest()
1908 self.assertEqual(expected_hashval, hashval)
1909
Simon Glass4f9ee832022-01-09 20:14:09 -07001910 def testVblockMissing(self):
1911 """Test that binman still produces an image if futility is missing"""
1912 entry_args = {
1913 'keydir': 'devkeys',
1914 }
1915 with test_util.capture_sys_output() as (_, stderr):
1916 self._DoTestFile('074_vblock.dts',
1917 force_missing_bintools='futility',
1918 entry_args=entry_args)
1919 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07001920 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass4f9ee832022-01-09 20:14:09 -07001921
Simon Glassb8ef5b62018-07-17 13:25:48 -06001922 def testTpl(self):
Simon Glass2090f1e2019-08-24 07:23:00 -06001923 """Test that an image with TPL and its device tree can be created"""
Simon Glassb8ef5b62018-07-17 13:25:48 -06001924 # ELF file with a '__bss_size' symbol
Simon Glass2090f1e2019-08-24 07:23:00 -06001925 self._SetupTplElf()
Simon Glass741f2d62018-10-01 12:22:30 -06001926 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glassb8ef5b62018-07-17 13:25:48 -06001927 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1928
Simon Glass15a587c2018-07-17 13:25:51 -06001929 def testUsesPos(self):
1930 """Test that the 'pos' property cannot be used anymore"""
1931 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001932 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass15a587c2018-07-17 13:25:51 -06001933 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1934 "'pos'", str(e.exception))
1935
Simon Glassd178eab2018-09-14 04:57:08 -06001936 def testFillZero(self):
1937 """Test for an fill entry type with a size of 0"""
Simon Glass741f2d62018-10-01 12:22:30 -06001938 data = self._DoReadFile('080_fill_empty.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07001939 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glassd178eab2018-09-14 04:57:08 -06001940
Simon Glass0b489362018-09-14 04:57:09 -06001941 def testTextMissing(self):
1942 """Test for a text entry type where there is no text"""
1943 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06001944 self._DoReadFileDtb('066_text.dts',)
Simon Glass0b489362018-09-14 04:57:09 -06001945 self.assertIn("Node '/binman/text': No value provided for text label "
1946 "'test-id'", str(e.exception))
1947
Simon Glass35b384c2018-09-14 04:57:10 -06001948 def testPackStart16Tpl(self):
1949 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass9255f3c2019-08-24 07:23:01 -06001950 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glass35b384c2018-09-14 04:57:10 -06001951 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1952
Simon Glass0bfa7b02018-09-14 04:57:12 -06001953 def testSelectImage(self):
1954 """Test that we can select which images to build"""
Simon Glasseb833d82019-04-25 21:58:34 -06001955 expected = 'Skipping images: image1'
Simon Glass0bfa7b02018-09-14 04:57:12 -06001956
Simon Glasseb833d82019-04-25 21:58:34 -06001957 # We should only get the expected message in verbose mode
Simon Glassee0c9a72019-07-08 13:18:48 -06001958 for verbosity in (0, 2):
Simon Glasseb833d82019-04-25 21:58:34 -06001959 with test_util.capture_sys_output() as (stdout, stderr):
1960 retcode = self._DoTestFile('006_dual_image.dts',
1961 verbosity=verbosity,
1962 images=['image2'])
1963 self.assertEqual(0, retcode)
1964 if verbosity:
1965 self.assertIn(expected, stdout.getvalue())
1966 else:
1967 self.assertNotIn(expected, stdout.getvalue())
1968
Simon Glassc1aa66e2022-01-29 14:14:04 -07001969 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1970 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassf86a7362019-07-20 12:24:10 -06001971 self._CleanupOutputDir()
Simon Glass0bfa7b02018-09-14 04:57:12 -06001972
Simon Glass6ed45ba2018-09-14 04:57:24 -06001973 def testUpdateFdtAll(self):
1974 """Test that all device trees are updated with offset/size info"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06001975 self._SetupSplElf()
1976 self._SetupTplElf()
Simon Glass3c081312019-07-08 14:25:26 -06001977 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glass6ed45ba2018-09-14 04:57:24 -06001978
1979 base_expected = {
Simon Glass6ed45ba2018-09-14 04:57:24 -06001980 'offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07001981 'image-pos': 0,
1982 'size': 2320,
Simon Glass6ed45ba2018-09-14 04:57:24 -06001983 'section:offset': 0,
Simon Glass6ad24522022-02-28 07:16:54 -07001984 'section:image-pos': 0,
1985 'section:size': 565,
1986 'section/u-boot-dtb:offset': 0,
1987 'section/u-boot-dtb:image-pos': 0,
1988 'section/u-boot-dtb:size': 565,
1989 'u-boot-spl-dtb:offset': 565,
1990 'u-boot-spl-dtb:image-pos': 565,
1991 'u-boot-spl-dtb:size': 585,
1992 'u-boot-tpl-dtb:offset': 1150,
1993 'u-boot-tpl-dtb:image-pos': 1150,
1994 'u-boot-tpl-dtb:size': 585,
1995 'u-boot-vpl-dtb:image-pos': 1735,
1996 'u-boot-vpl-dtb:offset': 1735,
1997 'u-boot-vpl-dtb:size': 585,
Simon Glass6ed45ba2018-09-14 04:57:24 -06001998 }
1999
2000 # We expect three device-tree files in the output, one after the other.
2001 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2002 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2003 # main U-Boot tree. All three should have the same postions and offset.
2004 start = 0
Simon Glass6ad24522022-02-28 07:16:54 -07002005 self.maxDiff = None
2006 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06002007 dtb = fdt.Fdt.FromData(data[start:])
2008 dtb.Scan()
Simon Glass12bb1a92019-07-20 12:23:51 -06002009 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass6ad24522022-02-28 07:16:54 -07002010 ['spl', 'tpl', 'vpl'])
Simon Glass6ed45ba2018-09-14 04:57:24 -06002011 expected = dict(base_expected)
2012 if item:
2013 expected[item] = 0
2014 self.assertEqual(expected, props)
2015 start += dtb._fdt_obj.totalsize()
2016
2017 def testUpdateFdtOutput(self):
2018 """Test that output DTB files are updated"""
2019 try:
Simon Glass741f2d62018-10-01 12:22:30 -06002020 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glass6ed45ba2018-09-14 04:57:24 -06002021 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2022
2023 # Unfortunately, compiling a source file always results in a file
2024 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass741f2d62018-10-01 12:22:30 -06002025 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glass6ed45ba2018-09-14 04:57:24 -06002026 # binman as a file called u-boot.dtb. To fix this, copy the file
2027 # over to the expected place.
Simon Glass6ed45ba2018-09-14 04:57:24 -06002028 start = 0
2029 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass6ad24522022-02-28 07:16:54 -07002030 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glass6ed45ba2018-09-14 04:57:24 -06002031 dtb = fdt.Fdt.FromData(data[start:])
2032 size = dtb._fdt_obj.totalsize()
Simon Glassc1aa66e2022-01-29 14:14:04 -07002033 pathname = tools.get_output_filename(os.path.split(fname)[1])
2034 outdata = tools.read_file(pathname)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002035 name = os.path.split(fname)[0]
2036
2037 if name:
Simon Glass6ad24522022-02-28 07:16:54 -07002038 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glass6ed45ba2018-09-14 04:57:24 -06002039 else:
2040 orig_indata = dtb_data
2041 self.assertNotEqual(outdata, orig_indata,
2042 "Expected output file '%s' be updated" % pathname)
2043 self.assertEqual(outdata, data[start:start + size],
2044 "Expected output file '%s' to match output image" %
2045 pathname)
2046 start += size
2047 finally:
2048 self._ResetDtbs()
2049
Simon Glass83d73c22018-09-14 04:57:26 -06002050 def _decompress(self, data):
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002051 bintool = self.comp_bintools['lz4']
2052 return bintool.decompress(data)
Simon Glass83d73c22018-09-14 04:57:26 -06002053
2054 def testCompress(self):
2055 """Test compression of blobs"""
Simon Glassac62fba2019-07-08 13:18:53 -06002056 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002057 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass83d73c22018-09-14 04:57:26 -06002058 use_real_dtb=True, update_dtb=True)
2059 dtb = fdt.Fdt(out_dtb_fname)
2060 dtb.Scan()
2061 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2062 orig = self._decompress(data)
2063 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass97c3e9a2020-10-26 17:40:15 -06002064
2065 # Do a sanity check on various fields
2066 image = control.images['image']
2067 entries = image.GetEntries()
2068 self.assertEqual(1, len(entries))
2069
2070 entry = entries['blob']
2071 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2072 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2073 orig = self._decompress(entry.data)
2074 self.assertEqual(orig, entry.uncomp_data)
2075
Simon Glass63e7ba62020-10-26 17:40:16 -06002076 self.assertEqual(image.data, entry.data)
2077
Simon Glass83d73c22018-09-14 04:57:26 -06002078 expected = {
2079 'blob:uncomp-size': len(COMPRESS_DATA),
2080 'blob:size': len(data),
2081 'size': len(data),
2082 }
2083 self.assertEqual(expected, props)
2084
Simon Glass0a98b282018-09-14 04:57:28 -06002085 def testFiles(self):
2086 """Test bringing in multiple files"""
Simon Glass741f2d62018-10-01 12:22:30 -06002087 data = self._DoReadFile('084_files.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002088 self.assertEqual(FILES_DATA, data)
2089
2090 def testFilesCompress(self):
2091 """Test bringing in multiple files and compressing them"""
Simon Glassac62fba2019-07-08 13:18:53 -06002092 self._CheckLz4()
Simon Glass741f2d62018-10-01 12:22:30 -06002093 data = self._DoReadFile('085_files_compress.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002094
2095 image = control.images['image']
2096 entries = image.GetEntries()
2097 files = entries['files']
Simon Glass8beb11e2019-07-08 14:25:47 -06002098 entries = files._entries
Simon Glass0a98b282018-09-14 04:57:28 -06002099
Simon Glassc6c10e72019-05-17 22:00:46 -06002100 orig = b''
Simon Glass0a98b282018-09-14 04:57:28 -06002101 for i in range(1, 3):
2102 key = '%d.dat' % i
2103 start = entries[key].image_pos
2104 len = entries[key].size
2105 chunk = data[start:start + len]
2106 orig += self._decompress(chunk)
2107
2108 self.assertEqual(FILES_DATA, orig)
2109
2110 def testFilesMissing(self):
2111 """Test missing files"""
2112 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002113 data = self._DoReadFile('086_files_none.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002114 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2115 'no files', str(e.exception))
2116
2117 def testFilesNoPattern(self):
2118 """Test missing files"""
2119 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002120 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glass0a98b282018-09-14 04:57:28 -06002121 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2122 str(e.exception))
2123
Simon Glass80a66ae2022-03-05 20:18:59 -07002124 def testExtendSize(self):
2125 """Test an extending entry"""
2126 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassba64a0b2018-09-14 04:57:29 -06002127 map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002128 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2129 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2130 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2131 tools.get_bytes(ord('d'), 8))
Simon Glassba64a0b2018-09-14 04:57:29 -06002132 self.assertEqual(expect, data)
2133 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700213400000000 00000000 00000028 image
Simon Glassba64a0b2018-09-14 04:57:29 -0600213500000000 00000000 00000008 fill
213600000008 00000008 00000004 u-boot
21370000000c 0000000c 00000004 section
21380000000c 00000000 00000003 intel-mrc
213900000010 00000010 00000004 u-boot2
214000000014 00000014 0000000c section2
214100000014 00000000 00000008 fill
21420000001c 00000008 00000004 u-boot
214300000020 00000020 00000008 fill2
2144''', map_data)
2145
Simon Glass80a66ae2022-03-05 20:18:59 -07002146 def testExtendSizeBad(self):
2147 """Test an extending entry which fails to provide contents"""
Simon Glass163ed6c2018-09-14 04:57:36 -06002148 with test_util.capture_sys_output() as (stdout, stderr):
2149 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002150 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassba64a0b2018-09-14 04:57:29 -06002151 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2152 'expanding entry', str(e.exception))
2153
Simon Glasse0e5df92018-09-14 04:57:31 -06002154 def testHash(self):
2155 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002156 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002157 use_real_dtb=True, update_dtb=True)
2158 dtb = fdt.Fdt(out_dtb_fname)
2159 dtb.Scan()
2160 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2161 m = hashlib.sha256()
2162 m.update(U_BOOT_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002163 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002164
2165 def testHashNoAlgo(self):
2166 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002167 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glasse0e5df92018-09-14 04:57:31 -06002168 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2169 'hash node', str(e.exception))
2170
2171 def testHashBadAlgo(self):
2172 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002173 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass8db1f992022-02-08 10:59:44 -07002174 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glasse0e5df92018-09-14 04:57:31 -06002175 str(e.exception))
2176
2177 def testHashSection(self):
2178 """Test hashing of the contents of an entry"""
Simon Glass741f2d62018-10-01 12:22:30 -06002179 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glasse0e5df92018-09-14 04:57:31 -06002180 use_real_dtb=True, update_dtb=True)
2181 dtb = fdt.Fdt(out_dtb_fname)
2182 dtb.Scan()
2183 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2184 m = hashlib.sha256()
2185 m.update(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002186 m.update(tools.get_bytes(ord('a'), 16))
Simon Glassc6c10e72019-05-17 22:00:46 -06002187 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glasse0e5df92018-09-14 04:57:31 -06002188
Simon Glassf0253632018-09-14 04:57:32 -06002189 def testPackUBootTplMicrocode(self):
2190 """Test that x86 microcode can be handled correctly in TPL
2191
2192 We expect to see the following in the image, in order:
2193 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2194 place
2195 u-boot-tpl.dtb with the microcode removed
2196 the microcode
2197 """
Simon Glass2090f1e2019-08-24 07:23:00 -06002198 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass741f2d62018-10-01 12:22:30 -06002199 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glassf0253632018-09-14 04:57:32 -06002200 U_BOOT_TPL_NODTB_DATA)
Simon Glassc6c10e72019-05-17 22:00:46 -06002201 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2202 b'ter somewhere in here', first)
Simon Glassf0253632018-09-14 04:57:32 -06002203
Simon Glassf8f8df62018-09-14 04:57:34 -06002204 def testFmapX86(self):
2205 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002206 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassf8f8df62018-09-14 04:57:34 -06002207 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002208 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002209 self.assertEqual(expected, data[:32])
2210 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2211
2212 self.assertEqual(0x100, fhdr.image_size)
2213
2214 self.assertEqual(0, fentries[0].offset)
2215 self.assertEqual(4, fentries[0].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002216 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002217
2218 self.assertEqual(4, fentries[1].offset)
2219 self.assertEqual(3, fentries[1].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002220 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002221
2222 self.assertEqual(32, fentries[2].offset)
2223 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2224 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glassc6c10e72019-05-17 22:00:46 -06002225 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassf8f8df62018-09-14 04:57:34 -06002226
2227 def testFmapX86Section(self):
2228 """Basic test of generation of a flashrom fmap"""
Simon Glass741f2d62018-10-01 12:22:30 -06002229 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002230 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassf8f8df62018-09-14 04:57:34 -06002231 self.assertEqual(expected, data[:32])
2232 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2233
Simon Glass17365752021-04-03 11:05:10 +13002234 self.assertEqual(0x180, fhdr.image_size)
2235 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glassc7722e82021-04-03 11:05:09 +13002236 fiter = iter(fentries)
Simon Glassf8f8df62018-09-14 04:57:34 -06002237
Simon Glassc7722e82021-04-03 11:05:09 +13002238 fentry = next(fiter)
2239 self.assertEqual(b'U_BOOT', fentry.name)
2240 self.assertEqual(0, fentry.offset)
2241 self.assertEqual(4, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002242
Simon Glassc7722e82021-04-03 11:05:09 +13002243 fentry = next(fiter)
Simon Glass17365752021-04-03 11:05:10 +13002244 self.assertEqual(b'SECTION', fentry.name)
2245 self.assertEqual(4, fentry.offset)
2246 self.assertEqual(0x20 + expect_size, fentry.size)
2247
2248 fentry = next(fiter)
Simon Glassc7722e82021-04-03 11:05:09 +13002249 self.assertEqual(b'INTEL_MRC', fentry.name)
2250 self.assertEqual(4, fentry.offset)
2251 self.assertEqual(3, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002252
Simon Glassc7722e82021-04-03 11:05:09 +13002253 fentry = next(fiter)
2254 self.assertEqual(b'FMAP', fentry.name)
2255 self.assertEqual(36, fentry.offset)
2256 self.assertEqual(expect_size, fentry.size)
Simon Glassf8f8df62018-09-14 04:57:34 -06002257
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002258 def testElf(self):
2259 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002260 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002261 self._SetupTplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002262 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002263 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002264 data = self._DoReadFile('096_elf.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002265
Simon Glass093d1682019-07-08 13:18:25 -06002266 def testElfStrip(self):
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002267 """Basic test of ELF entries"""
Simon Glass11ae93e2018-10-01 21:12:47 -06002268 self._SetupSplElf()
Simon Glass53e22bf2019-08-24 07:22:53 -06002269 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002270 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass741f2d62018-10-01 12:22:30 -06002271 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassfe1ae3e2018-09-14 04:57:35 -06002272
Simon Glass163ed6c2018-09-14 04:57:36 -06002273 def testPackOverlapMap(self):
2274 """Test that overlapping regions are detected"""
2275 with test_util.capture_sys_output() as (stdout, stderr):
2276 with self.assertRaises(ValueError) as e:
Simon Glass741f2d62018-10-01 12:22:30 -06002277 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002278 map_fname = tools.get_output_filename('image.map')
Simon Glass163ed6c2018-09-14 04:57:36 -06002279 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2280 stdout.getvalue())
2281
2282 # We should not get an inmage, but there should be a map file
Simon Glassc1aa66e2022-01-29 14:14:04 -07002283 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glass163ed6c2018-09-14 04:57:36 -06002284 self.assertTrue(os.path.exists(map_fname))
Simon Glassc1aa66e2022-01-29 14:14:04 -07002285 map_data = tools.read_file(map_fname, binary=False)
Simon Glass163ed6c2018-09-14 04:57:36 -06002286 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -07002287<none> 00000000 00000008 image
Simon Glass163ed6c2018-09-14 04:57:36 -06002288<none> 00000000 00000004 u-boot
2289<none> 00000003 00000004 u-boot-align
2290''', map_data)
2291
Simon Glass093d1682019-07-08 13:18:25 -06002292 def testPackRefCode(self):
Simon Glass3ae192c2018-10-01 12:22:31 -06002293 """Test that an image with an Intel Reference code binary works"""
2294 data = self._DoReadFile('100_intel_refcode.dts')
2295 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2296
Simon Glass9481c802019-04-25 21:58:39 -06002297 def testSectionOffset(self):
2298 """Tests use of a section with an offset"""
2299 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2300 map=True)
2301 self.assertEqual('''ImagePos Offset Size Name
Simon Glass193d3db2023-02-07 14:34:18 -0700230200000000 00000000 00000038 image
Simon Glass9481c802019-04-25 21:58:39 -0600230300000004 00000004 00000010 section@0
230400000004 00000000 00000004 u-boot
230500000018 00000018 00000010 section@1
230600000018 00000000 00000004 u-boot
23070000002c 0000002c 00000004 section@2
23080000002c 00000000 00000004 u-boot
2309''', map_data)
2310 self.assertEqual(data,
Simon Glassc1aa66e2022-01-29 14:14:04 -07002311 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2312 tools.get_bytes(0x21, 12) +
2313 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2314 tools.get_bytes(0x61, 12) +
2315 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2316 tools.get_bytes(0x26, 8))
Simon Glass9481c802019-04-25 21:58:39 -06002317
Simon Glassac62fba2019-07-08 13:18:53 -06002318 def testCbfsRaw(self):
2319 """Test base handling of a Coreboot Filesystem (CBFS)
2320
2321 The exact contents of the CBFS is verified by similar tests in
2322 cbfs_util_test.py. The tests here merely check that the files added to
2323 the CBFS can be found in the final image.
2324 """
2325 data = self._DoReadFile('102_cbfs_raw.dts')
2326 size = 0xb0
2327
2328 cbfs = cbfs_util.CbfsReader(data)
2329 self.assertEqual(size, cbfs.rom_size)
2330
2331 self.assertIn('u-boot-dtb', cbfs.files)
2332 cfile = cbfs.files['u-boot-dtb']
2333 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2334
2335 def testCbfsArch(self):
2336 """Test on non-x86 architecture"""
2337 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2338 size = 0x100
2339
2340 cbfs = cbfs_util.CbfsReader(data)
2341 self.assertEqual(size, cbfs.rom_size)
2342
2343 self.assertIn('u-boot-dtb', cbfs.files)
2344 cfile = cbfs.files['u-boot-dtb']
2345 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2346
2347 def testCbfsStage(self):
2348 """Tests handling of a Coreboot Filesystem (CBFS)"""
2349 if not elf.ELF_TOOLS:
2350 self.skipTest('Python elftools not available')
2351 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2352 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2353 size = 0xb0
2354
2355 data = self._DoReadFile('104_cbfs_stage.dts')
2356 cbfs = cbfs_util.CbfsReader(data)
2357 self.assertEqual(size, cbfs.rom_size)
2358
2359 self.assertIn('u-boot', cbfs.files)
2360 cfile = cbfs.files['u-boot']
2361 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2362
2363 def testCbfsRawCompress(self):
2364 """Test handling of compressing raw files"""
2365 self._CheckLz4()
2366 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2367 size = 0x140
2368
2369 cbfs = cbfs_util.CbfsReader(data)
2370 self.assertIn('u-boot', cbfs.files)
2371 cfile = cbfs.files['u-boot']
2372 self.assertEqual(COMPRESS_DATA, cfile.data)
2373
2374 def testCbfsBadArch(self):
2375 """Test handling of a bad architecture"""
2376 with self.assertRaises(ValueError) as e:
2377 self._DoReadFile('106_cbfs_bad_arch.dts')
2378 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2379
2380 def testCbfsNoSize(self):
2381 """Test handling of a missing size property"""
2382 with self.assertRaises(ValueError) as e:
2383 self._DoReadFile('107_cbfs_no_size.dts')
2384 self.assertIn('entry must have a size property', str(e.exception))
2385
Simon Glasse2f04742021-11-23 11:03:54 -07002386 def testCbfsNoContents(self):
Simon Glassac62fba2019-07-08 13:18:53 -06002387 """Test handling of a CBFS entry which does not provide contentsy"""
2388 with self.assertRaises(ValueError) as e:
2389 self._DoReadFile('108_cbfs_no_contents.dts')
2390 self.assertIn('Could not complete processing of contents',
2391 str(e.exception))
2392
2393 def testCbfsBadCompress(self):
2394 """Test handling of a bad architecture"""
2395 with self.assertRaises(ValueError) as e:
2396 self._DoReadFile('109_cbfs_bad_compress.dts')
2397 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2398 str(e.exception))
2399
2400 def testCbfsNamedEntries(self):
2401 """Test handling of named entries"""
2402 data = self._DoReadFile('110_cbfs_name.dts')
2403
2404 cbfs = cbfs_util.CbfsReader(data)
2405 self.assertIn('FRED', cbfs.files)
2406 cfile1 = cbfs.files['FRED']
2407 self.assertEqual(U_BOOT_DATA, cfile1.data)
2408
2409 self.assertIn('hello', cbfs.files)
2410 cfile2 = cbfs.files['hello']
2411 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2412
Simon Glassc5ac1382019-07-08 13:18:54 -06002413 def _SetupIfwi(self, fname):
2414 """Set up to run an IFWI test
2415
2416 Args:
2417 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2418 """
2419 self._SetupSplElf()
Simon Glass2090f1e2019-08-24 07:23:00 -06002420 self._SetupTplElf()
Simon Glassc5ac1382019-07-08 13:18:54 -06002421
2422 # Intel Integrated Firmware Image (IFWI) file
2423 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2424 data = fd.read()
2425 TestFunctional._MakeInputFile(fname,data)
2426
2427 def _CheckIfwi(self, data):
2428 """Check that an image with an IFWI contains the correct output
2429
2430 Args:
2431 data: Conents of output file
2432 """
Simon Glassc1aa66e2022-01-29 14:14:04 -07002433 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glassc5ac1382019-07-08 13:18:54 -06002434 if data[:0x1000] != expected_desc:
2435 self.fail('Expected descriptor binary at start of image')
2436
2437 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glassc1aa66e2022-01-29 14:14:04 -07002438 image_fname = tools.get_output_filename('image.bin')
2439 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass532ae702022-01-09 20:14:01 -07002440 ifwitool = bintool.Bintool.create('ifwitool')
2441 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glassc5ac1382019-07-08 13:18:54 -06002442
Simon Glassc1aa66e2022-01-29 14:14:04 -07002443 tpl_data = tools.read_file(tpl_fname)
Simon Glasse95be632019-08-24 07:22:51 -06002444 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glassc5ac1382019-07-08 13:18:54 -06002445
2446 def testPackX86RomIfwi(self):
2447 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2448 self._SetupIfwi('fitimage.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002449 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002450 self._CheckIfwi(data)
2451
2452 def testPackX86RomIfwiNoDesc(self):
2453 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2454 self._SetupIfwi('ifwi.bin')
Simon Glass9255f3c2019-08-24 07:23:01 -06002455 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002456 self._CheckIfwi(data)
2457
2458 def testPackX86RomIfwiNoData(self):
2459 """Test that an x86 ROM with IFWI handles missing data"""
2460 self._SetupIfwi('ifwi.bin')
2461 with self.assertRaises(ValueError) as e:
Simon Glass9255f3c2019-08-24 07:23:01 -06002462 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glassc5ac1382019-07-08 13:18:54 -06002463 self.assertIn('Could not complete processing of contents',
2464 str(e.exception))
Simon Glass53af22a2018-07-17 13:25:32 -06002465
Simon Glass4f9ee832022-01-09 20:14:09 -07002466 def testIfwiMissing(self):
2467 """Test that binman still produces an image if ifwitool is missing"""
2468 self._SetupIfwi('fitimage.bin')
2469 with test_util.capture_sys_output() as (_, stderr):
2470 self._DoTestFile('111_x86_rom_ifwi.dts',
2471 force_missing_bintools='ifwitool')
2472 err = stderr.getvalue()
2473 self.assertRegex(err,
Simon Glass193d3db2023-02-07 14:34:18 -07002474 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass4f9ee832022-01-09 20:14:09 -07002475
Simon Glasse073d4e2019-07-08 13:18:56 -06002476 def testCbfsOffset(self):
2477 """Test a CBFS with files at particular offsets
2478
2479 Like all CFBS tests, this is just checking the logic that calls
2480 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2481 """
2482 data = self._DoReadFile('114_cbfs_offset.dts')
2483 size = 0x200
2484
2485 cbfs = cbfs_util.CbfsReader(data)
2486 self.assertEqual(size, cbfs.rom_size)
2487
2488 self.assertIn('u-boot', cbfs.files)
2489 cfile = cbfs.files['u-boot']
2490 self.assertEqual(U_BOOT_DATA, cfile.data)
2491 self.assertEqual(0x40, cfile.cbfs_offset)
2492
2493 self.assertIn('u-boot-dtb', cbfs.files)
2494 cfile2 = cbfs.files['u-boot-dtb']
2495 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2496 self.assertEqual(0x140, cfile2.cbfs_offset)
2497
Simon Glass086cec92019-07-08 14:25:27 -06002498 def testFdtmap(self):
2499 """Test an FDT map can be inserted in the image"""
2500 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2501 fdtmap_data = data[len(U_BOOT_DATA):]
2502 magic = fdtmap_data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002503 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002504 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass086cec92019-07-08 14:25:27 -06002505
2506 fdt_data = fdtmap_data[16:]
2507 dtb = fdt.Fdt.FromData(fdt_data)
2508 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002509 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass086cec92019-07-08 14:25:27 -06002510 self.assertEqual({
2511 'image-pos': 0,
2512 'offset': 0,
2513 'u-boot:offset': 0,
2514 'u-boot:size': len(U_BOOT_DATA),
2515 'u-boot:image-pos': 0,
2516 'fdtmap:image-pos': 4,
2517 'fdtmap:offset': 4,
2518 'fdtmap:size': len(fdtmap_data),
2519 'size': len(data),
2520 }, props)
2521
2522 def testFdtmapNoMatch(self):
2523 """Check handling of an FDT map when the section cannot be found"""
2524 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2525
2526 # Mangle the section name, which should cause a mismatch between the
2527 # correct FDT path and the one expected by the section
2528 image = control.images['image']
Simon Glasscf228942019-07-08 14:25:28 -06002529 image._node.path += '-suffix'
Simon Glass086cec92019-07-08 14:25:27 -06002530 entries = image.GetEntries()
2531 fdtmap = entries['fdtmap']
2532 with self.assertRaises(ValueError) as e:
2533 fdtmap._GetFdtmap()
2534 self.assertIn("Cannot locate node for path '/binman-suffix'",
2535 str(e.exception))
2536
Simon Glasscf228942019-07-08 14:25:28 -06002537 def testFdtmapHeader(self):
2538 """Test an FDT map and image header can be inserted in the image"""
2539 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2540 fdtmap_pos = len(U_BOOT_DATA)
2541 fdtmap_data = data[fdtmap_pos:]
2542 fdt_data = fdtmap_data[16:]
2543 dtb = fdt.Fdt.FromData(fdt_data)
2544 fdt_size = dtb.GetFdtObj().totalsize()
2545 hdr_data = data[-8:]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002546 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002547 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2548 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2549
2550 def testFdtmapHeaderStart(self):
2551 """Test an image header can be inserted at the image start"""
2552 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2553 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2554 hdr_data = data[:8]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002555 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002556 offset = struct.unpack('<I', hdr_data[4:])[0]
2557 self.assertEqual(fdtmap_pos, offset)
2558
2559 def testFdtmapHeaderPos(self):
2560 """Test an image header can be inserted at a chosen position"""
2561 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2562 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2563 hdr_data = data[0x80:0x88]
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002564 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscf228942019-07-08 14:25:28 -06002565 offset = struct.unpack('<I', hdr_data[4:])[0]
2566 self.assertEqual(fdtmap_pos, offset)
2567
2568 def testHeaderMissingFdtmap(self):
2569 """Test an image header requires an fdtmap"""
2570 with self.assertRaises(ValueError) as e:
2571 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2572 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2573 str(e.exception))
2574
2575 def testHeaderNoLocation(self):
2576 """Test an image header with a no specified location is detected"""
2577 with self.assertRaises(ValueError) as e:
2578 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2579 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2580 str(e.exception))
2581
Simon Glassc52c9e72019-07-08 14:25:37 -06002582 def testEntryExpand(self):
Simon Glass80a66ae2022-03-05 20:18:59 -07002583 """Test extending an entry after it is packed"""
2584 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002585 self.assertEqual(b'aaa', data[:3])
2586 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2587 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002588
Simon Glass80a66ae2022-03-05 20:18:59 -07002589 def testEntryExtendBad(self):
2590 """Test extending an entry after it is packed, twice"""
Simon Glassc52c9e72019-07-08 14:25:37 -06002591 with self.assertRaises(ValueError) as e:
Simon Glass80a66ae2022-03-05 20:18:59 -07002592 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass61ec04f2019-07-20 12:23:58 -06002593 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glassc52c9e72019-07-08 14:25:37 -06002594 str(e.exception))
2595
Simon Glass80a66ae2022-03-05 20:18:59 -07002596 def testEntryExtendSection(self):
2597 """Test extending an entry within a section after it is packed"""
2598 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass79d3c582019-07-20 12:23:57 -06002599 self.assertEqual(b'aaa', data[:3])
2600 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2601 self.assertEqual(b'aaa', data[-3:])
Simon Glassc52c9e72019-07-08 14:25:37 -06002602
Simon Glass6c223fd2019-07-08 14:25:38 -06002603 def testCompressDtb(self):
2604 """Test that compress of device-tree files is supported"""
2605 self._CheckLz4()
2606 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2607 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2608 comp_data = data[len(U_BOOT_DATA):]
2609 orig = self._decompress(comp_data)
2610 dtb = fdt.Fdt.FromData(orig)
2611 dtb.Scan()
2612 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2613 expected = {
2614 'u-boot:size': len(U_BOOT_DATA),
2615 'u-boot-dtb:uncomp-size': len(orig),
2616 'u-boot-dtb:size': len(comp_data),
2617 'size': len(data),
2618 }
2619 self.assertEqual(expected, props)
2620
Simon Glass69f7cb32019-07-08 14:25:41 -06002621 def testCbfsUpdateFdt(self):
2622 """Test that we can update the device tree with CBFS offset/size info"""
2623 self._CheckLz4()
2624 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2625 update_dtb=True)
2626 dtb = fdt.Fdt(out_dtb_fname)
2627 dtb.Scan()
Simon Glass6ccbfcd2019-07-20 12:23:47 -06002628 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass69f7cb32019-07-08 14:25:41 -06002629 del props['cbfs/u-boot:size']
2630 self.assertEqual({
2631 'offset': 0,
2632 'size': len(data),
2633 'image-pos': 0,
2634 'cbfs:offset': 0,
2635 'cbfs:size': len(data),
2636 'cbfs:image-pos': 0,
2637 'cbfs/u-boot:offset': 0x38,
2638 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2639 'cbfs/u-boot:image-pos': 0x38,
2640 'cbfs/u-boot-dtb:offset': 0xb8,
2641 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2642 'cbfs/u-boot-dtb:image-pos': 0xb8,
2643 }, props)
2644
Simon Glass8a1ad062019-07-08 14:25:42 -06002645 def testCbfsBadType(self):
2646 """Test an image header with a no specified location is detected"""
2647 with self.assertRaises(ValueError) as e:
2648 self._DoReadFile('126_cbfs_bad_type.dts')
2649 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2650
Simon Glass41b8ba02019-07-08 14:25:43 -06002651 def testList(self):
2652 """Test listing the files in an image"""
2653 self._CheckLz4()
2654 data = self._DoReadFile('127_list.dts')
2655 image = control.images['image']
2656 entries = image.BuildEntryList()
2657 self.assertEqual(7, len(entries))
2658
2659 ent = entries[0]
2660 self.assertEqual(0, ent.indent)
Simon Glass193d3db2023-02-07 14:34:18 -07002661 self.assertEqual('image', ent.name)
Simon Glass41b8ba02019-07-08 14:25:43 -06002662 self.assertEqual('section', ent.etype)
2663 self.assertEqual(len(data), ent.size)
2664 self.assertEqual(0, ent.image_pos)
2665 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002666 self.assertEqual(0, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002667
2668 ent = entries[1]
2669 self.assertEqual(1, ent.indent)
2670 self.assertEqual('u-boot', ent.name)
2671 self.assertEqual('u-boot', ent.etype)
2672 self.assertEqual(len(U_BOOT_DATA), ent.size)
2673 self.assertEqual(0, ent.image_pos)
2674 self.assertEqual(None, ent.uncomp_size)
2675 self.assertEqual(0, ent.offset)
2676
2677 ent = entries[2]
2678 self.assertEqual(1, ent.indent)
2679 self.assertEqual('section', ent.name)
2680 self.assertEqual('section', ent.etype)
2681 section_size = ent.size
2682 self.assertEqual(0x100, ent.image_pos)
2683 self.assertEqual(None, ent.uncomp_size)
Simon Glass8beb11e2019-07-08 14:25:47 -06002684 self.assertEqual(0x100, ent.offset)
Simon Glass41b8ba02019-07-08 14:25:43 -06002685
2686 ent = entries[3]
2687 self.assertEqual(2, ent.indent)
2688 self.assertEqual('cbfs', ent.name)
2689 self.assertEqual('cbfs', ent.etype)
2690 self.assertEqual(0x400, ent.size)
2691 self.assertEqual(0x100, ent.image_pos)
2692 self.assertEqual(None, ent.uncomp_size)
2693 self.assertEqual(0, ent.offset)
2694
2695 ent = entries[4]
2696 self.assertEqual(3, ent.indent)
2697 self.assertEqual('u-boot', ent.name)
2698 self.assertEqual('u-boot', ent.etype)
2699 self.assertEqual(len(U_BOOT_DATA), ent.size)
2700 self.assertEqual(0x138, ent.image_pos)
2701 self.assertEqual(None, ent.uncomp_size)
2702 self.assertEqual(0x38, ent.offset)
2703
2704 ent = entries[5]
2705 self.assertEqual(3, ent.indent)
2706 self.assertEqual('u-boot-dtb', ent.name)
2707 self.assertEqual('text', ent.etype)
2708 self.assertGreater(len(COMPRESS_DATA), ent.size)
2709 self.assertEqual(0x178, ent.image_pos)
2710 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2711 self.assertEqual(0x78, ent.offset)
2712
2713 ent = entries[6]
2714 self.assertEqual(2, ent.indent)
2715 self.assertEqual('u-boot-dtb', ent.name)
2716 self.assertEqual('u-boot-dtb', ent.etype)
2717 self.assertEqual(0x500, ent.image_pos)
2718 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2719 dtb_size = ent.size
2720 # Compressing this data expands it since headers are added
2721 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2722 self.assertEqual(0x400, ent.offset)
2723
2724 self.assertEqual(len(data), 0x100 + section_size)
2725 self.assertEqual(section_size, 0x400 + dtb_size)
2726
Simon Glasse1925fa2019-07-08 14:25:44 -06002727 def testFindFdtmap(self):
2728 """Test locating an FDT map in an image"""
2729 self._CheckLz4()
2730 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2731 image = control.images['image']
2732 entries = image.GetEntries()
2733 entry = entries['fdtmap']
2734 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2735
2736 def testFindFdtmapMissing(self):
2737 """Test failing to locate an FDP map"""
2738 data = self._DoReadFile('005_simple.dts')
2739 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2740
Simon Glass2d260032019-07-08 14:25:45 -06002741 def testFindImageHeader(self):
2742 """Test locating a image header"""
2743 self._CheckLz4()
Simon Glassffded752019-07-08 14:25:46 -06002744 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002745 image = control.images['image']
2746 entries = image.GetEntries()
2747 entry = entries['fdtmap']
2748 # The header should point to the FDT map
2749 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2750
2751 def testFindImageHeaderStart(self):
2752 """Test locating a image header located at the start of an image"""
Simon Glassffded752019-07-08 14:25:46 -06002753 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glass2d260032019-07-08 14:25:45 -06002754 image = control.images['image']
2755 entries = image.GetEntries()
2756 entry = entries['fdtmap']
2757 # The header should point to the FDT map
2758 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2759
2760 def testFindImageHeaderMissing(self):
2761 """Test failing to locate an image header"""
2762 data = self._DoReadFile('005_simple.dts')
2763 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2764
Simon Glassffded752019-07-08 14:25:46 -06002765 def testReadImage(self):
2766 """Test reading an image and accessing its FDT map"""
2767 self._CheckLz4()
2768 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002769 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002770 orig_image = control.images['image']
2771 image = Image.FromFile(image_fname)
2772 self.assertEqual(orig_image.GetEntries().keys(),
2773 image.GetEntries().keys())
2774
2775 orig_entry = orig_image.GetEntries()['fdtmap']
2776 entry = image.GetEntries()['fdtmap']
2777 self.assertEquals(orig_entry.offset, entry.offset)
2778 self.assertEquals(orig_entry.size, entry.size)
2779 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2780
2781 def testReadImageNoHeader(self):
2782 """Test accessing an image's FDT map without an image header"""
2783 self._CheckLz4()
2784 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002785 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002786 image = Image.FromFile(image_fname)
2787 self.assertTrue(isinstance(image, Image))
Simon Glass10f9d002019-07-20 12:23:50 -06002788 self.assertEqual('image', image.image_name[-5:])
Simon Glassffded752019-07-08 14:25:46 -06002789
2790 def testReadImageFail(self):
2791 """Test failing to read an image image's FDT map"""
2792 self._DoReadFile('005_simple.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002793 image_fname = tools.get_output_filename('image.bin')
Simon Glassffded752019-07-08 14:25:46 -06002794 with self.assertRaises(ValueError) as e:
2795 image = Image.FromFile(image_fname)
2796 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glasse073d4e2019-07-08 13:18:56 -06002797
Simon Glass61f564d2019-07-08 14:25:48 -06002798 def testListCmd(self):
2799 """Test listing the files in an image using an Fdtmap"""
2800 self._CheckLz4()
2801 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2802
2803 # lz4 compression size differs depending on the version
2804 image = control.images['image']
2805 entries = image.GetEntries()
2806 section_size = entries['section'].size
2807 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2808 fdtmap_offset = entries['fdtmap'].offset
2809
Simon Glassf86a7362019-07-20 12:24:10 -06002810 try:
2811 tmpdir, updated_fname = self._SetupImageInTmpdir()
2812 with test_util.capture_sys_output() as (stdout, stderr):
2813 self._DoBinman('ls', '-i', updated_fname)
2814 finally:
2815 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002816 lines = stdout.getvalue().splitlines()
2817 expected = [
2818'Name Image-pos Size Entry-type Offset Uncomp-size',
2819'----------------------------------------------------------------------',
Simon Glass193d3db2023-02-07 14:34:18 -07002820'image 0 c00 section 0',
Simon Glass61f564d2019-07-08 14:25:48 -06002821' u-boot 0 4 u-boot 0',
2822' section 100 %x section 100' % section_size,
2823' cbfs 100 400 cbfs 0',
2824' u-boot 138 4 u-boot 38',
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002825' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glass61f564d2019-07-08 14:25:48 -06002826' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002827' fdtmap %x 3bd fdtmap %x' %
Simon Glass61f564d2019-07-08 14:25:48 -06002828 (fdtmap_offset, fdtmap_offset),
2829' image-header bf8 8 image-header bf8',
2830 ]
2831 self.assertEqual(expected, lines)
2832
2833 def testListCmdFail(self):
2834 """Test failing to list an image"""
2835 self._DoReadFile('005_simple.dts')
Simon Glassf86a7362019-07-20 12:24:10 -06002836 try:
2837 tmpdir, updated_fname = self._SetupImageInTmpdir()
2838 with self.assertRaises(ValueError) as e:
2839 self._DoBinman('ls', '-i', updated_fname)
2840 finally:
2841 shutil.rmtree(tmpdir)
Simon Glass61f564d2019-07-08 14:25:48 -06002842 self.assertIn("Cannot find FDT map in image", str(e.exception))
2843
2844 def _RunListCmd(self, paths, expected):
2845 """List out entries and check the result
2846
2847 Args:
2848 paths: List of paths to pass to the list command
2849 expected: Expected list of filenames to be returned, in order
2850 """
2851 self._CheckLz4()
2852 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002853 image_fname = tools.get_output_filename('image.bin')
Simon Glass61f564d2019-07-08 14:25:48 -06002854 image = Image.FromFile(image_fname)
2855 lines = image.GetListEntries(paths)[1]
2856 files = [line[0].strip() for line in lines[1:]]
2857 self.assertEqual(expected, files)
2858
2859 def testListCmdSection(self):
2860 """Test listing the files in a section"""
2861 self._RunListCmd(['section'],
2862 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2863
2864 def testListCmdFile(self):
2865 """Test listing a particular file"""
2866 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2867
2868 def testListCmdWildcard(self):
2869 """Test listing a wildcarded file"""
2870 self._RunListCmd(['*boot*'],
2871 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2872
2873 def testListCmdWildcardMulti(self):
2874 """Test listing a wildcarded file"""
2875 self._RunListCmd(['*cb*', '*head*'],
2876 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2877
2878 def testListCmdEmpty(self):
2879 """Test listing a wildcarded file"""
2880 self._RunListCmd(['nothing'], [])
2881
2882 def testListCmdPath(self):
2883 """Test listing the files in a sub-entry of a section"""
2884 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2885
Simon Glassf667e452019-07-08 14:25:50 -06002886 def _RunExtractCmd(self, entry_name, decomp=True):
2887 """Extract an entry from an image
2888
2889 Args:
2890 entry_name: Entry name to extract
2891 decomp: True to decompress the data if compressed, False to leave
2892 it in its raw uncompressed format
2893
2894 Returns:
2895 data from entry
2896 """
2897 self._CheckLz4()
2898 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002899 image_fname = tools.get_output_filename('image.bin')
Simon Glassf667e452019-07-08 14:25:50 -06002900 return control.ReadEntry(image_fname, entry_name, decomp)
2901
2902 def testExtractSimple(self):
2903 """Test extracting a single file"""
2904 data = self._RunExtractCmd('u-boot')
2905 self.assertEqual(U_BOOT_DATA, data)
2906
Simon Glass71ce0ba2019-07-08 14:25:52 -06002907 def testExtractSection(self):
2908 """Test extracting the files in a section"""
2909 data = self._RunExtractCmd('section')
2910 cbfs_data = data[:0x400]
2911 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassb6ee0cf2019-10-31 07:43:03 -06002912 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass71ce0ba2019-07-08 14:25:52 -06002913 dtb_data = data[0x400:]
2914 dtb = self._decompress(dtb_data)
2915 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2916
2917 def testExtractCompressed(self):
2918 """Test extracting compressed data"""
2919 data = self._RunExtractCmd('section/u-boot-dtb')
2920 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2921
2922 def testExtractRaw(self):
2923 """Test extracting compressed data without decompressing it"""
2924 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2925 dtb = self._decompress(data)
2926 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2927
2928 def testExtractCbfs(self):
2929 """Test extracting CBFS data"""
2930 data = self._RunExtractCmd('section/cbfs/u-boot')
2931 self.assertEqual(U_BOOT_DATA, data)
2932
2933 def testExtractCbfsCompressed(self):
2934 """Test extracting CBFS compressed data"""
2935 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2936 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2937
2938 def testExtractCbfsRaw(self):
2939 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002940 bintool = self.comp_bintools['lzma_alone']
2941 self._CheckBintool(bintool)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002942 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02002943 dtb = bintool.decompress(data)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002944 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2945
Simon Glassf667e452019-07-08 14:25:50 -06002946 def testExtractBadEntry(self):
2947 """Test extracting a bad section path"""
2948 with self.assertRaises(ValueError) as e:
2949 self._RunExtractCmd('section/does-not-exist')
2950 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2951 str(e.exception))
2952
2953 def testExtractMissingFile(self):
2954 """Test extracting file that does not exist"""
2955 with self.assertRaises(IOError) as e:
2956 control.ReadEntry('missing-file', 'name')
2957
2958 def testExtractBadFile(self):
2959 """Test extracting an invalid file"""
2960 fname = os.path.join(self._indir, 'badfile')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002961 tools.write_file(fname, b'')
Simon Glassf667e452019-07-08 14:25:50 -06002962 with self.assertRaises(ValueError) as e:
2963 control.ReadEntry(fname, 'name')
2964
Simon Glass71ce0ba2019-07-08 14:25:52 -06002965 def testExtractCmd(self):
2966 """Test extracting a file fron an image on the command line"""
2967 self._CheckLz4()
2968 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002969 fname = os.path.join(self._indir, 'output.extact')
Simon Glassf86a7362019-07-20 12:24:10 -06002970 try:
2971 tmpdir, updated_fname = self._SetupImageInTmpdir()
2972 with test_util.capture_sys_output() as (stdout, stderr):
2973 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2974 '-f', fname)
2975 finally:
2976 shutil.rmtree(tmpdir)
Simon Glassc1aa66e2022-01-29 14:14:04 -07002977 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002978 self.assertEqual(U_BOOT_DATA, data)
2979
2980 def testExtractOneEntry(self):
2981 """Test extracting a single entry fron an image """
2982 self._CheckLz4()
2983 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07002984 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06002985 fname = os.path.join(self._indir, 'output.extact')
2986 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07002987 data = tools.read_file(fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06002988 self.assertEqual(U_BOOT_DATA, data)
2989
2990 def _CheckExtractOutput(self, decomp):
2991 """Helper to test file output with and without decompression
2992
2993 Args:
2994 decomp: True to decompress entry data, False to output it raw
2995 """
2996 def _CheckPresent(entry_path, expect_data, expect_size=None):
2997 """Check and remove expected file
2998
2999 This checks the data/size of a file and removes the file both from
3000 the outfiles set and from the output directory. Once all files are
3001 processed, both the set and directory should be empty.
3002
3003 Args:
3004 entry_path: Entry path
3005 expect_data: Data to expect in file, or None to skip check
3006 expect_size: Size of data to expect in file, or None to skip
3007 """
3008 path = os.path.join(outdir, entry_path)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003009 data = tools.read_file(path)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003010 os.remove(path)
3011 if expect_data:
3012 self.assertEqual(expect_data, data)
3013 elif expect_size:
3014 self.assertEqual(expect_size, len(data))
3015 outfiles.remove(path)
3016
3017 def _CheckDirPresent(name):
3018 """Remove expected directory
3019
3020 This gives an error if the directory does not exist as expected
3021
3022 Args:
3023 name: Name of directory to remove
3024 """
3025 path = os.path.join(outdir, name)
3026 os.rmdir(path)
3027
3028 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003029 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003030 outdir = os.path.join(self._indir, 'extract')
3031 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3032
3033 # Create a set of all file that were output (should be 9)
3034 outfiles = set()
3035 for root, dirs, files in os.walk(outdir):
3036 outfiles |= set([os.path.join(root, fname) for fname in files])
3037 self.assertEqual(9, len(outfiles))
3038 self.assertEqual(9, len(einfos))
3039
3040 image = control.images['image']
3041 entries = image.GetEntries()
3042
3043 # Check the 9 files in various ways
3044 section = entries['section']
3045 section_entries = section.GetEntries()
3046 cbfs_entries = section_entries['cbfs'].GetEntries()
3047 _CheckPresent('u-boot', U_BOOT_DATA)
3048 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3049 dtb_len = EXTRACT_DTB_SIZE
3050 if not decomp:
3051 dtb_len = cbfs_entries['u-boot-dtb'].size
3052 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3053 if not decomp:
3054 dtb_len = section_entries['u-boot-dtb'].size
3055 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3056
3057 fdtmap = entries['fdtmap']
3058 _CheckPresent('fdtmap', fdtmap.data)
3059 hdr = entries['image-header']
3060 _CheckPresent('image-header', hdr.data)
3061
3062 _CheckPresent('section/root', section.data)
3063 cbfs = section_entries['cbfs']
3064 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003065 data = tools.read_file(image_fname)
Simon Glass71ce0ba2019-07-08 14:25:52 -06003066 _CheckPresent('root', data)
3067
3068 # There should be no files left. Remove all the directories to check.
3069 # If there are any files/dirs remaining, one of these checks will fail.
3070 self.assertEqual(0, len(outfiles))
3071 _CheckDirPresent('section/cbfs')
3072 _CheckDirPresent('section')
3073 _CheckDirPresent('')
3074 self.assertFalse(os.path.exists(outdir))
3075
3076 def testExtractAllEntries(self):
3077 """Test extracting all entries"""
3078 self._CheckLz4()
3079 self._CheckExtractOutput(decomp=True)
3080
3081 def testExtractAllEntriesRaw(self):
3082 """Test extracting all entries without decompressing them"""
3083 self._CheckLz4()
3084 self._CheckExtractOutput(decomp=False)
3085
3086 def testExtractSelectedEntries(self):
3087 """Test extracting some entries"""
3088 self._CheckLz4()
3089 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003090 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003091 outdir = os.path.join(self._indir, 'extract')
3092 einfos = control.ExtractEntries(image_fname, None, outdir,
3093 ['*cb*', '*head*'])
3094
3095 # File output is tested by testExtractAllEntries(), so just check that
3096 # the expected entries are selected
3097 names = [einfo.name for einfo in einfos]
3098 self.assertEqual(names,
3099 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3100
3101 def testExtractNoEntryPaths(self):
3102 """Test extracting some entries"""
3103 self._CheckLz4()
3104 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003105 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003106 with self.assertRaises(ValueError) as e:
3107 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassbb5edc12019-07-20 12:24:14 -06003108 self.assertIn('Must specify an entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003109 str(e.exception))
3110
3111 def testExtractTooManyEntryPaths(self):
3112 """Test extracting some entries"""
3113 self._CheckLz4()
3114 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003115 image_fname = tools.get_output_filename('image.bin')
Simon Glass71ce0ba2019-07-08 14:25:52 -06003116 with self.assertRaises(ValueError) as e:
3117 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassbb5edc12019-07-20 12:24:14 -06003118 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass71ce0ba2019-07-08 14:25:52 -06003119 str(e.exception))
3120
Simon Glasse2705fa2019-07-08 14:25:53 -06003121 def testPackAlignSection(self):
3122 """Test that sections can have alignment"""
3123 self._DoReadFile('131_pack_align_section.dts')
3124
3125 self.assertIn('image', control.images)
3126 image = control.images['image']
3127 entries = image.GetEntries()
3128 self.assertEqual(3, len(entries))
3129
3130 # First u-boot
3131 self.assertIn('u-boot', entries)
3132 entry = entries['u-boot']
3133 self.assertEqual(0, entry.offset)
3134 self.assertEqual(0, entry.image_pos)
3135 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3136 self.assertEqual(len(U_BOOT_DATA), entry.size)
3137
3138 # Section0
3139 self.assertIn('section0', entries)
3140 section0 = entries['section0']
3141 self.assertEqual(0x10, section0.offset)
3142 self.assertEqual(0x10, section0.image_pos)
3143 self.assertEqual(len(U_BOOT_DATA), section0.size)
3144
3145 # Second u-boot
3146 section_entries = section0.GetEntries()
3147 self.assertIn('u-boot', section_entries)
3148 entry = section_entries['u-boot']
3149 self.assertEqual(0, entry.offset)
3150 self.assertEqual(0x10, entry.image_pos)
3151 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3152 self.assertEqual(len(U_BOOT_DATA), entry.size)
3153
3154 # Section1
3155 self.assertIn('section1', entries)
3156 section1 = entries['section1']
3157 self.assertEqual(0x14, section1.offset)
3158 self.assertEqual(0x14, section1.image_pos)
3159 self.assertEqual(0x20, section1.size)
3160
3161 # Second u-boot
3162 section_entries = section1.GetEntries()
3163 self.assertIn('u-boot', section_entries)
3164 entry = section_entries['u-boot']
3165 self.assertEqual(0, entry.offset)
3166 self.assertEqual(0x14, entry.image_pos)
3167 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3168 self.assertEqual(len(U_BOOT_DATA), entry.size)
3169
3170 # Section2
3171 self.assertIn('section2', section_entries)
3172 section2 = section_entries['section2']
3173 self.assertEqual(0x4, section2.offset)
3174 self.assertEqual(0x18, section2.image_pos)
3175 self.assertEqual(4, section2.size)
3176
3177 # Third u-boot
3178 section_entries = section2.GetEntries()
3179 self.assertIn('u-boot', section_entries)
3180 entry = section_entries['u-boot']
3181 self.assertEqual(0, entry.offset)
3182 self.assertEqual(0x18, entry.image_pos)
3183 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3184 self.assertEqual(len(U_BOOT_DATA), entry.size)
3185
Simon Glass51014aa2019-07-20 12:23:56 -06003186 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3187 dts='132_replace.dts'):
Simon Glass10f9d002019-07-20 12:23:50 -06003188 """Replace an entry in an image
3189
3190 This writes the entry data to update it, then opens the updated file and
3191 returns the value that it now finds there.
3192
3193 Args:
3194 entry_name: Entry name to replace
3195 data: Data to replace it with
3196 decomp: True to compress the data if needed, False if data is
3197 already compressed so should be used as is
Simon Glass51014aa2019-07-20 12:23:56 -06003198 allow_resize: True to allow entries to change size, False to raise
3199 an exception
Simon Glass10f9d002019-07-20 12:23:50 -06003200
3201 Returns:
3202 Tuple:
3203 data from entry
3204 data from fdtmap (excluding header)
Simon Glass51014aa2019-07-20 12:23:56 -06003205 Image object that was modified
Simon Glass10f9d002019-07-20 12:23:50 -06003206 """
Simon Glass51014aa2019-07-20 12:23:56 -06003207 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass10f9d002019-07-20 12:23:50 -06003208 update_dtb=True)[1]
3209
3210 self.assertIn('image', control.images)
3211 image = control.images['image']
3212 entries = image.GetEntries()
3213 orig_dtb_data = entries['u-boot-dtb'].data
3214 orig_fdtmap_data = entries['fdtmap'].data
3215
Simon Glassc1aa66e2022-01-29 14:14:04 -07003216 image_fname = tools.get_output_filename('image.bin')
3217 updated_fname = tools.get_output_filename('image-updated.bin')
3218 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass51014aa2019-07-20 12:23:56 -06003219 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3220 allow_resize)
Simon Glass10f9d002019-07-20 12:23:50 -06003221 data = control.ReadEntry(updated_fname, entry_name, decomp)
3222
Simon Glass51014aa2019-07-20 12:23:56 -06003223 # The DT data should not change unless resized:
3224 if not allow_resize:
3225 new_dtb_data = entries['u-boot-dtb'].data
3226 self.assertEqual(new_dtb_data, orig_dtb_data)
3227 new_fdtmap_data = entries['fdtmap'].data
3228 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass10f9d002019-07-20 12:23:50 -06003229
Simon Glass51014aa2019-07-20 12:23:56 -06003230 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass10f9d002019-07-20 12:23:50 -06003231
3232 def testReplaceSimple(self):
3233 """Test replacing a single file"""
3234 expected = b'x' * len(U_BOOT_DATA)
Simon Glass51014aa2019-07-20 12:23:56 -06003235 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3236 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003237 self.assertEqual(expected, data)
3238
3239 # Test that the state looks right. There should be an FDT for the fdtmap
3240 # that we jsut read back in, and it should match what we find in the
3241 # 'control' tables. Checking for an FDT that does not exist should
3242 # return None.
3243 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glass51014aa2019-07-20 12:23:56 -06003244 self.assertIsNotNone(path)
Simon Glass10f9d002019-07-20 12:23:50 -06003245 self.assertEqual(expected_fdtmap, fdtmap)
3246
3247 dtb = state.GetFdtForEtype('fdtmap')
3248 self.assertEqual(dtb.GetContents(), fdtmap)
3249
3250 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3251 self.assertIsNone(missing_path)
3252 self.assertIsNone(missing_fdtmap)
3253
3254 missing_dtb = state.GetFdtForEtype('missing')
3255 self.assertIsNone(missing_dtb)
3256
3257 self.assertEqual('/binman', state.fdt_path_prefix)
3258
3259 def testReplaceResizeFail(self):
3260 """Test replacing a file by something larger"""
3261 expected = U_BOOT_DATA + b'x'
3262 with self.assertRaises(ValueError) as e:
Simon Glass51014aa2019-07-20 12:23:56 -06003263 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3264 dts='139_replace_repack.dts')
Simon Glass10f9d002019-07-20 12:23:50 -06003265 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3266 str(e.exception))
3267
3268 def testReplaceMulti(self):
3269 """Test replacing entry data where multiple images are generated"""
3270 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3271 update_dtb=True)[0]
3272 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003273 updated_fname = tools.get_output_filename('image-updated.bin')
3274 tools.write_file(updated_fname, data)
Simon Glass10f9d002019-07-20 12:23:50 -06003275 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003276 control.WriteEntry(updated_fname, entry_name, expected,
3277 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003278 data = control.ReadEntry(updated_fname, entry_name)
3279 self.assertEqual(expected, data)
3280
3281 # Check the state looks right.
3282 self.assertEqual('/binman/image', state.fdt_path_prefix)
3283
3284 # Now check we can write the first image
Simon Glassc1aa66e2022-01-29 14:14:04 -07003285 image_fname = tools.get_output_filename('first-image.bin')
3286 updated_fname = tools.get_output_filename('first-updated.bin')
3287 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass10f9d002019-07-20 12:23:50 -06003288 entry_name = 'u-boot'
Simon Glass51014aa2019-07-20 12:23:56 -06003289 control.WriteEntry(updated_fname, entry_name, expected,
3290 allow_resize=False)
Simon Glass10f9d002019-07-20 12:23:50 -06003291 data = control.ReadEntry(updated_fname, entry_name)
3292 self.assertEqual(expected, data)
3293
3294 # Check the state looks right.
3295 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass8beb11e2019-07-08 14:25:47 -06003296
Simon Glass12bb1a92019-07-20 12:23:51 -06003297 def testUpdateFdtAllRepack(self):
3298 """Test that all device trees are updated with offset/size info"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003299 self._SetupSplElf()
3300 self._SetupTplElf()
Simon Glass12bb1a92019-07-20 12:23:51 -06003301 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3302 SECTION_SIZE = 0x300
3303 DTB_SIZE = 602
3304 FDTMAP_SIZE = 608
3305 base_expected = {
3306 'offset': 0,
3307 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3308 'image-pos': 0,
3309 'section:offset': 0,
3310 'section:size': SECTION_SIZE,
3311 'section:image-pos': 0,
3312 'section/u-boot-dtb:offset': 4,
3313 'section/u-boot-dtb:size': 636,
3314 'section/u-boot-dtb:image-pos': 4,
3315 'u-boot-spl-dtb:offset': SECTION_SIZE,
3316 'u-boot-spl-dtb:size': DTB_SIZE,
3317 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3318 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3319 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3320 'u-boot-tpl-dtb:size': DTB_SIZE,
3321 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3322 'fdtmap:size': FDTMAP_SIZE,
3323 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3324 }
3325 main_expected = {
3326 'section:orig-size': SECTION_SIZE,
3327 'section/u-boot-dtb:orig-offset': 4,
3328 }
3329
3330 # We expect three device-tree files in the output, with the first one
3331 # within a fixed-size section.
3332 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3333 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3334 # main U-Boot tree. All three should have the same positions and offset
3335 # except that the main tree should include the main_expected properties
3336 start = 4
3337 for item in ['', 'spl', 'tpl', None]:
3338 if item is None:
3339 start += 16 # Move past fdtmap header
3340 dtb = fdt.Fdt.FromData(data[start:])
3341 dtb.Scan()
3342 props = self._GetPropTree(dtb,
3343 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3344 prefix='/' if item is None else '/binman/')
3345 expected = dict(base_expected)
3346 if item:
3347 expected[item] = 0
3348 else:
3349 # Main DTB and fdtdec should include the 'orig-' properties
3350 expected.update(main_expected)
3351 # Helpful for debugging:
3352 #for prop in sorted(props):
3353 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3354 self.assertEqual(expected, props)
3355 if item == '':
3356 start = SECTION_SIZE
3357 else:
3358 start += dtb._fdt_obj.totalsize()
3359
Simon Glasseba1f0c2019-07-20 12:23:55 -06003360 def testFdtmapHeaderMiddle(self):
3361 """Test an FDT map in the middle of an image when it should be at end"""
3362 with self.assertRaises(ValueError) as e:
3363 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3364 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3365 str(e.exception))
3366
3367 def testFdtmapHeaderStartBad(self):
3368 """Test an FDT map in middle of an image when it should be at start"""
3369 with self.assertRaises(ValueError) as e:
3370 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3371 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3372 str(e.exception))
3373
3374 def testFdtmapHeaderEndBad(self):
3375 """Test an FDT map at the start of an image when it should be at end"""
3376 with self.assertRaises(ValueError) as e:
3377 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3378 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3379 str(e.exception))
3380
3381 def testFdtmapHeaderNoSize(self):
3382 """Test an image header at the end of an image with undefined size"""
3383 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3384
Simon Glass51014aa2019-07-20 12:23:56 -06003385 def testReplaceResize(self):
3386 """Test replacing a single file in an entry with a larger file"""
3387 expected = U_BOOT_DATA + b'x'
3388 data, _, image = self._RunReplaceCmd('u-boot', expected,
3389 dts='139_replace_repack.dts')
3390 self.assertEqual(expected, data)
3391
3392 entries = image.GetEntries()
3393 dtb_data = entries['u-boot-dtb'].data
3394 dtb = fdt.Fdt.FromData(dtb_data)
3395 dtb.Scan()
3396
3397 # The u-boot section should now be larger in the dtb
3398 node = dtb.GetNode('/binman/u-boot')
3399 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3400
3401 # Same for the fdtmap
3402 fdata = entries['fdtmap'].data
3403 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3404 fdtb.Scan()
3405 fnode = fdtb.GetNode('/u-boot')
3406 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3407
3408 def testReplaceResizeNoRepack(self):
3409 """Test replacing an entry with a larger file when not allowed"""
3410 expected = U_BOOT_DATA + b'x'
3411 with self.assertRaises(ValueError) as e:
3412 self._RunReplaceCmd('u-boot', expected)
3413 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3414 str(e.exception))
3415
Simon Glass61ec04f2019-07-20 12:23:58 -06003416 def testEntryShrink(self):
3417 """Test contracting an entry after it is packed"""
3418 try:
3419 state.SetAllowEntryContraction(True)
3420 data = self._DoReadFileDtb('140_entry_shrink.dts',
3421 update_dtb=True)[0]
3422 finally:
3423 state.SetAllowEntryContraction(False)
3424 self.assertEqual(b'a', data[:1])
3425 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3426 self.assertEqual(b'a', data[-1:])
3427
3428 def testEntryShrinkFail(self):
3429 """Test not being allowed to contract an entry after it is packed"""
3430 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3431
3432 # In this case there is a spare byte at the end of the data. The size of
3433 # the contents is only 1 byte but we still have the size before it
3434 # shrunk.
3435 self.assertEqual(b'a\0', data[:2])
3436 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3437 self.assertEqual(b'a\0', data[-2:])
3438
Simon Glass27145fd2019-07-20 12:24:01 -06003439 def testDescriptorOffset(self):
3440 """Test that the Intel descriptor is always placed at at the start"""
3441 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3442 image = control.images['image']
3443 entries = image.GetEntries()
3444 desc = entries['intel-descriptor']
3445 self.assertEqual(0xff800000, desc.offset);
3446 self.assertEqual(0xff800000, desc.image_pos);
3447
Simon Glasseb0f4a42019-07-20 12:24:06 -06003448 def testReplaceCbfs(self):
3449 """Test replacing a single file in CBFS without changing the size"""
3450 self._CheckLz4()
3451 expected = b'x' * len(U_BOOT_DATA)
3452 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003453 updated_fname = tools.get_output_filename('image-updated.bin')
3454 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003455 entry_name = 'section/cbfs/u-boot'
3456 control.WriteEntry(updated_fname, entry_name, expected,
3457 allow_resize=True)
3458 data = control.ReadEntry(updated_fname, entry_name)
3459 self.assertEqual(expected, data)
3460
3461 def testReplaceResizeCbfs(self):
3462 """Test replacing a single file in CBFS with one of a different size"""
3463 self._CheckLz4()
3464 expected = U_BOOT_DATA + b'x'
3465 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003466 updated_fname = tools.get_output_filename('image-updated.bin')
3467 tools.write_file(updated_fname, data)
Simon Glasseb0f4a42019-07-20 12:24:06 -06003468 entry_name = 'section/cbfs/u-boot'
3469 control.WriteEntry(updated_fname, entry_name, expected,
3470 allow_resize=True)
3471 data = control.ReadEntry(updated_fname, entry_name)
3472 self.assertEqual(expected, data)
3473
Simon Glassa6cb9952019-07-20 12:24:15 -06003474 def _SetupForReplace(self):
3475 """Set up some files to use to replace entries
3476
3477 This generates an image, copies it to a new file, extracts all the files
3478 in it and updates some of them
3479
3480 Returns:
3481 List
3482 Image filename
3483 Output directory
3484 Expected values for updated entries, each a string
3485 """
3486 data = self._DoReadFileRealDtb('143_replace_all.dts')
3487
Simon Glassc1aa66e2022-01-29 14:14:04 -07003488 updated_fname = tools.get_output_filename('image-updated.bin')
3489 tools.write_file(updated_fname, data)
Simon Glassa6cb9952019-07-20 12:24:15 -06003490
3491 outdir = os.path.join(self._indir, 'extract')
3492 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3493
3494 expected1 = b'x' + U_BOOT_DATA + b'y'
3495 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003496 tools.write_file(u_boot_fname1, expected1)
Simon Glassa6cb9952019-07-20 12:24:15 -06003497
3498 expected2 = b'a' + U_BOOT_DATA + b'b'
3499 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003500 tools.write_file(u_boot_fname2, expected2)
Simon Glassa6cb9952019-07-20 12:24:15 -06003501
3502 expected_text = b'not the same text'
3503 text_fname = os.path.join(outdir, 'text')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003504 tools.write_file(text_fname, expected_text)
Simon Glassa6cb9952019-07-20 12:24:15 -06003505
3506 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3507 dtb = fdt.FdtScan(dtb_fname)
3508 node = dtb.GetNode('/binman/text')
3509 node.AddString('my-property', 'the value')
3510 dtb.Sync(auto_resize=True)
3511 dtb.Flush()
3512
3513 return updated_fname, outdir, expected1, expected2, expected_text
3514
3515 def _CheckReplaceMultiple(self, entry_paths):
3516 """Handle replacing the contents of multiple entries
3517
3518 Args:
3519 entry_paths: List of entry paths to replace
3520
3521 Returns:
3522 List
3523 Dict of entries in the image:
3524 key: Entry name
3525 Value: Entry object
3526 Expected values for updated entries, each a string
3527 """
3528 updated_fname, outdir, expected1, expected2, expected_text = (
3529 self._SetupForReplace())
3530 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3531
3532 image = Image.FromFile(updated_fname)
3533 image.LoadData()
3534 return image.GetEntries(), expected1, expected2, expected_text
3535
3536 def testReplaceAll(self):
3537 """Test replacing the contents of all entries"""
3538 entries, expected1, expected2, expected_text = (
3539 self._CheckReplaceMultiple([]))
3540 data = entries['u-boot'].data
3541 self.assertEqual(expected1, data)
3542
3543 data = entries['u-boot2'].data
3544 self.assertEqual(expected2, data)
3545
3546 data = entries['text'].data
3547 self.assertEqual(expected_text, data)
3548
3549 # Check that the device tree is updated
3550 data = entries['u-boot-dtb'].data
3551 dtb = fdt.Fdt.FromData(data)
3552 dtb.Scan()
3553 node = dtb.GetNode('/binman/text')
3554 self.assertEqual('the value', node.props['my-property'].value)
3555
3556 def testReplaceSome(self):
3557 """Test replacing the contents of a few entries"""
3558 entries, expected1, expected2, expected_text = (
3559 self._CheckReplaceMultiple(['u-boot2', 'text']))
3560
3561 # This one should not change
3562 data = entries['u-boot'].data
3563 self.assertEqual(U_BOOT_DATA, data)
3564
3565 data = entries['u-boot2'].data
3566 self.assertEqual(expected2, data)
3567
3568 data = entries['text'].data
3569 self.assertEqual(expected_text, data)
3570
3571 def testReplaceCmd(self):
3572 """Test replacing a file fron an image on the command line"""
3573 self._DoReadFileRealDtb('143_replace_all.dts')
3574
3575 try:
3576 tmpdir, updated_fname = self._SetupImageInTmpdir()
3577
3578 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3579 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003580 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003581
3582 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003583 data = tools.read_file(updated_fname)
Simon Glassa6cb9952019-07-20 12:24:15 -06003584 self.assertEqual(expected, data[:len(expected)])
3585 map_fname = os.path.join(tmpdir, 'image-updated.map')
3586 self.assertFalse(os.path.exists(map_fname))
3587 finally:
3588 shutil.rmtree(tmpdir)
3589
3590 def testReplaceCmdSome(self):
3591 """Test replacing some files fron an image on the command line"""
3592 updated_fname, outdir, expected1, expected2, expected_text = (
3593 self._SetupForReplace())
3594
3595 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3596 'u-boot2', 'text')
3597
Simon Glassc1aa66e2022-01-29 14:14:04 -07003598 tools.prepare_output_dir(None)
Simon Glassa6cb9952019-07-20 12:24:15 -06003599 image = Image.FromFile(updated_fname)
3600 image.LoadData()
3601 entries = image.GetEntries()
3602
3603 # This one should not change
3604 data = entries['u-boot'].data
3605 self.assertEqual(U_BOOT_DATA, data)
3606
3607 data = entries['u-boot2'].data
3608 self.assertEqual(expected2, data)
3609
3610 data = entries['text'].data
3611 self.assertEqual(expected_text, data)
3612
3613 def testReplaceMissing(self):
3614 """Test replacing entries where the file is missing"""
3615 updated_fname, outdir, expected1, expected2, expected_text = (
3616 self._SetupForReplace())
3617
3618 # Remove one of the files, to generate a warning
3619 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3620 os.remove(u_boot_fname1)
3621
3622 with test_util.capture_sys_output() as (stdout, stderr):
3623 control.ReplaceEntries(updated_fname, None, outdir, [])
3624 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass38fdb4c2020-07-09 18:39:39 -06003625 stderr.getvalue())
Simon Glassa6cb9952019-07-20 12:24:15 -06003626
3627 def testReplaceCmdMap(self):
3628 """Test replacing a file fron an image on the command line"""
3629 self._DoReadFileRealDtb('143_replace_all.dts')
3630
3631 try:
3632 tmpdir, updated_fname = self._SetupImageInTmpdir()
3633
3634 fname = os.path.join(self._indir, 'update-u-boot.bin')
3635 expected = b'x' * len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003636 tools.write_file(fname, expected)
Simon Glassa6cb9952019-07-20 12:24:15 -06003637
3638 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3639 '-f', fname, '-m')
3640 map_fname = os.path.join(tmpdir, 'image-updated.map')
3641 self.assertTrue(os.path.exists(map_fname))
3642 finally:
3643 shutil.rmtree(tmpdir)
3644
3645 def testReplaceNoEntryPaths(self):
3646 """Test replacing an entry without an entry path"""
3647 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003648 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003649 with self.assertRaises(ValueError) as e:
3650 control.ReplaceEntries(image_fname, 'fname', None, [])
3651 self.assertIn('Must specify an entry path to read with -f',
3652 str(e.exception))
3653
3654 def testReplaceTooManyEntryPaths(self):
3655 """Test extracting some entries"""
3656 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003657 image_fname = tools.get_output_filename('image.bin')
Simon Glassa6cb9952019-07-20 12:24:15 -06003658 with self.assertRaises(ValueError) as e:
3659 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3660 self.assertIn('Must specify exactly one entry path to write with -f',
3661 str(e.exception))
3662
Simon Glass2250ee62019-08-24 07:22:48 -06003663 def testPackReset16(self):
3664 """Test that an image with an x86 reset16 region can be created"""
3665 data = self._DoReadFile('144_x86_reset16.dts')
3666 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3667
3668 def testPackReset16Spl(self):
3669 """Test that an image with an x86 reset16-spl region can be created"""
3670 data = self._DoReadFile('145_x86_reset16_spl.dts')
3671 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3672
3673 def testPackReset16Tpl(self):
3674 """Test that an image with an x86 reset16-tpl region can be created"""
3675 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3676 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3677
Simon Glass5af12072019-08-24 07:22:50 -06003678 def testPackIntelFit(self):
3679 """Test that an image with an Intel FIT and pointer can be created"""
3680 data = self._DoReadFile('147_intel_fit.dts')
3681 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3682 fit = data[16:32];
3683 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3684 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3685
3686 image = control.images['image']
3687 entries = image.GetEntries()
3688 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3689 self.assertEqual(expected_ptr, ptr)
3690
3691 def testPackIntelFitMissing(self):
3692 """Test detection of a FIT pointer with not FIT region"""
3693 with self.assertRaises(ValueError) as e:
3694 self._DoReadFile('148_intel_fit_missing.dts')
3695 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3696 str(e.exception))
3697
Simon Glass7c150132019-11-06 17:22:44 -07003698 def _CheckSymbolsTplSection(self, dts, expected_vals):
3699 data = self._DoReadFile(dts)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003700 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass2090f1e2019-08-24 07:23:00 -06003701 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003702 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003703 self.assertEqual(expected1, data[:upto1])
3704
3705 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003706 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass2090f1e2019-08-24 07:23:00 -06003707 self.assertEqual(expected2, data[upto1:upto2])
3708
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003709 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glassc1aa66e2022-01-29 14:14:04 -07003710 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass2090f1e2019-08-24 07:23:00 -06003711 self.assertEqual(expected3, data[upto2:upto3])
3712
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003713 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass7c150132019-11-06 17:22:44 -07003714 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3715
3716 def testSymbolsTplSection(self):
3717 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3718 self._SetupSplElf('u_boot_binman_syms')
3719 self._SetupTplElf('u_boot_binman_syms')
3720 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003721 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass7c150132019-11-06 17:22:44 -07003722
3723 def testSymbolsTplSectionX86(self):
3724 """Test binman can assign symbols in a section with end-at-4gb"""
3725 self._SetupSplElf('u_boot_binman_syms_x86')
3726 self._SetupTplElf('u_boot_binman_syms_x86')
3727 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03003728 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass7c150132019-11-06 17:22:44 -07003729 0x04])
Simon Glass2090f1e2019-08-24 07:23:00 -06003730
Simon Glassbf4d0e22019-08-24 07:23:03 -06003731 def testPackX86RomIfwiSectiom(self):
3732 """Test that a section can be placed in an IFWI region"""
3733 self._SetupIfwi('fitimage.bin')
3734 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3735 self._CheckIfwi(data)
3736
Simon Glassea0fff92019-08-24 07:23:07 -06003737 def testPackFspM(self):
3738 """Test that an image with a FSP memory-init binary can be created"""
3739 data = self._DoReadFile('152_intel_fsp_m.dts')
3740 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3741
Simon Glassbc6a88f2019-10-20 21:31:35 -06003742 def testPackFspS(self):
3743 """Test that an image with a FSP silicon-init binary can be created"""
3744 data = self._DoReadFile('153_intel_fsp_s.dts')
3745 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassea0fff92019-08-24 07:23:07 -06003746
Simon Glass998d1482019-10-20 21:31:36 -06003747 def testPackFspT(self):
3748 """Test that an image with a FSP temp-ram-init binary can be created"""
3749 data = self._DoReadFile('154_intel_fsp_t.dts')
3750 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3751
Simon Glass0dc706f2020-07-09 18:39:31 -06003752 def testMkimage(self):
3753 """Test using mkimage to build an image"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003754 self._SetupSplElf()
Simon Glass0dc706f2020-07-09 18:39:31 -06003755 data = self._DoReadFile('156_mkimage.dts')
3756
3757 # Just check that the data appears in the file somewhere
3758 self.assertIn(U_BOOT_SPL_DATA, data)
3759
Simon Glass4f9ee832022-01-09 20:14:09 -07003760 def testMkimageMissing(self):
3761 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003762 self._SetupSplElf()
Simon Glass4f9ee832022-01-09 20:14:09 -07003763 with test_util.capture_sys_output() as (_, stderr):
3764 self._DoTestFile('156_mkimage.dts',
3765 force_missing_bintools='mkimage')
3766 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003767 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass4f9ee832022-01-09 20:14:09 -07003768
Simon Glassce867ad2020-07-09 18:39:36 -06003769 def testExtblob(self):
3770 """Test an image with an external blob"""
3771 data = self._DoReadFile('157_blob_ext.dts')
3772 self.assertEqual(REFCODE_DATA, data)
3773
3774 def testExtblobMissing(self):
3775 """Test an image with a missing external blob"""
3776 with self.assertRaises(ValueError) as e:
3777 self._DoReadFile('158_blob_ext_missing.dts')
3778 self.assertIn("Filename 'missing-file' not found in input path",
3779 str(e.exception))
3780
Simon Glass4f9f1052020-07-09 18:39:38 -06003781 def testExtblobMissingOk(self):
3782 """Test an image with an missing external blob that is allowed"""
Simon Glassb1cca952020-07-09 18:39:40 -06003783 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glassb38da152022-11-09 19:14:42 -07003784 ret = self._DoTestFile('158_blob_ext_missing.dts',
3785 allow_missing=True)
3786 self.assertEqual(103, ret)
Simon Glassb1cca952020-07-09 18:39:40 -06003787 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003788 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glassb38da152022-11-09 19:14:42 -07003789 self.assertIn('Some images are invalid', err)
3790
3791 def testExtblobMissingOkFlag(self):
3792 """Test an image with an missing external blob allowed with -W"""
3793 with test_util.capture_sys_output() as (stdout, stderr):
3794 ret = self._DoTestFile('158_blob_ext_missing.dts',
3795 allow_missing=True, ignore_missing=True)
3796 self.assertEqual(0, ret)
3797 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003798 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glassb38da152022-11-09 19:14:42 -07003799 self.assertIn('Some images are invalid', err)
Simon Glassb1cca952020-07-09 18:39:40 -06003800
3801 def testExtblobMissingOkSect(self):
3802 """Test an image with an missing external blob that is allowed"""
3803 with test_util.capture_sys_output() as (stdout, stderr):
3804 self._DoTestFile('159_blob_ext_missing_sect.dts',
3805 allow_missing=True)
3806 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003807 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass4f9f1052020-07-09 18:39:38 -06003808
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003809 def testPackX86RomMeMissingDesc(self):
3810 """Test that an missing Intel descriptor entry is allowed"""
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003811 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass52b10dd2020-07-25 15:11:19 -06003812 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003813 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003814 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003815
3816 def testPackX86RomMissingIfwi(self):
3817 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3818 self._SetupIfwi('fitimage.bin')
3819 pathname = os.path.join(self._indir, 'fitimage.bin')
3820 os.remove(pathname)
3821 with test_util.capture_sys_output() as (stdout, stderr):
3822 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3823 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07003824 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glass0ba4b3d2020-07-09 18:39:41 -06003825
Simon Glass8d2ef3e2022-02-11 13:23:21 -07003826 def testPackOverlapZero(self):
Simon Glassb3295fd2020-07-09 18:39:42 -06003827 """Test that zero-size overlapping regions are ignored"""
3828 self._DoTestFile('160_pack_overlap_zero.dts')
3829
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003830 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glassfdc34362020-07-09 18:39:45 -06003831 # The data should be inside the FIT
3832 dtb = fdt.Fdt.FromData(fit_data)
3833 dtb.Scan()
3834 fnode = dtb.GetNode('/images/kernel')
3835 self.assertIn('data', fnode.props)
3836
3837 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glassc1aa66e2022-01-29 14:14:04 -07003838 tools.write_file(fname, fit_data)
3839 out = tools.run('dumpimage', '-l', fname)
Simon Glassfdc34362020-07-09 18:39:45 -06003840
3841 # Check a few features to make sure the plumbing works. We don't need
3842 # to test the operation of mkimage or dumpimage here. First convert the
3843 # output into a dict where the keys are the fields printed by dumpimage
3844 # and the values are a list of values for each field
3845 lines = out.splitlines()
3846
3847 # Converts "Compression: gzip compressed" into two groups:
3848 # 'Compression' and 'gzip compressed'
3849 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3850 vals = collections.defaultdict(list)
3851 for line in lines:
3852 mat = re_line.match(line)
3853 vals[mat.group(1)].append(mat.group(2))
3854
3855 self.assertEquals('FIT description: test-desc', lines[0])
3856 self.assertIn('Created:', lines[1])
3857 self.assertIn('Image 0 (kernel)', vals)
3858 self.assertIn('Hash value', vals)
3859 data_sizes = vals.get('Data Size')
3860 self.assertIsNotNone(data_sizes)
3861 self.assertEqual(2, len(data_sizes))
3862 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003863 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3864 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3865
Alper Nebi Yasake7368782022-03-27 18:31:47 +03003866 # Check if entry listing correctly omits /images/
3867 image = control.images['image']
3868 fit_entry = image.GetEntries()['fit']
3869 subentries = list(fit_entry.GetEntries().keys())
3870 expected = ['kernel', 'fdt-1']
3871 self.assertEqual(expected, subentries)
3872
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003873 def testSimpleFit(self):
3874 """Test an image with a FIT inside"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06003875 self._SetupSplElf()
Alper Nebi Yasak21353312022-02-08 01:08:04 +03003876 data = self._DoReadFile('161_fit.dts')
3877 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3878 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3879 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3880
3881 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3882
3883 def testSimpleFitExpandsSubentries(self):
3884 """Test that FIT images expand their subentries"""
3885 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3886 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3887 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3888 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3889
3890 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glassfdc34362020-07-09 18:39:45 -06003891
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003892 def testSimpleFitImagePos(self):
3893 """Test that we have correct image-pos for FIT subentries"""
3894 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3895 update_dtb=True)
3896 dtb = fdt.Fdt(out_dtb_fname)
3897 dtb.Scan()
3898 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3899
Simon Glass38397d02022-03-05 20:19:01 -07003900 self.maxDiff = None
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003901 self.assertEqual({
3902 'image-pos': 0,
3903 'offset': 0,
3904 'size': 1890,
3905
3906 'u-boot:image-pos': 0,
3907 'u-boot:offset': 0,
3908 'u-boot:size': 4,
3909
3910 'fit:image-pos': 4,
3911 'fit:offset': 4,
3912 'fit:size': 1840,
3913
Simon Glass38397d02022-03-05 20:19:01 -07003914 'fit/images/kernel:image-pos': 304,
3915 'fit/images/kernel:offset': 300,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003916 'fit/images/kernel:size': 4,
3917
Simon Glass38397d02022-03-05 20:19:01 -07003918 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003919 'fit/images/kernel/u-boot:offset': 0,
3920 'fit/images/kernel/u-boot:size': 4,
3921
Simon Glass38397d02022-03-05 20:19:01 -07003922 'fit/images/fdt-1:image-pos': 552,
3923 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003924 'fit/images/fdt-1:size': 6,
3925
Simon Glass38397d02022-03-05 20:19:01 -07003926 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003927 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3928 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3929
3930 'u-boot-nodtb:image-pos': 1844,
3931 'u-boot-nodtb:offset': 1844,
3932 'u-boot-nodtb:size': 46,
3933 }, props)
3934
3935 # Actually check the data is where we think it is
3936 for node, expected in [
3937 ("u-boot", U_BOOT_DATA),
3938 ("fit/images/kernel", U_BOOT_DATA),
3939 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3940 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3941 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3942 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3943 ]:
3944 image_pos = props[f"{node}:image-pos"]
3945 size = props[f"{node}:size"]
3946 self.assertEqual(len(expected), size)
3947 self.assertEqual(expected, data[image_pos:image_pos+size])
3948
Simon Glassfdc34362020-07-09 18:39:45 -06003949 def testFitExternal(self):
Simon Glasse9d336d2020-09-01 05:13:55 -06003950 """Test an image with an FIT with external images"""
Simon Glassfdc34362020-07-09 18:39:45 -06003951 data = self._DoReadFile('162_fit_external.dts')
3952 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3953
Simon Glass8bc78b72022-01-09 20:13:39 -07003954 # Size of the external-data region as set up by mkimage
3955 external_data_size = len(U_BOOT_DATA) + 2
3956 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glassc1aa66e2022-01-29 14:14:04 -07003957 tools.align(external_data_size, 4) +
Simon Glass8bc78b72022-01-09 20:13:39 -07003958 len(U_BOOT_NODTB_DATA))
3959
Simon Glassfdc34362020-07-09 18:39:45 -06003960 # The data should be outside the FIT
3961 dtb = fdt.Fdt.FromData(fit_data)
3962 dtb.Scan()
3963 fnode = dtb.GetNode('/images/kernel')
3964 self.assertNotIn('data', fnode.props)
Simon Glass8bc78b72022-01-09 20:13:39 -07003965 self.assertEqual(len(U_BOOT_DATA),
3966 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3967 fit_pos = 0x400;
3968 self.assertEqual(
3969 fit_pos,
3970 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3971
3972 self.assertEquals(expected_size, len(data))
3973 actual_pos = len(U_BOOT_DATA) + fit_pos
3974 self.assertEqual(U_BOOT_DATA + b'aa',
3975 data[actual_pos:actual_pos + external_data_size])
Simon Glass12bb1a92019-07-20 12:23:51 -06003976
Alper Nebi Yasak73092222022-02-08 01:08:08 +03003977 def testFitExternalImagePos(self):
3978 """Test that we have correct image-pos for external FIT subentries"""
3979 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3980 update_dtb=True)
3981 dtb = fdt.Fdt(out_dtb_fname)
3982 dtb.Scan()
3983 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3984
3985 self.assertEqual({
3986 'image-pos': 0,
3987 'offset': 0,
3988 'size': 1082,
3989
3990 'u-boot:image-pos': 0,
3991 'u-boot:offset': 0,
3992 'u-boot:size': 4,
3993
3994 'fit:size': 1032,
3995 'fit:offset': 4,
3996 'fit:image-pos': 4,
3997
3998 'fit/images/kernel:size': 4,
3999 'fit/images/kernel:offset': 1024,
4000 'fit/images/kernel:image-pos': 1028,
4001
4002 'fit/images/kernel/u-boot:size': 4,
4003 'fit/images/kernel/u-boot:offset': 0,
4004 'fit/images/kernel/u-boot:image-pos': 1028,
4005
4006 'fit/images/fdt-1:size': 2,
4007 'fit/images/fdt-1:offset': 1028,
4008 'fit/images/fdt-1:image-pos': 1032,
4009
4010 'fit/images/fdt-1/_testing:size': 2,
4011 'fit/images/fdt-1/_testing:offset': 0,
4012 'fit/images/fdt-1/_testing:image-pos': 1032,
4013
4014 'u-boot-nodtb:image-pos': 1036,
4015 'u-boot-nodtb:offset': 1036,
4016 'u-boot-nodtb:size': 46,
4017 }, props)
4018
4019 # Actually check the data is where we think it is
4020 for node, expected in [
4021 ("u-boot", U_BOOT_DATA),
4022 ("fit/images/kernel", U_BOOT_DATA),
4023 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4024 ("fit/images/fdt-1", b'aa'),
4025 ("fit/images/fdt-1/_testing", b'aa'),
4026 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4027 ]:
4028 image_pos = props[f"{node}:image-pos"]
4029 size = props[f"{node}:size"]
4030 self.assertEqual(len(expected), size)
4031 self.assertEqual(expected, data[image_pos:image_pos+size])
4032
Simon Glass4f9ee832022-01-09 20:14:09 -07004033 def testFitMissing(self):
Simon Glass033828c2023-03-02 17:02:43 -07004034 """Test that binman complains if mkimage is missing"""
4035 with self.assertRaises(ValueError) as e:
4036 self._DoTestFile('162_fit_external.dts',
4037 force_missing_bintools='mkimage')
4038 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4039 str(e.exception))
4040
4041 def testFitMissingOK(self):
Simon Glass4f9ee832022-01-09 20:14:09 -07004042 """Test that binman still produces a FIT image if mkimage is missing"""
4043 with test_util.capture_sys_output() as (_, stderr):
Simon Glass033828c2023-03-02 17:02:43 -07004044 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass4f9ee832022-01-09 20:14:09 -07004045 force_missing_bintools='mkimage')
4046 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004047 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass4f9ee832022-01-09 20:14:09 -07004048
Alper Nebi Yasak8001d0b2020-08-31 12:58:18 +03004049 def testSectionIgnoreHashSignature(self):
4050 """Test that sections ignore hash, signature nodes for its data"""
4051 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4052 expected = (U_BOOT_DATA + U_BOOT_DATA)
4053 self.assertEqual(expected, data)
4054
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004055 def testPadInSections(self):
4056 """Test pad-before, pad-after for entries in sections"""
Simon Glassf90d9062020-10-26 17:40:09 -06004057 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4058 '166_pad_in_sections.dts', update_dtb=True)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004059 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4060 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasak3fdeb142020-08-31 12:58:19 +03004061 U_BOOT_DATA)
4062 self.assertEqual(expected, data)
4063
Simon Glassf90d9062020-10-26 17:40:09 -06004064 dtb = fdt.Fdt(out_dtb_fname)
4065 dtb.Scan()
4066 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4067 expected = {
4068 'image-pos': 0,
4069 'offset': 0,
4070 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4071
4072 'section:image-pos': 0,
4073 'section:offset': 0,
4074 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4075
4076 'section/before:image-pos': 0,
4077 'section/before:offset': 0,
4078 'section/before:size': len(U_BOOT_DATA),
4079
4080 'section/u-boot:image-pos': 4,
4081 'section/u-boot:offset': 4,
4082 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4083
4084 'section/after:image-pos': 26,
4085 'section/after:offset': 26,
4086 'section/after:size': len(U_BOOT_DATA),
4087 }
4088 self.assertEqual(expected, props)
4089
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004090 def testFitImageSubentryAlignment(self):
4091 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03004092 self._SetupSplElf()
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004093 entry_args = {
4094 'test-id': TEXT_DATA,
4095 }
4096 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4097 entry_args=entry_args)
4098 dtb = fdt.Fdt.FromData(data)
4099 dtb.Scan()
4100
4101 node = dtb.GetNode('/images/kernel')
4102 data = dtb.GetProps(node)["data"].bytes
4103 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glassc1aa66e2022-01-29 14:14:04 -07004104 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4105 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004106 self.assertEqual(expected, data)
4107
4108 node = dtb.GetNode('/images/fdt-1')
4109 data = dtb.GetProps(node)["data"].bytes
Simon Glassc1aa66e2022-01-29 14:14:04 -07004110 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4111 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004112 U_BOOT_DTB_DATA)
4113 self.assertEqual(expected, data)
4114
4115 def testFitExtblobMissingOk(self):
4116 """Test a FIT with a missing external blob that is allowed"""
4117 with test_util.capture_sys_output() as (stdout, stderr):
4118 self._DoTestFile('168_fit_missing_blob.dts',
4119 allow_missing=True)
4120 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004121 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakfe057012020-08-31 12:58:20 +03004122
Simon Glass3decfa32020-09-01 05:13:54 -06004123 def testBlobNamedByArgMissing(self):
4124 """Test handling of a missing entry arg"""
4125 with self.assertRaises(ValueError) as e:
4126 self._DoReadFile('068_blob_named_by_arg.dts')
4127 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4128 str(e.exception))
4129
Simon Glassdc2f81a2020-09-01 05:13:58 -06004130 def testPackBl31(self):
4131 """Test that an image with an ATF BL31 binary can be created"""
4132 data = self._DoReadFile('169_atf_bl31.dts')
4133 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4134
Samuel Holland18bd4552020-10-21 21:12:15 -05004135 def testPackScp(self):
4136 """Test that an image with an SCP binary can be created"""
4137 data = self._DoReadFile('172_scp.dts')
4138 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4139
Simon Glass6cf99532020-09-01 05:13:59 -06004140 def testFitFdt(self):
4141 """Test an image with an FIT with multiple FDT images"""
4142 def _CheckFdt(seq, expected_data):
4143 """Check the FDT nodes
4144
4145 Args:
4146 seq: Sequence number to check (0 or 1)
4147 expected_data: Expected contents of 'data' property
4148 """
4149 name = 'fdt-%d' % seq
4150 fnode = dtb.GetNode('/images/%s' % name)
4151 self.assertIsNotNone(fnode)
4152 self.assertEqual({'description','type', 'compression', 'data'},
4153 set(fnode.props.keys()))
4154 self.assertEqual(expected_data, fnode.props['data'].bytes)
4155 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4156 fnode.props['description'].value)
Jan Kiszkab2106612022-02-28 17:06:20 +01004157 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glass6cf99532020-09-01 05:13:59 -06004158
4159 def _CheckConfig(seq, expected_data):
4160 """Check the configuration nodes
4161
4162 Args:
4163 seq: Sequence number to check (0 or 1)
4164 expected_data: Expected contents of 'data' property
4165 """
4166 cnode = dtb.GetNode('/configurations')
4167 self.assertIn('default', cnode.props)
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004168 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glass6cf99532020-09-01 05:13:59 -06004169
4170 name = 'config-%d' % seq
4171 fnode = dtb.GetNode('/configurations/%s' % name)
4172 self.assertIsNotNone(fnode)
4173 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4174 set(fnode.props.keys()))
4175 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4176 fnode.props['description'].value)
4177 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4178
4179 entry_args = {
4180 'of-list': 'test-fdt1 test-fdt2',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004181 'default-dt': 'test-fdt2',
Simon Glass6cf99532020-09-01 05:13:59 -06004182 }
4183 data = self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004184 '170_fit_fdt.dts',
Simon Glass6cf99532020-09-01 05:13:59 -06004185 entry_args=entry_args,
4186 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4187 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4188 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4189
4190 dtb = fdt.Fdt.FromData(fit_data)
4191 dtb.Scan()
4192 fnode = dtb.GetNode('/images/kernel')
4193 self.assertIn('data', fnode.props)
4194
4195 # Check all the properties in fdt-1 and fdt-2
4196 _CheckFdt(1, TEST_FDT1_DATA)
4197 _CheckFdt(2, TEST_FDT2_DATA)
4198
4199 # Check configurations
4200 _CheckConfig(1, TEST_FDT1_DATA)
4201 _CheckConfig(2, TEST_FDT2_DATA)
4202
4203 def testFitFdtMissingList(self):
4204 """Test handling of a missing 'of-list' entry arg"""
4205 with self.assertRaises(ValueError) as e:
Bin Mengaa75ce92021-05-10 20:23:32 +08004206 self._DoReadFile('170_fit_fdt.dts')
Simon Glass6cf99532020-09-01 05:13:59 -06004207 self.assertIn("Generator node requires 'of-list' entry argument",
4208 str(e.exception))
4209
4210 def testFitFdtEmptyList(self):
4211 """Test handling of an empty 'of-list' entry arg"""
4212 entry_args = {
4213 'of-list': '',
4214 }
4215 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4216
4217 def testFitFdtMissingProp(self):
4218 """Test handling of a missing 'fit,fdt-list' property"""
4219 with self.assertRaises(ValueError) as e:
4220 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4221 self.assertIn("Generator node requires 'fit,fdt-list' property",
4222 str(e.exception))
Simon Glassdc2f81a2020-09-01 05:13:58 -06004223
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004224 def testFitFdtMissing(self):
4225 """Test handling of a missing 'default-dt' entry arg"""
4226 entry_args = {
4227 'of-list': 'test-fdt1 test-fdt2',
4228 }
4229 with self.assertRaises(ValueError) as e:
4230 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004231 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004232 entry_args=entry_args,
4233 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4234 self.assertIn("Generated 'default' node requires default-dt entry argument",
4235 str(e.exception))
4236
4237 def testFitFdtNotInList(self):
4238 """Test handling of a default-dt that is not in the of-list"""
4239 entry_args = {
4240 'of-list': 'test-fdt1 test-fdt2',
4241 'default-dt': 'test-fdt3',
4242 }
4243 with self.assertRaises(ValueError) as e:
4244 self._DoReadFileDtb(
Bin Mengaa75ce92021-05-10 20:23:32 +08004245 '170_fit_fdt.dts',
Simon Glassc0f1ebe2020-09-06 10:39:08 -06004246 entry_args=entry_args,
4247 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4248 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4249 str(e.exception))
4250
Simon Glassb2381432020-09-06 10:39:09 -06004251 def testFitExtblobMissingHelp(self):
4252 """Test display of help messages when an external blob is missing"""
4253 control.missing_blob_help = control._ReadMissingBlobHelp()
4254 control.missing_blob_help['wibble'] = 'Wibble test'
4255 control.missing_blob_help['another'] = 'Another test'
4256 with test_util.capture_sys_output() as (stdout, stderr):
4257 self._DoTestFile('168_fit_missing_blob.dts',
4258 allow_missing=True)
4259 err = stderr.getvalue()
4260
4261 # We can get the tag from the name, the type or the missing-msg
4262 # property. Check all three.
4263 self.assertIn('You may need to build ARM Trusted', err)
4264 self.assertIn('Wibble test', err)
4265 self.assertIn('Another test', err)
4266
Simon Glass204aa782020-09-06 10:35:32 -06004267 def testMissingBlob(self):
4268 """Test handling of a blob containing a missing file"""
4269 with self.assertRaises(ValueError) as e:
4270 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4271 self.assertIn("Filename 'missing' not found in input path",
4272 str(e.exception))
4273
Simon Glassfb91d562020-09-06 10:35:33 -06004274 def testEnvironment(self):
4275 """Test adding a U-Boot environment"""
4276 data = self._DoReadFile('174_env.dts')
4277 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4278 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4279 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4280 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4281 env)
4282
4283 def testEnvironmentNoSize(self):
4284 """Test that a missing 'size' property is detected"""
4285 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004286 self._DoTestFile('175_env_no_size.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004287 self.assertIn("'u-boot-env' entry must have a size property",
4288 str(e.exception))
4289
4290 def testEnvironmentTooSmall(self):
4291 """Test handling of an environment that does not fit"""
4292 with self.assertRaises(ValueError) as e:
Simon Glassa4dfe3e2020-10-26 17:40:00 -06004293 self._DoTestFile('176_env_too_small.dts')
Simon Glassfb91d562020-09-06 10:35:33 -06004294
4295 # checksum, start byte, environment with \0 terminator, final \0
4296 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4297 short = need - 0x8
4298 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4299 str(e.exception))
4300
Simon Glassf2c0dd82020-10-26 17:40:01 -06004301 def testSkipAtStart(self):
4302 """Test handling of skip-at-start section"""
4303 data = self._DoReadFile('177_skip_at_start.dts')
4304 self.assertEqual(U_BOOT_DATA, data)
4305
4306 image = control.images['image']
4307 entries = image.GetEntries()
4308 section = entries['section']
4309 self.assertEqual(0, section.offset)
4310 self.assertEqual(len(U_BOOT_DATA), section.size)
4311 self.assertEqual(U_BOOT_DATA, section.GetData())
4312
4313 entry = section.GetEntries()['u-boot']
4314 self.assertEqual(16, entry.offset)
4315 self.assertEqual(len(U_BOOT_DATA), entry.size)
4316 self.assertEqual(U_BOOT_DATA, entry.data)
4317
4318 def testSkipAtStartPad(self):
4319 """Test handling of skip-at-start section with padded entry"""
4320 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004321 before = tools.get_bytes(0, 8)
4322 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004323 all = before + U_BOOT_DATA + after
4324 self.assertEqual(all, data)
4325
4326 image = control.images['image']
4327 entries = image.GetEntries()
4328 section = entries['section']
4329 self.assertEqual(0, section.offset)
4330 self.assertEqual(len(all), section.size)
4331 self.assertEqual(all, section.GetData())
4332
4333 entry = section.GetEntries()['u-boot']
4334 self.assertEqual(16, entry.offset)
4335 self.assertEqual(len(all), entry.size)
4336 self.assertEqual(U_BOOT_DATA, entry.data)
4337
4338 def testSkipAtStartSectionPad(self):
4339 """Test handling of skip-at-start section with padding"""
4340 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004341 before = tools.get_bytes(0, 8)
4342 after = tools.get_bytes(0, 4)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004343 all = before + U_BOOT_DATA + after
Simon Glassd1d3ad72020-10-26 17:40:13 -06004344 self.assertEqual(all, data)
Simon Glassf2c0dd82020-10-26 17:40:01 -06004345
4346 image = control.images['image']
4347 entries = image.GetEntries()
4348 section = entries['section']
4349 self.assertEqual(0, section.offset)
4350 self.assertEqual(len(all), section.size)
Simon Glass63e7ba62020-10-26 17:40:16 -06004351 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glassd1d3ad72020-10-26 17:40:13 -06004352 self.assertEqual(all, section.GetPaddedData())
Simon Glassf2c0dd82020-10-26 17:40:01 -06004353
4354 entry = section.GetEntries()['u-boot']
4355 self.assertEqual(16, entry.offset)
4356 self.assertEqual(len(U_BOOT_DATA), entry.size)
4357 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassfb91d562020-09-06 10:35:33 -06004358
Simon Glass7d398bb2020-10-26 17:40:14 -06004359 def testSectionPad(self):
4360 """Testing padding with sections"""
4361 data = self._DoReadFile('180_section_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004362 expected = (tools.get_bytes(ord('&'), 3) +
4363 tools.get_bytes(ord('!'), 5) +
Simon Glass7d398bb2020-10-26 17:40:14 -06004364 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004365 tools.get_bytes(ord('!'), 1) +
4366 tools.get_bytes(ord('&'), 2))
Simon Glass7d398bb2020-10-26 17:40:14 -06004367 self.assertEqual(expected, data)
4368
4369 def testSectionAlign(self):
4370 """Testing alignment with sections"""
4371 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4372 expected = (b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004373 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glass7d398bb2020-10-26 17:40:14 -06004374 b'\0' + # fill section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004375 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glass7d398bb2020-10-26 17:40:14 -06004376 U_BOOT_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004377 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4378 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glass7d398bb2020-10-26 17:40:14 -06004379 self.assertEqual(expected, data)
4380
Simon Glass8f5ef892020-10-26 17:40:25 -06004381 def testCompressImage(self):
4382 """Test compression of the entire image"""
4383 self._CheckLz4()
4384 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4385 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4386 dtb = fdt.Fdt(out_dtb_fname)
4387 dtb.Scan()
4388 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4389 'uncomp-size'])
4390 orig = self._decompress(data)
4391 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4392
4393 # Do a sanity check on various fields
4394 image = control.images['image']
4395 entries = image.GetEntries()
4396 self.assertEqual(2, len(entries))
4397
4398 entry = entries['blob']
4399 self.assertEqual(COMPRESS_DATA, entry.data)
4400 self.assertEqual(len(COMPRESS_DATA), entry.size)
4401
4402 entry = entries['u-boot']
4403 self.assertEqual(U_BOOT_DATA, entry.data)
4404 self.assertEqual(len(U_BOOT_DATA), entry.size)
4405
4406 self.assertEqual(len(data), image.size)
4407 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4408 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4409 orig = self._decompress(image.data)
4410 self.assertEqual(orig, image.uncomp_data)
4411
4412 expected = {
4413 'blob:offset': 0,
4414 'blob:size': len(COMPRESS_DATA),
4415 'u-boot:offset': len(COMPRESS_DATA),
4416 'u-boot:size': len(U_BOOT_DATA),
4417 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4418 'offset': 0,
4419 'image-pos': 0,
4420 'size': len(data),
4421 }
4422 self.assertEqual(expected, props)
4423
4424 def testCompressImageLess(self):
4425 """Test compression where compression reduces the image size"""
4426 self._CheckLz4()
4427 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4428 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4429 dtb = fdt.Fdt(out_dtb_fname)
4430 dtb.Scan()
4431 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4432 'uncomp-size'])
4433 orig = self._decompress(data)
4434
4435 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4436
4437 # Do a sanity check on various fields
4438 image = control.images['image']
4439 entries = image.GetEntries()
4440 self.assertEqual(2, len(entries))
4441
4442 entry = entries['blob']
4443 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4444 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4445
4446 entry = entries['u-boot']
4447 self.assertEqual(U_BOOT_DATA, entry.data)
4448 self.assertEqual(len(U_BOOT_DATA), entry.size)
4449
4450 self.assertEqual(len(data), image.size)
4451 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4452 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4453 image.uncomp_size)
4454 orig = self._decompress(image.data)
4455 self.assertEqual(orig, image.uncomp_data)
4456
4457 expected = {
4458 'blob:offset': 0,
4459 'blob:size': len(COMPRESS_DATA_BIG),
4460 'u-boot:offset': len(COMPRESS_DATA_BIG),
4461 'u-boot:size': len(U_BOOT_DATA),
4462 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4463 'offset': 0,
4464 'image-pos': 0,
4465 'size': len(data),
4466 }
4467 self.assertEqual(expected, props)
4468
4469 def testCompressSectionSize(self):
4470 """Test compression of a section with a fixed size"""
4471 self._CheckLz4()
4472 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4473 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4474 dtb = fdt.Fdt(out_dtb_fname)
4475 dtb.Scan()
4476 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4477 'uncomp-size'])
4478 orig = self._decompress(data)
4479 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4480 expected = {
4481 'section/blob:offset': 0,
4482 'section/blob:size': len(COMPRESS_DATA),
4483 'section/u-boot:offset': len(COMPRESS_DATA),
4484 'section/u-boot:size': len(U_BOOT_DATA),
4485 'section:offset': 0,
4486 'section:image-pos': 0,
4487 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4488 'section:size': 0x30,
4489 'offset': 0,
4490 'image-pos': 0,
4491 'size': 0x30,
4492 }
4493 self.assertEqual(expected, props)
4494
4495 def testCompressSection(self):
4496 """Test compression of a section with no fixed size"""
4497 self._CheckLz4()
4498 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4499 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4500 dtb = fdt.Fdt(out_dtb_fname)
4501 dtb.Scan()
4502 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4503 'uncomp-size'])
4504 orig = self._decompress(data)
4505 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4506 expected = {
4507 'section/blob:offset': 0,
4508 'section/blob:size': len(COMPRESS_DATA),
4509 'section/u-boot:offset': len(COMPRESS_DATA),
4510 'section/u-boot:size': len(U_BOOT_DATA),
4511 'section:offset': 0,
4512 'section:image-pos': 0,
4513 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4514 'section:size': len(data),
4515 'offset': 0,
4516 'image-pos': 0,
4517 'size': len(data),
4518 }
4519 self.assertEqual(expected, props)
4520
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004521 def testLz4Missing(self):
4522 """Test that binman still produces an image if lz4 is missing"""
4523 with test_util.capture_sys_output() as (_, stderr):
4524 self._DoTestFile('185_compress_section.dts',
4525 force_missing_bintools='lz4')
4526 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07004527 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeierc3665a82022-08-19 16:25:31 +02004528
Simon Glass8f5ef892020-10-26 17:40:25 -06004529 def testCompressExtra(self):
4530 """Test compression of a section with no fixed size"""
4531 self._CheckLz4()
4532 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4533 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4534 dtb = fdt.Fdt(out_dtb_fname)
4535 dtb.Scan()
4536 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4537 'uncomp-size'])
4538
4539 base = data[len(U_BOOT_DATA):]
4540 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4541 rest = base[len(U_BOOT_DATA):]
4542
4543 # Check compressed data
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004544 bintool = self.comp_bintools['lz4']
4545 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004546 data1 = rest[:len(expect1)]
4547 section1 = self._decompress(data1)
4548 self.assertEquals(expect1, data1)
Simon Glass8f5ef892020-10-26 17:40:25 -06004549 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4550 rest1 = rest[len(expect1):]
4551
Stefan Herbrechtsmeiercbe2e752022-08-19 16:25:28 +02004552 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeierfa24f552022-08-19 16:25:23 +02004553 data2 = rest1[:len(expect2)]
4554 section2 = self._decompress(data2)
4555 self.assertEquals(expect2, data2)
Simon Glass8f5ef892020-10-26 17:40:25 -06004556 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4557 rest2 = rest1[len(expect2):]
4558
4559 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4560 len(expect2) + len(U_BOOT_DATA))
4561 #self.assertEquals(expect_size, len(data))
4562
4563 #self.assertEquals(U_BOOT_DATA, rest2)
4564
4565 self.maxDiff = None
4566 expected = {
4567 'u-boot:offset': 0,
4568 'u-boot:image-pos': 0,
4569 'u-boot:size': len(U_BOOT_DATA),
4570
4571 'base:offset': len(U_BOOT_DATA),
4572 'base:image-pos': len(U_BOOT_DATA),
4573 'base:size': len(data) - len(U_BOOT_DATA),
4574 'base/u-boot:offset': 0,
4575 'base/u-boot:image-pos': len(U_BOOT_DATA),
4576 'base/u-boot:size': len(U_BOOT_DATA),
4577 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4578 len(expect2),
4579 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4580 len(expect2),
4581 'base/u-boot2:size': len(U_BOOT_DATA),
4582
4583 'base/section:offset': len(U_BOOT_DATA),
4584 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4585 'base/section:size': len(expect1),
4586 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4587 'base/section/blob:offset': 0,
4588 'base/section/blob:size': len(COMPRESS_DATA),
4589 'base/section/u-boot:offset': len(COMPRESS_DATA),
4590 'base/section/u-boot:size': len(U_BOOT_DATA),
4591
4592 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4593 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4594 'base/section2:size': len(expect2),
4595 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4596 'base/section2/blob:offset': 0,
4597 'base/section2/blob:size': len(COMPRESS_DATA),
4598 'base/section2/blob2:offset': len(COMPRESS_DATA),
4599 'base/section2/blob2:size': len(COMPRESS_DATA),
4600
4601 'offset': 0,
4602 'image-pos': 0,
4603 'size': len(data),
4604 }
4605 self.assertEqual(expected, props)
4606
Simon Glass870a9ea2021-01-06 21:35:15 -07004607 def testSymbolsSubsection(self):
4608 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak367ecbf2022-06-18 15:13:11 +03004609 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass870a9ea2021-01-06 21:35:15 -07004610
Simon Glass939d1062021-01-06 21:35:16 -07004611 def testReadImageEntryArg(self):
4612 """Test reading an image that would need an entry arg to generate"""
4613 entry_args = {
4614 'cros-ec-rw-path': 'ecrw.bin',
4615 }
4616 data = self.data = self._DoReadFileDtb(
4617 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4618 entry_args=entry_args)
4619
Simon Glassc1aa66e2022-01-29 14:14:04 -07004620 image_fname = tools.get_output_filename('image.bin')
Simon Glass939d1062021-01-06 21:35:16 -07004621 orig_image = control.images['image']
4622
4623 # This should not generate an error about the missing 'cros-ec-rw-path'
4624 # since we are reading the image from a file. Compare with
4625 # testEntryArgsRequired()
4626 image = Image.FromFile(image_fname)
4627 self.assertEqual(orig_image.GetEntries().keys(),
4628 image.GetEntries().keys())
4629
Simon Glass6eb99322021-01-06 21:35:18 -07004630 def testFilesAlign(self):
4631 """Test alignment with files"""
4632 data = self._DoReadFile('190_files_align.dts')
4633
4634 # The first string is 15 bytes so will align to 16
4635 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4636 self.assertEqual(expect, data)
4637
Simon Glass5c6ba712021-01-06 21:35:19 -07004638 def testReadImageSkip(self):
4639 """Test reading an image and accessing its FDT map"""
4640 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004641 image_fname = tools.get_output_filename('image.bin')
Simon Glass5c6ba712021-01-06 21:35:19 -07004642 orig_image = control.images['image']
4643 image = Image.FromFile(image_fname)
4644 self.assertEqual(orig_image.GetEntries().keys(),
4645 image.GetEntries().keys())
4646
4647 orig_entry = orig_image.GetEntries()['fdtmap']
4648 entry = image.GetEntries()['fdtmap']
4649 self.assertEqual(orig_entry.offset, entry.offset)
4650 self.assertEqual(orig_entry.size, entry.size)
4651 self.assertEqual(16, entry.image_pos)
4652
4653 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4654
4655 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4656
Simon Glass77a64e02021-03-18 20:24:57 +13004657 def testTplNoDtb(self):
4658 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass0fe44dc2021-04-25 08:39:32 +12004659 self._SetupTplElf()
Simon Glass77a64e02021-03-18 20:24:57 +13004660 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4661 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4662 data[:len(U_BOOT_TPL_NODTB_DATA)])
4663
Simon Glassd26efc82021-03-18 20:24:58 +13004664 def testTplBssPad(self):
4665 """Test that we can pad TPL's BSS with zeros"""
4666 # ELF file with a '__bss_size' symbol
4667 self._SetupTplElf()
4668 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004669 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassd26efc82021-03-18 20:24:58 +13004670 data)
4671
4672 def testTplBssPadMissing(self):
4673 """Test that a missing symbol is detected"""
4674 self._SetupTplElf('u_boot_ucode_ptr')
4675 with self.assertRaises(ValueError) as e:
4676 self._DoReadFile('193_tpl_bss_pad.dts')
4677 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4678 str(e.exception))
4679
Simon Glass06684922021-03-18 20:25:07 +13004680 def checkDtbSizes(self, data, pad_len, start):
4681 """Check the size arguments in a dtb embedded in an image
4682
4683 Args:
4684 data: The image data
4685 pad_len: Length of the pad section in the image, in bytes
4686 start: Start offset of the devicetree to examine, within the image
4687
4688 Returns:
4689 Size of the devicetree in bytes
4690 """
4691 dtb_data = data[start:]
4692 dtb = fdt.Fdt.FromData(dtb_data)
4693 fdt_size = dtb.GetFdtObj().totalsize()
4694 dtb.Scan()
4695 props = self._GetPropTree(dtb, 'size')
4696 self.assertEqual({
4697 'size': len(data),
4698 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4699 'u-boot-spl/u-boot-spl-dtb:size': 801,
4700 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4701 'u-boot-spl:size': 860,
4702 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4703 'u-boot/u-boot-dtb:size': 781,
4704 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4705 'u-boot:size': 827,
4706 }, props)
4707 return fdt_size
4708
4709 def testExpanded(self):
4710 """Test that an expanded entry type is selected when needed"""
4711 self._SetupSplElf()
4712 self._SetupTplElf()
4713
4714 # SPL has a devicetree, TPL does not
4715 entry_args = {
4716 'spl-dtb': '1',
4717 'spl-bss-pad': 'y',
4718 'tpl-dtb': '',
4719 }
4720 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4721 entry_args=entry_args)
4722 image = control.images['image']
4723 entries = image.GetEntries()
4724 self.assertEqual(3, len(entries))
4725
4726 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4727 self.assertIn('u-boot', entries)
4728 entry = entries['u-boot']
4729 self.assertEqual('u-boot-expanded', entry.etype)
4730 subent = entry.GetEntries()
4731 self.assertEqual(2, len(subent))
4732 self.assertIn('u-boot-nodtb', subent)
4733 self.assertIn('u-boot-dtb', subent)
4734
4735 # Second, u-boot-spl, which should be expanded into three parts
4736 self.assertIn('u-boot-spl', entries)
4737 entry = entries['u-boot-spl']
4738 self.assertEqual('u-boot-spl-expanded', entry.etype)
4739 subent = entry.GetEntries()
4740 self.assertEqual(3, len(subent))
4741 self.assertIn('u-boot-spl-nodtb', subent)
4742 self.assertIn('u-boot-spl-bss-pad', subent)
4743 self.assertIn('u-boot-spl-dtb', subent)
4744
4745 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4746 # devicetree
4747 self.assertIn('u-boot-tpl', entries)
4748 entry = entries['u-boot-tpl']
4749 self.assertEqual('u-boot-tpl', entry.etype)
4750 self.assertEqual(None, entry.GetEntries())
4751
4752 def testExpandedTpl(self):
4753 """Test that an expanded entry type is selected for TPL when needed"""
4754 self._SetupTplElf()
4755
4756 entry_args = {
4757 'tpl-bss-pad': 'y',
4758 'tpl-dtb': 'y',
4759 }
4760 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4761 entry_args=entry_args)
4762 image = control.images['image']
4763 entries = image.GetEntries()
4764 self.assertEqual(1, len(entries))
4765
4766 # We only have u-boot-tpl, which be expanded
4767 self.assertIn('u-boot-tpl', entries)
4768 entry = entries['u-boot-tpl']
4769 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4770 subent = entry.GetEntries()
4771 self.assertEqual(3, len(subent))
4772 self.assertIn('u-boot-tpl-nodtb', subent)
4773 self.assertIn('u-boot-tpl-bss-pad', subent)
4774 self.assertIn('u-boot-tpl-dtb', subent)
4775
4776 def testExpandedNoPad(self):
4777 """Test an expanded entry without BSS pad enabled"""
4778 self._SetupSplElf()
4779 self._SetupTplElf()
4780
4781 # SPL has a devicetree, TPL does not
4782 entry_args = {
4783 'spl-dtb': 'something',
4784 'spl-bss-pad': 'n',
4785 'tpl-dtb': '',
4786 }
4787 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4788 entry_args=entry_args)
4789 image = control.images['image']
4790 entries = image.GetEntries()
4791
4792 # Just check u-boot-spl, which should be expanded into two parts
4793 self.assertIn('u-boot-spl', entries)
4794 entry = entries['u-boot-spl']
4795 self.assertEqual('u-boot-spl-expanded', entry.etype)
4796 subent = entry.GetEntries()
4797 self.assertEqual(2, len(subent))
4798 self.assertIn('u-boot-spl-nodtb', subent)
4799 self.assertIn('u-boot-spl-dtb', subent)
4800
4801 def testExpandedTplNoPad(self):
4802 """Test that an expanded entry type with padding disabled in TPL"""
4803 self._SetupTplElf()
4804
4805 entry_args = {
4806 'tpl-bss-pad': '',
4807 'tpl-dtb': 'y',
4808 }
4809 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4810 entry_args=entry_args)
4811 image = control.images['image']
4812 entries = image.GetEntries()
4813 self.assertEqual(1, len(entries))
4814
4815 # We only have u-boot-tpl, which be expanded
4816 self.assertIn('u-boot-tpl', entries)
4817 entry = entries['u-boot-tpl']
4818 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4819 subent = entry.GetEntries()
4820 self.assertEqual(2, len(subent))
4821 self.assertIn('u-boot-tpl-nodtb', subent)
4822 self.assertIn('u-boot-tpl-dtb', subent)
4823
4824 def testFdtInclude(self):
4825 """Test that an Fdt is update within all binaries"""
4826 self._SetupSplElf()
4827 self._SetupTplElf()
4828
4829 # SPL has a devicetree, TPL does not
4830 self.maxDiff = None
4831 entry_args = {
4832 'spl-dtb': '1',
4833 'spl-bss-pad': 'y',
4834 'tpl-dtb': '',
4835 }
4836 # Build the image. It includes two separate devicetree binaries, each
4837 # with their own contents, but all contain the binman definition.
4838 data = self._DoReadFileDtb(
4839 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4840 update_dtb=True, entry_args=entry_args)[0]
4841 pad_len = 10
4842
4843 # Check the U-Boot dtb
4844 start = len(U_BOOT_NODTB_DATA)
4845 fdt_size = self.checkDtbSizes(data, pad_len, start)
4846
4847 # Now check SPL
4848 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4849 fdt_size = self.checkDtbSizes(data, pad_len, start)
4850
4851 # TPL has no devicetree
4852 start += fdt_size + len(U_BOOT_TPL_DATA)
4853 self.assertEqual(len(data), start)
Simon Glass7d398bb2020-10-26 17:40:14 -06004854
Simon Glass3d433382021-03-21 18:24:30 +13004855 def testSymbolsExpanded(self):
4856 """Test binman can assign symbols in expanded entries"""
4857 entry_args = {
4858 'spl-dtb': '1',
4859 }
4860 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4861 U_BOOT_SPL_DTB_DATA, 0x38,
4862 entry_args=entry_args, use_expanded=True)
4863
Simon Glass189f2912021-03-21 18:24:31 +13004864 def testCollection(self):
4865 """Test a collection"""
4866 data = self._DoReadFile('198_collection.dts')
4867 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glassc1aa66e2022-01-29 14:14:04 -07004868 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4869 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glass189f2912021-03-21 18:24:31 +13004870 data)
4871
Simon Glass631f7522021-03-21 18:24:32 +13004872 def testCollectionSection(self):
4873 """Test a collection where a section must be built first"""
4874 # Sections never have their contents when GetData() is called, but when
Simon Glassd34bcdd2021-11-23 11:03:47 -07004875 # BuildSectionData() is called with required=True, a section will force
Simon Glass631f7522021-03-21 18:24:32 +13004876 # building the contents, producing an error is anything is still
4877 # missing.
4878 data = self._DoReadFile('199_collection_section.dts')
4879 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glassc1aa66e2022-01-29 14:14:04 -07004880 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4881 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass631f7522021-03-21 18:24:32 +13004882 data)
4883
Simon Glass5ff9fed2021-03-21 18:24:33 +13004884 def testAlignDefault(self):
4885 """Test that default alignment works on sections"""
4886 data = self._DoReadFile('200_align_default.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07004887 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glass5ff9fed2021-03-21 18:24:33 +13004888 U_BOOT_DATA)
4889 # Special alignment for section
Simon Glassc1aa66e2022-01-29 14:14:04 -07004890 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glass5ff9fed2021-03-21 18:24:33 +13004891 # No alignment within the nested section
4892 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4893 # Now the final piece, which should be default-aligned
Simon Glassc1aa66e2022-01-29 14:14:04 -07004894 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glass5ff9fed2021-03-21 18:24:33 +13004895 self.assertEqual(expected, data)
Simon Glass631f7522021-03-21 18:24:32 +13004896
Bin Meng4c4d6072021-05-10 20:23:33 +08004897 def testPackOpenSBI(self):
4898 """Test that an image with an OpenSBI binary can be created"""
4899 data = self._DoReadFile('201_opensbi.dts')
4900 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4901
Simon Glassc69d19c2021-07-06 10:36:37 -06004902 def testSectionsSingleThread(self):
4903 """Test sections without multithreading"""
4904 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glassc1aa66e2022-01-29 14:14:04 -07004905 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4906 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4907 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassc69d19c2021-07-06 10:36:37 -06004908 self.assertEqual(expected, data)
4909
4910 def testThreadTimeout(self):
4911 """Test handling a thread that takes too long"""
4912 with self.assertRaises(ValueError) as e:
4913 self._DoTestFile('202_section_timeout.dts',
4914 test_section_timeout=True)
Simon Glassb2dfe832021-10-18 12:13:15 -06004915 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glassc69d19c2021-07-06 10:36:37 -06004916
Simon Glass03ebc202021-07-06 10:36:41 -06004917 def testTiming(self):
4918 """Test output of timing information"""
4919 data = self._DoReadFile('055_sections.dts')
4920 with test_util.capture_sys_output() as (stdout, stderr):
4921 state.TimingShow()
4922 self.assertIn('read:', stdout.getvalue())
4923 self.assertIn('compress:', stdout.getvalue())
4924
Simon Glass0427bed2021-11-03 21:09:18 -06004925 def testUpdateFdtInElf(self):
4926 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004927 if not elf.ELF_TOOLS:
4928 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004929 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4930 outfile = os.path.join(self._indir, 'u-boot.out')
4931 begin_sym = 'dtb_embed_begin'
4932 end_sym = 'dtb_embed_end'
4933 retcode = self._DoTestFile(
4934 '060_fdt_update.dts', update_dtb=True,
4935 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4936 self.assertEqual(0, retcode)
4937
4938 # Check that the output file does in fact contact a dtb with the binman
4939 # definition in the correct place
4940 syms = elf.GetSymbolFileOffset(infile,
4941 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07004942 data = tools.read_file(outfile)
Simon Glass0427bed2021-11-03 21:09:18 -06004943 dtb_data = data[syms['dtb_embed_begin'].offset:
4944 syms['dtb_embed_end'].offset]
4945
4946 dtb = fdt.Fdt.FromData(dtb_data)
4947 dtb.Scan()
4948 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4949 self.assertEqual({
4950 'image-pos': 0,
4951 'offset': 0,
4952 '_testing:offset': 32,
4953 '_testing:size': 2,
4954 '_testing:image-pos': 32,
4955 'section@0/u-boot:offset': 0,
4956 'section@0/u-boot:size': len(U_BOOT_DATA),
4957 'section@0/u-boot:image-pos': 0,
4958 'section@0:offset': 0,
4959 'section@0:size': 16,
4960 'section@0:image-pos': 0,
4961
4962 'section@1/u-boot:offset': 0,
4963 'section@1/u-boot:size': len(U_BOOT_DATA),
4964 'section@1/u-boot:image-pos': 16,
4965 'section@1:offset': 16,
4966 'section@1:size': 16,
4967 'section@1:image-pos': 16,
4968 'size': 40
4969 }, props)
4970
4971 def testUpdateFdtInElfInvalid(self):
4972 """Test that invalid args are detected with --update-fdt-in-elf"""
4973 with self.assertRaises(ValueError) as e:
4974 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4975 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4976 str(e.exception))
4977
4978 def testUpdateFdtInElfNoSyms(self):
4979 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004980 if not elf.ELF_TOOLS:
4981 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004982 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4983 outfile = ''
4984 begin_sym = 'wrong_begin'
4985 end_sym = 'wrong_end'
4986 with self.assertRaises(ValueError) as e:
4987 self._DoTestFile(
4988 '060_fdt_update.dts',
4989 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4990 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4991 str(e.exception))
4992
4993 def testUpdateFdtInElfTooSmall(self):
4994 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02004995 if not elf.ELF_TOOLS:
4996 self.skipTest('Python elftools not available')
Simon Glass0427bed2021-11-03 21:09:18 -06004997 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4998 outfile = os.path.join(self._indir, 'u-boot.out')
4999 begin_sym = 'dtb_embed_begin'
5000 end_sym = 'dtb_embed_end'
5001 with self.assertRaises(ValueError) as e:
5002 self._DoTestFile(
5003 '060_fdt_update.dts', update_dtb=True,
5004 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5005 self.assertRegex(
5006 str(e.exception),
5007 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5008
Simon Glassc475dec2021-11-23 11:03:42 -07005009 def testVersion(self):
5010 """Test we can get the binman version"""
5011 version = '(unreleased)'
5012 self.assertEqual(version, state.GetVersion(self._indir))
5013
5014 with self.assertRaises(SystemExit):
5015 with test_util.capture_sys_output() as (_, stderr):
5016 self._DoBinman('-V')
5017 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5018
5019 # Try running the tool too, just to be safe
5020 result = self._RunBinman('-V')
5021 self.assertEqual('Binman %s\n' % version, result.stderr)
5022
5023 # Set up a version file to make sure that works
5024 version = 'v2025.01-rc2'
Simon Glassc1aa66e2022-01-29 14:14:04 -07005025 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glassc475dec2021-11-23 11:03:42 -07005026 binary=False)
5027 self.assertEqual(version, state.GetVersion(self._indir))
5028
Simon Glass943bf782021-11-23 21:09:50 -07005029 def testAltFormat(self):
5030 """Test that alternative formats can be used to extract"""
5031 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5032
5033 try:
5034 tmpdir, updated_fname = self._SetupImageInTmpdir()
5035 with test_util.capture_sys_output() as (stdout, _):
5036 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5037 self.assertEqual(
5038 '''Flag (-F) Entry type Description
5039fdt fdtmap Extract the devicetree blob from the fdtmap
5040''',
5041 stdout.getvalue())
5042
5043 dtb = os.path.join(tmpdir, 'fdt.dtb')
5044 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5045 dtb, 'fdtmap')
5046
5047 # Check that we can read it and it can be scanning, meaning it does
5048 # not have a 16-byte fdtmap header
Simon Glassc1aa66e2022-01-29 14:14:04 -07005049 data = tools.read_file(dtb)
Simon Glass943bf782021-11-23 21:09:50 -07005050 dtb = fdt.Fdt.FromData(data)
5051 dtb.Scan()
5052
5053 # Now check u-boot which has no alt_format
5054 fname = os.path.join(tmpdir, 'fdt.dtb')
5055 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5056 '-f', fname, 'u-boot')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005057 data = tools.read_file(fname)
Simon Glass943bf782021-11-23 21:09:50 -07005058 self.assertEqual(U_BOOT_DATA, data)
5059
5060 finally:
5061 shutil.rmtree(tmpdir)
5062
Simon Glasscc2c5002021-11-23 21:09:52 -07005063 def testExtblobList(self):
5064 """Test an image with an external blob list"""
5065 data = self._DoReadFile('215_blob_ext_list.dts')
5066 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5067
5068 def testExtblobListMissing(self):
5069 """Test an image with a missing external blob"""
5070 with self.assertRaises(ValueError) as e:
5071 self._DoReadFile('216_blob_ext_list_missing.dts')
5072 self.assertIn("Filename 'missing-file' not found in input path",
5073 str(e.exception))
5074
5075 def testExtblobListMissingOk(self):
5076 """Test an image with an missing external blob that is allowed"""
5077 with test_util.capture_sys_output() as (stdout, stderr):
5078 self._DoTestFile('216_blob_ext_list_missing.dts',
5079 allow_missing=True)
5080 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005081 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glasscc2c5002021-11-23 21:09:52 -07005082
Simon Glass75989722021-11-23 21:08:59 -07005083 def testFip(self):
5084 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5085 data = self._DoReadFile('203_fip.dts')
5086 hdr, fents = fip_util.decode_fip(data)
5087 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5088 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5089 self.assertEqual(0x123, hdr.flags)
5090
5091 self.assertEqual(2, len(fents))
5092
5093 fent = fents[0]
5094 self.assertEqual(
5095 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5096 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5097 self.assertEqual('soc-fw', fent.fip_type)
5098 self.assertEqual(0x88, fent.offset)
5099 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5100 self.assertEqual(0x123456789abcdef, fent.flags)
5101 self.assertEqual(ATF_BL31_DATA, fent.data)
5102 self.assertEqual(True, fent.valid)
5103
5104 fent = fents[1]
5105 self.assertEqual(
5106 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5107 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5108 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5109 self.assertEqual(0x8c, fent.offset)
5110 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5111 self.assertEqual(0, fent.flags)
5112 self.assertEqual(ATF_BL2U_DATA, fent.data)
5113 self.assertEqual(True, fent.valid)
5114
5115 def testFipOther(self):
5116 """Basic FIP with something that isn't a external blob"""
5117 data = self._DoReadFile('204_fip_other.dts')
5118 hdr, fents = fip_util.decode_fip(data)
5119
5120 self.assertEqual(2, len(fents))
5121 fent = fents[1]
5122 self.assertEqual('rot-cert', fent.fip_type)
5123 self.assertEqual(b'aa', fent.data)
5124
Simon Glass75989722021-11-23 21:08:59 -07005125 def testFipNoType(self):
5126 """FIP with an entry of an unknown type"""
5127 with self.assertRaises(ValueError) as e:
5128 self._DoReadFile('205_fip_no_type.dts')
5129 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5130 str(e.exception))
5131
5132 def testFipUuid(self):
5133 """Basic FIP with a manual uuid"""
5134 data = self._DoReadFile('206_fip_uuid.dts')
5135 hdr, fents = fip_util.decode_fip(data)
5136
5137 self.assertEqual(2, len(fents))
5138 fent = fents[1]
5139 self.assertEqual(None, fent.fip_type)
5140 self.assertEqual(
5141 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5142 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5143 fent.uuid)
5144 self.assertEqual(U_BOOT_DATA, fent.data)
5145
5146 def testFipLs(self):
5147 """Test listing a FIP"""
5148 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5149 hdr, fents = fip_util.decode_fip(data)
5150
5151 try:
5152 tmpdir, updated_fname = self._SetupImageInTmpdir()
5153 with test_util.capture_sys_output() as (stdout, stderr):
5154 self._DoBinman('ls', '-i', updated_fname)
5155 finally:
5156 shutil.rmtree(tmpdir)
5157 lines = stdout.getvalue().splitlines()
5158 expected = [
Simon Glass193d3db2023-02-07 14:34:18 -07005159'Name Image-pos Size Entry-type Offset Uncomp-size',
5160'--------------------------------------------------------------',
5161'image 0 2d3 section 0',
5162' atf-fip 0 90 atf-fip 0',
5163' soc-fw 88 4 blob-ext 88',
5164' u-boot 8c 4 u-boot 8c',
5165' fdtmap 90 243 fdtmap 90',
Simon Glass75989722021-11-23 21:08:59 -07005166]
5167 self.assertEqual(expected, lines)
5168
5169 image = control.images['image']
5170 entries = image.GetEntries()
5171 fdtmap = entries['fdtmap']
5172
5173 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5174 magic = fdtmap_data[:8]
5175 self.assertEqual(b'_FDTMAP_', magic)
Simon Glassc1aa66e2022-01-29 14:14:04 -07005176 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass75989722021-11-23 21:08:59 -07005177
5178 fdt_data = fdtmap_data[16:]
5179 dtb = fdt.Fdt.FromData(fdt_data)
5180 dtb.Scan()
5181 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5182 self.assertEqual({
5183 'atf-fip/soc-fw:image-pos': 136,
5184 'atf-fip/soc-fw:offset': 136,
5185 'atf-fip/soc-fw:size': 4,
5186 'atf-fip/u-boot:image-pos': 140,
5187 'atf-fip/u-boot:offset': 140,
5188 'atf-fip/u-boot:size': 4,
5189 'atf-fip:image-pos': 0,
5190 'atf-fip:offset': 0,
5191 'atf-fip:size': 144,
5192 'image-pos': 0,
5193 'offset': 0,
5194 'fdtmap:image-pos': fdtmap.image_pos,
5195 'fdtmap:offset': fdtmap.offset,
5196 'fdtmap:size': len(fdtmap_data),
5197 'size': len(data),
5198 }, props)
5199
5200 def testFipExtractOneEntry(self):
5201 """Test extracting a single entry fron an FIP"""
5202 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005203 image_fname = tools.get_output_filename('image.bin')
Simon Glass75989722021-11-23 21:08:59 -07005204 fname = os.path.join(self._indir, 'output.extact')
5205 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glassc1aa66e2022-01-29 14:14:04 -07005206 data = tools.read_file(fname)
Simon Glass75989722021-11-23 21:08:59 -07005207 self.assertEqual(U_BOOT_DATA, data)
5208
5209 def testFipReplace(self):
5210 """Test replacing a single file in a FIP"""
Simon Glassc1aa66e2022-01-29 14:14:04 -07005211 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass75989722021-11-23 21:08:59 -07005212 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glassc1aa66e2022-01-29 14:14:04 -07005213 updated_fname = tools.get_output_filename('image-updated.bin')
5214 tools.write_file(updated_fname, data)
Simon Glass75989722021-11-23 21:08:59 -07005215 entry_name = 'atf-fip/u-boot'
5216 control.WriteEntry(updated_fname, entry_name, expected,
5217 allow_resize=True)
5218 actual = control.ReadEntry(updated_fname, entry_name)
5219 self.assertEqual(expected, actual)
5220
Simon Glassc1aa66e2022-01-29 14:14:04 -07005221 new_data = tools.read_file(updated_fname)
Simon Glass75989722021-11-23 21:08:59 -07005222 hdr, fents = fip_util.decode_fip(new_data)
5223
5224 self.assertEqual(2, len(fents))
5225
5226 # Check that the FIP entry is updated
5227 fent = fents[1]
5228 self.assertEqual(0x8c, fent.offset)
5229 self.assertEqual(len(expected), fent.size)
5230 self.assertEqual(0, fent.flags)
5231 self.assertEqual(expected, fent.data)
5232 self.assertEqual(True, fent.valid)
5233
5234 def testFipMissing(self):
5235 with test_util.capture_sys_output() as (stdout, stderr):
5236 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5237 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005238 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass75989722021-11-23 21:08:59 -07005239
5240 def testFipSize(self):
5241 """Test a FIP with a size property"""
5242 data = self._DoReadFile('210_fip_size.dts')
5243 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5244 hdr, fents = fip_util.decode_fip(data)
5245 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5246 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5247
5248 self.assertEqual(1, len(fents))
5249
5250 fent = fents[0]
5251 self.assertEqual('soc-fw', fent.fip_type)
5252 self.assertEqual(0x60, fent.offset)
5253 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5254 self.assertEqual(ATF_BL31_DATA, fent.data)
5255 self.assertEqual(True, fent.valid)
5256
5257 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glassc1aa66e2022-01-29 14:14:04 -07005258 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass75989722021-11-23 21:08:59 -07005259
5260 def testFipBadAlign(self):
5261 """Test that an invalid alignment value in a FIP is detected"""
5262 with self.assertRaises(ValueError) as e:
5263 self._DoTestFile('211_fip_bad_align.dts')
5264 self.assertIn(
5265 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5266 str(e.exception))
5267
5268 def testFipCollection(self):
5269 """Test using a FIP in a collection"""
5270 data = self._DoReadFile('212_fip_collection.dts')
5271 entry1 = control.images['image'].GetEntries()['collection']
5272 data1 = data[:entry1.size]
5273 hdr1, fents2 = fip_util.decode_fip(data1)
5274
5275 entry2 = control.images['image'].GetEntries()['atf-fip']
5276 data2 = data[entry2.offset:entry2.offset + entry2.size]
5277 hdr1, fents2 = fip_util.decode_fip(data2)
5278
5279 # The 'collection' entry should have U-Boot included at the end
5280 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5281 self.assertEqual(data1, data2 + U_BOOT_DATA)
5282 self.assertEqual(U_BOOT_DATA, data1[-4:])
5283
5284 # There should be a U-Boot after the final FIP
5285 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glassc69d19c2021-07-06 10:36:37 -06005286
Simon Glass32d4f102022-01-12 13:10:35 -07005287 def testFakeBlob(self):
5288 """Test handling of faking an external blob"""
5289 with test_util.capture_sys_output() as (stdout, stderr):
5290 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5291 allow_fake_blobs=True)
5292 err = stderr.getvalue()
5293 self.assertRegex(
5294 err,
5295 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glass32d4f102022-01-12 13:10:35 -07005296
Simon Glassf4590e02022-01-09 20:13:46 -07005297 def testExtblobListFaked(self):
5298 """Test an extblob with missing external blob that are faked"""
5299 with test_util.capture_sys_output() as (stdout, stderr):
5300 self._DoTestFile('216_blob_ext_list_missing.dts',
5301 allow_fake_blobs=True)
5302 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005303 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassf4590e02022-01-09 20:13:46 -07005304
Simon Glass56ee85e2022-01-09 20:13:57 -07005305 def testListBintools(self):
5306 args = ['tool', '--list']
5307 with test_util.capture_sys_output() as (stdout, _):
5308 self._DoBinman(*args)
5309 out = stdout.getvalue().splitlines()
5310 self.assertTrue(len(out) >= 2)
5311
5312 def testFetchBintools(self):
5313 def fail_download(url):
Simon Glassc1aa66e2022-01-29 14:14:04 -07005314 """Take the tools.download() function by raising an exception"""
Simon Glass56ee85e2022-01-09 20:13:57 -07005315 raise urllib.error.URLError('my error')
5316
5317 args = ['tool']
5318 with self.assertRaises(ValueError) as e:
5319 self._DoBinman(*args)
5320 self.assertIn("Invalid arguments to 'tool' subcommand",
5321 str(e.exception))
5322
5323 args = ['tool', '--fetch']
5324 with self.assertRaises(ValueError) as e:
5325 self._DoBinman(*args)
5326 self.assertIn('Please specify bintools to fetch', str(e.exception))
5327
5328 args = ['tool', '--fetch', '_testing']
Simon Glassc1aa66e2022-01-29 14:14:04 -07005329 with unittest.mock.patch.object(tools, 'download',
Simon Glass56ee85e2022-01-09 20:13:57 -07005330 side_effect=fail_download):
5331 with test_util.capture_sys_output() as (stdout, _):
5332 self._DoBinman(*args)
5333 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5334
Simon Glassbc570642022-01-09 20:14:11 -07005335 def testBintoolDocs(self):
5336 """Test for creation of bintool documentation"""
5337 with test_util.capture_sys_output() as (stdout, stderr):
5338 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5339 self.assertTrue(len(stdout.getvalue()) > 0)
5340
5341 def testBintoolDocsMissing(self):
5342 """Test handling of missing bintool documentation"""
5343 with self.assertRaises(ValueError) as e:
5344 with test_util.capture_sys_output() as (stdout, stderr):
5345 control.write_bintool_docs(
5346 control.bintool.Bintool.get_tool_list(), 'mkimage')
5347 self.assertIn('Documentation is missing for modules: mkimage',
5348 str(e.exception))
5349
Jan Kiszkafcc87ef2022-01-28 20:37:53 +01005350 def testListWithGenNode(self):
5351 """Check handling of an FDT map when the section cannot be found"""
5352 entry_args = {
5353 'of-list': 'test-fdt1 test-fdt2',
5354 }
5355 data = self._DoReadFileDtb(
5356 '219_fit_gennode.dts',
5357 entry_args=entry_args,
5358 use_real_dtb=True,
5359 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5360
5361 try:
5362 tmpdir, updated_fname = self._SetupImageInTmpdir()
5363 with test_util.capture_sys_output() as (stdout, stderr):
5364 self._RunBinman('ls', '-i', updated_fname)
5365 finally:
5366 shutil.rmtree(tmpdir)
5367
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005368 def testFitSubentryUsesBintool(self):
5369 """Test that binman FIT subentries can use bintools"""
5370 command.test_result = self._HandleGbbCommand
5371 entry_args = {
5372 'keydir': 'devkeys',
5373 'bmpblk': 'bmpblk.bin',
5374 }
5375 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5376 entry_args=entry_args)
5377
Alper Nebi Yasakf3078d42022-02-08 01:08:07 +03005378 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5379 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasaked293c32022-02-08 01:08:05 +03005380 self.assertIn(expected, data)
5381
5382 def testFitSubentryMissingBintool(self):
5383 """Test that binman reports missing bintools for FIT subentries"""
5384 entry_args = {
5385 'keydir': 'devkeys',
5386 }
5387 with test_util.capture_sys_output() as (_, stderr):
5388 self._DoTestFile('220_fit_subentry_bintool.dts',
5389 force_missing_bintools='futility', entry_args=entry_args)
5390 err = stderr.getvalue()
Simon Glass193d3db2023-02-07 14:34:18 -07005391 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass32d4f102022-01-12 13:10:35 -07005392
Alper Nebi Yasakee813c82022-02-09 22:02:35 +03005393 def testFitSubentryHashSubnode(self):
5394 """Test an image with a FIT inside"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005395 self._SetupSplElf()
Alper Nebi Yasakee813c82022-02-09 22:02:35 +03005396 data, _, _, out_dtb_name = self._DoReadFileDtb(
5397 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5398
5399 mkimage_dtb = fdt.Fdt.FromData(data)
5400 mkimage_dtb.Scan()
5401 binman_dtb = fdt.Fdt(out_dtb_name)
5402 binman_dtb.Scan()
5403
5404 # Check that binman didn't add hash values
5405 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5406 self.assertNotIn('value', fnode.props)
5407
5408 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5409 self.assertNotIn('value', fnode.props)
5410
5411 # Check that mkimage added hash values
5412 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5413 self.assertIn('value', fnode.props)
5414
5415 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5416 self.assertIn('value', fnode.props)
5417
Roger Quadros47f420a2022-02-19 20:50:04 +02005418 def testPackTeeOs(self):
5419 """Test that an image with an TEE binary can be created"""
5420 data = self._DoReadFile('222_tee_os.dts')
5421 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5422
Simon Glass6a0b5f82022-02-08 11:50:03 -07005423 def testFitFdtOper(self):
5424 """Check handling of a specified FIT operation"""
5425 entry_args = {
5426 'of-list': 'test-fdt1 test-fdt2',
5427 'default-dt': 'test-fdt2',
5428 }
5429 self._DoReadFileDtb(
5430 '223_fit_fdt_oper.dts',
5431 entry_args=entry_args,
5432 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5433
5434 def testFitFdtBadOper(self):
5435 """Check handling of an FDT map when the section cannot be found"""
5436 with self.assertRaises(ValueError) as exc:
5437 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glassce4e4022022-03-05 20:19:09 -07005438 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass6a0b5f82022-02-08 11:50:03 -07005439 str(exc.exception))
5440
Simon Glass80a66ae2022-03-05 20:18:59 -07005441 def test_uses_expand_size(self):
5442 """Test that the 'expand-size' property cannot be used anymore"""
5443 with self.assertRaises(ValueError) as e:
5444 data = self._DoReadFile('225_expand_size_bad.dts')
5445 self.assertIn(
5446 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5447 str(e.exception))
5448
Simon Glass40c8bdd2022-03-05 20:19:12 -07005449 def testFitSplitElf(self):
5450 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005451 if not elf.ELF_TOOLS:
5452 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005453 entry_args = {
5454 'of-list': 'test-fdt1 test-fdt2',
5455 'default-dt': 'test-fdt2',
5456 'atf-bl31-path': 'bl31.elf',
5457 'tee-os-path': 'tee.elf',
5458 }
5459 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5460 data = self._DoReadFileDtb(
5461 '226_fit_split_elf.dts',
5462 entry_args=entry_args,
5463 extra_indirs=[test_subdir])[0]
5464
5465 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5466 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5467
5468 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5469 'data', 'load'}
5470 dtb = fdt.Fdt.FromData(fit_data)
5471 dtb.Scan()
5472
5473 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5474 segments, entry = elf.read_loadable_segments(elf_data)
5475
5476 # We assume there are two segments
5477 self.assertEquals(2, len(segments))
5478
5479 atf1 = dtb.GetNode('/images/atf-1')
5480 _, start, data = segments[0]
5481 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5482 self.assertEqual(entry,
5483 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5484 self.assertEqual(start,
5485 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5486 self.assertEqual(data, atf1.props['data'].bytes)
5487
Jonas Karlman00b3d532023-01-21 19:01:48 +00005488 hash_node = atf1.FindNode('hash')
5489 self.assertIsNotNone(hash_node)
5490 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5491
Simon Glass40c8bdd2022-03-05 20:19:12 -07005492 atf2 = dtb.GetNode('/images/atf-2')
5493 self.assertEqual(base_keys, atf2.props.keys())
5494 _, start, data = segments[1]
5495 self.assertEqual(start,
5496 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5497 self.assertEqual(data, atf2.props['data'].bytes)
5498
Jonas Karlman00b3d532023-01-21 19:01:48 +00005499 hash_node = atf2.FindNode('hash')
5500 self.assertIsNotNone(hash_node)
5501 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5502
5503 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5504 self.assertIsNotNone(hash_node)
5505 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5506
Simon Glass40c8bdd2022-03-05 20:19:12 -07005507 conf = dtb.GetNode('/configurations')
5508 self.assertEqual({'default'}, conf.props.keys())
5509
5510 for subnode in conf.subnodes:
5511 self.assertEqual({'description', 'fdt', 'loadables'},
5512 subnode.props.keys())
5513 self.assertEqual(
5514 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5515 fdt_util.GetStringList(subnode, 'loadables'))
5516
5517 def _check_bad_fit(self, dts):
5518 """Check a bad FIT
5519
5520 This runs with the given dts and returns the assertion raised
5521
5522 Args:
5523 dts (str): dts filename to use
5524
5525 Returns:
5526 str: Assertion string raised
5527 """
5528 entry_args = {
5529 'of-list': 'test-fdt1 test-fdt2',
5530 'default-dt': 'test-fdt2',
5531 'atf-bl31-path': 'bl31.elf',
5532 'tee-os-path': 'tee.elf',
5533 }
5534 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5535 with self.assertRaises(ValueError) as exc:
5536 self._DoReadFileDtb(dts, entry_args=entry_args,
5537 extra_indirs=[test_subdir])[0]
5538 return str(exc.exception)
5539
5540 def testFitSplitElfBadElf(self):
5541 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005542 if not elf.ELF_TOOLS:
5543 self.skipTest('Python elftools not available')
Simon Glass40c8bdd2022-03-05 20:19:12 -07005544 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5545 entry_args = {
5546 'of-list': 'test-fdt1 test-fdt2',
5547 'default-dt': 'test-fdt2',
5548 'atf-bl31-path': 'bad.elf',
5549 'tee-os-path': 'tee.elf',
5550 }
5551 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5552 with self.assertRaises(ValueError) as exc:
5553 self._DoReadFileDtb(
5554 '226_fit_split_elf.dts',
5555 entry_args=entry_args,
5556 extra_indirs=[test_subdir])[0]
5557 self.assertIn(
5558 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5559 str(exc.exception))
5560
Simon Glass40c8bdd2022-03-05 20:19:12 -07005561 def checkFitSplitElf(self, **kwargs):
Simon Glass7960a0a2022-08-07 09:46:46 -06005562 """Test an split-elf FIT with a missing ELF file
5563
5564 Args:
5565 kwargs (dict of str): Arguments to pass to _DoTestFile()
5566
5567 Returns:
5568 tuple:
5569 str: stdout result
5570 str: stderr result
5571 """
Simon Glass40c8bdd2022-03-05 20:19:12 -07005572 entry_args = {
5573 'of-list': 'test-fdt1 test-fdt2',
5574 'default-dt': 'test-fdt2',
5575 'atf-bl31-path': 'bl31.elf',
5576 'tee-os-path': 'missing.elf',
5577 }
5578 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5579 with test_util.capture_sys_output() as (stdout, stderr):
5580 self._DoTestFile(
5581 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7960a0a2022-08-07 09:46:46 -06005582 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5583 out = stdout.getvalue()
5584 err = stderr.getvalue()
5585 return out, err
Simon Glass40c8bdd2022-03-05 20:19:12 -07005586
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005587 def testFitSplitElfBadDirective(self):
5588 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5589 if not elf.ELF_TOOLS:
5590 self.skipTest('Python elftools not available')
5591 err = self._check_bad_fit('227_fit_bad_dir.dts')
5592 self.assertIn(
5593 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5594 err)
5595
5596 def testFitSplitElfBadDirectiveConfig(self):
5597 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5598 if not elf.ELF_TOOLS:
5599 self.skipTest('Python elftools not available')
5600 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5601 self.assertEqual(
5602 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5603 err)
5604
5605
Simon Glass40c8bdd2022-03-05 20:19:12 -07005606 def testFitSplitElfMissing(self):
5607 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005608 if not elf.ELF_TOOLS:
5609 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005610 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005611 self.assertRegex(
5612 err,
5613 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005614 self.assertNotRegex(out, '.*Faked blob.*')
5615 fname = tools.get_output_filename('binman-fake/missing.elf')
5616 self.assertFalse(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005617
5618 def testFitSplitElfFaked(self):
5619 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier6ac7a832022-08-19 16:25:18 +02005620 if not elf.ELF_TOOLS:
5621 self.skipTest('Python elftools not available')
Simon Glass7960a0a2022-08-07 09:46:46 -06005622 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass40c8bdd2022-03-05 20:19:12 -07005623 self.assertRegex(
5624 err,
5625 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7960a0a2022-08-07 09:46:46 -06005626 self.assertRegex(
5627 out,
5628 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5629 fname = tools.get_output_filename('binman-fake/missing.elf')
5630 self.assertTrue(os.path.exists(fname))
Simon Glass40c8bdd2022-03-05 20:19:12 -07005631
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005632 def testMkimageMissingBlob(self):
5633 """Test using mkimage to build an image"""
5634 with test_util.capture_sys_output() as (stdout, stderr):
5635 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5636 allow_fake_blobs=True)
5637 err = stderr.getvalue()
5638 self.assertRegex(
5639 err,
5640 "Image '.*' has faked external blobs and is non-functional: .*")
5641
Philippe Reynesb1c50932022-03-28 22:57:04 +02005642 def testPreLoad(self):
5643 """Test an image with a pre-load header"""
5644 entry_args = {
5645 'pre-load-key-path': '.',
5646 }
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005647 data, _, _, _ = self._DoReadFileDtb('230_pre_load.dts',
Philippe Reynesb1c50932022-03-28 22:57:04 +02005648 entry_args=entry_args)
5649 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5650 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5651 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005652 data = self._DoReadFile('230_pre_load.dts')
Philippe Reynesb1c50932022-03-28 22:57:04 +02005653 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5654 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5655 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5656
5657 def testPreLoadPkcs(self):
5658 """Test an image with a pre-load header with padding pkcs"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005659 data = self._DoReadFile('231_pre_load_pkcs.dts')
Philippe Reynesb1c50932022-03-28 22:57:04 +02005660 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5661 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5662 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5663
5664 def testPreLoadPss(self):
5665 """Test an image with a pre-load header with padding pss"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005666 data = self._DoReadFile('232_pre_load_pss.dts')
Philippe Reynesb1c50932022-03-28 22:57:04 +02005667 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5668 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5669 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5670
5671 def testPreLoadInvalidPadding(self):
5672 """Test an image with a pre-load header with an invalid padding"""
5673 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005674 data = self._DoReadFile('233_pre_load_invalid_padding.dts')
Philippe Reynesb1c50932022-03-28 22:57:04 +02005675
5676 def testPreLoadInvalidSha(self):
5677 """Test an image with a pre-load header with an invalid hash"""
5678 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005679 data = self._DoReadFile('234_pre_load_invalid_sha.dts')
Philippe Reynesb1c50932022-03-28 22:57:04 +02005680
5681 def testPreLoadInvalidAlgo(self):
5682 """Test an image with a pre-load header with an invalid algo"""
5683 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005684 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesb1c50932022-03-28 22:57:04 +02005685
5686 def testPreLoadInvalidKey(self):
5687 """Test an image with a pre-load header with an invalid key"""
5688 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005689 data = self._DoReadFile('236_pre_load_invalid_key.dts')
Roger Quadros47f420a2022-02-19 20:50:04 +02005690
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005691 def _CheckSafeUniqueNames(self, *images):
5692 """Check all entries of given images for unsafe unique names"""
5693 for image in images:
5694 entries = {}
5695 image._CollectEntries(entries, {}, image)
5696 for entry in entries.values():
5697 uniq = entry.GetUniqueName()
5698
5699 # Used as part of a filename, so must not be absolute paths.
5700 self.assertFalse(os.path.isabs(uniq))
5701
5702 def testSafeUniqueNames(self):
5703 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005704 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005705
5706 orig_image = control.images['image']
5707 image_fname = tools.get_output_filename('image.bin')
5708 image = Image.FromFile(image_fname)
5709
5710 self._CheckSafeUniqueNames(orig_image, image)
5711
5712 def testSafeUniqueNamesMulti(self):
5713 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005714 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak67bf2c82022-03-27 18:31:44 +03005715
5716 orig_image = control.images['image']
5717 image_fname = tools.get_output_filename('image.bin')
5718 image = Image.FromFile(image_fname)
5719
5720 self._CheckSafeUniqueNames(orig_image, image)
5721
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005722 def testReplaceCmdWithBintool(self):
5723 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005724 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005725 expected = U_BOOT_DATA + b'aa'
5726 self.assertEqual(expected, data[:len(expected)])
5727
5728 try:
5729 tmpdir, updated_fname = self._SetupImageInTmpdir()
5730 fname = os.path.join(tmpdir, 'update-testing.bin')
5731 tools.write_file(fname, b'zz')
5732 self._DoBinman('replace', '-i', updated_fname,
5733 '_testing', '-f', fname)
5734
5735 data = tools.read_file(updated_fname)
5736 expected = U_BOOT_DATA + b'zz'
5737 self.assertEqual(expected, data[:len(expected)])
5738 finally:
5739 shutil.rmtree(tmpdir)
5740
5741 def testReplaceCmdOtherWithBintool(self):
5742 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005743 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03005744 expected = U_BOOT_DATA + b'aa'
5745 self.assertEqual(expected, data[:len(expected)])
5746
5747 try:
5748 tmpdir, updated_fname = self._SetupImageInTmpdir()
5749 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5750 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5751 self._DoBinman('replace', '-i', updated_fname,
5752 'u-boot', '-f', fname)
5753
5754 data = tools.read_file(updated_fname)
5755 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5756 self.assertEqual(expected, data[:len(expected)])
5757 finally:
5758 shutil.rmtree(tmpdir)
5759
Alper Nebi Yasake2ce4fb2022-03-27 18:31:46 +03005760 def testReplaceResizeNoRepackSameSize(self):
5761 """Test replacing entries with same-size data without repacking"""
5762 expected = b'x' * len(U_BOOT_DATA)
5763 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5764 self.assertEqual(expected, data)
5765
5766 path, fdtmap = state.GetFdtContents('fdtmap')
5767 self.assertIsNotNone(path)
5768 self.assertEqual(expected_fdtmap, fdtmap)
5769
5770 def testReplaceResizeNoRepackSmallerSize(self):
5771 """Test replacing entries with smaller-size data without repacking"""
5772 new_data = b'x'
5773 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5774 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5775 self.assertEqual(expected, data)
5776
5777 path, fdtmap = state.GetFdtContents('fdtmap')
5778 self.assertIsNotNone(path)
5779 self.assertEqual(expected_fdtmap, fdtmap)
5780
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005781 def testExtractFit(self):
5782 """Test extracting a FIT section"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005783 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005784 image_fname = tools.get_output_filename('image.bin')
5785
5786 fit_data = control.ReadEntry(image_fname, 'fit')
5787 fit = fdt.Fdt.FromData(fit_data)
5788 fit.Scan()
5789
5790 # Check subentry data inside the extracted fit
5791 for node_path, expected in [
5792 ('/images/kernel', U_BOOT_DATA),
5793 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5794 ('/images/scr-1', COMPRESS_DATA),
5795 ]:
5796 node = fit.GetNode(node_path)
5797 data = fit.GetProps(node)['data'].bytes
5798 self.assertEqual(expected, data)
5799
5800 def testExtractFitSubentries(self):
5801 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005802 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak74d3b232022-03-27 18:31:48 +03005803 image_fname = tools.get_output_filename('image.bin')
5804
5805 for entry_path, expected in [
5806 ('fit/kernel', U_BOOT_DATA),
5807 ('fit/kernel/u-boot', U_BOOT_DATA),
5808 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5809 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5810 ('fit/scr-1', COMPRESS_DATA),
5811 ('fit/scr-1/blob', COMPRESS_DATA),
5812 ]:
5813 data = control.ReadEntry(image_fname, entry_path)
5814 self.assertEqual(expected, data)
5815
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005816 def testReplaceFitSubentryLeafSameSize(self):
5817 """Test replacing a FIT leaf subentry with same-size data"""
5818 new_data = b'x' * len(U_BOOT_DATA)
5819 data, expected_fdtmap, _ = self._RunReplaceCmd(
5820 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005821 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005822 self.assertEqual(new_data, data)
5823
5824 path, fdtmap = state.GetFdtContents('fdtmap')
5825 self.assertIsNotNone(path)
5826 self.assertEqual(expected_fdtmap, fdtmap)
5827
5828 def testReplaceFitSubentryLeafBiggerSize(self):
5829 """Test replacing a FIT leaf subentry with bigger-size data"""
5830 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5831 data, expected_fdtmap, _ = self._RunReplaceCmd(
5832 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005833 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005834 self.assertEqual(new_data, data)
5835
5836 # Will be repacked, so fdtmap must change
5837 path, fdtmap = state.GetFdtContents('fdtmap')
5838 self.assertIsNotNone(path)
5839 self.assertNotEqual(expected_fdtmap, fdtmap)
5840
5841 def testReplaceFitSubentryLeafSmallerSize(self):
5842 """Test replacing a FIT leaf subentry with smaller-size data"""
5843 new_data = b'x'
5844 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5845 data, expected_fdtmap, _ = self._RunReplaceCmd(
5846 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005847 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak99283e52022-03-27 18:31:49 +03005848 self.assertEqual(expected, data)
5849
5850 path, fdtmap = state.GetFdtContents('fdtmap')
5851 self.assertIsNotNone(path)
5852 self.assertEqual(expected_fdtmap, fdtmap)
5853
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005854 def testReplaceSectionSimple(self):
Simon Glass7caa3722023-03-02 17:02:44 -07005855 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005856 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass7caa3722023-03-02 17:02:44 -07005857 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5858 new_data, dts='241_replace_section_simple.dts')
5859 self.assertEqual(new_data, data)
5860
5861 entries = image.GetEntries()
5862 self.assertIn('section', entries)
5863 entry = entries['section']
5864 self.assertEqual(len(new_data), entry.size)
5865
5866 def testReplaceSectionLarger(self):
5867 """Test replacing a simple section with larger data"""
5868 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5869 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5870 new_data, dts='241_replace_section_simple.dts')
5871 self.assertEqual(new_data, data)
5872
5873 entries = image.GetEntries()
5874 self.assertIn('section', entries)
5875 entry = entries['section']
5876 self.assertEqual(len(new_data), entry.size)
5877 fentry = entries['fdtmap']
5878 self.assertEqual(entry.offset + entry.size, fentry.offset)
5879
5880 def testReplaceSectionSmaller(self):
5881 """Test replacing a simple section with smaller data"""
5882 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5883 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5884 new_data, dts='241_replace_section_simple.dts')
5885 self.assertEqual(new_data, data)
5886
5887 # The new size is the same as the old, just with a pad byte at the end
5888 entries = image.GetEntries()
5889 self.assertIn('section', entries)
5890 entry = entries['section']
5891 self.assertEqual(len(new_data), entry.size)
5892
5893 def testReplaceSectionSmallerAllow(self):
5894 """Test failing to replace a simple section with smaller data"""
5895 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5896 try:
5897 state.SetAllowEntryContraction(True)
5898 with self.assertRaises(ValueError) as exc:
5899 self._RunReplaceCmd('section', new_data,
5900 dts='241_replace_section_simple.dts')
5901 finally:
5902 state.SetAllowEntryContraction(False)
5903
5904 # Since we have no information about the position of things within the
5905 # section, we cannot adjust the position of /section-u-boot so it ends
5906 # up outside the section
Simon Glass73593e42022-08-13 11:40:46 -06005907 self.assertIn(
Simon Glass7caa3722023-03-02 17:02:44 -07005908 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5909 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glass73593e42022-08-13 11:40:46 -06005910 str(exc.exception))
Alper Nebi Yasak82337bb2022-03-27 18:31:50 +03005911
Simon Glassdfe1db42022-08-13 11:40:48 -06005912 def testMkimageImagename(self):
5913 """Test using mkimage with -n holding the data too"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005914 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005915 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glassdfe1db42022-08-13 11:40:48 -06005916
5917 # Check that the data appears in the file somewhere
5918 self.assertIn(U_BOOT_SPL_DATA, data)
5919
Simon Glassf3543e62022-09-06 20:26:52 -06005920 # Get struct legacy_img_hdr -> ih_name
Simon Glassdfe1db42022-08-13 11:40:48 -06005921 name = data[0x20:0x40]
5922
5923 # Build the filename that we expect to be placed in there, by virtue of
5924 # the -n paraameter
5925 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5926
5927 # Check that the image name is set to the temporary filename used
5928 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5929
Simon Glass9db9e932022-08-13 11:40:49 -06005930 def testMkimageImage(self):
5931 """Test using mkimage with -n holding the data too"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005932 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005933 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06005934
5935 # Check that the data appears in the file somewhere
5936 self.assertIn(U_BOOT_SPL_DATA, data)
5937
Simon Glassf3543e62022-09-06 20:26:52 -06005938 # Get struct legacy_img_hdr -> ih_name
Simon Glass9db9e932022-08-13 11:40:49 -06005939 name = data[0x20:0x40]
5940
5941 # Build the filename that we expect to be placed in there, by virtue of
5942 # the -n paraameter
5943 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5944
5945 # Check that the image name is set to the temporary filename used
5946 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5947
5948 # Check the corect data is in the imagename file
5949 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5950
5951 def testMkimageImageNoContent(self):
5952 """Test using mkimage with -n and no data"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005953 self._SetupSplElf()
Simon Glass9db9e932022-08-13 11:40:49 -06005954 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005955 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06005956 self.assertIn('Could not complete processing of contents',
5957 str(exc.exception))
5958
5959 def testMkimageImageBad(self):
5960 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005961 self._SetupSplElf()
Simon Glass9db9e932022-08-13 11:40:49 -06005962 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005963 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glass9db9e932022-08-13 11:40:49 -06005964 self.assertIn('Cannot use both imagename node and data-to-imagename',
5965 str(exc.exception))
5966
Simon Glassd626e822022-08-13 11:40:50 -06005967 def testCollectionOther(self):
5968 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005969 data = self._DoReadFile('246_collection_other.dts')
Simon Glassd626e822022-08-13 11:40:50 -06005970 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5971 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5972 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5973 data)
5974
5975 def testMkimageCollection(self):
5976 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06005977 self._SetupSplElf()
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005978 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassd626e822022-08-13 11:40:50 -06005979 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5980 self.assertEqual(expect, data[:len(expect)])
5981
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02005982 def testCompressDtbPrependInvalid(self):
5983 """Test that invalid header is detected"""
5984 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005985 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02005986 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5987 "'u-boot-dtb': 'invalid'", str(e.exception))
5988
5989 def testCompressDtbPrependLength(self):
5990 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02005991 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier6aa80002022-08-19 16:25:25 +02005992 image = control.images['image']
5993 entries = image.GetEntries()
5994 self.assertIn('u-boot-dtb', entries)
5995 u_boot_dtb = entries['u-boot-dtb']
5996 self.assertIn('fdtmap', entries)
5997 fdtmap = entries['fdtmap']
5998
5999 image_fname = tools.get_output_filename('image.bin')
6000 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6001 dtb = fdt.Fdt.FromData(orig)
6002 dtb.Scan()
6003 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6004 expected = {
6005 'u-boot:size': len(U_BOOT_DATA),
6006 'u-boot-dtb:uncomp-size': len(orig),
6007 'u-boot-dtb:size': u_boot_dtb.size,
6008 'fdtmap:size': fdtmap.size,
6009 'size': len(data),
6010 }
6011 self.assertEqual(expected, props)
6012
6013 # Check implementation
6014 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6015 rest = data[len(U_BOOT_DATA):]
6016 comp_data_len = struct.unpack('<I', rest[:4])[0]
6017 comp_data = rest[4:4 + comp_data_len]
6018 orig2 = self._decompress(comp_data)
6019 self.assertEqual(orig, orig2)
6020
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02006021 def testInvalidCompress(self):
6022 """Test that invalid compress algorithm is detected"""
6023 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006024 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeierec7d27d2022-08-19 16:25:30 +02006025 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6026
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02006027 def testCompUtilCompressions(self):
6028 """Test compression algorithms"""
6029 for bintool in self.comp_bintools.values():
6030 self._CheckBintool(bintool)
6031 data = bintool.compress(COMPRESS_DATA)
6032 self.assertNotEqual(COMPRESS_DATA, data)
6033 orig = bintool.decompress(data)
6034 self.assertEquals(COMPRESS_DATA, orig)
6035
6036 def testCompUtilVersions(self):
6037 """Test tool version of compression algorithms"""
6038 for bintool in self.comp_bintools.values():
6039 self._CheckBintool(bintool)
6040 version = bintool.version()
6041 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6042
6043 def testCompUtilPadding(self):
6044 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006045 # Skip zstd because it doesn't support padding
6046 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeierda1af352022-08-19 16:25:32 +02006047 self._CheckBintool(bintool)
6048 data = bintool.compress(COMPRESS_DATA)
6049 self.assertNotEqual(COMPRESS_DATA, data)
6050 data += tools.get_bytes(0, 64)
6051 orig = bintool.decompress(data)
6052 self.assertEquals(COMPRESS_DATA, orig)
6053
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006054 def testCompressDtbZstd(self):
6055 """Test that zstd compress of device-tree files failed"""
6056 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier5cb0b252022-08-23 12:46:09 +02006057 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiercd15b642022-08-19 16:25:38 +02006058 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6059 "requires a length header", str(e.exception))
6060
Quentin Schulz4d91df02022-09-02 15:10:48 +02006061 def testMkimageMultipleDataFiles(self):
6062 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006063 self._SetupSplElf()
6064 self._SetupTplElf()
Quentin Schulz4d91df02022-09-02 15:10:48 +02006065 data = self._DoReadFile('252_mkimage_mult_data.dts')
6066 # Size of files are packed in their 4B big-endian format
6067 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6068 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6069 # Size info is always followed by a 4B zero value.
6070 expect += tools.get_bytes(0, 4)
6071 expect += U_BOOT_TPL_DATA
6072 # All but last files are 4B-aligned
6073 align_pad = len(U_BOOT_TPL_DATA) % 4
6074 if align_pad:
6075 expect += tools.get_bytes(0, align_pad)
6076 expect += U_BOOT_SPL_DATA
6077 self.assertEqual(expect, data[-len(expect):])
6078
Marek Vasutfadad3a2023-07-18 07:23:58 -06006079 def testMkimageMultipleExpanded(self):
6080 """Test passing multiple files to mkimage in a mkimage entry"""
6081 self._SetupSplElf()
6082 self._SetupTplElf()
6083 entry_args = {
6084 'spl-bss-pad': 'y',
6085 'spl-dtb': 'y',
6086 }
6087 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6088 use_expanded=True, entry_args=entry_args)[0]
6089 pad_len = 10
6090 tpl_expect = U_BOOT_TPL_DATA
6091 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6092 spl_expect += U_BOOT_SPL_DTB_DATA
6093
6094 content = data[0x40:]
6095 lens = struct.unpack('>III', content[:12])
6096
6097 # Size of files are packed in their 4B big-endian format
6098 # Size info is always followed by a 4B zero value.
6099 self.assertEqual(len(tpl_expect), lens[0])
6100 self.assertEqual(len(spl_expect), lens[1])
6101 self.assertEqual(0, lens[2])
6102
6103 rest = content[12:]
6104 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6105
6106 rest = rest[len(tpl_expect):]
6107 align_pad = len(tpl_expect) % 4
6108 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6109 rest = rest[align_pad:]
6110 self.assertEqual(spl_expect, rest)
6111
Quentin Schulz4d91df02022-09-02 15:10:48 +02006112 def testMkimageMultipleNoContent(self):
6113 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006114 self._SetupSplElf()
Quentin Schulz4d91df02022-09-02 15:10:48 +02006115 with self.assertRaises(ValueError) as exc:
6116 self._DoReadFile('253_mkimage_mult_no_content.dts')
6117 self.assertIn('Could not complete processing of contents',
6118 str(exc.exception))
6119
Quentin Schulz6cc29dc2022-09-02 15:10:49 +02006120 def testMkimageFilename(self):
6121 """Test using mkimage to build a binary with a filename"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006122 self._SetupSplElf()
Quentin Schulz6cc29dc2022-09-02 15:10:49 +02006123 retcode = self._DoTestFile('254_mkimage_filename.dts')
6124 self.assertEqual(0, retcode)
6125 fname = tools.get_output_filename('mkimage-test.bin')
6126 self.assertTrue(os.path.exists(fname))
6127
Simon Glass6ad24522022-02-28 07:16:54 -07006128 def testVpl(self):
6129 """Test that an image with VPL and its device tree can be created"""
6130 # ELF file with a '__bss_size' symbol
6131 self._SetupVplElf()
6132 data = self._DoReadFile('255_u_boot_vpl.dts')
6133 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6134
6135 def testVplNoDtb(self):
6136 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6137 self._SetupVplElf()
6138 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6139 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6140 data[:len(U_BOOT_VPL_NODTB_DATA)])
6141
6142 def testExpandedVpl(self):
6143 """Test that an expanded entry type is selected for TPL when needed"""
6144 self._SetupVplElf()
6145
6146 entry_args = {
6147 'vpl-bss-pad': 'y',
6148 'vpl-dtb': 'y',
6149 }
6150 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6151 entry_args=entry_args)
6152 image = control.images['image']
6153 entries = image.GetEntries()
6154 self.assertEqual(1, len(entries))
6155
6156 # We only have u-boot-vpl, which be expanded
6157 self.assertIn('u-boot-vpl', entries)
6158 entry = entries['u-boot-vpl']
6159 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6160 subent = entry.GetEntries()
6161 self.assertEqual(3, len(subent))
6162 self.assertIn('u-boot-vpl-nodtb', subent)
6163 self.assertIn('u-boot-vpl-bss-pad', subent)
6164 self.assertIn('u-boot-vpl-dtb', subent)
6165
6166 def testVplBssPadMissing(self):
6167 """Test that a missing symbol is detected"""
6168 self._SetupVplElf('u_boot_ucode_ptr')
6169 with self.assertRaises(ValueError) as e:
6170 self._DoReadFile('258_vpl_bss_pad.dts')
6171 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6172 str(e.exception))
6173
Neha Malcom Francis3545e852022-10-17 16:36:25 +05306174 def testSymlink(self):
6175 """Test that image files can be named"""
6176 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6177 self.assertEqual(0, retcode)
6178 image = control.images['test_image']
6179 fname = tools.get_output_filename('test_image.bin')
6180 sname = tools.get_output_filename('symlink_to_test.bin')
6181 self.assertTrue(os.path.islink(sname))
6182 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasak8ee4ec92022-03-27 18:31:45 +03006183
Simon Glassd2afb9e2022-10-20 18:22:47 -06006184 def testSymbolsElf(self):
6185 """Test binman can assign symbols embedded in an ELF file"""
6186 if not elf.ELF_TOOLS:
6187 self.skipTest('Python elftools not available')
6188 self._SetupTplElf('u_boot_binman_syms')
6189 self._SetupVplElf('u_boot_binman_syms')
6190 self._SetupSplElf('u_boot_binman_syms')
6191 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6192 image_fname = tools.get_output_filename('image.bin')
6193
6194 image = control.images['image']
6195 entries = image.GetEntries()
6196
6197 for entry in entries.values():
6198 # No symbols in u-boot and it has faked contents anyway
6199 if entry.name == 'u-boot':
6200 continue
6201 edata = data[entry.image_pos:entry.image_pos + entry.size]
6202 efname = tools.get_output_filename(f'edata-{entry.name}')
6203 tools.write_file(efname, edata)
6204
6205 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6206 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6207 for name, sym in syms.items():
6208 msg = 'test'
6209 val = elf.GetSymbolValue(sym, edata, msg)
6210 entry_m = re_name.match(name)
6211 if entry_m:
6212 ename, prop = entry_m.group(1), entry_m.group(3)
6213 entry, entry_name, prop_name = image.LookupEntry(entries,
6214 name, msg)
6215 if prop_name == 'offset':
6216 expect_val = entry.offset
6217 elif prop_name == 'image_pos':
6218 expect_val = entry.image_pos
6219 elif prop_name == 'size':
6220 expect_val = entry.size
6221 self.assertEqual(expect_val, val)
6222
6223 def testSymbolsElfBad(self):
6224 """Check error when trying to write symbols without the elftools lib"""
6225 if not elf.ELF_TOOLS:
6226 self.skipTest('Python elftools not available')
6227 self._SetupTplElf('u_boot_binman_syms')
6228 self._SetupVplElf('u_boot_binman_syms')
6229 self._SetupSplElf('u_boot_binman_syms')
6230 try:
6231 elf.ELF_TOOLS = False
6232 with self.assertRaises(ValueError) as exc:
6233 self._DoReadFileDtb('260_symbols_elf.dts')
6234 finally:
6235 elf.ELF_TOOLS = True
6236 self.assertIn(
6237 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6238 'Cannot write symbols to an ELF file without Python elftools',
6239 str(exc.exception))
6240
Simon Glassefddab62023-01-07 14:07:08 -07006241 def testSectionFilename(self):
6242 """Check writing of section contents to a file"""
6243 data = self._DoReadFile('261_section_fname.dts')
6244 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6245 tools.get_bytes(ord('!'), 7) +
6246 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6247 self.assertEqual(expected, data)
6248
6249 sect_fname = tools.get_output_filename('outfile.bin')
6250 self.assertTrue(os.path.exists(sect_fname))
6251 sect_data = tools.read_file(sect_fname)
6252 self.assertEqual(U_BOOT_DATA, sect_data)
6253
Simon Glassc8c9f312023-01-07 14:07:12 -07006254 def testAbsent(self):
6255 """Check handling of absent entries"""
6256 data = self._DoReadFile('262_absent.dts')
6257 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6258
Simon Glass2f80c5e2023-01-07 14:07:14 -07006259 def testPackTeeOsOptional(self):
6260 """Test that an image with an optional TEE binary can be created"""
6261 entry_args = {
6262 'tee-os-path': 'tee.elf',
6263 }
6264 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6265 entry_args=entry_args)[0]
6266 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6267
6268 def checkFitTee(self, dts, tee_fname):
6269 """Check that a tee-os entry works and returns data
6270
6271 Args:
6272 dts (str): Device tree filename to use
6273 tee_fname (str): filename containing tee-os
6274
6275 Returns:
6276 bytes: Image contents
6277 """
6278 if not elf.ELF_TOOLS:
6279 self.skipTest('Python elftools not available')
6280 entry_args = {
6281 'of-list': 'test-fdt1 test-fdt2',
6282 'default-dt': 'test-fdt2',
6283 'tee-os-path': tee_fname,
6284 }
6285 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6286 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6287 extra_indirs=[test_subdir])[0]
6288 return data
6289
6290 def testFitTeeOsOptionalFit(self):
6291 """Test an image with a FIT with an optional OP-TEE binary"""
6292 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6293
6294 # There should be only one node, holding the data set up in SetUpClass()
6295 # for tee.bin
6296 dtb = fdt.Fdt.FromData(data)
6297 dtb.Scan()
6298 node = dtb.GetNode('/images/tee-1')
6299 self.assertEqual(TEE_ADDR,
6300 fdt_util.fdt32_to_cpu(node.props['load'].value))
6301 self.assertEqual(TEE_ADDR,
6302 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6303 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6304
6305 def testFitTeeOsOptionalFitBad(self):
6306 """Test an image with a FIT with an optional OP-TEE binary"""
6307 with self.assertRaises(ValueError) as exc:
6308 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6309 self.assertIn(
6310 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6311 str(exc.exception))
6312
6313 def testFitTeeOsBad(self):
6314 """Test an OP-TEE binary with wrong formats"""
6315 self.make_tee_bin('tee.bad1', 123)
6316 with self.assertRaises(ValueError) as exc:
6317 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6318 self.assertIn(
6319 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6320 str(exc.exception))
6321
6322 self.make_tee_bin('tee.bad2', 0, b'extra data')
6323 with self.assertRaises(ValueError) as exc:
6324 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6325 self.assertIn(
6326 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6327 str(exc.exception))
6328
Simon Glass67a05012023-01-07 14:07:15 -07006329 def testExtblobOptional(self):
6330 """Test an image with an external blob that is optional"""
6331 with test_util.capture_sys_output() as (stdout, stderr):
6332 data = self._DoReadFile('266_blob_ext_opt.dts')
6333 self.assertEqual(REFCODE_DATA, data)
6334 err = stderr.getvalue()
6335 self.assertRegex(
6336 err,
6337 "Image '.*' is missing external blobs but is still functional: missing")
6338
Simon Glass0b079fc2023-01-11 16:10:12 -07006339 def testSectionInner(self):
6340 """Test an inner section with a size"""
6341 data = self._DoReadFile('267_section_inner.dts')
6342 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6343 self.assertEqual(expected, data)
6344
Simon Glass62ef2f72023-01-11 16:10:14 -07006345 def testNull(self):
6346 """Test an image with a null entry"""
6347 data = self._DoReadFile('268_null.dts')
6348 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6349
Simon Glass9766f692023-01-11 16:10:16 -07006350 def testOverlap(self):
6351 """Test an image with a overlapping entry"""
6352 data = self._DoReadFile('269_overlap.dts')
6353 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6354
6355 image = control.images['image']
6356 entries = image.GetEntries()
6357
6358 self.assertIn('inset', entries)
6359 inset = entries['inset']
6360 self.assertEqual(1, inset.offset);
6361 self.assertEqual(1, inset.image_pos);
6362 self.assertEqual(2, inset.size);
6363
6364 def testOverlapNull(self):
6365 """Test an image with a null overlap"""
6366 data = self._DoReadFile('270_overlap_null.dts')
6367 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6368
6369 # Check the FMAP
6370 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6371 self.assertEqual(4, fhdr.nareas)
6372 fiter = iter(fentries)
6373
6374 fentry = next(fiter)
6375 self.assertEqual(b'SECTION', fentry.name)
6376 self.assertEqual(0, fentry.offset)
6377 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6378 self.assertEqual(0, fentry.flags)
6379
6380 fentry = next(fiter)
6381 self.assertEqual(b'U_BOOT', fentry.name)
6382 self.assertEqual(0, fentry.offset)
6383 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6384 self.assertEqual(0, fentry.flags)
6385
6386 # Make sure that the NULL entry appears in the FMAP
6387 fentry = next(fiter)
6388 self.assertEqual(b'NULL', fentry.name)
6389 self.assertEqual(1, fentry.offset)
6390 self.assertEqual(2, fentry.size)
6391 self.assertEqual(0, fentry.flags)
6392
6393 fentry = next(fiter)
6394 self.assertEqual(b'FMAP', fentry.name)
6395 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6396
6397 def testOverlapBad(self):
6398 """Test an image with a bad overlapping entry"""
6399 with self.assertRaises(ValueError) as exc:
6400 self._DoReadFile('271_overlap_bad.dts')
6401 self.assertIn(
6402 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6403 str(exc.exception))
6404
6405 def testOverlapNoOffset(self):
6406 """Test an image with a bad overlapping entry"""
6407 with self.assertRaises(ValueError) as exc:
6408 self._DoReadFile('272_overlap_no_size.dts')
6409 self.assertIn(
6410 "Node '/binman/inset': 'fill' entry is missing properties: size",
6411 str(exc.exception))
6412
Simon Glassc1157862023-01-11 16:10:17 -07006413 def testBlobSymbol(self):
6414 """Test a blob with symbols read from an ELF file"""
6415 elf_fname = self.ElfTestFile('blob_syms')
6416 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6417 TestFunctional._MakeInputFile('blob_syms.bin',
6418 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6419
6420 data = self._DoReadFile('273_blob_symbol.dts')
6421
6422 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6423 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6424 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6425 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6426 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6427
6428 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6429 expected = sym_values
6430 self.assertEqual(expected, data[:len(expected)])
6431
Simon Glass571bc4e2023-01-11 16:10:19 -07006432 def testOffsetFromElf(self):
6433 """Test a blob with symbols read from an ELF file"""
6434 elf_fname = self.ElfTestFile('blob_syms')
6435 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6436 TestFunctional._MakeInputFile('blob_syms.bin',
6437 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6438
6439 data = self._DoReadFile('274_offset_from_elf.dts')
6440
6441 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6442 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6443
6444 image = control.images['image']
6445 entries = image.GetEntries()
6446
6447 self.assertIn('inset', entries)
6448 inset = entries['inset']
6449
6450 self.assertEqual(base + 4, inset.offset);
6451 self.assertEqual(base + 4, inset.image_pos);
6452 self.assertEqual(4, inset.size);
6453
6454 self.assertIn('inset2', entries)
6455 inset = entries['inset2']
6456 self.assertEqual(base + 8, inset.offset);
6457 self.assertEqual(base + 8, inset.image_pos);
6458 self.assertEqual(4, inset.size);
6459
Jonas Karlman9b2fd2d2023-01-21 19:01:39 +00006460 def testFitAlign(self):
6461 """Test an image with an FIT with aligned external data"""
6462 data = self._DoReadFile('275_fit_align.dts')
6463 self.assertEqual(4096, len(data))
6464
6465 dtb = fdt.Fdt.FromData(data)
6466 dtb.Scan()
6467
6468 props = self._GetPropTree(dtb, ['data-position'])
6469 expected = {
6470 'u-boot:data-position': 1024,
6471 'fdt-1:data-position': 2048,
6472 'fdt-2:data-position': 3072,
6473 }
6474 self.assertEqual(expected, props)
6475
Jonas Karlmanf584d442023-01-21 19:02:12 +00006476 def testFitFirmwareLoadables(self):
6477 """Test an image with an FIT that use fit,firmware"""
6478 if not elf.ELF_TOOLS:
6479 self.skipTest('Python elftools not available')
6480 entry_args = {
6481 'of-list': 'test-fdt1',
6482 'default-dt': 'test-fdt1',
6483 'atf-bl31-path': 'bl31.elf',
6484 'tee-os-path': 'missing.bin',
6485 }
6486 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass7c4027a2023-02-23 18:18:01 -07006487 with test_util.capture_sys_output() as (stdout, stderr):
6488 data = self._DoReadFileDtb(
6489 '276_fit_firmware_loadables.dts',
6490 entry_args=entry_args,
6491 extra_indirs=[test_subdir])[0]
Jonas Karlmanf584d442023-01-21 19:02:12 +00006492
6493 dtb = fdt.Fdt.FromData(data)
6494 dtb.Scan()
6495
6496 node = dtb.GetNode('/configurations/conf-uboot-1')
6497 self.assertEqual('u-boot', node.props['firmware'].value)
6498 self.assertEqual(['atf-1', 'atf-2'],
6499 fdt_util.GetStringList(node, 'loadables'))
6500
6501 node = dtb.GetNode('/configurations/conf-atf-1')
6502 self.assertEqual('atf-1', node.props['firmware'].value)
6503 self.assertEqual(['u-boot', 'atf-2'],
6504 fdt_util.GetStringList(node, 'loadables'))
6505
6506 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6507 self.assertEqual('u-boot', node.props['firmware'].value)
6508 self.assertEqual(['atf-1', 'atf-2'],
6509 fdt_util.GetStringList(node, 'loadables'))
6510
6511 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6512 self.assertEqual('atf-1', node.props['firmware'].value)
6513 self.assertEqual(['u-boot', 'atf-2'],
6514 fdt_util.GetStringList(node, 'loadables'))
6515
6516 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6517 self.assertEqual('atf-1', node.props['firmware'].value)
6518 self.assertEqual(['u-boot', 'atf-2'],
6519 fdt_util.GetStringList(node, 'loadables'))
6520
Simon Glassfe7e9242023-02-22 12:14:49 -07006521 def testTooldir(self):
6522 """Test that we can specify the tooldir"""
6523 with test_util.capture_sys_output() as (stdout, stderr):
6524 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6525 'tool', '-l'))
6526 self.assertEqual('fred', bintool.Bintool.tooldir)
6527
6528 # Check that the toolpath is updated correctly
6529 self.assertEqual(['fred'], tools.tool_search_paths)
6530
6531 # Try with a few toolpaths; the tooldir should be at the end
6532 with test_util.capture_sys_output() as (stdout, stderr):
6533 self.assertEqual(0, self._DoBinman(
6534 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6535 'tool', '-l'))
6536 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6537
Simon Glass7caa3722023-03-02 17:02:44 -07006538 def testReplaceSectionEntry(self):
6539 """Test replacing an entry in a section"""
6540 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6541 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6542 expect_data, dts='241_replace_section_simple.dts')
6543 self.assertEqual(expect_data, entry_data)
6544
6545 entries = image.GetEntries()
6546 self.assertIn('section', entries)
6547 section = entries['section']
6548
6549 sect_entries = section.GetEntries()
6550 self.assertIn('blob', sect_entries)
6551 entry = sect_entries['blob']
6552 self.assertEqual(len(expect_data), entry.size)
6553
6554 fname = tools.get_output_filename('image-updated.bin')
6555 data = tools.read_file(fname)
6556
6557 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6558 self.assertEqual(expect_data, new_blob_data)
6559
6560 self.assertEqual(U_BOOT_DATA,
6561 data[entry.image_pos + len(expect_data):]
6562 [:len(U_BOOT_DATA)])
6563
6564 def testReplaceSectionDeep(self):
6565 """Test replacing an entry in two levels of sections"""
6566 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6567 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6568 'section/section/blob', expect_data,
6569 dts='278_replace_section_deep.dts')
6570 self.assertEqual(expect_data, entry_data)
6571
6572 entries = image.GetEntries()
6573 self.assertIn('section', entries)
6574 section = entries['section']
6575
6576 subentries = section.GetEntries()
6577 self.assertIn('section', subentries)
6578 section = subentries['section']
6579
6580 sect_entries = section.GetEntries()
6581 self.assertIn('blob', sect_entries)
6582 entry = sect_entries['blob']
6583 self.assertEqual(len(expect_data), entry.size)
6584
6585 fname = tools.get_output_filename('image-updated.bin')
6586 data = tools.read_file(fname)
6587
6588 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6589 self.assertEqual(expect_data, new_blob_data)
6590
6591 self.assertEqual(U_BOOT_DATA,
6592 data[entry.image_pos + len(expect_data):]
6593 [:len(U_BOOT_DATA)])
6594
6595 def testReplaceFitSibling(self):
6596 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006597 self._SetupSplElf()
Simon Glass7caa3722023-03-02 17:02:44 -07006598 fname = TestFunctional._MakeInputFile('once', b'available once')
6599 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6600 os.remove(fname)
6601
6602 try:
6603 tmpdir, updated_fname = self._SetupImageInTmpdir()
6604
6605 fname = os.path.join(tmpdir, 'update-blob')
6606 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6607 tools.write_file(fname, expected)
6608
6609 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6610 data = tools.read_file(updated_fname)
6611 start = len(U_BOOT_DTB_DATA)
6612 self.assertEqual(expected, data[start:start + len(expected)])
6613 map_fname = os.path.join(tmpdir, 'image-updated.map')
6614 self.assertFalse(os.path.exists(map_fname))
6615 finally:
6616 shutil.rmtree(tmpdir)
6617
Simon Glass953d4172023-03-02 17:02:45 -07006618 def testX509Cert(self):
6619 """Test creating an X509 certificate"""
6620 keyfile = self.TestFile('key.key')
6621 entry_args = {
6622 'keyfile': keyfile,
6623 }
6624 data = self._DoReadFileDtb('279_x509_cert.dts',
6625 entry_args=entry_args)[0]
6626 cert = data[:-4]
6627 self.assertEqual(U_BOOT_DATA, data[-4:])
6628
6629 # TODO: verify the signature
6630
6631 def testX509CertMissing(self):
6632 """Test that binman still produces an image if openssl is missing"""
6633 keyfile = self.TestFile('key.key')
6634 entry_args = {
6635 'keyfile': 'keyfile',
6636 }
6637 with test_util.capture_sys_output() as (_, stderr):
6638 self._DoTestFile('279_x509_cert.dts',
6639 force_missing_bintools='openssl',
6640 entry_args=entry_args)
6641 err = stderr.getvalue()
6642 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6643
Jonas Karlman05b978b2023-02-25 19:01:33 +00006644 def testPackRockchipTpl(self):
6645 """Test that an image with a Rockchip TPL binary can be created"""
6646 data = self._DoReadFile('277_rockchip_tpl.dts')
6647 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6648
Jonas Karlman40389c22023-02-25 19:01:35 +00006649 def testMkimageMissingBlobMultiple(self):
6650 """Test missing blob with mkimage entry and multiple-data-files"""
6651 with test_util.capture_sys_output() as (stdout, stderr):
6652 self._DoTestFile('278_mkimage_missing_multiple.dts', allow_missing=True)
6653 err = stderr.getvalue()
6654 self.assertIn("is missing external blobs and is non-functional", err)
6655
6656 with self.assertRaises(ValueError) as e:
6657 self._DoTestFile('278_mkimage_missing_multiple.dts', allow_missing=False)
6658 self.assertIn("not found in input path", str(e.exception))
6659
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +00006660 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6661 """Prepare sign environment
6662
6663 Create private and public keys, add pubkey into dtb.
6664
6665 Returns:
6666 Tuple:
6667 FIT container
6668 Image name
6669 Private key
6670 DTB
6671 """
Marek Vasutfadad3a2023-07-18 07:23:58 -06006672 self._SetupSplElf()
Ivan Mikhaylov5b34efe2023-03-08 01:13:40 +00006673 data = self._DoReadFileRealDtb(dts)
6674 updated_fname = tools.get_output_filename('image-updated.bin')
6675 tools.write_file(updated_fname, data)
6676 dtb = tools.get_output_filename('source.dtb')
6677 private_key = tools.get_output_filename('test_key.key')
6678 public_key = tools.get_output_filename('test_key.crt')
6679 fit = tools.get_output_filename('fit.fit')
6680 key_dir = tools.get_output_dir()
6681
6682 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6683 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6684 private_key, '-out', public_key)
6685 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6686 '-n', 'test_key', '-r', 'conf', dtb)
6687
6688 return fit, updated_fname, private_key, dtb
6689
6690 def testSignSimple(self):
6691 """Test that a FIT container can be signed in image"""
6692 is_signed = False
6693 fit, fname, private_key, dtb = self._PrepareSignEnv()
6694
6695 # do sign with private key
6696 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6697 ['fit'])
6698 is_signed = self._CheckSign(fit, dtb)
6699
6700 self.assertEqual(is_signed, True)
6701
6702 def testSignExactFIT(self):
6703 """Test that a FIT container can be signed and replaced in image"""
6704 is_signed = False
6705 fit, fname, private_key, dtb = self._PrepareSignEnv()
6706
6707 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6708 args = []
6709 if self.toolpath:
6710 for path in self.toolpath:
6711 args += ['--toolpath', path]
6712
6713 # do sign with private key
6714 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6715 'sha256,rsa4096', '-f', fit, 'fit')
6716 is_signed = self._CheckSign(fit, dtb)
6717
6718 self.assertEqual(is_signed, True)
6719
6720 def testSignNonFit(self):
6721 """Test a non-FIT entry cannot be signed"""
6722 is_signed = False
6723 fit, fname, private_key, _ = self._PrepareSignEnv(
6724 '281_sign_non_fit.dts')
6725
6726 # do sign with private key
6727 with self.assertRaises(ValueError) as e:
6728 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6729 'sha256,rsa4096', '-f', fit, 'u-boot')
6730 self.assertIn(
6731 "Node '/u-boot': Updating signatures is not supported with this entry type",
6732 str(e.exception))
6733
6734 def testSignMissingMkimage(self):
6735 """Test that FIT signing handles a missing mkimage tool"""
6736 fit, fname, private_key, _ = self._PrepareSignEnv()
6737
6738 # try to sign with a missing mkimage tool
6739 bintool.Bintool.set_missing_list(['mkimage'])
6740 with self.assertRaises(ValueError) as e:
6741 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6742 ['fit'])
6743 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6744
Simon Glass4649bea2023-07-18 07:23:54 -06006745 def testSymbolNoWrite(self):
6746 """Test disabling of symbol writing"""
Marek Vasutfadad3a2023-07-18 07:23:58 -06006747 self._SetupSplElf()
Simon Glass4649bea2023-07-18 07:23:54 -06006748 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6749 no_write_symbols=True)
6750
6751 def testSymbolNoWriteExpanded(self):
6752 """Test disabling of symbol writing in expanded entries"""
6753 entry_args = {
6754 'spl-dtb': '1',
6755 }
6756 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6757 U_BOOT_SPL_DTB_DATA, 0x38,
6758 entry_args=entry_args, use_expanded=True,
6759 no_write_symbols=True)
6760
Marek Vasutfadad3a2023-07-18 07:23:58 -06006761 def testMkimageSpecial(self):
6762 """Test mkimage ignores special hash-1 node"""
6763 data = self._DoReadFile('283_mkimage_special.dts')
6764
6765 # Just check that the data appears in the file somewhere
6766 self.assertIn(U_BOOT_DATA, data)
6767
Simon Glassb1e40ee2023-07-18 07:23:59 -06006768 def testFitFdtList(self):
6769 """Test an image with an FIT with the fit,fdt-list-val option"""
6770 entry_args = {
6771 'default-dt': 'test-fdt2',
6772 }
6773 data = self._DoReadFileDtb(
6774 '284_fit_fdt_list.dts',
6775 entry_args=entry_args,
6776 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6777 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6778 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6779
Simon Glasse1ad57e2023-07-18 07:24:01 -06006780 def testSplEmptyBss(self):
6781 """Test an expanded SPL with a zero-size BSS"""
6782 # ELF file with a '__bss_size' symbol
6783 self._SetupSplElf(src_fname='bss_data_zero')
6784
6785 entry_args = {
6786 'spl-bss-pad': 'y',
6787 'spl-dtb': 'y',
6788 }
6789 data = self._DoReadFileDtb('285_spl_expand.dts',
6790 use_expanded=True, entry_args=entry_args)[0]
6791
Simon Glassf6abd522023-07-18 07:24:04 -06006792 def testTemplate(self):
6793 """Test using a template"""
6794 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6795 data = self._DoReadFile('286_template.dts')
6796 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6797 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6798 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6799
Simon Glass35f72fb2023-07-18 07:24:05 -06006800 def testTemplateBlobMulti(self):
6801 """Test using a template with 'multiple-images' enabled"""
6802 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6803 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6804 retcode = self._DoTestFile('287_template_multi.dts')
6805
6806 self.assertEqual(0, retcode)
6807 image = control.images['image']
6808 image_fname = tools.get_output_filename('my-image.bin')
6809 data = tools.read_file(image_fname)
6810 self.assertEqual(b'blob@@@@other', data)
6811
Simon Glassdb0e3f12023-07-18 07:24:06 -06006812 def testTemplateFit(self):
6813 """Test using a template in a FIT"""
6814 fit_data = self._DoReadFile('288_template_fit.dts')
6815 fname = os.path.join(self._indir, 'fit_data.fit')
6816 tools.write_file(fname, fit_data)
6817 out = tools.run('dumpimage', '-l', fname)
6818
Simon Glass696f2b72023-07-18 07:24:07 -06006819 def testTemplateSection(self):
6820 """Test using a template in a section (not at top level)"""
6821 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6822 data = self._DoReadFile('289_template_section.dts')
6823 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6824 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6825 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6826
Simon Glass23b96e92023-07-18 07:24:08 -06006827 def testMkimageSymbols(self):
6828 """Test using mkimage to build an image with symbols in it"""
6829 self._SetupSplElf('u_boot_binman_syms')
6830 data = self._DoReadFile('290_mkimage_sym.dts')
6831
6832 image = control.images['image']
6833 entries = image.GetEntries()
6834 self.assertIn('u-boot', entries)
6835 u_boot = entries['u-boot']
6836
6837 mkim = entries['mkimage']
6838 mkim_entries = mkim.GetEntries()
6839 self.assertIn('u-boot-spl', mkim_entries)
6840 spl = mkim_entries['u-boot-spl']
6841 self.assertIn('u-boot-spl2', mkim_entries)
6842 spl2 = mkim_entries['u-boot-spl2']
6843
6844 # skip the mkimage header and the area sizes
6845 mk_data = data[mkim.offset + 0x40:]
6846 size, term = struct.unpack('>LL', mk_data[:8])
6847
6848 # There should be only one image, so check that the zero terminator is
6849 # present
6850 self.assertEqual(0, term)
6851
6852 content = mk_data[8:8 + size]
6853
6854 # The image should contain the symbols from u_boot_binman_syms.c
6855 # Note that image_pos is adjusted by the base address of the image,
6856 # which is 0x10 in our test image
6857 spl_data = content[:0x18]
6858 content = content[0x1b:]
6859
6860 # After the header is a table of offsets for each image. There should
6861 # only be one image, then a 0 terminator, so figure out the real start
6862 # of the image data
6863 base = 0x40 + 8
6864
6865 # Check symbols in both u-boot-spl and u-boot-spl2
6866 for i in range(2):
6867 vals = struct.unpack('<LLQLL', spl_data)
6868
6869 # The image should contain the symbols from u_boot_binman_syms.c
6870 # Note that image_pos is adjusted by the base address of the image,
6871 # which is 0x10 in our 'u_boot_binman_syms' test image
6872 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6873 self.assertEqual(base, vals[1])
6874 self.assertEqual(spl2.offset, vals[2])
6875 # figure out the internal positions of its components
6876 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6877
6878 # Check that spl and spl2 are actually at the indicated positions
6879 self.assertEqual(
6880 elf.BINMAN_SYM_MAGIC_VALUE,
6881 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6882 self.assertEqual(
6883 elf.BINMAN_SYM_MAGIC_VALUE,
6884 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6885
6886 self.assertEqual(len(U_BOOT_DATA), vals[4])
6887
6888 # Move to next
6889 spl_data = content[:0x18]
6890
Neha Malcom Francis6c66ccf2023-07-22 00:14:24 +05306891 def testTIBoardConfig(self):
6892 """Test that a schema validated board config file can be generated"""
6893 data = self._DoReadFile('277_ti_board_cfg.dts')
6894 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
6895
6896 def testTIBoardConfigCombined(self):
6897 """Test that a schema validated combined board config file can be generated"""
6898 data = self._DoReadFile('278_ti_board_cfg_combined.dts')
6899 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
6900 self.assertGreater(data, configlen_noheader)
6901
6902 def testTIBoardConfigNoDataType(self):
6903 """Test that error is thrown when data type is not supported"""
6904 with self.assertRaises(ValueError) as e:
6905 data = self._DoReadFile('279_ti_board_cfg_no_type.dts')
6906 self.assertIn("Schema validation error", str(e.exception))
Simon Glassefddab62023-01-07 14:07:08 -07006907
Simon Glass9fc60b42017-11-12 21:52:22 -07006908if __name__ == "__main__":
6909 unittest.main()