blob: 376af9fa0806c84a3918c2cca95720a5e1b43dd4 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass57454f42016-11-25 20:15:52 -07002# Copyright (c) 2016 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glass57454f42016-11-25 20:15:52 -07005# To run a single test, change to this directory, and:
6#
7# python -m unittest func_test.TestFunctional.testHelp
8
Simon Glass45d556d2020-07-09 18:39:45 -06009import collections
Simon Glassc585dd42020-04-17 18:09:03 -060010import gzip
Simon Glassae7cf032018-09-14 04:57:31 -060011import hashlib
Simon Glass57454f42016-11-25 20:15:52 -070012from optparse import OptionParser
13import os
Simon Glass45d556d2020-07-09 18:39:45 -060014import re
Simon Glass57454f42016-11-25 20:15:52 -070015import shutil
16import struct
17import sys
18import tempfile
19import unittest
Simon Glass162017b2022-01-09 20:13:57 -070020import unittest.mock
21import urllib.error
Simon Glass57454f42016-11-25 20:15:52 -070022
Simon Glass4eae9252022-01-09 20:13:50 -070023from binman import bintool
Simon Glassc585dd42020-04-17 18:09:03 -060024from binman import cbfs_util
25from binman import cmdline
26from binman import control
27from binman import elf
28from binman import elf_test
Simon Glass3efb2972021-11-23 21:08:59 -070029from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060030from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060031from binman import state
32from dtoc import fdt
33from dtoc import fdt_util
34from binman.etype import fdtmap
35from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060036from binman.image import Image
Simon Glass131444f2023-02-23 18:18:04 -070037from u_boot_pylib import command
38from u_boot_pylib import test_util
39from u_boot_pylib import tools
40from u_boot_pylib import tout
Simon Glass57454f42016-11-25 20:15:52 -070041
42# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060043U_BOOT_DATA = b'1234'
44U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +030045U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
46U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
Simon Glass56d05412022-02-28 07:16:54 -070047U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_'
Simon Glass303f62f2019-05-17 22:00:46 -060048BLOB_DATA = b'89'
49ME_DATA = b'0abcd'
50VGA_DATA = b'vga'
51U_BOOT_DTB_DATA = b'udtb'
52U_BOOT_SPL_DTB_DATA = b'spldtb'
53U_BOOT_TPL_DTB_DATA = b'tpldtb'
Simon Glass56d05412022-02-28 07:16:54 -070054U_BOOT_VPL_DTB_DATA = b'vpldtb'
Simon Glass303f62f2019-05-17 22:00:46 -060055X86_START16_DATA = b'start16'
56X86_START16_SPL_DATA = b'start16spl'
57X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060058X86_RESET16_DATA = b'reset16'
59X86_RESET16_SPL_DATA = b'reset16spl'
60X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-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 Glass56d05412022-02-28 07:16:54 -070065U_BOOT_VPL_NODTB_DATA = b'vplnodtb'
Alper Nebi Yasak09fb0612022-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 Glass303f62f2019-05-17 22:00:46 -060069FSP_DATA = b'fsp'
70CMC_DATA = b'cmc'
71VBT_DATA = b'vbt'
72MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060073TEXT_DATA = 'text'
74TEXT_DATA2 = 'text2'
75TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-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 Glassccec0262019-07-08 13:18:42 -060082COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060083COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060084REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060085FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060086FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060087FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060088ATF_BL31_DATA = b'bl31'
Roger Quadros5cdcea02022-02-19 20:50:04 +020089TEE_OS_DATA = b'this is some tee OS data'
Simon Glass3efb2972021-11-23 21:08:59 -070090ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080091OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050092SCP_DATA = b'scp'
Jonas Karlman35305492023-02-25 19:01:33 +000093ROCKCHIP_TPL_DATA = b'rockchip-tpl'
Simon Glassa435cd12020-09-01 05:13:59 -060094TEST_FDT1_DATA = b'fdt1'
95TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060096ENV_DATA = b'var1=1\nvar2="2"'
Philippe Reynesebe96cb2022-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 Francis3b788942023-07-22 00:14:24 +0530100TI_BOARD_CONFIG_DATA = b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530101TI_UNSECURE_DATA = b'unsecuredata'
Simon Glassa435cd12020-09-01 05:13:59 -0600102
103# Subdirectory of the input dir to use to put test FDTs
104TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600105
Simon Glass2c6adba2019-07-20 12:23:47 -0600106# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600107EXTRACT_DTB_SIZE = 0x3c9
108
Simon Glass2c6adba2019-07-20 12:23:47 -0600109# Properties expected to be in the device tree when update_dtb is used
110BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
111
Simon Glassfb30e292019-07-20 12:23:51 -0600112# Extra properties expected to be in the device tree when allow-repack is used
113REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
114
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200115# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200116COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700117
Simon Glassad5cfe12023-01-07 14:07:14 -0700118TEE_ADDR = 0x5678
119
Simon Glass57454f42016-11-25 20:15:52 -0700120class TestFunctional(unittest.TestCase):
121 """Functional tests for binman
122
123 Most of these use a sample .dts file to build an image and then check
124 that it looks correct. The sample files are in the test/ subdirectory
125 and are numbered.
126
127 For each entry type a very small test file is created using fixed
128 string contents. This makes it easy to test that things look right, and
129 debug problems.
130
131 In some cases a 'real' file must be used - these are also supplied in
132 the test/ diurectory.
133 """
134 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600135 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700136 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600137 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700138
Simon Glass57454f42016-11-25 20:15:52 -0700139 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600140 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
141 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700142
143 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600144 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700145
146 # Create some test files
147 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
148 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
149 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600150 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700151 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700152 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700153 TestFunctional._MakeInputFile('me.bin', ME_DATA)
154 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600155 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600156
Jagdish Gediya311d4842018-09-03 21:35:08 +0530157 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600158
Simon Glassabab18c2019-08-24 07:22:49 -0600159 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
160 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700161 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600162 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600163 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600164
165 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
166 X86_RESET16_DATA)
167 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
168 X86_RESET16_SPL_DATA)
169 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
170 X86_RESET16_TPL_DATA)
171
Simon Glass57454f42016-11-25 20:15:52 -0700172 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700173 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
174 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600175 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
176 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700177 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
178 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700179 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
180 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700181 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700182 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600183 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600184 TestFunctional._MakeInputDir('devkeys')
185 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600186 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600187 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600188 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600189 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700190
Simon Glassf6290892019-08-24 07:22:53 -0600191 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
192 elf_test.BuildElfTestFiles(cls._elf_testdir)
193
Simon Glass72232452016-11-25 20:15:53 -0700194 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600195 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700196 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700197
198 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600199 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700200
Simon Glass862f8e22019-08-24 07:22:43 -0600201 shutil.copytree(cls.TestFile('files'),
202 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600203
Neha Malcom Francis3b788942023-07-22 00:14:24 +0530204 shutil.copytree(cls.TestFile('yaml'),
205 os.path.join(cls._indir, 'yaml'))
206
Simon Glass7ba33592018-09-14 04:57:26 -0600207 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600208 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600209 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200210 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700211 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800212 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500213 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman35305492023-02-25 19:01:33 +0000214 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +0530215 TestFunctional._MakeInputFile('ti_unsecure.bin', TI_UNSECURE_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600216
Simon Glassa435cd12020-09-01 05:13:59 -0600217 # Add a few .dtb files for testing
218 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
219 TEST_FDT1_DATA)
220 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
221 TEST_FDT2_DATA)
222
Simon Glassa0729502020-09-06 10:35:33 -0600223 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
224
Simon Glass5f423422022-03-05 20:19:12 -0700225 # ELF file with two sections in different parts of memory, used for both
226 # ATF and OP_TEE
227 TestFunctional._MakeInputFile('bl31.elf',
228 tools.read_file(cls.ElfTestFile('elf_sections')))
229 TestFunctional._MakeInputFile('tee.elf',
230 tools.read_file(cls.ElfTestFile('elf_sections')))
231
Simon Glassad5cfe12023-01-07 14:07:14 -0700232 # Newer OP_TEE file in v1 binary format
233 cls.make_tee_bin('tee.bin')
234
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200235 cls.comp_bintools = {}
236 for name in COMP_BINTOOLS:
237 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600238
Simon Glass57454f42016-11-25 20:15:52 -0700239 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600240 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700241 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600242 if cls.preserve_indir:
243 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600244 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600245 if cls._indir:
246 shutil.rmtree(cls._indir)
247 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700248
Simon Glass1c420c92019-07-08 13:18:49 -0600249 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600250 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600251 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600252 """Accept arguments controlling test execution
253
254 Args:
255 preserve_indir: Preserve the shared input directory used by all
256 tests in this class.
257 preserve_outdir: Preserve the output directories used by tests. Each
258 test has its own, so this is normally only useful when running a
259 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600260 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600261 """
262 cls.preserve_indir = preserve_indir
263 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600264 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600265 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600266
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200267 def _CheckBintool(self, bintool):
268 if not bintool.is_present():
269 self.skipTest('%s not available' % bintool.name)
270
Simon Glass1de34482019-07-08 13:18:53 -0600271 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200272 bintool = self.comp_bintools['lz4']
273 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600274
Simon Glassee9d10d2019-07-20 12:24:09 -0600275 def _CleanupOutputDir(self):
276 """Remove the temporary output directory"""
277 if self.preserve_outdirs:
278 print('Preserving output dir: %s' % tools.outdir)
279 else:
Simon Glass80025522022-01-29 14:14:04 -0700280 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600281
Simon Glass57454f42016-11-25 20:15:52 -0700282 def setUp(self):
283 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700284 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700285 command.test_result = None
286
287 def tearDown(self):
288 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600289 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700290
Simon Glassb3d6fc72019-07-20 12:24:10 -0600291 def _SetupImageInTmpdir(self):
292 """Set up the output image in a new temporary directory
293
294 This is used when an image has been generated in the output directory,
295 but we want to run binman again. This will create a new output
296 directory and fail to delete the original one.
297
298 This creates a new temporary directory, copies the image to it (with a
299 new name) and removes the old output directory.
300
301 Returns:
302 Tuple:
303 Temporary directory to use
304 New image filename
305 """
Simon Glass80025522022-01-29 14:14:04 -0700306 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600307 tmpdir = tempfile.mkdtemp(prefix='binman.')
308 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700309 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600310 self._CleanupOutputDir()
311 return tmpdir, updated_fname
312
Simon Glass8425a1f2018-07-17 13:25:48 -0600313 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600314 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600315 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
316 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
317 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700318 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600319
Simon Glass57454f42016-11-25 20:15:52 -0700320 def _RunBinman(self, *args, **kwargs):
321 """Run binman using the command line
322
323 Args:
324 Arguments to pass, as a list of strings
325 kwargs: Arguments to pass to Command.RunPipe()
326 """
Simon Glass840be732022-01-29 14:14:05 -0700327 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700328 capture=True, capture_stderr=True, raise_on_error=False)
329 if result.return_code and kwargs.get('raise_on_error', True):
330 raise Exception("Error running '%s': %s" % (' '.join(args),
331 result.stdout + result.stderr))
332 return result
333
Simon Glassf46732a2019-07-08 14:25:29 -0600334 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700335 """Run binman using directly (in the same process)
336
337 Args:
338 Arguments to pass, as a list of strings
339 Returns:
340 Return value (0 for success)
341 """
Simon Glassf46732a2019-07-08 14:25:29 -0600342 argv = list(argv)
343 args = cmdline.ParseArgs(argv)
344 args.pager = 'binman-invalid-pager'
345 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700346
347 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600348 # args.verbosity = tout.DEBUG
349 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700350
Simon Glass91710b32018-07-17 13:25:32 -0600351 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600352 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300353 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100354 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700355 test_section_timeout=False, update_fdt_in_elf=None,
Andrew Davis6b463da2023-07-22 00:14:44 +0530356 force_missing_bintools='', ignore_missing=False, output_dir=None):
Simon Glass57454f42016-11-25 20:15:52 -0700357 """Run binman with a given test file
358
359 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600360 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600361 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600362 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600363 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600364 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600365 entry_args: Dict of entry args to supply to binman
366 key: arg name
367 value: value of that arg
368 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600369 use_real_dtb: True to use the test file as the contents of
370 the u-boot-dtb entry. Normally this is not needed and the
371 test contents (the U_BOOT_DTB_DATA string) can be used.
372 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300373 use_expanded: True to use expanded entries where available, e.g.
374 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600375 verbosity: Verbosity level to use (0-3, None=don't set it)
376 allow_missing: Set the '--allow-missing' flag so that missing
377 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100378 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600379 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600380 threads: Number of threads to use (None for default, 0 for
381 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600382 test_section_timeout: True to force the first time to timeout, as
383 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600384 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass66152ce2022-01-09 20:14:09 -0700385 force_missing_tools (str): comma-separated list of bintools to
386 regard as missing
Andrew Davis6b463da2023-07-22 00:14:44 +0530387 output_dir: Specific output directory to use for image using -O
Simon Glass9a798402021-11-03 21:09:17 -0600388
389 Returns:
390 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700391 """
Simon Glassf46732a2019-07-08 14:25:29 -0600392 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700393 if debug:
394 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600395 if verbosity is not None:
396 args.append('-v%d' % verbosity)
397 elif self.verbosity:
398 args.append('-v%d' % self.verbosity)
399 if self.toolpath:
400 for path in self.toolpath:
401 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600402 if threads is not None:
403 args.append('-T%d' % threads)
404 if test_section_timeout:
405 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600406 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600407 if map:
408 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600409 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600410 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600411 if not use_real_dtb:
412 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300413 if not use_expanded:
414 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600415 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600416 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600417 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600418 if allow_missing:
419 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700420 if ignore_missing:
421 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100422 if allow_fake_blobs:
423 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700424 if force_missing_bintools:
425 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600426 if update_fdt_in_elf:
427 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600428 if images:
429 for image in images:
430 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600431 if extra_indirs:
432 for indir in extra_indirs:
433 args += ['-I', indir]
Andrew Davis6b463da2023-07-22 00:14:44 +0530434 if output_dir:
435 args += ['-O', output_dir]
Simon Glass075a45c2017-11-13 18:55:00 -0700436 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700437
438 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700439 """Set up a new test device-tree file
440
441 The given file is compiled and set up as the device tree to be used
442 for ths test.
443
444 Args:
445 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600446 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700447
448 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600449 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700450 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600451 tmpdir = tempfile.mkdtemp(prefix='binmant.')
452 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600453 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700454 data = fd.read()
455 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600456 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600457 return data
Simon Glass57454f42016-11-25 20:15:52 -0700458
Simon Glass56d05412022-02-28 07:16:54 -0700459 def _GetDtbContentsForSpls(self, dtb_data, name):
460 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600461
462 For testing we don't actually have different versions of the DTB. With
463 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
464 we don't normally have any unwanted nodes.
465
466 We still want the DTBs for SPL and TPL to be different though, since
467 otherwise it is confusing to know which one we are looking at. So add
468 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600469
470 Args:
471 dtb_data: dtb data to modify (this should be a value devicetree)
472 name: Name of a new property to add
473
474 Returns:
475 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600476 """
477 dtb = fdt.Fdt.FromData(dtb_data)
478 dtb.Scan()
479 dtb.GetNode('/binman').AddZeroProp(name)
480 dtb.Sync(auto_resize=True)
481 dtb.Pack()
482 return dtb.GetContents()
483
Simon Glassed930672021-03-18 20:25:05 +1300484 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
485 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600486 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700487 """Run binman and return the resulting image
488
489 This runs binman with a given test file and then reads the resulting
490 output file. It is a shortcut function since most tests need to do
491 these steps.
492
493 Raises an assertion failure if binman returns a non-zero exit code.
494
495 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600496 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700497 use_real_dtb: True to use the test file as the contents of
498 the u-boot-dtb entry. Normally this is not needed and the
499 test contents (the U_BOOT_DTB_DATA string) can be used.
500 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300501 use_expanded: True to use expanded entries where available, e.g.
502 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600503 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600504 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600505 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600506 entry_args: Dict of entry args to supply to binman
507 key: arg name
508 value: value of that arg
509 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
510 function. If reset_dtbs is True, then the original test dtb
511 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600512 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600513 threads: Number of threads to use (None for default, 0 for
514 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700515
516 Returns:
517 Tuple:
518 Resulting image contents
519 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600520 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600521 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700522 """
Simon Glass72232452016-11-25 20:15:53 -0700523 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700524 # Use the compiled test file as the u-boot-dtb input
525 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700526 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600527
528 # For testing purposes, make a copy of the DT for SPL and TPL. Add
529 # a node indicating which it is, so aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700530 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600531 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
532 outfile = os.path.join(self._indir, dtb_fname)
533 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700534 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700535
536 try:
Simon Glass91710b32018-07-17 13:25:32 -0600537 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600538 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600539 use_expanded=use_expanded, extra_indirs=extra_indirs,
540 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700541 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700542 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700543
544 # Find the (only) image, read it and return its contents
545 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700546 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600547 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600548 if map:
Simon Glass80025522022-01-29 14:14:04 -0700549 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600550 with open(map_fname) as fd:
551 map_data = fd.read()
552 else:
553 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600554 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600555 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700556 finally:
557 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600558 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600559 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700560
Simon Glass5b4bce32019-07-08 14:25:26 -0600561 def _DoReadFileRealDtb(self, fname):
562 """Run binman with a real .dtb file and return the resulting data
563
564 Args:
565 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
566
567 Returns:
568 Resulting image contents
569 """
570 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
571
Simon Glass72232452016-11-25 20:15:53 -0700572 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600573 """Helper function which discards the device-tree binary
574
575 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600576 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600577 use_real_dtb: True to use the test file as the contents of
578 the u-boot-dtb entry. Normally this is not needed and the
579 test contents (the U_BOOT_DTB_DATA string) can be used.
580 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600581
582 Returns:
583 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600584 """
Simon Glass72232452016-11-25 20:15:53 -0700585 return self._DoReadFileDtb(fname, use_real_dtb)[0]
586
Simon Glass57454f42016-11-25 20:15:52 -0700587 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600588 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700589 """Create a new test input file, creating directories as needed
590
591 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600592 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700593 contents: File contents to write in to the file
594 Returns:
595 Full pathname of file created
596 """
Simon Glass862f8e22019-08-24 07:22:43 -0600597 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700598 dirname = os.path.dirname(pathname)
599 if dirname and not os.path.exists(dirname):
600 os.makedirs(dirname)
601 with open(pathname, 'wb') as fd:
602 fd.write(contents)
603 return pathname
604
605 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600606 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600607 """Create a new test input directory, creating directories as needed
608
609 Args:
610 dirname: Directory name to create
611
612 Returns:
613 Full pathname of directory created
614 """
Simon Glass862f8e22019-08-24 07:22:43 -0600615 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600616 if not os.path.exists(pathname):
617 os.makedirs(pathname)
618 return pathname
619
620 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600621 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600622 """Set up an ELF file with a '_dt_ucode_base_size' symbol
623
624 Args:
625 Filename of ELF file to use as SPL
626 """
Simon Glass93a806f2019-08-24 07:22:59 -0600627 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700628 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600629
630 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600631 def _SetupTplElf(cls, src_fname='bss_data'):
632 """Set up an ELF file with a '_dt_ucode_base_size' symbol
633
634 Args:
635 Filename of ELF file to use as TPL
636 """
637 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700638 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600639
640 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700641 def _SetupVplElf(cls, src_fname='bss_data'):
642 """Set up an ELF file with a '_dt_ucode_base_size' symbol
643
644 Args:
645 Filename of ELF file to use as VPL
646 """
647 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
648 tools.read_file(cls.ElfTestFile(src_fname)))
649
650 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600651 def _SetupDescriptor(cls):
652 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
653 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
654
655 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600656 def TestFile(cls, fname):
657 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700658
Simon Glassf6290892019-08-24 07:22:53 -0600659 @classmethod
660 def ElfTestFile(cls, fname):
661 return os.path.join(cls._elf_testdir, fname)
662
Simon Glassad5cfe12023-01-07 14:07:14 -0700663 @classmethod
664 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
665 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
666 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
667 dummy, paged_sz) + U_BOOT_DATA
668 data += extra_data
669 TestFunctional._MakeInputFile(fname, data)
670
Simon Glass57454f42016-11-25 20:15:52 -0700671 def AssertInList(self, grep_list, target):
672 """Assert that at least one of a list of things is in a target
673
674 Args:
675 grep_list: List of strings to check
676 target: Target string
677 """
678 for grep in grep_list:
679 if grep in target:
680 return
Simon Glass848cdb52019-05-17 22:00:50 -0600681 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700682
683 def CheckNoGaps(self, entries):
684 """Check that all entries fit together without gaps
685
686 Args:
687 entries: List of entries to check
688 """
Simon Glasse8561af2018-08-01 15:22:37 -0600689 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700690 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600691 self.assertEqual(offset, entry.offset)
692 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700693
Simon Glass72232452016-11-25 20:15:53 -0700694 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600695 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700696
697 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600698 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700699
700 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600701 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700702 """
703 return struct.unpack('>L', dtb[4:8])[0]
704
Simon Glass0f621332019-07-08 14:25:27 -0600705 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600706 def AddNode(node, path):
707 if node.name != '/':
708 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600709 for prop in node.props.values():
710 if prop.name in prop_names:
711 prop_path = path + ':' + prop.name
712 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
713 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600714 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600715 AddNode(subnode, path)
716
717 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600718 AddNode(dtb.GetRoot(), '')
719 return tree
720
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000721 def _CheckSign(self, fit, key):
722 try:
723 tools.run('fit_check_sign', '-k', key, '-f', fit)
724 except:
725 self.fail('Expected signed FIT container')
726 return False
727 return True
728
Simon Glass57454f42016-11-25 20:15:52 -0700729 def testRun(self):
730 """Test a basic run with valid args"""
731 result = self._RunBinman('-h')
732
733 def testFullHelp(self):
734 """Test that the full help is displayed with -H"""
735 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300736 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500737 # Remove possible extraneous strings
738 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
739 gothelp = result.stdout.replace(extra, '')
740 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700741 self.assertEqual(0, len(result.stderr))
742 self.assertEqual(0, result.return_code)
743
744 def testFullHelpInternal(self):
745 """Test that the full help is displayed with -H"""
746 try:
747 command.test_result = command.CommandResult()
748 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300749 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700750 finally:
751 command.test_result = None
752
753 def testHelp(self):
754 """Test that the basic help is displayed with -h"""
755 result = self._RunBinman('-h')
756 self.assertTrue(len(result.stdout) > 200)
757 self.assertEqual(0, len(result.stderr))
758 self.assertEqual(0, result.return_code)
759
Simon Glass57454f42016-11-25 20:15:52 -0700760 def testBoard(self):
761 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600762 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700763 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300764 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700765 self.assertEqual(0, result)
766
767 def testNeedBoard(self):
768 """Test that we get an error when no board ius supplied"""
769 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600770 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700771 self.assertIn("Must provide a board to process (use -b <board>)",
772 str(e.exception))
773
774 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600775 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700776 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600777 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700778 # We get one error from libfdt, and a different one from fdtget.
779 self.AssertInList(["Couldn't open blob from 'missing_file'",
780 'No such file or directory'], str(e.exception))
781
782 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600783 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700784
785 Since this is a source file it should be compiled and the error
786 will come from the device-tree compiler (dtc).
787 """
788 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600789 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700790 self.assertIn("FATAL ERROR: Unable to parse input tree",
791 str(e.exception))
792
793 def testMissingNode(self):
794 """Test that a device tree without a 'binman' node generates an error"""
795 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600796 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700797 self.assertIn("does not have a 'binman' node", str(e.exception))
798
799 def testEmpty(self):
800 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600801 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700802 self.assertEqual(0, len(result.stderr))
803 self.assertEqual(0, result.return_code)
804
805 def testInvalidEntry(self):
806 """Test that an invalid entry is flagged"""
807 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600808 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600809 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700810 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
811 "'/binman/not-a-valid-type'", str(e.exception))
812
813 def testSimple(self):
814 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600815 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700816 self.assertEqual(U_BOOT_DATA, data)
817
Simon Glass075a45c2017-11-13 18:55:00 -0700818 def testSimpleDebug(self):
819 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600820 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700821
Simon Glass57454f42016-11-25 20:15:52 -0700822 def testDual(self):
823 """Test that we can handle creating two images
824
825 This also tests image padding.
826 """
Simon Glass511f6582018-10-01 12:22:30 -0600827 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700828 self.assertEqual(0, retcode)
829
830 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600831 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700832 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700833 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600834 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700835 data = fd.read()
836 self.assertEqual(U_BOOT_DATA, data)
837
838 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600839 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700840 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700841 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600842 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700843 data = fd.read()
844 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700845 self.assertEqual(tools.get_bytes(0, 3), data[:3])
846 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700847
848 def testBadAlign(self):
849 """Test that an invalid alignment value is detected"""
850 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600851 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700852 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
853 "of two", str(e.exception))
854
855 def testPackSimple(self):
856 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600857 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700858 self.assertEqual(0, retcode)
859 self.assertIn('image', control.images)
860 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600861 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700862 self.assertEqual(5, len(entries))
863
864 # First u-boot
865 self.assertIn('u-boot', entries)
866 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600867 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700868 self.assertEqual(len(U_BOOT_DATA), entry.size)
869
870 # Second u-boot, aligned to 16-byte boundary
871 self.assertIn('u-boot-align', entries)
872 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600873 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700874 self.assertEqual(len(U_BOOT_DATA), entry.size)
875
876 # Third u-boot, size 23 bytes
877 self.assertIn('u-boot-size', entries)
878 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600879 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700880 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
881 self.assertEqual(23, entry.size)
882
883 # Fourth u-boot, placed immediate after the above
884 self.assertIn('u-boot-next', entries)
885 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600886 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700887 self.assertEqual(len(U_BOOT_DATA), entry.size)
888
Simon Glasse8561af2018-08-01 15:22:37 -0600889 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700890 self.assertIn('u-boot-fixed', entries)
891 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600892 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700893 self.assertEqual(len(U_BOOT_DATA), entry.size)
894
Simon Glass39dd2152019-07-08 14:25:47 -0600895 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700896
897 def testPackExtra(self):
898 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600899 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
900 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700901
Simon Glass57454f42016-11-25 20:15:52 -0700902 self.assertIn('image', control.images)
903 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600904 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600905 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700906
Samuel Hollande2574022023-01-21 17:25:16 -0600907 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700908 self.assertIn('u-boot', entries)
909 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600910 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700911 self.assertEqual(3, entry.pad_before)
912 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600913 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700914 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
915 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600916 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700917
918 # Second u-boot has an aligned size, but it has no effect
919 self.assertIn('u-boot-align-size-nop', entries)
920 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600921 self.assertEqual(pos, entry.offset)
922 self.assertEqual(len(U_BOOT_DATA), entry.size)
923 self.assertEqual(U_BOOT_DATA, entry.data)
924 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
925 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700926
927 # Third u-boot has an aligned size too
928 self.assertIn('u-boot-align-size', entries)
929 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600930 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700931 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600932 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700933 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600934 data[pos:pos + entry.size])
935 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700936
937 # Fourth u-boot has an aligned end
938 self.assertIn('u-boot-align-end', entries)
939 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600940 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700941 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600942 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700943 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600944 data[pos:pos + entry.size])
945 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700946
947 # Fifth u-boot immediately afterwards
948 self.assertIn('u-boot-align-both', entries)
949 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600950 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700951 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600952 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700953 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600954 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700955
Samuel Hollande2574022023-01-21 17:25:16 -0600956 # Sixth u-boot with both minimum size and aligned size
957 self.assertIn('u-boot-min-size', entries)
958 entry = entries['u-boot-min-size']
959 self.assertEqual(128, entry.offset)
960 self.assertEqual(32, entry.size)
961 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
962 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
963 data[pos:pos + entry.size])
964
Simon Glass57454f42016-11-25 20:15:52 -0700965 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -0600966 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700967
Simon Glassafb9caa2020-10-26 17:40:10 -0600968 dtb = fdt.Fdt(out_dtb_fname)
969 dtb.Scan()
970 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
971 expected = {
972 'image-pos': 0,
973 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -0600974 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -0600975
976 'u-boot:image-pos': 0,
977 'u-boot:offset': 0,
978 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
979
980 'u-boot-align-size-nop:image-pos': 12,
981 'u-boot-align-size-nop:offset': 12,
982 'u-boot-align-size-nop:size': 4,
983
984 'u-boot-align-size:image-pos': 16,
985 'u-boot-align-size:offset': 16,
986 'u-boot-align-size:size': 32,
987
988 'u-boot-align-end:image-pos': 48,
989 'u-boot-align-end:offset': 48,
990 'u-boot-align-end:size': 16,
991
992 'u-boot-align-both:image-pos': 64,
993 'u-boot-align-both:offset': 64,
994 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -0600995
996 'u-boot-min-size:image-pos': 128,
997 'u-boot-min-size:offset': 128,
998 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -0600999 }
1000 self.assertEqual(expected, props)
1001
Simon Glass57454f42016-11-25 20:15:52 -07001002 def testPackAlignPowerOf2(self):
1003 """Test that invalid entry alignment is detected"""
1004 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001005 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001006 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1007 "of two", str(e.exception))
1008
1009 def testPackAlignSizePowerOf2(self):
1010 """Test that invalid entry size alignment is detected"""
1011 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001012 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001013 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1014 "power of two", str(e.exception))
1015
1016 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001017 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001018 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001019 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001020 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001021 "align 0x4 (4)", str(e.exception))
1022
1023 def testPackInvalidSizeAlign(self):
1024 """Test that invalid entry size alignment is detected"""
1025 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001026 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001027 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1028 "align-size 0x4 (4)", str(e.exception))
1029
1030 def testPackOverlap(self):
1031 """Test that overlapping regions are detected"""
1032 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001033 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001034 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001035 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1036 str(e.exception))
1037
1038 def testPackEntryOverflow(self):
1039 """Test that entries that overflow their size are detected"""
1040 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001041 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001042 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1043 "but entry size is 0x3 (3)", str(e.exception))
1044
1045 def testPackImageOverflow(self):
1046 """Test that entries which overflow the image size are detected"""
1047 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001048 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001049 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001050 "size 0x3 (3)", str(e.exception))
1051
1052 def testPackImageSize(self):
1053 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001054 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001055 self.assertEqual(0, retcode)
1056 self.assertIn('image', control.images)
1057 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001058 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001059
1060 def testPackImageSizeAlign(self):
1061 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001062 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001063 self.assertEqual(0, retcode)
1064 self.assertIn('image', control.images)
1065 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001066 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001067
1068 def testPackInvalidImageAlign(self):
1069 """Test that invalid image alignment is detected"""
1070 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001071 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001072 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001073 "align-size 0x8 (8)", str(e.exception))
1074
Simon Glass2a0fa982022-02-11 13:23:21 -07001075 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001076 """Test that invalid image alignment is detected"""
1077 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001078 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001079 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001080 "two", str(e.exception))
1081
1082 def testImagePadByte(self):
1083 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001084 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001085 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001086 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001087 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001088
1089 def testImageName(self):
1090 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001091 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001092 self.assertEqual(0, retcode)
1093 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001094 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001095 self.assertTrue(os.path.exists(fname))
1096
1097 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001098 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001099 self.assertTrue(os.path.exists(fname))
1100
1101 def testBlobFilename(self):
1102 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001103 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001104 self.assertEqual(BLOB_DATA, data)
1105
1106 def testPackSorted(self):
1107 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001108 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001109 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001110 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1111 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001112
Simon Glasse8561af2018-08-01 15:22:37 -06001113 def testPackZeroOffset(self):
1114 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001115 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001116 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001117 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001118 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001119 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1120 str(e.exception))
1121
1122 def testPackUbootDtb(self):
1123 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001124 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001125 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001126
1127 def testPackX86RomNoSize(self):
1128 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001129 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001130 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001131 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001132 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001133 "using end-at-4gb", str(e.exception))
1134
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301135 def test4gbAndSkipAtStartTogether(self):
1136 """Test that the end-at-4gb and skip-at-size property can't be used
1137 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001138 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301139 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001140 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001141 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301142 "'skip-at-start'", str(e.exception))
1143
Simon Glass72232452016-11-25 20:15:53 -07001144 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001145 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001146 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001147 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001148 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001149 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1150 "is outside the section '/binman' starting at "
1151 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001152 str(e.exception))
1153
1154 def testPackX86Rom(self):
1155 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001156 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001157 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001158 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1159 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001160
1161 def testPackX86RomMeNoDesc(self):
1162 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001163 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001164 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001165 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001166 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001167 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1168 str(e.exception))
1169 finally:
1170 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001171
1172 def testPackX86RomBadDesc(self):
1173 """Test that the Intel requires a descriptor entry"""
1174 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001175 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001176 self.assertIn("Node '/binman/intel-me': No offset set with "
1177 "offset-unset: should another entry provide this correct "
1178 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001179
1180 def testPackX86RomMe(self):
1181 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001182 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001183 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001184 if data[:0x1000] != expected_desc:
1185 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001186 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1187
1188 def testPackVga(self):
1189 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001190 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001191 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1192
1193 def testPackStart16(self):
1194 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001195 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001196 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1197
Jagdish Gediya311d4842018-09-03 21:35:08 +05301198 def testPackPowerpcMpc85xxBootpgResetvec(self):
1199 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1200 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001201 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301202 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1203
Simon Glass6ba679c2018-07-06 10:27:17 -06001204 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001205 """Handle running a test for insertion of microcode
1206
1207 Args:
1208 dts_fname: Name of test .dts file
1209 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001210 ucode_second: True if the microsecond entry is second instead of
1211 third
Simon Glass820af1d2018-07-06 10:27:16 -06001212
1213 Returns:
1214 Tuple:
1215 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001216 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001217 in the above (two 4-byte words)
1218 """
Simon Glass3d274232017-11-12 21:52:27 -07001219 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001220
1221 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001222 if ucode_second:
1223 ucode_content = data[len(nodtb_data):]
1224 ucode_pos = len(nodtb_data)
1225 dtb_with_ucode = ucode_content[16:]
1226 fdt_len = self.GetFdtLen(dtb_with_ucode)
1227 else:
1228 dtb_with_ucode = data[len(nodtb_data):]
1229 fdt_len = self.GetFdtLen(dtb_with_ucode)
1230 ucode_content = dtb_with_ucode[fdt_len:]
1231 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001232 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001233 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001234 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001235 dtb = fdt.FdtScan(fname)
1236 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001237 self.assertTrue(ucode)
1238 for node in ucode.subnodes:
1239 self.assertFalse(node.props.get('data'))
1240
Simon Glass72232452016-11-25 20:15:53 -07001241 # Check that the microcode appears immediately after the Fdt
1242 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001243 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001244 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1245 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001246 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001247
1248 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001249 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001250 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1251 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001252 u_boot = data[:len(nodtb_data)]
1253 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001254
1255 def testPackUbootMicrocode(self):
1256 """Test that x86 microcode can be handled correctly
1257
1258 We expect to see the following in the image, in order:
1259 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1260 place
1261 u-boot.dtb with the microcode removed
1262 the microcode
1263 """
Simon Glass511f6582018-10-01 12:22:30 -06001264 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001265 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001266 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1267 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001268
Simon Glassbac25c82017-05-27 07:38:26 -06001269 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001270 """Test that x86 microcode can be handled correctly
1271
1272 We expect to see the following in the image, in order:
1273 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1274 place
1275 u-boot.dtb with the microcode
1276 an empty microcode region
1277 """
1278 # We need the libfdt library to run this test since only that allows
1279 # finding the offset of a property. This is required by
1280 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001281 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001282
1283 second = data[len(U_BOOT_NODTB_DATA):]
1284
1285 fdt_len = self.GetFdtLen(second)
1286 third = second[fdt_len:]
1287 second = second[:fdt_len]
1288
Simon Glassbac25c82017-05-27 07:38:26 -06001289 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1290 self.assertIn(ucode_data, second)
1291 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001292
Simon Glassbac25c82017-05-27 07:38:26 -06001293 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001294 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001295 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1296 len(ucode_data))
1297 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001298 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1299 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001300
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001301 def testPackUbootSingleMicrocode(self):
1302 """Test that x86 microcode can be handled correctly with fdt_normal.
1303 """
Simon Glassbac25c82017-05-27 07:38:26 -06001304 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001305
Simon Glass996021e2016-11-25 20:15:54 -07001306 def testUBootImg(self):
1307 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001308 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001309 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001310
1311 def testNoMicrocode(self):
1312 """Test that a missing microcode region is detected"""
1313 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001314 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001315 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1316 "node found in ", str(e.exception))
1317
1318 def testMicrocodeWithoutNode(self):
1319 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1320 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001321 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001322 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1323 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1324
1325 def testMicrocodeWithoutNode2(self):
1326 """Test that a missing u-boot-ucode node is detected"""
1327 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001328 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001329 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1330 "microcode region u-boot-ucode", str(e.exception))
1331
1332 def testMicrocodeWithoutPtrInElf(self):
1333 """Test that a U-Boot binary without the microcode symbol is detected"""
1334 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001335 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001336 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001337 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001338
1339 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001340 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001341 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1342 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1343
1344 finally:
1345 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001346 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001347 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001348
1349 def testMicrocodeNotInImage(self):
1350 """Test that microcode must be placed within the image"""
1351 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001352 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001353 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1354 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001355 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001356
1357 def testWithoutMicrocode(self):
1358 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001359 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001360 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001361 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001362
1363 # Now check the device tree has no microcode
1364 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1365 second = data[len(U_BOOT_NODTB_DATA):]
1366
1367 fdt_len = self.GetFdtLen(second)
1368 self.assertEqual(dtb, second[:fdt_len])
1369
1370 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1371 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001372 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001373
1374 def testUnknownPosSize(self):
1375 """Test that microcode must be placed within the image"""
1376 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001377 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001378 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001379 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001380
1381 def testPackFsp(self):
1382 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001383 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001384 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1385
1386 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001387 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001388 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001389 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001390
1391 def testPackVbt(self):
1392 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001393 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001394 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001395
Simon Glass7f94e832017-11-12 21:52:25 -07001396 def testSplBssPad(self):
1397 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001398 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001399 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001400 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001401 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001402 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001403
Simon Glass04cda032018-10-01 21:12:42 -06001404 def testSplBssPadMissing(self):
1405 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001406 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001407 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001408 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001409 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1410 str(e.exception))
1411
Simon Glasse83679d2017-11-12 21:52:26 -07001412 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001413 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001414 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001415 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1416
Simon Glass6ba679c2018-07-06 10:27:17 -06001417 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1418 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001419
1420 We expect to see the following in the image, in order:
1421 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1422 correct place
1423 u-boot.dtb with the microcode removed
1424 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001425
1426 Args:
1427 dts: Device tree file to use for test
1428 ucode_second: True if the microsecond entry is second instead of
1429 third
Simon Glass3d274232017-11-12 21:52:27 -07001430 """
Simon Glass7057d022018-10-01 21:12:47 -06001431 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001432 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1433 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001434 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1435 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001436
Simon Glass6ba679c2018-07-06 10:27:17 -06001437 def testPackUbootSplMicrocode(self):
1438 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001439 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001440 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001441
1442 def testPackUbootSplMicrocodeReorder(self):
1443 """Test that order doesn't matter for microcode entries
1444
1445 This is the same as testPackUbootSplMicrocode but when we process the
1446 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1447 entry, so we reply on binman to try later.
1448 """
Simon Glass511f6582018-10-01 12:22:30 -06001449 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001450 ucode_second=True)
1451
Simon Glassa409c932017-11-12 21:52:28 -07001452 def testPackMrc(self):
1453 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001454 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001455 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1456
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001457 def testSplDtb(self):
1458 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001459 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001460 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001461 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1462
Simon Glass0a6da312017-11-13 18:54:56 -07001463 def testSplNoDtb(self):
1464 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001465 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001466 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001467 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1468
Simon Glass7098b7f2021-03-21 18:24:30 +13001469 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4abf7842023-07-18 07:23:54 -06001470 use_expanded=False, no_write_symbols=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001471 """Check the image contains the expected symbol values
1472
1473 Args:
1474 dts: Device tree file to use for test
1475 base_data: Data before and after 'u-boot' section
1476 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001477 entry_args: Dict of entry args to supply to binman
1478 key: arg name
1479 value: value of that arg
1480 use_expanded: True to use expanded entries where available, e.g.
1481 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001482 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001483 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001484 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1485 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001486 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001487 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001488 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001489
Simon Glass7057d022018-10-01 21:12:47 -06001490 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001491 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1492 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001493 # The image should contain the symbols from u_boot_binman_syms.c
1494 # Note that image_pos is adjusted by the base address of the image,
1495 # which is 0x10 in our test image
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001496 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1497 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glass31e04cb2021-03-18 20:24:56 +13001498 0x10 + u_boot_offset, 0x04)
Simon Glass4abf7842023-07-18 07:23:54 -06001499 if no_write_symbols:
1500 expected = (base_data +
1501 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1502 U_BOOT_DATA + base_data)
1503 else:
1504 expected = (sym_values + base_data[24:] +
1505 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1506 base_data[24:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001507 self.assertEqual(expected, data)
1508
Simon Glass31e04cb2021-03-18 20:24:56 +13001509 def testSymbols(self):
1510 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001511 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001512
1513 def testSymbolsNoDtb(self):
1514 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001515 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001516 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1517 0x38)
1518
Simon Glasse76a3e62018-06-01 09:38:11 -06001519 def testPackUnitAddress(self):
1520 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001521 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001522 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1523
Simon Glassa91e1152018-06-01 09:38:16 -06001524 def testSections(self):
1525 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001526 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001527 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1528 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1529 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001530 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001531
Simon Glass30732662018-06-01 09:38:20 -06001532 def testMap(self):
1533 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001534 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001535 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700153600000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600153700000000 00000000 00000010 section@0
153800000000 00000000 00000004 u-boot
153900000010 00000010 00000010 section@1
154000000010 00000000 00000004 u-boot
154100000020 00000020 00000004 section@2
154200000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001543''', map_data)
1544
Simon Glass3b78d532018-06-01 09:38:21 -06001545 def testNamePrefix(self):
1546 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001547 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001548 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700154900000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600155000000000 00000000 00000010 section@0
155100000000 00000000 00000004 ro-u-boot
155200000010 00000010 00000010 section@1
155300000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001554''', map_data)
1555
Simon Glass6ba679c2018-07-06 10:27:17 -06001556 def testUnknownContents(self):
1557 """Test that obtaining the contents works as expected"""
1558 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001559 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001560 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001561 "processing of contents: remaining ["
1562 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001563
Simon Glass2e1169f2018-07-06 10:27:19 -06001564 def testBadChangeSize(self):
1565 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001566 try:
1567 state.SetAllowEntryExpansion(False)
1568 with self.assertRaises(ValueError) as e:
1569 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001570 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001571 str(e.exception))
1572 finally:
1573 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001574
Simon Glassa87014e2018-07-06 10:27:42 -06001575 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001576 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001577 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001578 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001579 dtb = fdt.Fdt(out_dtb_fname)
1580 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001581 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001582 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001583 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001584 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001585 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001586 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001587 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001588 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001589 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001590 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001591 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001592 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001593 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001594
Simon Glasse8561af2018-08-01 15:22:37 -06001595 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001596 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001597 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001598 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001599 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001600 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001601 'size': 40
1602 }, props)
1603
1604 def testUpdateFdtBad(self):
1605 """Test that we detect when ProcessFdt never completes"""
1606 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001607 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001608 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001609 '[<binman.etype._testing.Entry__testing',
1610 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001611
Simon Glass91710b32018-07-17 13:25:32 -06001612 def testEntryArgs(self):
1613 """Test passing arguments to entries from the command line"""
1614 entry_args = {
1615 'test-str-arg': 'test1',
1616 'test-int-arg': '456',
1617 }
Simon Glass511f6582018-10-01 12:22:30 -06001618 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001619 self.assertIn('image', control.images)
1620 entry = control.images['image'].GetEntries()['_testing']
1621 self.assertEqual('test0', entry.test_str_fdt)
1622 self.assertEqual('test1', entry.test_str_arg)
1623 self.assertEqual(123, entry.test_int_fdt)
1624 self.assertEqual(456, entry.test_int_arg)
1625
1626 def testEntryArgsMissing(self):
1627 """Test missing arguments and properties"""
1628 entry_args = {
1629 'test-int-arg': '456',
1630 }
Simon Glass511f6582018-10-01 12:22:30 -06001631 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001632 entry = control.images['image'].GetEntries()['_testing']
1633 self.assertEqual('test0', entry.test_str_fdt)
1634 self.assertEqual(None, entry.test_str_arg)
1635 self.assertEqual(None, entry.test_int_fdt)
1636 self.assertEqual(456, entry.test_int_arg)
1637
1638 def testEntryArgsRequired(self):
1639 """Test missing arguments and properties"""
1640 entry_args = {
1641 'test-int-arg': '456',
1642 }
1643 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001644 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001645 self.assertIn("Node '/binman/_testing': "
1646 'Missing required properties/entry args: test-str-arg, '
1647 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001648 str(e.exception))
1649
1650 def testEntryArgsInvalidFormat(self):
1651 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001652 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1653 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001654 with self.assertRaises(ValueError) as e:
1655 self._DoBinman(*args)
1656 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1657
1658 def testEntryArgsInvalidInteger(self):
1659 """Test that an invalid entry-argument integer is detected"""
1660 entry_args = {
1661 'test-int-arg': 'abc',
1662 }
1663 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001664 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001665 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1666 "'test-int-arg' (value 'abc') to integer",
1667 str(e.exception))
1668
1669 def testEntryArgsInvalidDatatype(self):
1670 """Test that an invalid entry-argument datatype is detected
1671
1672 This test could be written in entry_test.py except that it needs
1673 access to control.entry_args, which seems more than that module should
1674 be able to see.
1675 """
1676 entry_args = {
1677 'test-bad-datatype-arg': '12',
1678 }
1679 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001680 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001681 entry_args=entry_args)
1682 self.assertIn('GetArg() internal error: Unknown data type ',
1683 str(e.exception))
1684
Simon Glass2ca52032018-07-17 13:25:33 -06001685 def testText(self):
1686 """Test for a text entry type"""
1687 entry_args = {
1688 'test-id': TEXT_DATA,
1689 'test-id2': TEXT_DATA2,
1690 'test-id3': TEXT_DATA3,
1691 }
Simon Glass511f6582018-10-01 12:22:30 -06001692 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001693 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001694 expected = (tools.to_bytes(TEXT_DATA) +
1695 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1696 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001697 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001698 self.assertEqual(expected, data)
1699
Simon Glass969616c2018-07-17 13:25:36 -06001700 def testEntryDocs(self):
1701 """Test for creation of entry documentation"""
1702 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001703 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001704 self.assertTrue(len(stdout.getvalue()) > 0)
1705
1706 def testEntryDocsMissing(self):
1707 """Test handling of missing entry documentation"""
1708 with self.assertRaises(ValueError) as e:
1709 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001710 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001711 self.assertIn('Documentation is missing for modules: u_boot',
1712 str(e.exception))
1713
Simon Glass704784b2018-07-17 13:25:38 -06001714 def testFmap(self):
1715 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001716 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001717 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001718 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1719 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001720 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001721 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001722 self.assertEqual(1, fhdr.ver_major)
1723 self.assertEqual(0, fhdr.ver_minor)
1724 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001725 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001726 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001727 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001728 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001729 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001730
Simon Glass82059c22021-04-03 11:05:09 +13001731 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001732 self.assertEqual(b'SECTION0', fentry.name)
1733 self.assertEqual(0, fentry.offset)
1734 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001735 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001736
1737 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001738 self.assertEqual(b'RO_U_BOOT', fentry.name)
1739 self.assertEqual(0, fentry.offset)
1740 self.assertEqual(4, fentry.size)
1741 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001742
Simon Glass82059c22021-04-03 11:05:09 +13001743 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001744 self.assertEqual(b'SECTION1', fentry.name)
1745 self.assertEqual(16, fentry.offset)
1746 self.assertEqual(16, fentry.size)
1747 self.assertEqual(0, fentry.flags)
1748
1749 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001750 self.assertEqual(b'RW_U_BOOT', fentry.name)
1751 self.assertEqual(16, fentry.offset)
1752 self.assertEqual(4, fentry.size)
1753 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001754
Simon Glass82059c22021-04-03 11:05:09 +13001755 fentry = next(fiter)
1756 self.assertEqual(b'FMAP', fentry.name)
1757 self.assertEqual(32, fentry.offset)
1758 self.assertEqual(expect_size, fentry.size)
1759 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001760
Simon Glassdb168d42018-07-17 13:25:39 -06001761 def testBlobNamedByArg(self):
1762 """Test we can add a blob with the filename coming from an entry arg"""
1763 entry_args = {
1764 'cros-ec-rw-path': 'ecrw.bin',
1765 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001766 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001767
Simon Glass53f53992018-07-17 13:25:40 -06001768 def testFill(self):
1769 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001770 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001771 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001772 self.assertEqual(expected, data)
1773
1774 def testFillNoSize(self):
1775 """Test for an fill entry type with no size"""
1776 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001777 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001778 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001779 str(e.exception))
1780
Simon Glassc1ae83c2018-07-17 13:25:44 -06001781 def _HandleGbbCommand(self, pipe_list):
1782 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001783 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001784 fname = pipe_list[0][-1]
1785 # Append our GBB data to the file, which will happen every time the
1786 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001787 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001788 fd.write(GBB_DATA)
1789 return command.CommandResult()
1790
1791 def testGbb(self):
1792 """Test for the Chromium OS Google Binary Block"""
1793 command.test_result = self._HandleGbbCommand
1794 entry_args = {
1795 'keydir': 'devkeys',
1796 'bmpblk': 'bmpblk.bin',
1797 }
Simon Glass511f6582018-10-01 12:22:30 -06001798 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001799
1800 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001801 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1802 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001803 self.assertEqual(expected, data)
1804
1805 def testGbbTooSmall(self):
1806 """Test for the Chromium OS Google Binary Block being large enough"""
1807 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001808 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001809 self.assertIn("Node '/binman/gbb': GBB is too small",
1810 str(e.exception))
1811
1812 def testGbbNoSize(self):
1813 """Test for the Chromium OS Google Binary Block having a size"""
1814 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001815 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001816 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1817 str(e.exception))
1818
Simon Glass66152ce2022-01-09 20:14:09 -07001819 def testGbbMissing(self):
1820 """Test that binman still produces an image if futility is missing"""
1821 entry_args = {
1822 'keydir': 'devkeys',
1823 }
1824 with test_util.capture_sys_output() as (_, stderr):
1825 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1826 entry_args=entry_args)
1827 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001828 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001829
Simon Glass5c350162018-07-17 13:25:47 -06001830 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001831 """Fake calls to the futility utility
1832
1833 The expected pipe is:
1834
1835 [('futility', 'vbutil_firmware', '--vblock',
1836 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1837 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1838 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1839 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1840
1841 This writes to the output file (here, 'vblock.vblock'). If
1842 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1843 of the input data (here, 'input.vblock').
1844 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001845 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001846 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001847 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001848 if self._hash_data:
1849 infile = pipe_list[0][11]
1850 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001851 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001852 m.update(data)
1853 fd.write(m.digest())
1854 else:
1855 fd.write(VBLOCK_DATA)
1856
Simon Glass5c350162018-07-17 13:25:47 -06001857 return command.CommandResult()
1858
1859 def testVblock(self):
1860 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001861 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001862 command.test_result = self._HandleVblockCommand
1863 entry_args = {
1864 'keydir': 'devkeys',
1865 }
Simon Glass511f6582018-10-01 12:22:30 -06001866 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001867 entry_args=entry_args)
1868 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1869 self.assertEqual(expected, data)
1870
1871 def testVblockNoContent(self):
1872 """Test we detect a vblock which has no content to sign"""
1873 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001874 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001875 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001876 'property', str(e.exception))
1877
1878 def testVblockBadPhandle(self):
1879 """Test that we detect a vblock with an invalid phandle in contents"""
1880 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001881 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001882 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1883 '1000', str(e.exception))
1884
1885 def testVblockBadEntry(self):
1886 """Test that we detect an entry that points to a non-entry"""
1887 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001888 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001889 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1890 "'other'", str(e.exception))
1891
Simon Glass220c6222021-01-06 21:35:17 -07001892 def testVblockContent(self):
1893 """Test that the vblock signs the right data"""
1894 self._hash_data = True
1895 command.test_result = self._HandleVblockCommand
1896 entry_args = {
1897 'keydir': 'devkeys',
1898 }
1899 data = self._DoReadFileDtb(
1900 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1901 entry_args=entry_args)[0]
1902 hashlen = 32 # SHA256 hash is 32 bytes
1903 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1904 hashval = data[-hashlen:]
1905 dtb = data[len(U_BOOT_DATA):-hashlen]
1906
1907 expected_data = U_BOOT_DATA + dtb
1908
1909 # The hashval should be a hash of the dtb
1910 m = hashlib.sha256()
1911 m.update(expected_data)
1912 expected_hashval = m.digest()
1913 self.assertEqual(expected_hashval, hashval)
1914
Simon Glass66152ce2022-01-09 20:14:09 -07001915 def testVblockMissing(self):
1916 """Test that binman still produces an image if futility is missing"""
1917 entry_args = {
1918 'keydir': 'devkeys',
1919 }
1920 with test_util.capture_sys_output() as (_, stderr):
1921 self._DoTestFile('074_vblock.dts',
1922 force_missing_bintools='futility',
1923 entry_args=entry_args)
1924 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001925 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001926
Simon Glass8425a1f2018-07-17 13:25:48 -06001927 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001928 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001929 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001930 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001931 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001932 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1933
Simon Glass24b97442018-07-17 13:25:51 -06001934 def testUsesPos(self):
1935 """Test that the 'pos' property cannot be used anymore"""
1936 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001937 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001938 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1939 "'pos'", str(e.exception))
1940
Simon Glass274bf092018-09-14 04:57:08 -06001941 def testFillZero(self):
1942 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001943 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001944 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001945
Simon Glass267de432018-09-14 04:57:09 -06001946 def testTextMissing(self):
1947 """Test for a text entry type where there is no text"""
1948 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001949 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001950 self.assertIn("Node '/binman/text': No value provided for text label "
1951 "'test-id'", str(e.exception))
1952
Simon Glassed40e962018-09-14 04:57:10 -06001953 def testPackStart16Tpl(self):
1954 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001955 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001956 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1957
Simon Glass3b376c32018-09-14 04:57:12 -06001958 def testSelectImage(self):
1959 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001960 expected = 'Skipping images: image1'
1961
1962 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001963 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001964 with test_util.capture_sys_output() as (stdout, stderr):
1965 retcode = self._DoTestFile('006_dual_image.dts',
1966 verbosity=verbosity,
1967 images=['image2'])
1968 self.assertEqual(0, retcode)
1969 if verbosity:
1970 self.assertIn(expected, stdout.getvalue())
1971 else:
1972 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001973
Simon Glass80025522022-01-29 14:14:04 -07001974 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1975 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001976 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001977
Simon Glasse219aa42018-09-14 04:57:24 -06001978 def testUpdateFdtAll(self):
1979 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001980 self._SetupSplElf()
1981 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06001982 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001983
1984 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06001985 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001986 'image-pos': 0,
1987 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06001988 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001989 'section:image-pos': 0,
1990 'section:size': 565,
1991 'section/u-boot-dtb:offset': 0,
1992 'section/u-boot-dtb:image-pos': 0,
1993 'section/u-boot-dtb:size': 565,
1994 'u-boot-spl-dtb:offset': 565,
1995 'u-boot-spl-dtb:image-pos': 565,
1996 'u-boot-spl-dtb:size': 585,
1997 'u-boot-tpl-dtb:offset': 1150,
1998 'u-boot-tpl-dtb:image-pos': 1150,
1999 'u-boot-tpl-dtb:size': 585,
2000 'u-boot-vpl-dtb:image-pos': 1735,
2001 'u-boot-vpl-dtb:offset': 1735,
2002 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002003 }
2004
2005 # We expect three device-tree files in the output, one after the other.
2006 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2007 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2008 # main U-Boot tree. All three should have the same postions and offset.
2009 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002010 self.maxDiff = None
2011 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002012 dtb = fdt.Fdt.FromData(data[start:])
2013 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002014 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002015 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002016 expected = dict(base_expected)
2017 if item:
2018 expected[item] = 0
2019 self.assertEqual(expected, props)
2020 start += dtb._fdt_obj.totalsize()
2021
2022 def testUpdateFdtOutput(self):
2023 """Test that output DTB files are updated"""
2024 try:
Simon Glass511f6582018-10-01 12:22:30 -06002025 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002026 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2027
2028 # Unfortunately, compiling a source file always results in a file
2029 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002030 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002031 # binman as a file called u-boot.dtb. To fix this, copy the file
2032 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002033 start = 0
2034 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002035 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002036 dtb = fdt.Fdt.FromData(data[start:])
2037 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002038 pathname = tools.get_output_filename(os.path.split(fname)[1])
2039 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002040 name = os.path.split(fname)[0]
2041
2042 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002043 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002044 else:
2045 orig_indata = dtb_data
2046 self.assertNotEqual(outdata, orig_indata,
2047 "Expected output file '%s' be updated" % pathname)
2048 self.assertEqual(outdata, data[start:start + size],
2049 "Expected output file '%s' to match output image" %
2050 pathname)
2051 start += size
2052 finally:
2053 self._ResetDtbs()
2054
Simon Glass7ba33592018-09-14 04:57:26 -06002055 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002056 bintool = self.comp_bintools['lz4']
2057 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002058
2059 def testCompress(self):
2060 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002061 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002062 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002063 use_real_dtb=True, update_dtb=True)
2064 dtb = fdt.Fdt(out_dtb_fname)
2065 dtb.Scan()
2066 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2067 orig = self._decompress(data)
2068 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002069
2070 # Do a sanity check on various fields
2071 image = control.images['image']
2072 entries = image.GetEntries()
2073 self.assertEqual(1, len(entries))
2074
2075 entry = entries['blob']
2076 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2077 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2078 orig = self._decompress(entry.data)
2079 self.assertEqual(orig, entry.uncomp_data)
2080
Simon Glass72eeff12020-10-26 17:40:16 -06002081 self.assertEqual(image.data, entry.data)
2082
Simon Glass7ba33592018-09-14 04:57:26 -06002083 expected = {
2084 'blob:uncomp-size': len(COMPRESS_DATA),
2085 'blob:size': len(data),
2086 'size': len(data),
2087 }
2088 self.assertEqual(expected, props)
2089
Simon Glassac6328c2018-09-14 04:57:28 -06002090 def testFiles(self):
2091 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002092 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002093 self.assertEqual(FILES_DATA, data)
2094
2095 def testFilesCompress(self):
2096 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002097 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002098 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002099
2100 image = control.images['image']
2101 entries = image.GetEntries()
2102 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002103 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002104
Simon Glass303f62f2019-05-17 22:00:46 -06002105 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002106 for i in range(1, 3):
2107 key = '%d.dat' % i
2108 start = entries[key].image_pos
2109 len = entries[key].size
2110 chunk = data[start:start + len]
2111 orig += self._decompress(chunk)
2112
2113 self.assertEqual(FILES_DATA, orig)
2114
2115 def testFilesMissing(self):
2116 """Test missing files"""
2117 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002118 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002119 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2120 'no files', str(e.exception))
2121
2122 def testFilesNoPattern(self):
2123 """Test missing files"""
2124 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002125 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002126 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2127 str(e.exception))
2128
Simon Glassdd156a42022-03-05 20:18:59 -07002129 def testExtendSize(self):
2130 """Test an extending entry"""
2131 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002132 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002133 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2134 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2135 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2136 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002137 self.assertEqual(expect, data)
2138 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700213900000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600214000000000 00000000 00000008 fill
214100000008 00000008 00000004 u-boot
21420000000c 0000000c 00000004 section
21430000000c 00000000 00000003 intel-mrc
214400000010 00000010 00000004 u-boot2
214500000014 00000014 0000000c section2
214600000014 00000000 00000008 fill
21470000001c 00000008 00000004 u-boot
214800000020 00000020 00000008 fill2
2149''', map_data)
2150
Simon Glassdd156a42022-03-05 20:18:59 -07002151 def testExtendSizeBad(self):
2152 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002153 with test_util.capture_sys_output() as (stdout, stderr):
2154 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002155 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002156 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2157 'expanding entry', str(e.exception))
2158
Simon Glassae7cf032018-09-14 04:57:31 -06002159 def testHash(self):
2160 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002161 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002162 use_real_dtb=True, update_dtb=True)
2163 dtb = fdt.Fdt(out_dtb_fname)
2164 dtb.Scan()
2165 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2166 m = hashlib.sha256()
2167 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002168 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002169
2170 def testHashNoAlgo(self):
2171 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002172 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002173 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2174 'hash node', str(e.exception))
2175
2176 def testHashBadAlgo(self):
2177 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002178 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002179 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002180 str(e.exception))
2181
2182 def testHashSection(self):
2183 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002184 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002185 use_real_dtb=True, update_dtb=True)
2186 dtb = fdt.Fdt(out_dtb_fname)
2187 dtb.Scan()
2188 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2189 m = hashlib.sha256()
2190 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002191 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002192 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002193
Simon Glass3fb4f422018-09-14 04:57:32 -06002194 def testPackUBootTplMicrocode(self):
2195 """Test that x86 microcode can be handled correctly in TPL
2196
2197 We expect to see the following in the image, in order:
2198 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2199 place
2200 u-boot-tpl.dtb with the microcode removed
2201 the microcode
2202 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002203 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002204 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002205 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002206 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2207 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002208
Simon Glassc64aea52018-09-14 04:57:34 -06002209 def testFmapX86(self):
2210 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002211 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002212 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002213 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002214 self.assertEqual(expected, data[:32])
2215 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2216
2217 self.assertEqual(0x100, fhdr.image_size)
2218
2219 self.assertEqual(0, fentries[0].offset)
2220 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002221 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002222
2223 self.assertEqual(4, fentries[1].offset)
2224 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002225 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002226
2227 self.assertEqual(32, fentries[2].offset)
2228 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2229 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002230 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002231
2232 def testFmapX86Section(self):
2233 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002234 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002235 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002236 self.assertEqual(expected, data[:32])
2237 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2238
Simon Glassb1d414c2021-04-03 11:05:10 +13002239 self.assertEqual(0x180, fhdr.image_size)
2240 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002241 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002242
Simon Glass82059c22021-04-03 11:05:09 +13002243 fentry = next(fiter)
2244 self.assertEqual(b'U_BOOT', fentry.name)
2245 self.assertEqual(0, fentry.offset)
2246 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002247
Simon Glass82059c22021-04-03 11:05:09 +13002248 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002249 self.assertEqual(b'SECTION', fentry.name)
2250 self.assertEqual(4, fentry.offset)
2251 self.assertEqual(0x20 + expect_size, fentry.size)
2252
2253 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002254 self.assertEqual(b'INTEL_MRC', fentry.name)
2255 self.assertEqual(4, fentry.offset)
2256 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002257
Simon Glass82059c22021-04-03 11:05:09 +13002258 fentry = next(fiter)
2259 self.assertEqual(b'FMAP', fentry.name)
2260 self.assertEqual(36, fentry.offset)
2261 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002262
Simon Glassb1714232018-09-14 04:57:35 -06002263 def testElf(self):
2264 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002265 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002266 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002267 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002268 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002269 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002270
Simon Glass0d673792019-07-08 13:18:25 -06002271 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002272 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002273 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002274 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002275 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002276 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002277
Simon Glasscd817d52018-09-14 04:57:36 -06002278 def testPackOverlapMap(self):
2279 """Test that overlapping regions are detected"""
2280 with test_util.capture_sys_output() as (stdout, stderr):
2281 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002282 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002283 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002284 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2285 stdout.getvalue())
2286
2287 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002288 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002289 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002290 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002291 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002292<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002293<none> 00000000 00000004 u-boot
2294<none> 00000003 00000004 u-boot-align
2295''', map_data)
2296
Simon Glass0d673792019-07-08 13:18:25 -06002297 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002298 """Test that an image with an Intel Reference code binary works"""
2299 data = self._DoReadFile('100_intel_refcode.dts')
2300 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2301
Simon Glasseb023b32019-04-25 21:58:39 -06002302 def testSectionOffset(self):
2303 """Tests use of a section with an offset"""
2304 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2305 map=True)
2306 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700230700000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600230800000004 00000004 00000010 section@0
230900000004 00000000 00000004 u-boot
231000000018 00000018 00000010 section@1
231100000018 00000000 00000004 u-boot
23120000002c 0000002c 00000004 section@2
23130000002c 00000000 00000004 u-boot
2314''', map_data)
2315 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002316 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2317 tools.get_bytes(0x21, 12) +
2318 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2319 tools.get_bytes(0x61, 12) +
2320 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2321 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002322
Simon Glass1de34482019-07-08 13:18:53 -06002323 def testCbfsRaw(self):
2324 """Test base handling of a Coreboot Filesystem (CBFS)
2325
2326 The exact contents of the CBFS is verified by similar tests in
2327 cbfs_util_test.py. The tests here merely check that the files added to
2328 the CBFS can be found in the final image.
2329 """
2330 data = self._DoReadFile('102_cbfs_raw.dts')
2331 size = 0xb0
2332
2333 cbfs = cbfs_util.CbfsReader(data)
2334 self.assertEqual(size, cbfs.rom_size)
2335
2336 self.assertIn('u-boot-dtb', cbfs.files)
2337 cfile = cbfs.files['u-boot-dtb']
2338 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2339
2340 def testCbfsArch(self):
2341 """Test on non-x86 architecture"""
2342 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2343 size = 0x100
2344
2345 cbfs = cbfs_util.CbfsReader(data)
2346 self.assertEqual(size, cbfs.rom_size)
2347
2348 self.assertIn('u-boot-dtb', cbfs.files)
2349 cfile = cbfs.files['u-boot-dtb']
2350 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2351
2352 def testCbfsStage(self):
2353 """Tests handling of a Coreboot Filesystem (CBFS)"""
2354 if not elf.ELF_TOOLS:
2355 self.skipTest('Python elftools not available')
2356 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2357 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2358 size = 0xb0
2359
2360 data = self._DoReadFile('104_cbfs_stage.dts')
2361 cbfs = cbfs_util.CbfsReader(data)
2362 self.assertEqual(size, cbfs.rom_size)
2363
2364 self.assertIn('u-boot', cbfs.files)
2365 cfile = cbfs.files['u-boot']
2366 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2367
2368 def testCbfsRawCompress(self):
2369 """Test handling of compressing raw files"""
2370 self._CheckLz4()
2371 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2372 size = 0x140
2373
2374 cbfs = cbfs_util.CbfsReader(data)
2375 self.assertIn('u-boot', cbfs.files)
2376 cfile = cbfs.files['u-boot']
2377 self.assertEqual(COMPRESS_DATA, cfile.data)
2378
2379 def testCbfsBadArch(self):
2380 """Test handling of a bad architecture"""
2381 with self.assertRaises(ValueError) as e:
2382 self._DoReadFile('106_cbfs_bad_arch.dts')
2383 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2384
2385 def testCbfsNoSize(self):
2386 """Test handling of a missing size property"""
2387 with self.assertRaises(ValueError) as e:
2388 self._DoReadFile('107_cbfs_no_size.dts')
2389 self.assertIn('entry must have a size property', str(e.exception))
2390
Simon Glass3e28f4f2021-11-23 11:03:54 -07002391 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002392 """Test handling of a CBFS entry which does not provide contentsy"""
2393 with self.assertRaises(ValueError) as e:
2394 self._DoReadFile('108_cbfs_no_contents.dts')
2395 self.assertIn('Could not complete processing of contents',
2396 str(e.exception))
2397
2398 def testCbfsBadCompress(self):
2399 """Test handling of a bad architecture"""
2400 with self.assertRaises(ValueError) as e:
2401 self._DoReadFile('109_cbfs_bad_compress.dts')
2402 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2403 str(e.exception))
2404
2405 def testCbfsNamedEntries(self):
2406 """Test handling of named entries"""
2407 data = self._DoReadFile('110_cbfs_name.dts')
2408
2409 cbfs = cbfs_util.CbfsReader(data)
2410 self.assertIn('FRED', cbfs.files)
2411 cfile1 = cbfs.files['FRED']
2412 self.assertEqual(U_BOOT_DATA, cfile1.data)
2413
2414 self.assertIn('hello', cbfs.files)
2415 cfile2 = cbfs.files['hello']
2416 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2417
Simon Glass759af872019-07-08 13:18:54 -06002418 def _SetupIfwi(self, fname):
2419 """Set up to run an IFWI test
2420
2421 Args:
2422 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2423 """
2424 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002425 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002426
2427 # Intel Integrated Firmware Image (IFWI) file
2428 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2429 data = fd.read()
2430 TestFunctional._MakeInputFile(fname,data)
2431
2432 def _CheckIfwi(self, data):
2433 """Check that an image with an IFWI contains the correct output
2434
2435 Args:
2436 data: Conents of output file
2437 """
Simon Glass80025522022-01-29 14:14:04 -07002438 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002439 if data[:0x1000] != expected_desc:
2440 self.fail('Expected descriptor binary at start of image')
2441
2442 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002443 image_fname = tools.get_output_filename('image.bin')
2444 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002445 ifwitool = bintool.Bintool.create('ifwitool')
2446 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002447
Simon Glass80025522022-01-29 14:14:04 -07002448 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002449 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002450
2451 def testPackX86RomIfwi(self):
2452 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2453 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002454 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002455 self._CheckIfwi(data)
2456
2457 def testPackX86RomIfwiNoDesc(self):
2458 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2459 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002460 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002461 self._CheckIfwi(data)
2462
2463 def testPackX86RomIfwiNoData(self):
2464 """Test that an x86 ROM with IFWI handles missing data"""
2465 self._SetupIfwi('ifwi.bin')
2466 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002467 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002468 self.assertIn('Could not complete processing of contents',
2469 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002470
Simon Glass66152ce2022-01-09 20:14:09 -07002471 def testIfwiMissing(self):
2472 """Test that binman still produces an image if ifwitool is missing"""
2473 self._SetupIfwi('fitimage.bin')
2474 with test_util.capture_sys_output() as (_, stderr):
2475 self._DoTestFile('111_x86_rom_ifwi.dts',
2476 force_missing_bintools='ifwitool')
2477 err = stderr.getvalue()
2478 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002479 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002480
Simon Glassc2f1aed2019-07-08 13:18:56 -06002481 def testCbfsOffset(self):
2482 """Test a CBFS with files at particular offsets
2483
2484 Like all CFBS tests, this is just checking the logic that calls
2485 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2486 """
2487 data = self._DoReadFile('114_cbfs_offset.dts')
2488 size = 0x200
2489
2490 cbfs = cbfs_util.CbfsReader(data)
2491 self.assertEqual(size, cbfs.rom_size)
2492
2493 self.assertIn('u-boot', cbfs.files)
2494 cfile = cbfs.files['u-boot']
2495 self.assertEqual(U_BOOT_DATA, cfile.data)
2496 self.assertEqual(0x40, cfile.cbfs_offset)
2497
2498 self.assertIn('u-boot-dtb', cbfs.files)
2499 cfile2 = cbfs.files['u-boot-dtb']
2500 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2501 self.assertEqual(0x140, cfile2.cbfs_offset)
2502
Simon Glass0f621332019-07-08 14:25:27 -06002503 def testFdtmap(self):
2504 """Test an FDT map can be inserted in the image"""
2505 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2506 fdtmap_data = data[len(U_BOOT_DATA):]
2507 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002508 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002509 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002510
2511 fdt_data = fdtmap_data[16:]
2512 dtb = fdt.Fdt.FromData(fdt_data)
2513 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002514 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002515 self.assertEqual({
2516 'image-pos': 0,
2517 'offset': 0,
2518 'u-boot:offset': 0,
2519 'u-boot:size': len(U_BOOT_DATA),
2520 'u-boot:image-pos': 0,
2521 'fdtmap:image-pos': 4,
2522 'fdtmap:offset': 4,
2523 'fdtmap:size': len(fdtmap_data),
2524 'size': len(data),
2525 }, props)
2526
2527 def testFdtmapNoMatch(self):
2528 """Check handling of an FDT map when the section cannot be found"""
2529 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2530
2531 # Mangle the section name, which should cause a mismatch between the
2532 # correct FDT path and the one expected by the section
2533 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002534 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002535 entries = image.GetEntries()
2536 fdtmap = entries['fdtmap']
2537 with self.assertRaises(ValueError) as e:
2538 fdtmap._GetFdtmap()
2539 self.assertIn("Cannot locate node for path '/binman-suffix'",
2540 str(e.exception))
2541
Simon Glasscec34ba2019-07-08 14:25:28 -06002542 def testFdtmapHeader(self):
2543 """Test an FDT map and image header can be inserted in the image"""
2544 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2545 fdtmap_pos = len(U_BOOT_DATA)
2546 fdtmap_data = data[fdtmap_pos:]
2547 fdt_data = fdtmap_data[16:]
2548 dtb = fdt.Fdt.FromData(fdt_data)
2549 fdt_size = dtb.GetFdtObj().totalsize()
2550 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002551 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002552 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2553 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2554
2555 def testFdtmapHeaderStart(self):
2556 """Test an image header can be inserted at the image start"""
2557 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2558 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2559 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002560 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002561 offset = struct.unpack('<I', hdr_data[4:])[0]
2562 self.assertEqual(fdtmap_pos, offset)
2563
2564 def testFdtmapHeaderPos(self):
2565 """Test an image header can be inserted at a chosen position"""
2566 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2567 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2568 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002569 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002570 offset = struct.unpack('<I', hdr_data[4:])[0]
2571 self.assertEqual(fdtmap_pos, offset)
2572
2573 def testHeaderMissingFdtmap(self):
2574 """Test an image header requires an fdtmap"""
2575 with self.assertRaises(ValueError) as e:
2576 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2577 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2578 str(e.exception))
2579
2580 def testHeaderNoLocation(self):
2581 """Test an image header with a no specified location is detected"""
2582 with self.assertRaises(ValueError) as e:
2583 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2584 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2585 str(e.exception))
2586
Simon Glasse61b6f62019-07-08 14:25:37 -06002587 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002588 """Test extending an entry after it is packed"""
2589 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002590 self.assertEqual(b'aaa', data[:3])
2591 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2592 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002593
Simon Glassdd156a42022-03-05 20:18:59 -07002594 def testEntryExtendBad(self):
2595 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002596 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002597 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002598 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002599 str(e.exception))
2600
Simon Glassdd156a42022-03-05 20:18:59 -07002601 def testEntryExtendSection(self):
2602 """Test extending an entry within a section after it is packed"""
2603 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002604 self.assertEqual(b'aaa', data[:3])
2605 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2606 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002607
Simon Glass90d29682019-07-08 14:25:38 -06002608 def testCompressDtb(self):
2609 """Test that compress of device-tree files is supported"""
2610 self._CheckLz4()
2611 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2612 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2613 comp_data = data[len(U_BOOT_DATA):]
2614 orig = self._decompress(comp_data)
2615 dtb = fdt.Fdt.FromData(orig)
2616 dtb.Scan()
2617 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2618 expected = {
2619 'u-boot:size': len(U_BOOT_DATA),
2620 'u-boot-dtb:uncomp-size': len(orig),
2621 'u-boot-dtb:size': len(comp_data),
2622 'size': len(data),
2623 }
2624 self.assertEqual(expected, props)
2625
Simon Glass151bbbf2019-07-08 14:25:41 -06002626 def testCbfsUpdateFdt(self):
2627 """Test that we can update the device tree with CBFS offset/size info"""
2628 self._CheckLz4()
2629 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2630 update_dtb=True)
2631 dtb = fdt.Fdt(out_dtb_fname)
2632 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002633 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002634 del props['cbfs/u-boot:size']
2635 self.assertEqual({
2636 'offset': 0,
2637 'size': len(data),
2638 'image-pos': 0,
2639 'cbfs:offset': 0,
2640 'cbfs:size': len(data),
2641 'cbfs:image-pos': 0,
2642 'cbfs/u-boot:offset': 0x38,
2643 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2644 'cbfs/u-boot:image-pos': 0x38,
2645 'cbfs/u-boot-dtb:offset': 0xb8,
2646 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2647 'cbfs/u-boot-dtb:image-pos': 0xb8,
2648 }, props)
2649
Simon Glass3c9b4f22019-07-08 14:25:42 -06002650 def testCbfsBadType(self):
2651 """Test an image header with a no specified location is detected"""
2652 with self.assertRaises(ValueError) as e:
2653 self._DoReadFile('126_cbfs_bad_type.dts')
2654 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2655
Simon Glass6b156f82019-07-08 14:25:43 -06002656 def testList(self):
2657 """Test listing the files in an image"""
2658 self._CheckLz4()
2659 data = self._DoReadFile('127_list.dts')
2660 image = control.images['image']
2661 entries = image.BuildEntryList()
2662 self.assertEqual(7, len(entries))
2663
2664 ent = entries[0]
2665 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002666 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002667 self.assertEqual('section', ent.etype)
2668 self.assertEqual(len(data), ent.size)
2669 self.assertEqual(0, ent.image_pos)
2670 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002671 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002672
2673 ent = entries[1]
2674 self.assertEqual(1, ent.indent)
2675 self.assertEqual('u-boot', ent.name)
2676 self.assertEqual('u-boot', ent.etype)
2677 self.assertEqual(len(U_BOOT_DATA), ent.size)
2678 self.assertEqual(0, ent.image_pos)
2679 self.assertEqual(None, ent.uncomp_size)
2680 self.assertEqual(0, ent.offset)
2681
2682 ent = entries[2]
2683 self.assertEqual(1, ent.indent)
2684 self.assertEqual('section', ent.name)
2685 self.assertEqual('section', ent.etype)
2686 section_size = ent.size
2687 self.assertEqual(0x100, ent.image_pos)
2688 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002689 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002690
2691 ent = entries[3]
2692 self.assertEqual(2, ent.indent)
2693 self.assertEqual('cbfs', ent.name)
2694 self.assertEqual('cbfs', ent.etype)
2695 self.assertEqual(0x400, ent.size)
2696 self.assertEqual(0x100, ent.image_pos)
2697 self.assertEqual(None, ent.uncomp_size)
2698 self.assertEqual(0, ent.offset)
2699
2700 ent = entries[4]
2701 self.assertEqual(3, ent.indent)
2702 self.assertEqual('u-boot', ent.name)
2703 self.assertEqual('u-boot', ent.etype)
2704 self.assertEqual(len(U_BOOT_DATA), ent.size)
2705 self.assertEqual(0x138, ent.image_pos)
2706 self.assertEqual(None, ent.uncomp_size)
2707 self.assertEqual(0x38, ent.offset)
2708
2709 ent = entries[5]
2710 self.assertEqual(3, ent.indent)
2711 self.assertEqual('u-boot-dtb', ent.name)
2712 self.assertEqual('text', ent.etype)
2713 self.assertGreater(len(COMPRESS_DATA), ent.size)
2714 self.assertEqual(0x178, ent.image_pos)
2715 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2716 self.assertEqual(0x78, ent.offset)
2717
2718 ent = entries[6]
2719 self.assertEqual(2, ent.indent)
2720 self.assertEqual('u-boot-dtb', ent.name)
2721 self.assertEqual('u-boot-dtb', ent.etype)
2722 self.assertEqual(0x500, ent.image_pos)
2723 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2724 dtb_size = ent.size
2725 # Compressing this data expands it since headers are added
2726 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2727 self.assertEqual(0x400, ent.offset)
2728
2729 self.assertEqual(len(data), 0x100 + section_size)
2730 self.assertEqual(section_size, 0x400 + dtb_size)
2731
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002732 def testFindFdtmap(self):
2733 """Test locating an FDT map in an image"""
2734 self._CheckLz4()
2735 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2736 image = control.images['image']
2737 entries = image.GetEntries()
2738 entry = entries['fdtmap']
2739 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2740
2741 def testFindFdtmapMissing(self):
2742 """Test failing to locate an FDP map"""
2743 data = self._DoReadFile('005_simple.dts')
2744 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2745
Simon Glassed39a3c2019-07-08 14:25:45 -06002746 def testFindImageHeader(self):
2747 """Test locating a image header"""
2748 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002749 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002750 image = control.images['image']
2751 entries = image.GetEntries()
2752 entry = entries['fdtmap']
2753 # The header should point to the FDT map
2754 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2755
2756 def testFindImageHeaderStart(self):
2757 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002758 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002759 image = control.images['image']
2760 entries = image.GetEntries()
2761 entry = entries['fdtmap']
2762 # The header should point to the FDT map
2763 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2764
2765 def testFindImageHeaderMissing(self):
2766 """Test failing to locate an image header"""
2767 data = self._DoReadFile('005_simple.dts')
2768 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2769
Simon Glassb8424fa2019-07-08 14:25:46 -06002770 def testReadImage(self):
2771 """Test reading an image and accessing its FDT map"""
2772 self._CheckLz4()
2773 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002774 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002775 orig_image = control.images['image']
2776 image = Image.FromFile(image_fname)
2777 self.assertEqual(orig_image.GetEntries().keys(),
2778 image.GetEntries().keys())
2779
2780 orig_entry = orig_image.GetEntries()['fdtmap']
2781 entry = image.GetEntries()['fdtmap']
2782 self.assertEquals(orig_entry.offset, entry.offset)
2783 self.assertEquals(orig_entry.size, entry.size)
2784 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2785
2786 def testReadImageNoHeader(self):
2787 """Test accessing an image's FDT map without an image header"""
2788 self._CheckLz4()
2789 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002790 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002791 image = Image.FromFile(image_fname)
2792 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002793 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002794
2795 def testReadImageFail(self):
2796 """Test failing to read an image image's FDT map"""
2797 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002798 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002799 with self.assertRaises(ValueError) as e:
2800 image = Image.FromFile(image_fname)
2801 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002802
Simon Glassb2fd11d2019-07-08 14:25:48 -06002803 def testListCmd(self):
2804 """Test listing the files in an image using an Fdtmap"""
2805 self._CheckLz4()
2806 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2807
2808 # lz4 compression size differs depending on the version
2809 image = control.images['image']
2810 entries = image.GetEntries()
2811 section_size = entries['section'].size
2812 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2813 fdtmap_offset = entries['fdtmap'].offset
2814
Simon Glassb3d6fc72019-07-20 12:24:10 -06002815 try:
2816 tmpdir, updated_fname = self._SetupImageInTmpdir()
2817 with test_util.capture_sys_output() as (stdout, stderr):
2818 self._DoBinman('ls', '-i', updated_fname)
2819 finally:
2820 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002821 lines = stdout.getvalue().splitlines()
2822 expected = [
2823'Name Image-pos Size Entry-type Offset Uncomp-size',
2824'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002825'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002826' u-boot 0 4 u-boot 0',
2827' section 100 %x section 100' % section_size,
2828' cbfs 100 400 cbfs 0',
2829' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002830' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002831' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002832' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002833 (fdtmap_offset, fdtmap_offset),
2834' image-header bf8 8 image-header bf8',
2835 ]
2836 self.assertEqual(expected, lines)
2837
2838 def testListCmdFail(self):
2839 """Test failing to list an image"""
2840 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002841 try:
2842 tmpdir, updated_fname = self._SetupImageInTmpdir()
2843 with self.assertRaises(ValueError) as e:
2844 self._DoBinman('ls', '-i', updated_fname)
2845 finally:
2846 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002847 self.assertIn("Cannot find FDT map in image", str(e.exception))
2848
2849 def _RunListCmd(self, paths, expected):
2850 """List out entries and check the result
2851
2852 Args:
2853 paths: List of paths to pass to the list command
2854 expected: Expected list of filenames to be returned, in order
2855 """
2856 self._CheckLz4()
2857 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002858 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002859 image = Image.FromFile(image_fname)
2860 lines = image.GetListEntries(paths)[1]
2861 files = [line[0].strip() for line in lines[1:]]
2862 self.assertEqual(expected, files)
2863
2864 def testListCmdSection(self):
2865 """Test listing the files in a section"""
2866 self._RunListCmd(['section'],
2867 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2868
2869 def testListCmdFile(self):
2870 """Test listing a particular file"""
2871 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2872
2873 def testListCmdWildcard(self):
2874 """Test listing a wildcarded file"""
2875 self._RunListCmd(['*boot*'],
2876 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2877
2878 def testListCmdWildcardMulti(self):
2879 """Test listing a wildcarded file"""
2880 self._RunListCmd(['*cb*', '*head*'],
2881 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2882
2883 def testListCmdEmpty(self):
2884 """Test listing a wildcarded file"""
2885 self._RunListCmd(['nothing'], [])
2886
2887 def testListCmdPath(self):
2888 """Test listing the files in a sub-entry of a section"""
2889 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2890
Simon Glass4c613bf2019-07-08 14:25:50 -06002891 def _RunExtractCmd(self, entry_name, decomp=True):
2892 """Extract an entry from an image
2893
2894 Args:
2895 entry_name: Entry name to extract
2896 decomp: True to decompress the data if compressed, False to leave
2897 it in its raw uncompressed format
2898
2899 Returns:
2900 data from entry
2901 """
2902 self._CheckLz4()
2903 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002904 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002905 return control.ReadEntry(image_fname, entry_name, decomp)
2906
2907 def testExtractSimple(self):
2908 """Test extracting a single file"""
2909 data = self._RunExtractCmd('u-boot')
2910 self.assertEqual(U_BOOT_DATA, data)
2911
Simon Glass980a2842019-07-08 14:25:52 -06002912 def testExtractSection(self):
2913 """Test extracting the files in a section"""
2914 data = self._RunExtractCmd('section')
2915 cbfs_data = data[:0x400]
2916 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002917 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002918 dtb_data = data[0x400:]
2919 dtb = self._decompress(dtb_data)
2920 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2921
2922 def testExtractCompressed(self):
2923 """Test extracting compressed data"""
2924 data = self._RunExtractCmd('section/u-boot-dtb')
2925 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2926
2927 def testExtractRaw(self):
2928 """Test extracting compressed data without decompressing it"""
2929 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2930 dtb = self._decompress(data)
2931 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2932
2933 def testExtractCbfs(self):
2934 """Test extracting CBFS data"""
2935 data = self._RunExtractCmd('section/cbfs/u-boot')
2936 self.assertEqual(U_BOOT_DATA, data)
2937
2938 def testExtractCbfsCompressed(self):
2939 """Test extracting CBFS compressed data"""
2940 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2941 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2942
2943 def testExtractCbfsRaw(self):
2944 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002945 bintool = self.comp_bintools['lzma_alone']
2946 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06002947 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002948 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06002949 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2950
Simon Glass4c613bf2019-07-08 14:25:50 -06002951 def testExtractBadEntry(self):
2952 """Test extracting a bad section path"""
2953 with self.assertRaises(ValueError) as e:
2954 self._RunExtractCmd('section/does-not-exist')
2955 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2956 str(e.exception))
2957
2958 def testExtractMissingFile(self):
2959 """Test extracting file that does not exist"""
2960 with self.assertRaises(IOError) as e:
2961 control.ReadEntry('missing-file', 'name')
2962
2963 def testExtractBadFile(self):
2964 """Test extracting an invalid file"""
2965 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002966 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002967 with self.assertRaises(ValueError) as e:
2968 control.ReadEntry(fname, 'name')
2969
Simon Glass980a2842019-07-08 14:25:52 -06002970 def testExtractCmd(self):
2971 """Test extracting a file fron an image on the command line"""
2972 self._CheckLz4()
2973 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002974 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002975 try:
2976 tmpdir, updated_fname = self._SetupImageInTmpdir()
2977 with test_util.capture_sys_output() as (stdout, stderr):
2978 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2979 '-f', fname)
2980 finally:
2981 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07002982 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002983 self.assertEqual(U_BOOT_DATA, data)
2984
2985 def testExtractOneEntry(self):
2986 """Test extracting a single entry fron an image """
2987 self._CheckLz4()
2988 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002989 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002990 fname = os.path.join(self._indir, 'output.extact')
2991 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07002992 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002993 self.assertEqual(U_BOOT_DATA, data)
2994
2995 def _CheckExtractOutput(self, decomp):
2996 """Helper to test file output with and without decompression
2997
2998 Args:
2999 decomp: True to decompress entry data, False to output it raw
3000 """
3001 def _CheckPresent(entry_path, expect_data, expect_size=None):
3002 """Check and remove expected file
3003
3004 This checks the data/size of a file and removes the file both from
3005 the outfiles set and from the output directory. Once all files are
3006 processed, both the set and directory should be empty.
3007
3008 Args:
3009 entry_path: Entry path
3010 expect_data: Data to expect in file, or None to skip check
3011 expect_size: Size of data to expect in file, or None to skip
3012 """
3013 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003014 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003015 os.remove(path)
3016 if expect_data:
3017 self.assertEqual(expect_data, data)
3018 elif expect_size:
3019 self.assertEqual(expect_size, len(data))
3020 outfiles.remove(path)
3021
3022 def _CheckDirPresent(name):
3023 """Remove expected directory
3024
3025 This gives an error if the directory does not exist as expected
3026
3027 Args:
3028 name: Name of directory to remove
3029 """
3030 path = os.path.join(outdir, name)
3031 os.rmdir(path)
3032
3033 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003034 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003035 outdir = os.path.join(self._indir, 'extract')
3036 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3037
3038 # Create a set of all file that were output (should be 9)
3039 outfiles = set()
3040 for root, dirs, files in os.walk(outdir):
3041 outfiles |= set([os.path.join(root, fname) for fname in files])
3042 self.assertEqual(9, len(outfiles))
3043 self.assertEqual(9, len(einfos))
3044
3045 image = control.images['image']
3046 entries = image.GetEntries()
3047
3048 # Check the 9 files in various ways
3049 section = entries['section']
3050 section_entries = section.GetEntries()
3051 cbfs_entries = section_entries['cbfs'].GetEntries()
3052 _CheckPresent('u-boot', U_BOOT_DATA)
3053 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3054 dtb_len = EXTRACT_DTB_SIZE
3055 if not decomp:
3056 dtb_len = cbfs_entries['u-boot-dtb'].size
3057 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3058 if not decomp:
3059 dtb_len = section_entries['u-boot-dtb'].size
3060 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3061
3062 fdtmap = entries['fdtmap']
3063 _CheckPresent('fdtmap', fdtmap.data)
3064 hdr = entries['image-header']
3065 _CheckPresent('image-header', hdr.data)
3066
3067 _CheckPresent('section/root', section.data)
3068 cbfs = section_entries['cbfs']
3069 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003070 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003071 _CheckPresent('root', data)
3072
3073 # There should be no files left. Remove all the directories to check.
3074 # If there are any files/dirs remaining, one of these checks will fail.
3075 self.assertEqual(0, len(outfiles))
3076 _CheckDirPresent('section/cbfs')
3077 _CheckDirPresent('section')
3078 _CheckDirPresent('')
3079 self.assertFalse(os.path.exists(outdir))
3080
3081 def testExtractAllEntries(self):
3082 """Test extracting all entries"""
3083 self._CheckLz4()
3084 self._CheckExtractOutput(decomp=True)
3085
3086 def testExtractAllEntriesRaw(self):
3087 """Test extracting all entries without decompressing them"""
3088 self._CheckLz4()
3089 self._CheckExtractOutput(decomp=False)
3090
3091 def testExtractSelectedEntries(self):
3092 """Test extracting some entries"""
3093 self._CheckLz4()
3094 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003095 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003096 outdir = os.path.join(self._indir, 'extract')
3097 einfos = control.ExtractEntries(image_fname, None, outdir,
3098 ['*cb*', '*head*'])
3099
3100 # File output is tested by testExtractAllEntries(), so just check that
3101 # the expected entries are selected
3102 names = [einfo.name for einfo in einfos]
3103 self.assertEqual(names,
3104 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3105
3106 def testExtractNoEntryPaths(self):
3107 """Test extracting some entries"""
3108 self._CheckLz4()
3109 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003110 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003111 with self.assertRaises(ValueError) as e:
3112 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003113 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003114 str(e.exception))
3115
3116 def testExtractTooManyEntryPaths(self):
3117 """Test extracting some entries"""
3118 self._CheckLz4()
3119 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003120 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003121 with self.assertRaises(ValueError) as e:
3122 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003123 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003124 str(e.exception))
3125
Simon Glass52d06212019-07-08 14:25:53 -06003126 def testPackAlignSection(self):
3127 """Test that sections can have alignment"""
3128 self._DoReadFile('131_pack_align_section.dts')
3129
3130 self.assertIn('image', control.images)
3131 image = control.images['image']
3132 entries = image.GetEntries()
3133 self.assertEqual(3, len(entries))
3134
3135 # First u-boot
3136 self.assertIn('u-boot', entries)
3137 entry = entries['u-boot']
3138 self.assertEqual(0, entry.offset)
3139 self.assertEqual(0, entry.image_pos)
3140 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3141 self.assertEqual(len(U_BOOT_DATA), entry.size)
3142
3143 # Section0
3144 self.assertIn('section0', entries)
3145 section0 = entries['section0']
3146 self.assertEqual(0x10, section0.offset)
3147 self.assertEqual(0x10, section0.image_pos)
3148 self.assertEqual(len(U_BOOT_DATA), section0.size)
3149
3150 # Second u-boot
3151 section_entries = section0.GetEntries()
3152 self.assertIn('u-boot', section_entries)
3153 entry = section_entries['u-boot']
3154 self.assertEqual(0, entry.offset)
3155 self.assertEqual(0x10, entry.image_pos)
3156 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3157 self.assertEqual(len(U_BOOT_DATA), entry.size)
3158
3159 # Section1
3160 self.assertIn('section1', entries)
3161 section1 = entries['section1']
3162 self.assertEqual(0x14, section1.offset)
3163 self.assertEqual(0x14, section1.image_pos)
3164 self.assertEqual(0x20, section1.size)
3165
3166 # Second u-boot
3167 section_entries = section1.GetEntries()
3168 self.assertIn('u-boot', section_entries)
3169 entry = section_entries['u-boot']
3170 self.assertEqual(0, entry.offset)
3171 self.assertEqual(0x14, entry.image_pos)
3172 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3173 self.assertEqual(len(U_BOOT_DATA), entry.size)
3174
3175 # Section2
3176 self.assertIn('section2', section_entries)
3177 section2 = section_entries['section2']
3178 self.assertEqual(0x4, section2.offset)
3179 self.assertEqual(0x18, section2.image_pos)
3180 self.assertEqual(4, section2.size)
3181
3182 # Third u-boot
3183 section_entries = section2.GetEntries()
3184 self.assertIn('u-boot', section_entries)
3185 entry = section_entries['u-boot']
3186 self.assertEqual(0, entry.offset)
3187 self.assertEqual(0x18, entry.image_pos)
3188 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3189 self.assertEqual(len(U_BOOT_DATA), entry.size)
3190
Simon Glassf8a54bc2019-07-20 12:23:56 -06003191 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3192 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003193 """Replace an entry in an image
3194
3195 This writes the entry data to update it, then opens the updated file and
3196 returns the value that it now finds there.
3197
3198 Args:
3199 entry_name: Entry name to replace
3200 data: Data to replace it with
3201 decomp: True to compress the data if needed, False if data is
3202 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003203 allow_resize: True to allow entries to change size, False to raise
3204 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003205
3206 Returns:
3207 Tuple:
3208 data from entry
3209 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003210 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003211 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003212 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003213 update_dtb=True)[1]
3214
3215 self.assertIn('image', control.images)
3216 image = control.images['image']
3217 entries = image.GetEntries()
3218 orig_dtb_data = entries['u-boot-dtb'].data
3219 orig_fdtmap_data = entries['fdtmap'].data
3220
Simon Glass80025522022-01-29 14:14:04 -07003221 image_fname = tools.get_output_filename('image.bin')
3222 updated_fname = tools.get_output_filename('image-updated.bin')
3223 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003224 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3225 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003226 data = control.ReadEntry(updated_fname, entry_name, decomp)
3227
Simon Glassf8a54bc2019-07-20 12:23:56 -06003228 # The DT data should not change unless resized:
3229 if not allow_resize:
3230 new_dtb_data = entries['u-boot-dtb'].data
3231 self.assertEqual(new_dtb_data, orig_dtb_data)
3232 new_fdtmap_data = entries['fdtmap'].data
3233 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003234
Simon Glassf8a54bc2019-07-20 12:23:56 -06003235 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003236
3237 def testReplaceSimple(self):
3238 """Test replacing a single file"""
3239 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003240 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3241 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003242 self.assertEqual(expected, data)
3243
3244 # Test that the state looks right. There should be an FDT for the fdtmap
3245 # that we jsut read back in, and it should match what we find in the
3246 # 'control' tables. Checking for an FDT that does not exist should
3247 # return None.
3248 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003249 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003250 self.assertEqual(expected_fdtmap, fdtmap)
3251
3252 dtb = state.GetFdtForEtype('fdtmap')
3253 self.assertEqual(dtb.GetContents(), fdtmap)
3254
3255 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3256 self.assertIsNone(missing_path)
3257 self.assertIsNone(missing_fdtmap)
3258
3259 missing_dtb = state.GetFdtForEtype('missing')
3260 self.assertIsNone(missing_dtb)
3261
3262 self.assertEqual('/binman', state.fdt_path_prefix)
3263
3264 def testReplaceResizeFail(self):
3265 """Test replacing a file by something larger"""
3266 expected = U_BOOT_DATA + b'x'
3267 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003268 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3269 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003270 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3271 str(e.exception))
3272
3273 def testReplaceMulti(self):
3274 """Test replacing entry data where multiple images are generated"""
3275 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3276 update_dtb=True)[0]
3277 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003278 updated_fname = tools.get_output_filename('image-updated.bin')
3279 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003280 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003281 control.WriteEntry(updated_fname, entry_name, expected,
3282 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003283 data = control.ReadEntry(updated_fname, entry_name)
3284 self.assertEqual(expected, data)
3285
3286 # Check the state looks right.
3287 self.assertEqual('/binman/image', state.fdt_path_prefix)
3288
3289 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003290 image_fname = tools.get_output_filename('first-image.bin')
3291 updated_fname = tools.get_output_filename('first-updated.bin')
3292 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003293 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003294 control.WriteEntry(updated_fname, entry_name, expected,
3295 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003296 data = control.ReadEntry(updated_fname, entry_name)
3297 self.assertEqual(expected, data)
3298
3299 # Check the state looks right.
3300 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003301
Simon Glassfb30e292019-07-20 12:23:51 -06003302 def testUpdateFdtAllRepack(self):
3303 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003304 self._SetupSplElf()
3305 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003306 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3307 SECTION_SIZE = 0x300
3308 DTB_SIZE = 602
3309 FDTMAP_SIZE = 608
3310 base_expected = {
3311 'offset': 0,
3312 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3313 'image-pos': 0,
3314 'section:offset': 0,
3315 'section:size': SECTION_SIZE,
3316 'section:image-pos': 0,
3317 'section/u-boot-dtb:offset': 4,
3318 'section/u-boot-dtb:size': 636,
3319 'section/u-boot-dtb:image-pos': 4,
3320 'u-boot-spl-dtb:offset': SECTION_SIZE,
3321 'u-boot-spl-dtb:size': DTB_SIZE,
3322 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3323 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3324 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3325 'u-boot-tpl-dtb:size': DTB_SIZE,
3326 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3327 'fdtmap:size': FDTMAP_SIZE,
3328 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3329 }
3330 main_expected = {
3331 'section:orig-size': SECTION_SIZE,
3332 'section/u-boot-dtb:orig-offset': 4,
3333 }
3334
3335 # We expect three device-tree files in the output, with the first one
3336 # within a fixed-size section.
3337 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3338 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3339 # main U-Boot tree. All three should have the same positions and offset
3340 # except that the main tree should include the main_expected properties
3341 start = 4
3342 for item in ['', 'spl', 'tpl', None]:
3343 if item is None:
3344 start += 16 # Move past fdtmap header
3345 dtb = fdt.Fdt.FromData(data[start:])
3346 dtb.Scan()
3347 props = self._GetPropTree(dtb,
3348 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3349 prefix='/' if item is None else '/binman/')
3350 expected = dict(base_expected)
3351 if item:
3352 expected[item] = 0
3353 else:
3354 # Main DTB and fdtdec should include the 'orig-' properties
3355 expected.update(main_expected)
3356 # Helpful for debugging:
3357 #for prop in sorted(props):
3358 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3359 self.assertEqual(expected, props)
3360 if item == '':
3361 start = SECTION_SIZE
3362 else:
3363 start += dtb._fdt_obj.totalsize()
3364
Simon Glass11453762019-07-20 12:23:55 -06003365 def testFdtmapHeaderMiddle(self):
3366 """Test an FDT map in the middle of an image when it should be at end"""
3367 with self.assertRaises(ValueError) as e:
3368 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3369 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3370 str(e.exception))
3371
3372 def testFdtmapHeaderStartBad(self):
3373 """Test an FDT map in middle of an image when it should be at start"""
3374 with self.assertRaises(ValueError) as e:
3375 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3376 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3377 str(e.exception))
3378
3379 def testFdtmapHeaderEndBad(self):
3380 """Test an FDT map at the start of an image when it should be at end"""
3381 with self.assertRaises(ValueError) as e:
3382 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3383 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3384 str(e.exception))
3385
3386 def testFdtmapHeaderNoSize(self):
3387 """Test an image header at the end of an image with undefined size"""
3388 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3389
Simon Glassf8a54bc2019-07-20 12:23:56 -06003390 def testReplaceResize(self):
3391 """Test replacing a single file in an entry with a larger file"""
3392 expected = U_BOOT_DATA + b'x'
3393 data, _, image = self._RunReplaceCmd('u-boot', expected,
3394 dts='139_replace_repack.dts')
3395 self.assertEqual(expected, data)
3396
3397 entries = image.GetEntries()
3398 dtb_data = entries['u-boot-dtb'].data
3399 dtb = fdt.Fdt.FromData(dtb_data)
3400 dtb.Scan()
3401
3402 # The u-boot section should now be larger in the dtb
3403 node = dtb.GetNode('/binman/u-boot')
3404 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3405
3406 # Same for the fdtmap
3407 fdata = entries['fdtmap'].data
3408 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3409 fdtb.Scan()
3410 fnode = fdtb.GetNode('/u-boot')
3411 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3412
3413 def testReplaceResizeNoRepack(self):
3414 """Test replacing an entry with a larger file when not allowed"""
3415 expected = U_BOOT_DATA + b'x'
3416 with self.assertRaises(ValueError) as e:
3417 self._RunReplaceCmd('u-boot', expected)
3418 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3419 str(e.exception))
3420
Simon Glass9d8ee322019-07-20 12:23:58 -06003421 def testEntryShrink(self):
3422 """Test contracting an entry after it is packed"""
3423 try:
3424 state.SetAllowEntryContraction(True)
3425 data = self._DoReadFileDtb('140_entry_shrink.dts',
3426 update_dtb=True)[0]
3427 finally:
3428 state.SetAllowEntryContraction(False)
3429 self.assertEqual(b'a', data[:1])
3430 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3431 self.assertEqual(b'a', data[-1:])
3432
3433 def testEntryShrinkFail(self):
3434 """Test not being allowed to contract an entry after it is packed"""
3435 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3436
3437 # In this case there is a spare byte at the end of the data. The size of
3438 # the contents is only 1 byte but we still have the size before it
3439 # shrunk.
3440 self.assertEqual(b'a\0', data[:2])
3441 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3442 self.assertEqual(b'a\0', data[-2:])
3443
Simon Glass70e32982019-07-20 12:24:01 -06003444 def testDescriptorOffset(self):
3445 """Test that the Intel descriptor is always placed at at the start"""
3446 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3447 image = control.images['image']
3448 entries = image.GetEntries()
3449 desc = entries['intel-descriptor']
3450 self.assertEqual(0xff800000, desc.offset);
3451 self.assertEqual(0xff800000, desc.image_pos);
3452
Simon Glass37fdd142019-07-20 12:24:06 -06003453 def testReplaceCbfs(self):
3454 """Test replacing a single file in CBFS without changing the size"""
3455 self._CheckLz4()
3456 expected = b'x' * len(U_BOOT_DATA)
3457 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003458 updated_fname = tools.get_output_filename('image-updated.bin')
3459 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003460 entry_name = 'section/cbfs/u-boot'
3461 control.WriteEntry(updated_fname, entry_name, expected,
3462 allow_resize=True)
3463 data = control.ReadEntry(updated_fname, entry_name)
3464 self.assertEqual(expected, data)
3465
3466 def testReplaceResizeCbfs(self):
3467 """Test replacing a single file in CBFS with one of a different size"""
3468 self._CheckLz4()
3469 expected = U_BOOT_DATA + b'x'
3470 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003471 updated_fname = tools.get_output_filename('image-updated.bin')
3472 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003473 entry_name = 'section/cbfs/u-boot'
3474 control.WriteEntry(updated_fname, entry_name, expected,
3475 allow_resize=True)
3476 data = control.ReadEntry(updated_fname, entry_name)
3477 self.assertEqual(expected, data)
3478
Simon Glass30033c22019-07-20 12:24:15 -06003479 def _SetupForReplace(self):
3480 """Set up some files to use to replace entries
3481
3482 This generates an image, copies it to a new file, extracts all the files
3483 in it and updates some of them
3484
3485 Returns:
3486 List
3487 Image filename
3488 Output directory
3489 Expected values for updated entries, each a string
3490 """
3491 data = self._DoReadFileRealDtb('143_replace_all.dts')
3492
Simon Glass80025522022-01-29 14:14:04 -07003493 updated_fname = tools.get_output_filename('image-updated.bin')
3494 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003495
3496 outdir = os.path.join(self._indir, 'extract')
3497 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3498
3499 expected1 = b'x' + U_BOOT_DATA + b'y'
3500 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003501 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003502
3503 expected2 = b'a' + U_BOOT_DATA + b'b'
3504 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003505 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003506
3507 expected_text = b'not the same text'
3508 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003509 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003510
3511 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3512 dtb = fdt.FdtScan(dtb_fname)
3513 node = dtb.GetNode('/binman/text')
3514 node.AddString('my-property', 'the value')
3515 dtb.Sync(auto_resize=True)
3516 dtb.Flush()
3517
3518 return updated_fname, outdir, expected1, expected2, expected_text
3519
3520 def _CheckReplaceMultiple(self, entry_paths):
3521 """Handle replacing the contents of multiple entries
3522
3523 Args:
3524 entry_paths: List of entry paths to replace
3525
3526 Returns:
3527 List
3528 Dict of entries in the image:
3529 key: Entry name
3530 Value: Entry object
3531 Expected values for updated entries, each a string
3532 """
3533 updated_fname, outdir, expected1, expected2, expected_text = (
3534 self._SetupForReplace())
3535 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3536
3537 image = Image.FromFile(updated_fname)
3538 image.LoadData()
3539 return image.GetEntries(), expected1, expected2, expected_text
3540
3541 def testReplaceAll(self):
3542 """Test replacing the contents of all entries"""
3543 entries, expected1, expected2, expected_text = (
3544 self._CheckReplaceMultiple([]))
3545 data = entries['u-boot'].data
3546 self.assertEqual(expected1, data)
3547
3548 data = entries['u-boot2'].data
3549 self.assertEqual(expected2, data)
3550
3551 data = entries['text'].data
3552 self.assertEqual(expected_text, data)
3553
3554 # Check that the device tree is updated
3555 data = entries['u-boot-dtb'].data
3556 dtb = fdt.Fdt.FromData(data)
3557 dtb.Scan()
3558 node = dtb.GetNode('/binman/text')
3559 self.assertEqual('the value', node.props['my-property'].value)
3560
3561 def testReplaceSome(self):
3562 """Test replacing the contents of a few entries"""
3563 entries, expected1, expected2, expected_text = (
3564 self._CheckReplaceMultiple(['u-boot2', 'text']))
3565
3566 # This one should not change
3567 data = entries['u-boot'].data
3568 self.assertEqual(U_BOOT_DATA, data)
3569
3570 data = entries['u-boot2'].data
3571 self.assertEqual(expected2, data)
3572
3573 data = entries['text'].data
3574 self.assertEqual(expected_text, data)
3575
3576 def testReplaceCmd(self):
3577 """Test replacing a file fron an image on the command line"""
3578 self._DoReadFileRealDtb('143_replace_all.dts')
3579
3580 try:
3581 tmpdir, updated_fname = self._SetupImageInTmpdir()
3582
3583 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3584 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003585 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003586
3587 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003588 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003589 self.assertEqual(expected, data[:len(expected)])
3590 map_fname = os.path.join(tmpdir, 'image-updated.map')
3591 self.assertFalse(os.path.exists(map_fname))
3592 finally:
3593 shutil.rmtree(tmpdir)
3594
3595 def testReplaceCmdSome(self):
3596 """Test replacing some files fron an image on the command line"""
3597 updated_fname, outdir, expected1, expected2, expected_text = (
3598 self._SetupForReplace())
3599
3600 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3601 'u-boot2', 'text')
3602
Simon Glass80025522022-01-29 14:14:04 -07003603 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003604 image = Image.FromFile(updated_fname)
3605 image.LoadData()
3606 entries = image.GetEntries()
3607
3608 # This one should not change
3609 data = entries['u-boot'].data
3610 self.assertEqual(U_BOOT_DATA, data)
3611
3612 data = entries['u-boot2'].data
3613 self.assertEqual(expected2, data)
3614
3615 data = entries['text'].data
3616 self.assertEqual(expected_text, data)
3617
3618 def testReplaceMissing(self):
3619 """Test replacing entries where the file is missing"""
3620 updated_fname, outdir, expected1, expected2, expected_text = (
3621 self._SetupForReplace())
3622
3623 # Remove one of the files, to generate a warning
3624 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3625 os.remove(u_boot_fname1)
3626
3627 with test_util.capture_sys_output() as (stdout, stderr):
3628 control.ReplaceEntries(updated_fname, None, outdir, [])
3629 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003630 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003631
3632 def testReplaceCmdMap(self):
3633 """Test replacing a file fron an image on the command line"""
3634 self._DoReadFileRealDtb('143_replace_all.dts')
3635
3636 try:
3637 tmpdir, updated_fname = self._SetupImageInTmpdir()
3638
3639 fname = os.path.join(self._indir, 'update-u-boot.bin')
3640 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003641 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003642
3643 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3644 '-f', fname, '-m')
3645 map_fname = os.path.join(tmpdir, 'image-updated.map')
3646 self.assertTrue(os.path.exists(map_fname))
3647 finally:
3648 shutil.rmtree(tmpdir)
3649
3650 def testReplaceNoEntryPaths(self):
3651 """Test replacing an entry without an entry path"""
3652 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003653 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003654 with self.assertRaises(ValueError) as e:
3655 control.ReplaceEntries(image_fname, 'fname', None, [])
3656 self.assertIn('Must specify an entry path to read with -f',
3657 str(e.exception))
3658
3659 def testReplaceTooManyEntryPaths(self):
3660 """Test extracting some entries"""
3661 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003662 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003663 with self.assertRaises(ValueError) as e:
3664 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3665 self.assertIn('Must specify exactly one entry path to write with -f',
3666 str(e.exception))
3667
Simon Glass0b074d62019-08-24 07:22:48 -06003668 def testPackReset16(self):
3669 """Test that an image with an x86 reset16 region can be created"""
3670 data = self._DoReadFile('144_x86_reset16.dts')
3671 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3672
3673 def testPackReset16Spl(self):
3674 """Test that an image with an x86 reset16-spl region can be created"""
3675 data = self._DoReadFile('145_x86_reset16_spl.dts')
3676 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3677
3678 def testPackReset16Tpl(self):
3679 """Test that an image with an x86 reset16-tpl region can be created"""
3680 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3681 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3682
Simon Glass232f90c2019-08-24 07:22:50 -06003683 def testPackIntelFit(self):
3684 """Test that an image with an Intel FIT and pointer can be created"""
3685 data = self._DoReadFile('147_intel_fit.dts')
3686 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3687 fit = data[16:32];
3688 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3689 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3690
3691 image = control.images['image']
3692 entries = image.GetEntries()
3693 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3694 self.assertEqual(expected_ptr, ptr)
3695
3696 def testPackIntelFitMissing(self):
3697 """Test detection of a FIT pointer with not FIT region"""
3698 with self.assertRaises(ValueError) as e:
3699 self._DoReadFile('148_intel_fit_missing.dts')
3700 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3701 str(e.exception))
3702
Simon Glass72555fa2019-11-06 17:22:44 -07003703 def _CheckSymbolsTplSection(self, dts, expected_vals):
3704 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003705 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003706 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003707 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003708 self.assertEqual(expected1, data[:upto1])
3709
3710 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003711 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003712 self.assertEqual(expected2, data[upto1:upto2])
3713
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003714 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003715 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003716 self.assertEqual(expected3, data[upto2:upto3])
3717
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003718 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003719 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3720
3721 def testSymbolsTplSection(self):
3722 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3723 self._SetupSplElf('u_boot_binman_syms')
3724 self._SetupTplElf('u_boot_binman_syms')
3725 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003726 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003727
3728 def testSymbolsTplSectionX86(self):
3729 """Test binman can assign symbols in a section with end-at-4gb"""
3730 self._SetupSplElf('u_boot_binman_syms_x86')
3731 self._SetupTplElf('u_boot_binman_syms_x86')
3732 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003733 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003734 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003735
Simon Glass98c59572019-08-24 07:23:03 -06003736 def testPackX86RomIfwiSectiom(self):
3737 """Test that a section can be placed in an IFWI region"""
3738 self._SetupIfwi('fitimage.bin')
3739 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3740 self._CheckIfwi(data)
3741
Simon Glassba7985d2019-08-24 07:23:07 -06003742 def testPackFspM(self):
3743 """Test that an image with a FSP memory-init binary can be created"""
3744 data = self._DoReadFile('152_intel_fsp_m.dts')
3745 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3746
Simon Glass4d9086d2019-10-20 21:31:35 -06003747 def testPackFspS(self):
3748 """Test that an image with a FSP silicon-init binary can be created"""
3749 data = self._DoReadFile('153_intel_fsp_s.dts')
3750 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003751
Simon Glass9ea87b22019-10-20 21:31:36 -06003752 def testPackFspT(self):
3753 """Test that an image with a FSP temp-ram-init binary can be created"""
3754 data = self._DoReadFile('154_intel_fsp_t.dts')
3755 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3756
Simon Glass48f3aad2020-07-09 18:39:31 -06003757 def testMkimage(self):
3758 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003759 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003760 data = self._DoReadFile('156_mkimage.dts')
3761
3762 # Just check that the data appears in the file somewhere
3763 self.assertIn(U_BOOT_SPL_DATA, data)
3764
Simon Glass66152ce2022-01-09 20:14:09 -07003765 def testMkimageMissing(self):
3766 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003767 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003768 with test_util.capture_sys_output() as (_, stderr):
3769 self._DoTestFile('156_mkimage.dts',
3770 force_missing_bintools='mkimage')
3771 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003772 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003773
Simon Glass5e560182020-07-09 18:39:36 -06003774 def testExtblob(self):
3775 """Test an image with an external blob"""
3776 data = self._DoReadFile('157_blob_ext.dts')
3777 self.assertEqual(REFCODE_DATA, data)
3778
3779 def testExtblobMissing(self):
3780 """Test an image with a missing external blob"""
3781 with self.assertRaises(ValueError) as e:
3782 self._DoReadFile('158_blob_ext_missing.dts')
3783 self.assertIn("Filename 'missing-file' not found in input path",
3784 str(e.exception))
3785
Simon Glass5d94cc62020-07-09 18:39:38 -06003786 def testExtblobMissingOk(self):
3787 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003788 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003789 ret = self._DoTestFile('158_blob_ext_missing.dts',
3790 allow_missing=True)
3791 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003792 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003793 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003794 self.assertIn('Some images are invalid', err)
3795
3796 def testExtblobMissingOkFlag(self):
3797 """Test an image with an missing external blob allowed with -W"""
3798 with test_util.capture_sys_output() as (stdout, stderr):
3799 ret = self._DoTestFile('158_blob_ext_missing.dts',
3800 allow_missing=True, ignore_missing=True)
3801 self.assertEqual(0, ret)
3802 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003803 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003804 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003805
3806 def testExtblobMissingOkSect(self):
3807 """Test an image with an missing external blob that is allowed"""
3808 with test_util.capture_sys_output() as (stdout, stderr):
3809 self._DoTestFile('159_blob_ext_missing_sect.dts',
3810 allow_missing=True)
3811 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003812 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003813
Simon Glasse88cef92020-07-09 18:39:41 -06003814 def testPackX86RomMeMissingDesc(self):
3815 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003816 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003817 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003818 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003819 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003820
3821 def testPackX86RomMissingIfwi(self):
3822 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3823 self._SetupIfwi('fitimage.bin')
3824 pathname = os.path.join(self._indir, 'fitimage.bin')
3825 os.remove(pathname)
3826 with test_util.capture_sys_output() as (stdout, stderr):
3827 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3828 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003829 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003830
Simon Glass2a0fa982022-02-11 13:23:21 -07003831 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003832 """Test that zero-size overlapping regions are ignored"""
3833 self._DoTestFile('160_pack_overlap_zero.dts')
3834
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003835 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003836 # The data should be inside the FIT
3837 dtb = fdt.Fdt.FromData(fit_data)
3838 dtb.Scan()
3839 fnode = dtb.GetNode('/images/kernel')
3840 self.assertIn('data', fnode.props)
3841
3842 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003843 tools.write_file(fname, fit_data)
3844 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003845
3846 # Check a few features to make sure the plumbing works. We don't need
3847 # to test the operation of mkimage or dumpimage here. First convert the
3848 # output into a dict where the keys are the fields printed by dumpimage
3849 # and the values are a list of values for each field
3850 lines = out.splitlines()
3851
3852 # Converts "Compression: gzip compressed" into two groups:
3853 # 'Compression' and 'gzip compressed'
3854 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3855 vals = collections.defaultdict(list)
3856 for line in lines:
3857 mat = re_line.match(line)
3858 vals[mat.group(1)].append(mat.group(2))
3859
3860 self.assertEquals('FIT description: test-desc', lines[0])
3861 self.assertIn('Created:', lines[1])
3862 self.assertIn('Image 0 (kernel)', vals)
3863 self.assertIn('Hash value', vals)
3864 data_sizes = vals.get('Data Size')
3865 self.assertIsNotNone(data_sizes)
3866 self.assertEqual(2, len(data_sizes))
3867 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003868 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3869 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3870
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003871 # Check if entry listing correctly omits /images/
3872 image = control.images['image']
3873 fit_entry = image.GetEntries()['fit']
3874 subentries = list(fit_entry.GetEntries().keys())
3875 expected = ['kernel', 'fdt-1']
3876 self.assertEqual(expected, subentries)
3877
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003878 def testSimpleFit(self):
3879 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003880 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003881 data = self._DoReadFile('161_fit.dts')
3882 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3883 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3884 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3885
3886 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3887
3888 def testSimpleFitExpandsSubentries(self):
3889 """Test that FIT images expand their subentries"""
3890 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3891 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3892 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3893 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3894
3895 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003896
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003897 def testSimpleFitImagePos(self):
3898 """Test that we have correct image-pos for FIT subentries"""
3899 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3900 update_dtb=True)
3901 dtb = fdt.Fdt(out_dtb_fname)
3902 dtb.Scan()
3903 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3904
Simon Glassb7bad182022-03-05 20:19:01 -07003905 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003906 self.assertEqual({
3907 'image-pos': 0,
3908 'offset': 0,
3909 'size': 1890,
3910
3911 'u-boot:image-pos': 0,
3912 'u-boot:offset': 0,
3913 'u-boot:size': 4,
3914
3915 'fit:image-pos': 4,
3916 'fit:offset': 4,
3917 'fit:size': 1840,
3918
Simon Glassb7bad182022-03-05 20:19:01 -07003919 'fit/images/kernel:image-pos': 304,
3920 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003921 'fit/images/kernel:size': 4,
3922
Simon Glassb7bad182022-03-05 20:19:01 -07003923 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003924 'fit/images/kernel/u-boot:offset': 0,
3925 'fit/images/kernel/u-boot:size': 4,
3926
Simon Glassb7bad182022-03-05 20:19:01 -07003927 'fit/images/fdt-1:image-pos': 552,
3928 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003929 'fit/images/fdt-1:size': 6,
3930
Simon Glassb7bad182022-03-05 20:19:01 -07003931 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003932 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3933 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3934
3935 'u-boot-nodtb:image-pos': 1844,
3936 'u-boot-nodtb:offset': 1844,
3937 'u-boot-nodtb:size': 46,
3938 }, props)
3939
3940 # Actually check the data is where we think it is
3941 for node, expected in [
3942 ("u-boot", U_BOOT_DATA),
3943 ("fit/images/kernel", U_BOOT_DATA),
3944 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3945 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3946 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3947 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3948 ]:
3949 image_pos = props[f"{node}:image-pos"]
3950 size = props[f"{node}:size"]
3951 self.assertEqual(len(expected), size)
3952 self.assertEqual(expected, data[image_pos:image_pos+size])
3953
Simon Glass45d556d2020-07-09 18:39:45 -06003954 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003955 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003956 data = self._DoReadFile('162_fit_external.dts')
3957 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3958
Simon Glass7932c882022-01-09 20:13:39 -07003959 # Size of the external-data region as set up by mkimage
3960 external_data_size = len(U_BOOT_DATA) + 2
3961 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003962 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003963 len(U_BOOT_NODTB_DATA))
3964
Simon Glass45d556d2020-07-09 18:39:45 -06003965 # The data should be outside the FIT
3966 dtb = fdt.Fdt.FromData(fit_data)
3967 dtb.Scan()
3968 fnode = dtb.GetNode('/images/kernel')
3969 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003970 self.assertEqual(len(U_BOOT_DATA),
3971 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3972 fit_pos = 0x400;
3973 self.assertEqual(
3974 fit_pos,
3975 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3976
3977 self.assertEquals(expected_size, len(data))
3978 actual_pos = len(U_BOOT_DATA) + fit_pos
3979 self.assertEqual(U_BOOT_DATA + b'aa',
3980 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003981
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003982 def testFitExternalImagePos(self):
3983 """Test that we have correct image-pos for external FIT subentries"""
3984 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3985 update_dtb=True)
3986 dtb = fdt.Fdt(out_dtb_fname)
3987 dtb.Scan()
3988 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3989
3990 self.assertEqual({
3991 'image-pos': 0,
3992 'offset': 0,
3993 'size': 1082,
3994
3995 'u-boot:image-pos': 0,
3996 'u-boot:offset': 0,
3997 'u-boot:size': 4,
3998
3999 'fit:size': 1032,
4000 'fit:offset': 4,
4001 'fit:image-pos': 4,
4002
4003 'fit/images/kernel:size': 4,
4004 'fit/images/kernel:offset': 1024,
4005 'fit/images/kernel:image-pos': 1028,
4006
4007 'fit/images/kernel/u-boot:size': 4,
4008 'fit/images/kernel/u-boot:offset': 0,
4009 'fit/images/kernel/u-boot:image-pos': 1028,
4010
4011 'fit/images/fdt-1:size': 2,
4012 'fit/images/fdt-1:offset': 1028,
4013 'fit/images/fdt-1:image-pos': 1032,
4014
4015 'fit/images/fdt-1/_testing:size': 2,
4016 'fit/images/fdt-1/_testing:offset': 0,
4017 'fit/images/fdt-1/_testing:image-pos': 1032,
4018
4019 'u-boot-nodtb:image-pos': 1036,
4020 'u-boot-nodtb:offset': 1036,
4021 'u-boot-nodtb:size': 46,
4022 }, props)
4023
4024 # Actually check the data is where we think it is
4025 for node, expected in [
4026 ("u-boot", U_BOOT_DATA),
4027 ("fit/images/kernel", U_BOOT_DATA),
4028 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4029 ("fit/images/fdt-1", b'aa'),
4030 ("fit/images/fdt-1/_testing", b'aa'),
4031 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4032 ]:
4033 image_pos = props[f"{node}:image-pos"]
4034 size = props[f"{node}:size"]
4035 self.assertEqual(len(expected), size)
4036 self.assertEqual(expected, data[image_pos:image_pos+size])
4037
Simon Glass66152ce2022-01-09 20:14:09 -07004038 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004039 """Test that binman complains if mkimage is missing"""
4040 with self.assertRaises(ValueError) as e:
4041 self._DoTestFile('162_fit_external.dts',
4042 force_missing_bintools='mkimage')
4043 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4044 str(e.exception))
4045
4046 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004047 """Test that binman still produces a FIT image if mkimage is missing"""
4048 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004049 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004050 force_missing_bintools='mkimage')
4051 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004052 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004053
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004054 def testSectionIgnoreHashSignature(self):
4055 """Test that sections ignore hash, signature nodes for its data"""
4056 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4057 expected = (U_BOOT_DATA + U_BOOT_DATA)
4058 self.assertEqual(expected, data)
4059
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004060 def testPadInSections(self):
4061 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004062 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4063 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004064 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4065 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004066 U_BOOT_DATA)
4067 self.assertEqual(expected, data)
4068
Simon Glassd12599d2020-10-26 17:40:09 -06004069 dtb = fdt.Fdt(out_dtb_fname)
4070 dtb.Scan()
4071 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4072 expected = {
4073 'image-pos': 0,
4074 'offset': 0,
4075 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4076
4077 'section:image-pos': 0,
4078 'section:offset': 0,
4079 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4080
4081 'section/before:image-pos': 0,
4082 'section/before:offset': 0,
4083 'section/before:size': len(U_BOOT_DATA),
4084
4085 'section/u-boot:image-pos': 4,
4086 'section/u-boot:offset': 4,
4087 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4088
4089 'section/after:image-pos': 26,
4090 'section/after:offset': 26,
4091 'section/after:size': len(U_BOOT_DATA),
4092 }
4093 self.assertEqual(expected, props)
4094
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004095 def testFitImageSubentryAlignment(self):
4096 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004097 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004098 entry_args = {
4099 'test-id': TEXT_DATA,
4100 }
4101 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4102 entry_args=entry_args)
4103 dtb = fdt.Fdt.FromData(data)
4104 dtb.Scan()
4105
4106 node = dtb.GetNode('/images/kernel')
4107 data = dtb.GetProps(node)["data"].bytes
4108 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004109 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4110 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004111 self.assertEqual(expected, data)
4112
4113 node = dtb.GetNode('/images/fdt-1')
4114 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004115 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4116 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004117 U_BOOT_DTB_DATA)
4118 self.assertEqual(expected, data)
4119
4120 def testFitExtblobMissingOk(self):
4121 """Test a FIT with a missing external blob that is allowed"""
4122 with test_util.capture_sys_output() as (stdout, stderr):
4123 self._DoTestFile('168_fit_missing_blob.dts',
4124 allow_missing=True)
4125 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004126 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004127
Simon Glass21db0ff2020-09-01 05:13:54 -06004128 def testBlobNamedByArgMissing(self):
4129 """Test handling of a missing entry arg"""
4130 with self.assertRaises(ValueError) as e:
4131 self._DoReadFile('068_blob_named_by_arg.dts')
4132 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4133 str(e.exception))
4134
Simon Glass559c4de2020-09-01 05:13:58 -06004135 def testPackBl31(self):
4136 """Test that an image with an ATF BL31 binary can be created"""
4137 data = self._DoReadFile('169_atf_bl31.dts')
4138 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4139
Samuel Holland9d8cc632020-10-21 21:12:15 -05004140 def testPackScp(self):
4141 """Test that an image with an SCP binary can be created"""
4142 data = self._DoReadFile('172_scp.dts')
4143 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4144
Simon Glassa435cd12020-09-01 05:13:59 -06004145 def testFitFdt(self):
4146 """Test an image with an FIT with multiple FDT images"""
4147 def _CheckFdt(seq, expected_data):
4148 """Check the FDT nodes
4149
4150 Args:
4151 seq: Sequence number to check (0 or 1)
4152 expected_data: Expected contents of 'data' property
4153 """
4154 name = 'fdt-%d' % seq
4155 fnode = dtb.GetNode('/images/%s' % name)
4156 self.assertIsNotNone(fnode)
4157 self.assertEqual({'description','type', 'compression', 'data'},
4158 set(fnode.props.keys()))
4159 self.assertEqual(expected_data, fnode.props['data'].bytes)
4160 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4161 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004162 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004163
4164 def _CheckConfig(seq, expected_data):
4165 """Check the configuration nodes
4166
4167 Args:
4168 seq: Sequence number to check (0 or 1)
4169 expected_data: Expected contents of 'data' property
4170 """
4171 cnode = dtb.GetNode('/configurations')
4172 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004173 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004174
4175 name = 'config-%d' % seq
4176 fnode = dtb.GetNode('/configurations/%s' % name)
4177 self.assertIsNotNone(fnode)
4178 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4179 set(fnode.props.keys()))
4180 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4181 fnode.props['description'].value)
4182 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4183
4184 entry_args = {
4185 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004186 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004187 }
4188 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004189 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004190 entry_args=entry_args,
4191 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4192 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4193 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4194
4195 dtb = fdt.Fdt.FromData(fit_data)
4196 dtb.Scan()
4197 fnode = dtb.GetNode('/images/kernel')
4198 self.assertIn('data', fnode.props)
4199
4200 # Check all the properties in fdt-1 and fdt-2
4201 _CheckFdt(1, TEST_FDT1_DATA)
4202 _CheckFdt(2, TEST_FDT2_DATA)
4203
4204 # Check configurations
4205 _CheckConfig(1, TEST_FDT1_DATA)
4206 _CheckConfig(2, TEST_FDT2_DATA)
4207
4208 def testFitFdtMissingList(self):
4209 """Test handling of a missing 'of-list' entry arg"""
4210 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004211 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004212 self.assertIn("Generator node requires 'of-list' entry argument",
4213 str(e.exception))
4214
4215 def testFitFdtEmptyList(self):
4216 """Test handling of an empty 'of-list' entry arg"""
4217 entry_args = {
4218 'of-list': '',
4219 }
4220 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4221
4222 def testFitFdtMissingProp(self):
4223 """Test handling of a missing 'fit,fdt-list' property"""
4224 with self.assertRaises(ValueError) as e:
4225 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4226 self.assertIn("Generator node requires 'fit,fdt-list' property",
4227 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004228
Simon Glass1032acc2020-09-06 10:39:08 -06004229 def testFitFdtMissing(self):
4230 """Test handling of a missing 'default-dt' entry arg"""
4231 entry_args = {
4232 'of-list': 'test-fdt1 test-fdt2',
4233 }
4234 with self.assertRaises(ValueError) as e:
4235 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004236 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004237 entry_args=entry_args,
4238 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4239 self.assertIn("Generated 'default' node requires default-dt entry argument",
4240 str(e.exception))
4241
4242 def testFitFdtNotInList(self):
4243 """Test handling of a default-dt that is not in the of-list"""
4244 entry_args = {
4245 'of-list': 'test-fdt1 test-fdt2',
4246 'default-dt': 'test-fdt3',
4247 }
4248 with self.assertRaises(ValueError) as e:
4249 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004250 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004251 entry_args=entry_args,
4252 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4253 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4254 str(e.exception))
4255
Simon Glassa820af72020-09-06 10:39:09 -06004256 def testFitExtblobMissingHelp(self):
4257 """Test display of help messages when an external blob is missing"""
4258 control.missing_blob_help = control._ReadMissingBlobHelp()
4259 control.missing_blob_help['wibble'] = 'Wibble test'
4260 control.missing_blob_help['another'] = 'Another test'
4261 with test_util.capture_sys_output() as (stdout, stderr):
4262 self._DoTestFile('168_fit_missing_blob.dts',
4263 allow_missing=True)
4264 err = stderr.getvalue()
4265
4266 # We can get the tag from the name, the type or the missing-msg
4267 # property. Check all three.
4268 self.assertIn('You may need to build ARM Trusted', err)
4269 self.assertIn('Wibble test', err)
4270 self.assertIn('Another test', err)
4271
Simon Glass6f1f4d42020-09-06 10:35:32 -06004272 def testMissingBlob(self):
4273 """Test handling of a blob containing a missing file"""
4274 with self.assertRaises(ValueError) as e:
4275 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4276 self.assertIn("Filename 'missing' not found in input path",
4277 str(e.exception))
4278
Simon Glassa0729502020-09-06 10:35:33 -06004279 def testEnvironment(self):
4280 """Test adding a U-Boot environment"""
4281 data = self._DoReadFile('174_env.dts')
4282 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4283 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4284 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4285 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4286 env)
4287
4288 def testEnvironmentNoSize(self):
4289 """Test that a missing 'size' property is detected"""
4290 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004291 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004292 self.assertIn("'u-boot-env' entry must have a size property",
4293 str(e.exception))
4294
4295 def testEnvironmentTooSmall(self):
4296 """Test handling of an environment that does not fit"""
4297 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004298 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004299
4300 # checksum, start byte, environment with \0 terminator, final \0
4301 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4302 short = need - 0x8
4303 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4304 str(e.exception))
4305
Simon Glassd1fdf752020-10-26 17:40:01 -06004306 def testSkipAtStart(self):
4307 """Test handling of skip-at-start section"""
4308 data = self._DoReadFile('177_skip_at_start.dts')
4309 self.assertEqual(U_BOOT_DATA, data)
4310
4311 image = control.images['image']
4312 entries = image.GetEntries()
4313 section = entries['section']
4314 self.assertEqual(0, section.offset)
4315 self.assertEqual(len(U_BOOT_DATA), section.size)
4316 self.assertEqual(U_BOOT_DATA, section.GetData())
4317
4318 entry = section.GetEntries()['u-boot']
4319 self.assertEqual(16, entry.offset)
4320 self.assertEqual(len(U_BOOT_DATA), entry.size)
4321 self.assertEqual(U_BOOT_DATA, entry.data)
4322
4323 def testSkipAtStartPad(self):
4324 """Test handling of skip-at-start section with padded entry"""
4325 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004326 before = tools.get_bytes(0, 8)
4327 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004328 all = before + U_BOOT_DATA + after
4329 self.assertEqual(all, data)
4330
4331 image = control.images['image']
4332 entries = image.GetEntries()
4333 section = entries['section']
4334 self.assertEqual(0, section.offset)
4335 self.assertEqual(len(all), section.size)
4336 self.assertEqual(all, section.GetData())
4337
4338 entry = section.GetEntries()['u-boot']
4339 self.assertEqual(16, entry.offset)
4340 self.assertEqual(len(all), entry.size)
4341 self.assertEqual(U_BOOT_DATA, entry.data)
4342
4343 def testSkipAtStartSectionPad(self):
4344 """Test handling of skip-at-start section with padding"""
4345 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004346 before = tools.get_bytes(0, 8)
4347 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004348 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004349 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004350
4351 image = control.images['image']
4352 entries = image.GetEntries()
4353 section = entries['section']
4354 self.assertEqual(0, section.offset)
4355 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004356 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004357 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004358
4359 entry = section.GetEntries()['u-boot']
4360 self.assertEqual(16, entry.offset)
4361 self.assertEqual(len(U_BOOT_DATA), entry.size)
4362 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004363
Simon Glassbb395742020-10-26 17:40:14 -06004364 def testSectionPad(self):
4365 """Testing padding with sections"""
4366 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004367 expected = (tools.get_bytes(ord('&'), 3) +
4368 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004369 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004370 tools.get_bytes(ord('!'), 1) +
4371 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004372 self.assertEqual(expected, data)
4373
4374 def testSectionAlign(self):
4375 """Testing alignment with sections"""
4376 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4377 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004378 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004379 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004380 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004381 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004382 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4383 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004384 self.assertEqual(expected, data)
4385
Simon Glassd92c8362020-10-26 17:40:25 -06004386 def testCompressImage(self):
4387 """Test compression of the entire image"""
4388 self._CheckLz4()
4389 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4390 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4391 dtb = fdt.Fdt(out_dtb_fname)
4392 dtb.Scan()
4393 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4394 'uncomp-size'])
4395 orig = self._decompress(data)
4396 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4397
4398 # Do a sanity check on various fields
4399 image = control.images['image']
4400 entries = image.GetEntries()
4401 self.assertEqual(2, len(entries))
4402
4403 entry = entries['blob']
4404 self.assertEqual(COMPRESS_DATA, entry.data)
4405 self.assertEqual(len(COMPRESS_DATA), entry.size)
4406
4407 entry = entries['u-boot']
4408 self.assertEqual(U_BOOT_DATA, entry.data)
4409 self.assertEqual(len(U_BOOT_DATA), entry.size)
4410
4411 self.assertEqual(len(data), image.size)
4412 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4413 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4414 orig = self._decompress(image.data)
4415 self.assertEqual(orig, image.uncomp_data)
4416
4417 expected = {
4418 'blob:offset': 0,
4419 'blob:size': len(COMPRESS_DATA),
4420 'u-boot:offset': len(COMPRESS_DATA),
4421 'u-boot:size': len(U_BOOT_DATA),
4422 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4423 'offset': 0,
4424 'image-pos': 0,
4425 'size': len(data),
4426 }
4427 self.assertEqual(expected, props)
4428
4429 def testCompressImageLess(self):
4430 """Test compression where compression reduces the image size"""
4431 self._CheckLz4()
4432 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4433 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4434 dtb = fdt.Fdt(out_dtb_fname)
4435 dtb.Scan()
4436 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4437 'uncomp-size'])
4438 orig = self._decompress(data)
4439
4440 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4441
4442 # Do a sanity check on various fields
4443 image = control.images['image']
4444 entries = image.GetEntries()
4445 self.assertEqual(2, len(entries))
4446
4447 entry = entries['blob']
4448 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4449 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4450
4451 entry = entries['u-boot']
4452 self.assertEqual(U_BOOT_DATA, entry.data)
4453 self.assertEqual(len(U_BOOT_DATA), entry.size)
4454
4455 self.assertEqual(len(data), image.size)
4456 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4457 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4458 image.uncomp_size)
4459 orig = self._decompress(image.data)
4460 self.assertEqual(orig, image.uncomp_data)
4461
4462 expected = {
4463 'blob:offset': 0,
4464 'blob:size': len(COMPRESS_DATA_BIG),
4465 'u-boot:offset': len(COMPRESS_DATA_BIG),
4466 'u-boot:size': len(U_BOOT_DATA),
4467 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4468 'offset': 0,
4469 'image-pos': 0,
4470 'size': len(data),
4471 }
4472 self.assertEqual(expected, props)
4473
4474 def testCompressSectionSize(self):
4475 """Test compression of a section with a fixed size"""
4476 self._CheckLz4()
4477 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4478 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4479 dtb = fdt.Fdt(out_dtb_fname)
4480 dtb.Scan()
4481 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4482 'uncomp-size'])
4483 orig = self._decompress(data)
4484 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4485 expected = {
4486 'section/blob:offset': 0,
4487 'section/blob:size': len(COMPRESS_DATA),
4488 'section/u-boot:offset': len(COMPRESS_DATA),
4489 'section/u-boot:size': len(U_BOOT_DATA),
4490 'section:offset': 0,
4491 'section:image-pos': 0,
4492 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4493 'section:size': 0x30,
4494 'offset': 0,
4495 'image-pos': 0,
4496 'size': 0x30,
4497 }
4498 self.assertEqual(expected, props)
4499
4500 def testCompressSection(self):
4501 """Test compression of a section with no fixed size"""
4502 self._CheckLz4()
4503 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4504 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4505 dtb = fdt.Fdt(out_dtb_fname)
4506 dtb.Scan()
4507 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4508 'uncomp-size'])
4509 orig = self._decompress(data)
4510 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4511 expected = {
4512 'section/blob:offset': 0,
4513 'section/blob:size': len(COMPRESS_DATA),
4514 'section/u-boot:offset': len(COMPRESS_DATA),
4515 'section/u-boot:size': len(U_BOOT_DATA),
4516 'section:offset': 0,
4517 'section:image-pos': 0,
4518 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4519 'section:size': len(data),
4520 'offset': 0,
4521 'image-pos': 0,
4522 'size': len(data),
4523 }
4524 self.assertEqual(expected, props)
4525
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004526 def testLz4Missing(self):
4527 """Test that binman still produces an image if lz4 is missing"""
4528 with test_util.capture_sys_output() as (_, stderr):
4529 self._DoTestFile('185_compress_section.dts',
4530 force_missing_bintools='lz4')
4531 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004532 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004533
Simon Glassd92c8362020-10-26 17:40:25 -06004534 def testCompressExtra(self):
4535 """Test compression of a section with no fixed size"""
4536 self._CheckLz4()
4537 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4538 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4539 dtb = fdt.Fdt(out_dtb_fname)
4540 dtb.Scan()
4541 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4542 'uncomp-size'])
4543
4544 base = data[len(U_BOOT_DATA):]
4545 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4546 rest = base[len(U_BOOT_DATA):]
4547
4548 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004549 bintool = self.comp_bintools['lz4']
4550 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004551 data1 = rest[:len(expect1)]
4552 section1 = self._decompress(data1)
4553 self.assertEquals(expect1, data1)
Simon Glassd92c8362020-10-26 17:40:25 -06004554 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4555 rest1 = rest[len(expect1):]
4556
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004557 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004558 data2 = rest1[:len(expect2)]
4559 section2 = self._decompress(data2)
4560 self.assertEquals(expect2, data2)
Simon Glassd92c8362020-10-26 17:40:25 -06004561 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4562 rest2 = rest1[len(expect2):]
4563
4564 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4565 len(expect2) + len(U_BOOT_DATA))
4566 #self.assertEquals(expect_size, len(data))
4567
4568 #self.assertEquals(U_BOOT_DATA, rest2)
4569
4570 self.maxDiff = None
4571 expected = {
4572 'u-boot:offset': 0,
4573 'u-boot:image-pos': 0,
4574 'u-boot:size': len(U_BOOT_DATA),
4575
4576 'base:offset': len(U_BOOT_DATA),
4577 'base:image-pos': len(U_BOOT_DATA),
4578 'base:size': len(data) - len(U_BOOT_DATA),
4579 'base/u-boot:offset': 0,
4580 'base/u-boot:image-pos': len(U_BOOT_DATA),
4581 'base/u-boot:size': len(U_BOOT_DATA),
4582 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4583 len(expect2),
4584 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4585 len(expect2),
4586 'base/u-boot2:size': len(U_BOOT_DATA),
4587
4588 'base/section:offset': len(U_BOOT_DATA),
4589 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4590 'base/section:size': len(expect1),
4591 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4592 'base/section/blob:offset': 0,
4593 'base/section/blob:size': len(COMPRESS_DATA),
4594 'base/section/u-boot:offset': len(COMPRESS_DATA),
4595 'base/section/u-boot:size': len(U_BOOT_DATA),
4596
4597 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4598 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4599 'base/section2:size': len(expect2),
4600 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4601 'base/section2/blob:offset': 0,
4602 'base/section2/blob:size': len(COMPRESS_DATA),
4603 'base/section2/blob2:offset': len(COMPRESS_DATA),
4604 'base/section2/blob2:size': len(COMPRESS_DATA),
4605
4606 'offset': 0,
4607 'image-pos': 0,
4608 'size': len(data),
4609 }
4610 self.assertEqual(expected, props)
4611
Simon Glassecbe4732021-01-06 21:35:15 -07004612 def testSymbolsSubsection(self):
4613 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004614 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004615
Simon Glass3fb25402021-01-06 21:35:16 -07004616 def testReadImageEntryArg(self):
4617 """Test reading an image that would need an entry arg to generate"""
4618 entry_args = {
4619 'cros-ec-rw-path': 'ecrw.bin',
4620 }
4621 data = self.data = self._DoReadFileDtb(
4622 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4623 entry_args=entry_args)
4624
Simon Glass80025522022-01-29 14:14:04 -07004625 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004626 orig_image = control.images['image']
4627
4628 # This should not generate an error about the missing 'cros-ec-rw-path'
4629 # since we are reading the image from a file. Compare with
4630 # testEntryArgsRequired()
4631 image = Image.FromFile(image_fname)
4632 self.assertEqual(orig_image.GetEntries().keys(),
4633 image.GetEntries().keys())
4634
Simon Glassa2af7302021-01-06 21:35:18 -07004635 def testFilesAlign(self):
4636 """Test alignment with files"""
4637 data = self._DoReadFile('190_files_align.dts')
4638
4639 # The first string is 15 bytes so will align to 16
4640 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4641 self.assertEqual(expect, data)
4642
Simon Glassdb84b562021-01-06 21:35:19 -07004643 def testReadImageSkip(self):
4644 """Test reading an image and accessing its FDT map"""
4645 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004646 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004647 orig_image = control.images['image']
4648 image = Image.FromFile(image_fname)
4649 self.assertEqual(orig_image.GetEntries().keys(),
4650 image.GetEntries().keys())
4651
4652 orig_entry = orig_image.GetEntries()['fdtmap']
4653 entry = image.GetEntries()['fdtmap']
4654 self.assertEqual(orig_entry.offset, entry.offset)
4655 self.assertEqual(orig_entry.size, entry.size)
4656 self.assertEqual(16, entry.image_pos)
4657
4658 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4659
4660 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4661
Simon Glassc98de972021-03-18 20:24:57 +13004662 def testTplNoDtb(self):
4663 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004664 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004665 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4666 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4667 data[:len(U_BOOT_TPL_NODTB_DATA)])
4668
Simon Glass63f41d42021-03-18 20:24:58 +13004669 def testTplBssPad(self):
4670 """Test that we can pad TPL's BSS with zeros"""
4671 # ELF file with a '__bss_size' symbol
4672 self._SetupTplElf()
4673 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004674 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004675 data)
4676
4677 def testTplBssPadMissing(self):
4678 """Test that a missing symbol is detected"""
4679 self._SetupTplElf('u_boot_ucode_ptr')
4680 with self.assertRaises(ValueError) as e:
4681 self._DoReadFile('193_tpl_bss_pad.dts')
4682 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4683 str(e.exception))
4684
Simon Glass718b5292021-03-18 20:25:07 +13004685 def checkDtbSizes(self, data, pad_len, start):
4686 """Check the size arguments in a dtb embedded in an image
4687
4688 Args:
4689 data: The image data
4690 pad_len: Length of the pad section in the image, in bytes
4691 start: Start offset of the devicetree to examine, within the image
4692
4693 Returns:
4694 Size of the devicetree in bytes
4695 """
4696 dtb_data = data[start:]
4697 dtb = fdt.Fdt.FromData(dtb_data)
4698 fdt_size = dtb.GetFdtObj().totalsize()
4699 dtb.Scan()
4700 props = self._GetPropTree(dtb, 'size')
4701 self.assertEqual({
4702 'size': len(data),
4703 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4704 'u-boot-spl/u-boot-spl-dtb:size': 801,
4705 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4706 'u-boot-spl:size': 860,
4707 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4708 'u-boot/u-boot-dtb:size': 781,
4709 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4710 'u-boot:size': 827,
4711 }, props)
4712 return fdt_size
4713
4714 def testExpanded(self):
4715 """Test that an expanded entry type is selected when needed"""
4716 self._SetupSplElf()
4717 self._SetupTplElf()
4718
4719 # SPL has a devicetree, TPL does not
4720 entry_args = {
4721 'spl-dtb': '1',
4722 'spl-bss-pad': 'y',
4723 'tpl-dtb': '',
4724 }
4725 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4726 entry_args=entry_args)
4727 image = control.images['image']
4728 entries = image.GetEntries()
4729 self.assertEqual(3, len(entries))
4730
4731 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4732 self.assertIn('u-boot', entries)
4733 entry = entries['u-boot']
4734 self.assertEqual('u-boot-expanded', entry.etype)
4735 subent = entry.GetEntries()
4736 self.assertEqual(2, len(subent))
4737 self.assertIn('u-boot-nodtb', subent)
4738 self.assertIn('u-boot-dtb', subent)
4739
4740 # Second, u-boot-spl, which should be expanded into three parts
4741 self.assertIn('u-boot-spl', entries)
4742 entry = entries['u-boot-spl']
4743 self.assertEqual('u-boot-spl-expanded', entry.etype)
4744 subent = entry.GetEntries()
4745 self.assertEqual(3, len(subent))
4746 self.assertIn('u-boot-spl-nodtb', subent)
4747 self.assertIn('u-boot-spl-bss-pad', subent)
4748 self.assertIn('u-boot-spl-dtb', subent)
4749
4750 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4751 # devicetree
4752 self.assertIn('u-boot-tpl', entries)
4753 entry = entries['u-boot-tpl']
4754 self.assertEqual('u-boot-tpl', entry.etype)
4755 self.assertEqual(None, entry.GetEntries())
4756
4757 def testExpandedTpl(self):
4758 """Test that an expanded entry type is selected for TPL when needed"""
4759 self._SetupTplElf()
4760
4761 entry_args = {
4762 'tpl-bss-pad': 'y',
4763 'tpl-dtb': 'y',
4764 }
4765 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4766 entry_args=entry_args)
4767 image = control.images['image']
4768 entries = image.GetEntries()
4769 self.assertEqual(1, len(entries))
4770
4771 # We only have u-boot-tpl, which be expanded
4772 self.assertIn('u-boot-tpl', entries)
4773 entry = entries['u-boot-tpl']
4774 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4775 subent = entry.GetEntries()
4776 self.assertEqual(3, len(subent))
4777 self.assertIn('u-boot-tpl-nodtb', subent)
4778 self.assertIn('u-boot-tpl-bss-pad', subent)
4779 self.assertIn('u-boot-tpl-dtb', subent)
4780
4781 def testExpandedNoPad(self):
4782 """Test an expanded entry without BSS pad enabled"""
4783 self._SetupSplElf()
4784 self._SetupTplElf()
4785
4786 # SPL has a devicetree, TPL does not
4787 entry_args = {
4788 'spl-dtb': 'something',
4789 'spl-bss-pad': 'n',
4790 'tpl-dtb': '',
4791 }
4792 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4793 entry_args=entry_args)
4794 image = control.images['image']
4795 entries = image.GetEntries()
4796
4797 # Just check u-boot-spl, which should be expanded into two parts
4798 self.assertIn('u-boot-spl', entries)
4799 entry = entries['u-boot-spl']
4800 self.assertEqual('u-boot-spl-expanded', entry.etype)
4801 subent = entry.GetEntries()
4802 self.assertEqual(2, len(subent))
4803 self.assertIn('u-boot-spl-nodtb', subent)
4804 self.assertIn('u-boot-spl-dtb', subent)
4805
4806 def testExpandedTplNoPad(self):
4807 """Test that an expanded entry type with padding disabled in TPL"""
4808 self._SetupTplElf()
4809
4810 entry_args = {
4811 'tpl-bss-pad': '',
4812 'tpl-dtb': 'y',
4813 }
4814 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4815 entry_args=entry_args)
4816 image = control.images['image']
4817 entries = image.GetEntries()
4818 self.assertEqual(1, len(entries))
4819
4820 # We only have u-boot-tpl, which be expanded
4821 self.assertIn('u-boot-tpl', entries)
4822 entry = entries['u-boot-tpl']
4823 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4824 subent = entry.GetEntries()
4825 self.assertEqual(2, len(subent))
4826 self.assertIn('u-boot-tpl-nodtb', subent)
4827 self.assertIn('u-boot-tpl-dtb', subent)
4828
4829 def testFdtInclude(self):
4830 """Test that an Fdt is update within all binaries"""
4831 self._SetupSplElf()
4832 self._SetupTplElf()
4833
4834 # SPL has a devicetree, TPL does not
4835 self.maxDiff = None
4836 entry_args = {
4837 'spl-dtb': '1',
4838 'spl-bss-pad': 'y',
4839 'tpl-dtb': '',
4840 }
4841 # Build the image. It includes two separate devicetree binaries, each
4842 # with their own contents, but all contain the binman definition.
4843 data = self._DoReadFileDtb(
4844 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4845 update_dtb=True, entry_args=entry_args)[0]
4846 pad_len = 10
4847
4848 # Check the U-Boot dtb
4849 start = len(U_BOOT_NODTB_DATA)
4850 fdt_size = self.checkDtbSizes(data, pad_len, start)
4851
4852 # Now check SPL
4853 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4854 fdt_size = self.checkDtbSizes(data, pad_len, start)
4855
4856 # TPL has no devicetree
4857 start += fdt_size + len(U_BOOT_TPL_DATA)
4858 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004859
Simon Glass7098b7f2021-03-21 18:24:30 +13004860 def testSymbolsExpanded(self):
4861 """Test binman can assign symbols in expanded entries"""
4862 entry_args = {
4863 'spl-dtb': '1',
4864 }
4865 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4866 U_BOOT_SPL_DTB_DATA, 0x38,
4867 entry_args=entry_args, use_expanded=True)
4868
Simon Glasse1915782021-03-21 18:24:31 +13004869 def testCollection(self):
4870 """Test a collection"""
4871 data = self._DoReadFile('198_collection.dts')
4872 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004873 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4874 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004875 data)
4876
Simon Glass27a7f772021-03-21 18:24:32 +13004877 def testCollectionSection(self):
4878 """Test a collection where a section must be built first"""
4879 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004880 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004881 # building the contents, producing an error is anything is still
4882 # missing.
4883 data = self._DoReadFile('199_collection_section.dts')
4884 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004885 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4886 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004887 data)
4888
Simon Glassf427c5f2021-03-21 18:24:33 +13004889 def testAlignDefault(self):
4890 """Test that default alignment works on sections"""
4891 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004892 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004893 U_BOOT_DATA)
4894 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004895 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004896 # No alignment within the nested section
4897 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4898 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004899 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004900 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004901
Bin Mengc0b15742021-05-10 20:23:33 +08004902 def testPackOpenSBI(self):
4903 """Test that an image with an OpenSBI binary can be created"""
4904 data = self._DoReadFile('201_opensbi.dts')
4905 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4906
Simon Glass76f496d2021-07-06 10:36:37 -06004907 def testSectionsSingleThread(self):
4908 """Test sections without multithreading"""
4909 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004910 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4911 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4912 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004913 self.assertEqual(expected, data)
4914
4915 def testThreadTimeout(self):
4916 """Test handling a thread that takes too long"""
4917 with self.assertRaises(ValueError) as e:
4918 self._DoTestFile('202_section_timeout.dts',
4919 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004920 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004921
Simon Glass748a1d42021-07-06 10:36:41 -06004922 def testTiming(self):
4923 """Test output of timing information"""
4924 data = self._DoReadFile('055_sections.dts')
4925 with test_util.capture_sys_output() as (stdout, stderr):
4926 state.TimingShow()
4927 self.assertIn('read:', stdout.getvalue())
4928 self.assertIn('compress:', stdout.getvalue())
4929
Simon Glassadfb8492021-11-03 21:09:18 -06004930 def testUpdateFdtInElf(self):
4931 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004932 if not elf.ELF_TOOLS:
4933 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004934 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4935 outfile = os.path.join(self._indir, 'u-boot.out')
4936 begin_sym = 'dtb_embed_begin'
4937 end_sym = 'dtb_embed_end'
4938 retcode = self._DoTestFile(
4939 '060_fdt_update.dts', update_dtb=True,
4940 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4941 self.assertEqual(0, retcode)
4942
4943 # Check that the output file does in fact contact a dtb with the binman
4944 # definition in the correct place
4945 syms = elf.GetSymbolFileOffset(infile,
4946 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004947 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004948 dtb_data = data[syms['dtb_embed_begin'].offset:
4949 syms['dtb_embed_end'].offset]
4950
4951 dtb = fdt.Fdt.FromData(dtb_data)
4952 dtb.Scan()
4953 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4954 self.assertEqual({
4955 'image-pos': 0,
4956 'offset': 0,
4957 '_testing:offset': 32,
4958 '_testing:size': 2,
4959 '_testing:image-pos': 32,
4960 'section@0/u-boot:offset': 0,
4961 'section@0/u-boot:size': len(U_BOOT_DATA),
4962 'section@0/u-boot:image-pos': 0,
4963 'section@0:offset': 0,
4964 'section@0:size': 16,
4965 'section@0:image-pos': 0,
4966
4967 'section@1/u-boot:offset': 0,
4968 'section@1/u-boot:size': len(U_BOOT_DATA),
4969 'section@1/u-boot:image-pos': 16,
4970 'section@1:offset': 16,
4971 'section@1:size': 16,
4972 'section@1:image-pos': 16,
4973 'size': 40
4974 }, props)
4975
4976 def testUpdateFdtInElfInvalid(self):
4977 """Test that invalid args are detected with --update-fdt-in-elf"""
4978 with self.assertRaises(ValueError) as e:
4979 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4980 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4981 str(e.exception))
4982
4983 def testUpdateFdtInElfNoSyms(self):
4984 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004985 if not elf.ELF_TOOLS:
4986 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004987 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4988 outfile = ''
4989 begin_sym = 'wrong_begin'
4990 end_sym = 'wrong_end'
4991 with self.assertRaises(ValueError) as e:
4992 self._DoTestFile(
4993 '060_fdt_update.dts',
4994 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4995 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4996 str(e.exception))
4997
4998 def testUpdateFdtInElfTooSmall(self):
4999 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005000 if not elf.ELF_TOOLS:
5001 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06005002 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5003 outfile = os.path.join(self._indir, 'u-boot.out')
5004 begin_sym = 'dtb_embed_begin'
5005 end_sym = 'dtb_embed_end'
5006 with self.assertRaises(ValueError) as e:
5007 self._DoTestFile(
5008 '060_fdt_update.dts', update_dtb=True,
5009 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5010 self.assertRegex(
5011 str(e.exception),
5012 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5013
Simon Glass88e04da2021-11-23 11:03:42 -07005014 def testVersion(self):
5015 """Test we can get the binman version"""
5016 version = '(unreleased)'
5017 self.assertEqual(version, state.GetVersion(self._indir))
5018
5019 with self.assertRaises(SystemExit):
5020 with test_util.capture_sys_output() as (_, stderr):
5021 self._DoBinman('-V')
5022 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5023
5024 # Try running the tool too, just to be safe
5025 result = self._RunBinman('-V')
5026 self.assertEqual('Binman %s\n' % version, result.stderr)
5027
5028 # Set up a version file to make sure that works
5029 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005030 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005031 binary=False)
5032 self.assertEqual(version, state.GetVersion(self._indir))
5033
Simon Glass637958f2021-11-23 21:09:50 -07005034 def testAltFormat(self):
5035 """Test that alternative formats can be used to extract"""
5036 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5037
5038 try:
5039 tmpdir, updated_fname = self._SetupImageInTmpdir()
5040 with test_util.capture_sys_output() as (stdout, _):
5041 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5042 self.assertEqual(
5043 '''Flag (-F) Entry type Description
5044fdt fdtmap Extract the devicetree blob from the fdtmap
5045''',
5046 stdout.getvalue())
5047
5048 dtb = os.path.join(tmpdir, 'fdt.dtb')
5049 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5050 dtb, 'fdtmap')
5051
5052 # Check that we can read it and it can be scanning, meaning it does
5053 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005054 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005055 dtb = fdt.Fdt.FromData(data)
5056 dtb.Scan()
5057
5058 # Now check u-boot which has no alt_format
5059 fname = os.path.join(tmpdir, 'fdt.dtb')
5060 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5061 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005062 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005063 self.assertEqual(U_BOOT_DATA, data)
5064
5065 finally:
5066 shutil.rmtree(tmpdir)
5067
Simon Glass0b00ae62021-11-23 21:09:52 -07005068 def testExtblobList(self):
5069 """Test an image with an external blob list"""
5070 data = self._DoReadFile('215_blob_ext_list.dts')
5071 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5072
5073 def testExtblobListMissing(self):
5074 """Test an image with a missing external blob"""
5075 with self.assertRaises(ValueError) as e:
5076 self._DoReadFile('216_blob_ext_list_missing.dts')
5077 self.assertIn("Filename 'missing-file' not found in input path",
5078 str(e.exception))
5079
5080 def testExtblobListMissingOk(self):
5081 """Test an image with an missing external blob that is allowed"""
5082 with test_util.capture_sys_output() as (stdout, stderr):
5083 self._DoTestFile('216_blob_ext_list_missing.dts',
5084 allow_missing=True)
5085 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005086 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005087
Simon Glass3efb2972021-11-23 21:08:59 -07005088 def testFip(self):
5089 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5090 data = self._DoReadFile('203_fip.dts')
5091 hdr, fents = fip_util.decode_fip(data)
5092 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5093 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5094 self.assertEqual(0x123, hdr.flags)
5095
5096 self.assertEqual(2, len(fents))
5097
5098 fent = fents[0]
5099 self.assertEqual(
5100 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5101 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5102 self.assertEqual('soc-fw', fent.fip_type)
5103 self.assertEqual(0x88, fent.offset)
5104 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5105 self.assertEqual(0x123456789abcdef, fent.flags)
5106 self.assertEqual(ATF_BL31_DATA, fent.data)
5107 self.assertEqual(True, fent.valid)
5108
5109 fent = fents[1]
5110 self.assertEqual(
5111 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5112 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5113 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5114 self.assertEqual(0x8c, fent.offset)
5115 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5116 self.assertEqual(0, fent.flags)
5117 self.assertEqual(ATF_BL2U_DATA, fent.data)
5118 self.assertEqual(True, fent.valid)
5119
5120 def testFipOther(self):
5121 """Basic FIP with something that isn't a external blob"""
5122 data = self._DoReadFile('204_fip_other.dts')
5123 hdr, fents = fip_util.decode_fip(data)
5124
5125 self.assertEqual(2, len(fents))
5126 fent = fents[1]
5127 self.assertEqual('rot-cert', fent.fip_type)
5128 self.assertEqual(b'aa', fent.data)
5129
Simon Glass3efb2972021-11-23 21:08:59 -07005130 def testFipNoType(self):
5131 """FIP with an entry of an unknown type"""
5132 with self.assertRaises(ValueError) as e:
5133 self._DoReadFile('205_fip_no_type.dts')
5134 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5135 str(e.exception))
5136
5137 def testFipUuid(self):
5138 """Basic FIP with a manual uuid"""
5139 data = self._DoReadFile('206_fip_uuid.dts')
5140 hdr, fents = fip_util.decode_fip(data)
5141
5142 self.assertEqual(2, len(fents))
5143 fent = fents[1]
5144 self.assertEqual(None, fent.fip_type)
5145 self.assertEqual(
5146 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5147 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5148 fent.uuid)
5149 self.assertEqual(U_BOOT_DATA, fent.data)
5150
5151 def testFipLs(self):
5152 """Test listing a FIP"""
5153 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5154 hdr, fents = fip_util.decode_fip(data)
5155
5156 try:
5157 tmpdir, updated_fname = self._SetupImageInTmpdir()
5158 with test_util.capture_sys_output() as (stdout, stderr):
5159 self._DoBinman('ls', '-i', updated_fname)
5160 finally:
5161 shutil.rmtree(tmpdir)
5162 lines = stdout.getvalue().splitlines()
5163 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005164'Name Image-pos Size Entry-type Offset Uncomp-size',
5165'--------------------------------------------------------------',
5166'image 0 2d3 section 0',
5167' atf-fip 0 90 atf-fip 0',
5168' soc-fw 88 4 blob-ext 88',
5169' u-boot 8c 4 u-boot 8c',
5170' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005171]
5172 self.assertEqual(expected, lines)
5173
5174 image = control.images['image']
5175 entries = image.GetEntries()
5176 fdtmap = entries['fdtmap']
5177
5178 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5179 magic = fdtmap_data[:8]
5180 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005181 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005182
5183 fdt_data = fdtmap_data[16:]
5184 dtb = fdt.Fdt.FromData(fdt_data)
5185 dtb.Scan()
5186 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5187 self.assertEqual({
5188 'atf-fip/soc-fw:image-pos': 136,
5189 'atf-fip/soc-fw:offset': 136,
5190 'atf-fip/soc-fw:size': 4,
5191 'atf-fip/u-boot:image-pos': 140,
5192 'atf-fip/u-boot:offset': 140,
5193 'atf-fip/u-boot:size': 4,
5194 'atf-fip:image-pos': 0,
5195 'atf-fip:offset': 0,
5196 'atf-fip:size': 144,
5197 'image-pos': 0,
5198 'offset': 0,
5199 'fdtmap:image-pos': fdtmap.image_pos,
5200 'fdtmap:offset': fdtmap.offset,
5201 'fdtmap:size': len(fdtmap_data),
5202 'size': len(data),
5203 }, props)
5204
5205 def testFipExtractOneEntry(self):
5206 """Test extracting a single entry fron an FIP"""
5207 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005208 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005209 fname = os.path.join(self._indir, 'output.extact')
5210 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005211 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005212 self.assertEqual(U_BOOT_DATA, data)
5213
5214 def testFipReplace(self):
5215 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005216 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005217 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005218 updated_fname = tools.get_output_filename('image-updated.bin')
5219 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005220 entry_name = 'atf-fip/u-boot'
5221 control.WriteEntry(updated_fname, entry_name, expected,
5222 allow_resize=True)
5223 actual = control.ReadEntry(updated_fname, entry_name)
5224 self.assertEqual(expected, actual)
5225
Simon Glass80025522022-01-29 14:14:04 -07005226 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005227 hdr, fents = fip_util.decode_fip(new_data)
5228
5229 self.assertEqual(2, len(fents))
5230
5231 # Check that the FIP entry is updated
5232 fent = fents[1]
5233 self.assertEqual(0x8c, fent.offset)
5234 self.assertEqual(len(expected), fent.size)
5235 self.assertEqual(0, fent.flags)
5236 self.assertEqual(expected, fent.data)
5237 self.assertEqual(True, fent.valid)
5238
5239 def testFipMissing(self):
5240 with test_util.capture_sys_output() as (stdout, stderr):
5241 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5242 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005243 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005244
5245 def testFipSize(self):
5246 """Test a FIP with a size property"""
5247 data = self._DoReadFile('210_fip_size.dts')
5248 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5249 hdr, fents = fip_util.decode_fip(data)
5250 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5251 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5252
5253 self.assertEqual(1, len(fents))
5254
5255 fent = fents[0]
5256 self.assertEqual('soc-fw', fent.fip_type)
5257 self.assertEqual(0x60, fent.offset)
5258 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5259 self.assertEqual(ATF_BL31_DATA, fent.data)
5260 self.assertEqual(True, fent.valid)
5261
5262 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005263 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005264
5265 def testFipBadAlign(self):
5266 """Test that an invalid alignment value in a FIP is detected"""
5267 with self.assertRaises(ValueError) as e:
5268 self._DoTestFile('211_fip_bad_align.dts')
5269 self.assertIn(
5270 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5271 str(e.exception))
5272
5273 def testFipCollection(self):
5274 """Test using a FIP in a collection"""
5275 data = self._DoReadFile('212_fip_collection.dts')
5276 entry1 = control.images['image'].GetEntries()['collection']
5277 data1 = data[:entry1.size]
5278 hdr1, fents2 = fip_util.decode_fip(data1)
5279
5280 entry2 = control.images['image'].GetEntries()['atf-fip']
5281 data2 = data[entry2.offset:entry2.offset + entry2.size]
5282 hdr1, fents2 = fip_util.decode_fip(data2)
5283
5284 # The 'collection' entry should have U-Boot included at the end
5285 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5286 self.assertEqual(data1, data2 + U_BOOT_DATA)
5287 self.assertEqual(U_BOOT_DATA, data1[-4:])
5288
5289 # There should be a U-Boot after the final FIP
5290 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005291
Simon Glassccae6862022-01-12 13:10:35 -07005292 def testFakeBlob(self):
5293 """Test handling of faking an external blob"""
5294 with test_util.capture_sys_output() as (stdout, stderr):
5295 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5296 allow_fake_blobs=True)
5297 err = stderr.getvalue()
5298 self.assertRegex(
5299 err,
5300 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005301
Simon Glassceb5f912022-01-09 20:13:46 -07005302 def testExtblobListFaked(self):
5303 """Test an extblob with missing external blob that are faked"""
5304 with test_util.capture_sys_output() as (stdout, stderr):
5305 self._DoTestFile('216_blob_ext_list_missing.dts',
5306 allow_fake_blobs=True)
5307 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005308 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005309
Simon Glass162017b2022-01-09 20:13:57 -07005310 def testListBintools(self):
5311 args = ['tool', '--list']
5312 with test_util.capture_sys_output() as (stdout, _):
5313 self._DoBinman(*args)
5314 out = stdout.getvalue().splitlines()
5315 self.assertTrue(len(out) >= 2)
5316
5317 def testFetchBintools(self):
5318 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005319 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005320 raise urllib.error.URLError('my error')
5321
5322 args = ['tool']
5323 with self.assertRaises(ValueError) as e:
5324 self._DoBinman(*args)
5325 self.assertIn("Invalid arguments to 'tool' subcommand",
5326 str(e.exception))
5327
5328 args = ['tool', '--fetch']
5329 with self.assertRaises(ValueError) as e:
5330 self._DoBinman(*args)
5331 self.assertIn('Please specify bintools to fetch', str(e.exception))
5332
5333 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005334 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005335 side_effect=fail_download):
5336 with test_util.capture_sys_output() as (stdout, _):
5337 self._DoBinman(*args)
5338 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5339
Simon Glass620c4462022-01-09 20:14:11 -07005340 def testBintoolDocs(self):
5341 """Test for creation of bintool documentation"""
5342 with test_util.capture_sys_output() as (stdout, stderr):
5343 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5344 self.assertTrue(len(stdout.getvalue()) > 0)
5345
5346 def testBintoolDocsMissing(self):
5347 """Test handling of missing bintool documentation"""
5348 with self.assertRaises(ValueError) as e:
5349 with test_util.capture_sys_output() as (stdout, stderr):
5350 control.write_bintool_docs(
5351 control.bintool.Bintool.get_tool_list(), 'mkimage')
5352 self.assertIn('Documentation is missing for modules: mkimage',
5353 str(e.exception))
5354
Jan Kiszka58c407f2022-01-28 20:37:53 +01005355 def testListWithGenNode(self):
5356 """Check handling of an FDT map when the section cannot be found"""
5357 entry_args = {
5358 'of-list': 'test-fdt1 test-fdt2',
5359 }
5360 data = self._DoReadFileDtb(
5361 '219_fit_gennode.dts',
5362 entry_args=entry_args,
5363 use_real_dtb=True,
5364 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5365
5366 try:
5367 tmpdir, updated_fname = self._SetupImageInTmpdir()
5368 with test_util.capture_sys_output() as (stdout, stderr):
5369 self._RunBinman('ls', '-i', updated_fname)
5370 finally:
5371 shutil.rmtree(tmpdir)
5372
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005373 def testFitSubentryUsesBintool(self):
5374 """Test that binman FIT subentries can use bintools"""
5375 command.test_result = self._HandleGbbCommand
5376 entry_args = {
5377 'keydir': 'devkeys',
5378 'bmpblk': 'bmpblk.bin',
5379 }
5380 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5381 entry_args=entry_args)
5382
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005383 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5384 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005385 self.assertIn(expected, data)
5386
5387 def testFitSubentryMissingBintool(self):
5388 """Test that binman reports missing bintools for FIT subentries"""
5389 entry_args = {
5390 'keydir': 'devkeys',
5391 }
5392 with test_util.capture_sys_output() as (_, stderr):
5393 self._DoTestFile('220_fit_subentry_bintool.dts',
5394 force_missing_bintools='futility', entry_args=entry_args)
5395 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005396 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005397
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005398 def testFitSubentryHashSubnode(self):
5399 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005400 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005401 data, _, _, out_dtb_name = self._DoReadFileDtb(
5402 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5403
5404 mkimage_dtb = fdt.Fdt.FromData(data)
5405 mkimage_dtb.Scan()
5406 binman_dtb = fdt.Fdt(out_dtb_name)
5407 binman_dtb.Scan()
5408
5409 # Check that binman didn't add hash values
5410 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5411 self.assertNotIn('value', fnode.props)
5412
5413 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5414 self.assertNotIn('value', fnode.props)
5415
5416 # Check that mkimage added hash values
5417 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5418 self.assertIn('value', fnode.props)
5419
5420 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5421 self.assertIn('value', fnode.props)
5422
Roger Quadros5cdcea02022-02-19 20:50:04 +02005423 def testPackTeeOs(self):
5424 """Test that an image with an TEE binary can be created"""
5425 data = self._DoReadFile('222_tee_os.dts')
5426 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5427
Simon Glass912339f2022-02-08 11:50:03 -07005428 def testFitFdtOper(self):
5429 """Check handling of a specified FIT operation"""
5430 entry_args = {
5431 'of-list': 'test-fdt1 test-fdt2',
5432 'default-dt': 'test-fdt2',
5433 }
5434 self._DoReadFileDtb(
5435 '223_fit_fdt_oper.dts',
5436 entry_args=entry_args,
5437 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5438
5439 def testFitFdtBadOper(self):
5440 """Check handling of an FDT map when the section cannot be found"""
5441 with self.assertRaises(ValueError) as exc:
5442 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005443 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005444 str(exc.exception))
5445
Simon Glassdd156a42022-03-05 20:18:59 -07005446 def test_uses_expand_size(self):
5447 """Test that the 'expand-size' property cannot be used anymore"""
5448 with self.assertRaises(ValueError) as e:
5449 data = self._DoReadFile('225_expand_size_bad.dts')
5450 self.assertIn(
5451 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5452 str(e.exception))
5453
Simon Glass5f423422022-03-05 20:19:12 -07005454 def testFitSplitElf(self):
5455 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005456 if not elf.ELF_TOOLS:
5457 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005458 entry_args = {
5459 'of-list': 'test-fdt1 test-fdt2',
5460 'default-dt': 'test-fdt2',
5461 'atf-bl31-path': 'bl31.elf',
5462 'tee-os-path': 'tee.elf',
5463 }
5464 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5465 data = self._DoReadFileDtb(
5466 '226_fit_split_elf.dts',
5467 entry_args=entry_args,
5468 extra_indirs=[test_subdir])[0]
5469
5470 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5471 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5472
5473 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5474 'data', 'load'}
5475 dtb = fdt.Fdt.FromData(fit_data)
5476 dtb.Scan()
5477
5478 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5479 segments, entry = elf.read_loadable_segments(elf_data)
5480
5481 # We assume there are two segments
5482 self.assertEquals(2, len(segments))
5483
5484 atf1 = dtb.GetNode('/images/atf-1')
5485 _, start, data = segments[0]
5486 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5487 self.assertEqual(entry,
5488 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5489 self.assertEqual(start,
5490 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5491 self.assertEqual(data, atf1.props['data'].bytes)
5492
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005493 hash_node = atf1.FindNode('hash')
5494 self.assertIsNotNone(hash_node)
5495 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5496
Simon Glass5f423422022-03-05 20:19:12 -07005497 atf2 = dtb.GetNode('/images/atf-2')
5498 self.assertEqual(base_keys, atf2.props.keys())
5499 _, start, data = segments[1]
5500 self.assertEqual(start,
5501 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5502 self.assertEqual(data, atf2.props['data'].bytes)
5503
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005504 hash_node = atf2.FindNode('hash')
5505 self.assertIsNotNone(hash_node)
5506 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5507
5508 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5509 self.assertIsNotNone(hash_node)
5510 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5511
Simon Glass5f423422022-03-05 20:19:12 -07005512 conf = dtb.GetNode('/configurations')
5513 self.assertEqual({'default'}, conf.props.keys())
5514
5515 for subnode in conf.subnodes:
5516 self.assertEqual({'description', 'fdt', 'loadables'},
5517 subnode.props.keys())
5518 self.assertEqual(
5519 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5520 fdt_util.GetStringList(subnode, 'loadables'))
5521
5522 def _check_bad_fit(self, dts):
5523 """Check a bad FIT
5524
5525 This runs with the given dts and returns the assertion raised
5526
5527 Args:
5528 dts (str): dts filename to use
5529
5530 Returns:
5531 str: Assertion string raised
5532 """
5533 entry_args = {
5534 'of-list': 'test-fdt1 test-fdt2',
5535 'default-dt': 'test-fdt2',
5536 'atf-bl31-path': 'bl31.elf',
5537 'tee-os-path': 'tee.elf',
5538 }
5539 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5540 with self.assertRaises(ValueError) as exc:
5541 self._DoReadFileDtb(dts, entry_args=entry_args,
5542 extra_indirs=[test_subdir])[0]
5543 return str(exc.exception)
5544
5545 def testFitSplitElfBadElf(self):
5546 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005547 if not elf.ELF_TOOLS:
5548 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005549 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5550 entry_args = {
5551 'of-list': 'test-fdt1 test-fdt2',
5552 'default-dt': 'test-fdt2',
5553 'atf-bl31-path': 'bad.elf',
5554 'tee-os-path': 'tee.elf',
5555 }
5556 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5557 with self.assertRaises(ValueError) as exc:
5558 self._DoReadFileDtb(
5559 '226_fit_split_elf.dts',
5560 entry_args=entry_args,
5561 extra_indirs=[test_subdir])[0]
5562 self.assertIn(
5563 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5564 str(exc.exception))
5565
Simon Glass5f423422022-03-05 20:19:12 -07005566 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005567 """Test an split-elf FIT with a missing ELF file
5568
5569 Args:
5570 kwargs (dict of str): Arguments to pass to _DoTestFile()
5571
5572 Returns:
5573 tuple:
5574 str: stdout result
5575 str: stderr result
5576 """
Simon Glass5f423422022-03-05 20:19:12 -07005577 entry_args = {
5578 'of-list': 'test-fdt1 test-fdt2',
5579 'default-dt': 'test-fdt2',
5580 'atf-bl31-path': 'bl31.elf',
5581 'tee-os-path': 'missing.elf',
5582 }
5583 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5584 with test_util.capture_sys_output() as (stdout, stderr):
5585 self._DoTestFile(
5586 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005587 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5588 out = stdout.getvalue()
5589 err = stderr.getvalue()
5590 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005591
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005592 def testFitSplitElfBadDirective(self):
5593 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5594 if not elf.ELF_TOOLS:
5595 self.skipTest('Python elftools not available')
5596 err = self._check_bad_fit('227_fit_bad_dir.dts')
5597 self.assertIn(
5598 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5599 err)
5600
5601 def testFitSplitElfBadDirectiveConfig(self):
5602 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5603 if not elf.ELF_TOOLS:
5604 self.skipTest('Python elftools not available')
5605 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5606 self.assertEqual(
5607 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5608 err)
5609
5610
Simon Glass5f423422022-03-05 20:19:12 -07005611 def testFitSplitElfMissing(self):
5612 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005613 if not elf.ELF_TOOLS:
5614 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005615 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005616 self.assertRegex(
5617 err,
5618 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005619 self.assertNotRegex(out, '.*Faked blob.*')
5620 fname = tools.get_output_filename('binman-fake/missing.elf')
5621 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005622
5623 def testFitSplitElfFaked(self):
5624 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005625 if not elf.ELF_TOOLS:
5626 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005627 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005628 self.assertRegex(
5629 err,
5630 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005631 self.assertRegex(
5632 out,
5633 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5634 fname = tools.get_output_filename('binman-fake/missing.elf')
5635 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005636
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005637 def testMkimageMissingBlob(self):
5638 """Test using mkimage to build an image"""
5639 with test_util.capture_sys_output() as (stdout, stderr):
5640 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5641 allow_fake_blobs=True)
5642 err = stderr.getvalue()
5643 self.assertRegex(
5644 err,
5645 "Image '.*' has faked external blobs and is non-functional: .*")
5646
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005647 def testPreLoad(self):
5648 """Test an image with a pre-load header"""
5649 entry_args = {
Simon Glasse2dfb962023-07-24 09:19:57 -06005650 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005651 }
Simon Glasse2dfb962023-07-24 09:19:57 -06005652 data = self._DoReadFileDtb(
5653 '230_pre_load.dts', entry_args=entry_args,
5654 extra_indirs=[os.path.join(self._binman_dir, 'test')])[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005655 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5656 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5657 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Simon Glasse2dfb962023-07-24 09:19:57 -06005658
5659 def testPreLoadNoKey(self):
5660 """Test an image with a pre-load heade0r with missing key"""
5661 with self.assertRaises(FileNotFoundError) as exc:
5662 self._DoReadFile('230_pre_load.dts')
5663 self.assertIn("No such file or directory: 'dev.key'",
5664 str(exc.exception))
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005665
5666 def testPreLoadPkcs(self):
5667 """Test an image with a pre-load header with padding pkcs"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005668 entry_args = {
5669 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5670 }
5671 data = self._DoReadFileDtb('231_pre_load_pkcs.dts',
5672 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005673 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5674 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5675 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5676
5677 def testPreLoadPss(self):
5678 """Test an image with a pre-load header with padding pss"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005679 entry_args = {
5680 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5681 }
5682 data = self._DoReadFileDtb('232_pre_load_pss.dts',
5683 entry_args=entry_args)[0]
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005684 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5685 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5686 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5687
5688 def testPreLoadInvalidPadding(self):
5689 """Test an image with a pre-load header with an invalid padding"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005690 entry_args = {
5691 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5692 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005693 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005694 self._DoReadFileDtb('233_pre_load_invalid_padding.dts',
5695 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005696
5697 def testPreLoadInvalidSha(self):
5698 """Test an image with a pre-load header with an invalid hash"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005699 entry_args = {
5700 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5701 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005702 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005703 self._DoReadFileDtb('234_pre_load_invalid_sha.dts',
5704 entry_args=entry_args)
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005705
5706 def testPreLoadInvalidAlgo(self):
5707 """Test an image with a pre-load header with an invalid algo"""
5708 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005709 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005710
5711 def testPreLoadInvalidKey(self):
5712 """Test an image with a pre-load header with an invalid key"""
Simon Glasse2dfb962023-07-24 09:19:57 -06005713 entry_args = {
5714 'pre-load-key-path': os.path.join(self._binman_dir, 'test'),
5715 }
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005716 with self.assertRaises(ValueError) as e:
Simon Glasse2dfb962023-07-24 09:19:57 -06005717 data = self._DoReadFileDtb('236_pre_load_invalid_key.dts',
5718 entry_args=entry_args)
Roger Quadros5cdcea02022-02-19 20:50:04 +02005719
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005720 def _CheckSafeUniqueNames(self, *images):
5721 """Check all entries of given images for unsafe unique names"""
5722 for image in images:
5723 entries = {}
5724 image._CollectEntries(entries, {}, image)
5725 for entry in entries.values():
5726 uniq = entry.GetUniqueName()
5727
5728 # Used as part of a filename, so must not be absolute paths.
5729 self.assertFalse(os.path.isabs(uniq))
5730
5731 def testSafeUniqueNames(self):
5732 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005733 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005734
5735 orig_image = control.images['image']
5736 image_fname = tools.get_output_filename('image.bin')
5737 image = Image.FromFile(image_fname)
5738
5739 self._CheckSafeUniqueNames(orig_image, image)
5740
5741 def testSafeUniqueNamesMulti(self):
5742 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005743 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005744
5745 orig_image = control.images['image']
5746 image_fname = tools.get_output_filename('image.bin')
5747 image = Image.FromFile(image_fname)
5748
5749 self._CheckSafeUniqueNames(orig_image, image)
5750
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005751 def testReplaceCmdWithBintool(self):
5752 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005753 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005754 expected = U_BOOT_DATA + b'aa'
5755 self.assertEqual(expected, data[:len(expected)])
5756
5757 try:
5758 tmpdir, updated_fname = self._SetupImageInTmpdir()
5759 fname = os.path.join(tmpdir, 'update-testing.bin')
5760 tools.write_file(fname, b'zz')
5761 self._DoBinman('replace', '-i', updated_fname,
5762 '_testing', '-f', fname)
5763
5764 data = tools.read_file(updated_fname)
5765 expected = U_BOOT_DATA + b'zz'
5766 self.assertEqual(expected, data[:len(expected)])
5767 finally:
5768 shutil.rmtree(tmpdir)
5769
5770 def testReplaceCmdOtherWithBintool(self):
5771 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005772 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005773 expected = U_BOOT_DATA + b'aa'
5774 self.assertEqual(expected, data[:len(expected)])
5775
5776 try:
5777 tmpdir, updated_fname = self._SetupImageInTmpdir()
5778 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5779 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5780 self._DoBinman('replace', '-i', updated_fname,
5781 'u-boot', '-f', fname)
5782
5783 data = tools.read_file(updated_fname)
5784 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5785 self.assertEqual(expected, data[:len(expected)])
5786 finally:
5787 shutil.rmtree(tmpdir)
5788
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005789 def testReplaceResizeNoRepackSameSize(self):
5790 """Test replacing entries with same-size data without repacking"""
5791 expected = b'x' * len(U_BOOT_DATA)
5792 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5793 self.assertEqual(expected, data)
5794
5795 path, fdtmap = state.GetFdtContents('fdtmap')
5796 self.assertIsNotNone(path)
5797 self.assertEqual(expected_fdtmap, fdtmap)
5798
5799 def testReplaceResizeNoRepackSmallerSize(self):
5800 """Test replacing entries with smaller-size data without repacking"""
5801 new_data = b'x'
5802 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5803 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5804 self.assertEqual(expected, data)
5805
5806 path, fdtmap = state.GetFdtContents('fdtmap')
5807 self.assertIsNotNone(path)
5808 self.assertEqual(expected_fdtmap, fdtmap)
5809
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005810 def testExtractFit(self):
5811 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005812 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005813 image_fname = tools.get_output_filename('image.bin')
5814
5815 fit_data = control.ReadEntry(image_fname, 'fit')
5816 fit = fdt.Fdt.FromData(fit_data)
5817 fit.Scan()
5818
5819 # Check subentry data inside the extracted fit
5820 for node_path, expected in [
5821 ('/images/kernel', U_BOOT_DATA),
5822 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5823 ('/images/scr-1', COMPRESS_DATA),
5824 ]:
5825 node = fit.GetNode(node_path)
5826 data = fit.GetProps(node)['data'].bytes
5827 self.assertEqual(expected, data)
5828
5829 def testExtractFitSubentries(self):
5830 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005831 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005832 image_fname = tools.get_output_filename('image.bin')
5833
5834 for entry_path, expected in [
5835 ('fit/kernel', U_BOOT_DATA),
5836 ('fit/kernel/u-boot', U_BOOT_DATA),
5837 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5838 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5839 ('fit/scr-1', COMPRESS_DATA),
5840 ('fit/scr-1/blob', COMPRESS_DATA),
5841 ]:
5842 data = control.ReadEntry(image_fname, entry_path)
5843 self.assertEqual(expected, data)
5844
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005845 def testReplaceFitSubentryLeafSameSize(self):
5846 """Test replacing a FIT leaf subentry with same-size data"""
5847 new_data = b'x' * len(U_BOOT_DATA)
5848 data, expected_fdtmap, _ = self._RunReplaceCmd(
5849 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005850 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005851 self.assertEqual(new_data, data)
5852
5853 path, fdtmap = state.GetFdtContents('fdtmap')
5854 self.assertIsNotNone(path)
5855 self.assertEqual(expected_fdtmap, fdtmap)
5856
5857 def testReplaceFitSubentryLeafBiggerSize(self):
5858 """Test replacing a FIT leaf subentry with bigger-size data"""
5859 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5860 data, expected_fdtmap, _ = self._RunReplaceCmd(
5861 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005862 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005863 self.assertEqual(new_data, data)
5864
5865 # Will be repacked, so fdtmap must change
5866 path, fdtmap = state.GetFdtContents('fdtmap')
5867 self.assertIsNotNone(path)
5868 self.assertNotEqual(expected_fdtmap, fdtmap)
5869
5870 def testReplaceFitSubentryLeafSmallerSize(self):
5871 """Test replacing a FIT leaf subentry with smaller-size data"""
5872 new_data = b'x'
5873 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5874 data, expected_fdtmap, _ = self._RunReplaceCmd(
5875 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005876 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005877 self.assertEqual(expected, data)
5878
5879 path, fdtmap = state.GetFdtContents('fdtmap')
5880 self.assertIsNotNone(path)
5881 self.assertEqual(expected_fdtmap, fdtmap)
5882
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005883 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005884 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005885 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005886 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5887 new_data, dts='241_replace_section_simple.dts')
5888 self.assertEqual(new_data, data)
5889
5890 entries = image.GetEntries()
5891 self.assertIn('section', entries)
5892 entry = entries['section']
5893 self.assertEqual(len(new_data), entry.size)
5894
5895 def testReplaceSectionLarger(self):
5896 """Test replacing a simple section with larger data"""
5897 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5898 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5899 new_data, dts='241_replace_section_simple.dts')
5900 self.assertEqual(new_data, data)
5901
5902 entries = image.GetEntries()
5903 self.assertIn('section', entries)
5904 entry = entries['section']
5905 self.assertEqual(len(new_data), entry.size)
5906 fentry = entries['fdtmap']
5907 self.assertEqual(entry.offset + entry.size, fentry.offset)
5908
5909 def testReplaceSectionSmaller(self):
5910 """Test replacing a simple section with smaller data"""
5911 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5912 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5913 new_data, dts='241_replace_section_simple.dts')
5914 self.assertEqual(new_data, data)
5915
5916 # The new size is the same as the old, just with a pad byte at the end
5917 entries = image.GetEntries()
5918 self.assertIn('section', entries)
5919 entry = entries['section']
5920 self.assertEqual(len(new_data), entry.size)
5921
5922 def testReplaceSectionSmallerAllow(self):
5923 """Test failing to replace a simple section with smaller data"""
5924 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5925 try:
5926 state.SetAllowEntryContraction(True)
5927 with self.assertRaises(ValueError) as exc:
5928 self._RunReplaceCmd('section', new_data,
5929 dts='241_replace_section_simple.dts')
5930 finally:
5931 state.SetAllowEntryContraction(False)
5932
5933 # Since we have no information about the position of things within the
5934 # section, we cannot adjust the position of /section-u-boot so it ends
5935 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06005936 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07005937 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5938 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06005939 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005940
Simon Glass8fbca772022-08-13 11:40:48 -06005941 def testMkimageImagename(self):
5942 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005943 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005944 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005945
5946 # Check that the data appears in the file somewhere
5947 self.assertIn(U_BOOT_SPL_DATA, data)
5948
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005949 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005950 name = data[0x20:0x40]
5951
5952 # Build the filename that we expect to be placed in there, by virtue of
5953 # the -n paraameter
5954 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5955
5956 # Check that the image name is set to the temporary filename used
5957 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5958
Simon Glassb1669752022-08-13 11:40:49 -06005959 def testMkimageImage(self):
5960 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005961 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005962 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005963
5964 # Check that the data appears in the file somewhere
5965 self.assertIn(U_BOOT_SPL_DATA, data)
5966
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005967 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06005968 name = data[0x20:0x40]
5969
5970 # Build the filename that we expect to be placed in there, by virtue of
5971 # the -n paraameter
5972 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5973
5974 # Check that the image name is set to the temporary filename used
5975 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5976
5977 # Check the corect data is in the imagename file
5978 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5979
5980 def testMkimageImageNoContent(self):
5981 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005982 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06005983 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005984 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005985 self.assertIn('Could not complete processing of contents',
5986 str(exc.exception))
5987
5988 def testMkimageImageBad(self):
5989 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005990 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06005991 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005992 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005993 self.assertIn('Cannot use both imagename node and data-to-imagename',
5994 str(exc.exception))
5995
Simon Glassbd5cd882022-08-13 11:40:50 -06005996 def testCollectionOther(self):
5997 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005998 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005999 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
6000 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
6001 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
6002 data)
6003
6004 def testMkimageCollection(self):
6005 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006006 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006007 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06006008 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
6009 self.assertEqual(expect, data[:len(expect)])
6010
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006011 def testCompressDtbPrependInvalid(self):
6012 """Test that invalid header is detected"""
6013 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006014 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006015 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
6016 "'u-boot-dtb': 'invalid'", str(e.exception))
6017
6018 def testCompressDtbPrependLength(self):
6019 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006020 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02006021 image = control.images['image']
6022 entries = image.GetEntries()
6023 self.assertIn('u-boot-dtb', entries)
6024 u_boot_dtb = entries['u-boot-dtb']
6025 self.assertIn('fdtmap', entries)
6026 fdtmap = entries['fdtmap']
6027
6028 image_fname = tools.get_output_filename('image.bin')
6029 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6030 dtb = fdt.Fdt.FromData(orig)
6031 dtb.Scan()
6032 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6033 expected = {
6034 'u-boot:size': len(U_BOOT_DATA),
6035 'u-boot-dtb:uncomp-size': len(orig),
6036 'u-boot-dtb:size': u_boot_dtb.size,
6037 'fdtmap:size': fdtmap.size,
6038 'size': len(data),
6039 }
6040 self.assertEqual(expected, props)
6041
6042 # Check implementation
6043 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6044 rest = data[len(U_BOOT_DATA):]
6045 comp_data_len = struct.unpack('<I', rest[:4])[0]
6046 comp_data = rest[4:4 + comp_data_len]
6047 orig2 = self._decompress(comp_data)
6048 self.assertEqual(orig, orig2)
6049
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006050 def testInvalidCompress(self):
6051 """Test that invalid compress algorithm is detected"""
6052 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006053 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006054 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6055
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006056 def testCompUtilCompressions(self):
6057 """Test compression algorithms"""
6058 for bintool in self.comp_bintools.values():
6059 self._CheckBintool(bintool)
6060 data = bintool.compress(COMPRESS_DATA)
6061 self.assertNotEqual(COMPRESS_DATA, data)
6062 orig = bintool.decompress(data)
6063 self.assertEquals(COMPRESS_DATA, orig)
6064
6065 def testCompUtilVersions(self):
6066 """Test tool version of compression algorithms"""
6067 for bintool in self.comp_bintools.values():
6068 self._CheckBintool(bintool)
6069 version = bintool.version()
6070 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6071
6072 def testCompUtilPadding(self):
6073 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006074 # Skip zstd because it doesn't support padding
6075 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006076 self._CheckBintool(bintool)
6077 data = bintool.compress(COMPRESS_DATA)
6078 self.assertNotEqual(COMPRESS_DATA, data)
6079 data += tools.get_bytes(0, 64)
6080 orig = bintool.decompress(data)
6081 self.assertEquals(COMPRESS_DATA, orig)
6082
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006083 def testCompressDtbZstd(self):
6084 """Test that zstd compress of device-tree files failed"""
6085 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006086 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006087 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6088 "requires a length header", str(e.exception))
6089
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006090 def testMkimageMultipleDataFiles(self):
6091 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006092 self._SetupSplElf()
6093 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006094 data = self._DoReadFile('252_mkimage_mult_data.dts')
6095 # Size of files are packed in their 4B big-endian format
6096 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6097 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6098 # Size info is always followed by a 4B zero value.
6099 expect += tools.get_bytes(0, 4)
6100 expect += U_BOOT_TPL_DATA
6101 # All but last files are 4B-aligned
6102 align_pad = len(U_BOOT_TPL_DATA) % 4
6103 if align_pad:
6104 expect += tools.get_bytes(0, align_pad)
6105 expect += U_BOOT_SPL_DATA
6106 self.assertEqual(expect, data[-len(expect):])
6107
Marek Vasutf7413f02023-07-18 07:23:58 -06006108 def testMkimageMultipleExpanded(self):
6109 """Test passing multiple files to mkimage in a mkimage entry"""
6110 self._SetupSplElf()
6111 self._SetupTplElf()
6112 entry_args = {
6113 'spl-bss-pad': 'y',
6114 'spl-dtb': 'y',
6115 }
6116 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6117 use_expanded=True, entry_args=entry_args)[0]
6118 pad_len = 10
6119 tpl_expect = U_BOOT_TPL_DATA
6120 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6121 spl_expect += U_BOOT_SPL_DTB_DATA
6122
6123 content = data[0x40:]
6124 lens = struct.unpack('>III', content[:12])
6125
6126 # Size of files are packed in their 4B big-endian format
6127 # Size info is always followed by a 4B zero value.
6128 self.assertEqual(len(tpl_expect), lens[0])
6129 self.assertEqual(len(spl_expect), lens[1])
6130 self.assertEqual(0, lens[2])
6131
6132 rest = content[12:]
6133 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6134
6135 rest = rest[len(tpl_expect):]
6136 align_pad = len(tpl_expect) % 4
6137 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6138 rest = rest[align_pad:]
6139 self.assertEqual(spl_expect, rest)
6140
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006141 def testMkimageMultipleNoContent(self):
6142 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006143 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006144 with self.assertRaises(ValueError) as exc:
6145 self._DoReadFile('253_mkimage_mult_no_content.dts')
6146 self.assertIn('Could not complete processing of contents',
6147 str(exc.exception))
6148
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006149 def testMkimageFilename(self):
6150 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006151 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006152 retcode = self._DoTestFile('254_mkimage_filename.dts')
6153 self.assertEqual(0, retcode)
6154 fname = tools.get_output_filename('mkimage-test.bin')
6155 self.assertTrue(os.path.exists(fname))
6156
Simon Glass56d05412022-02-28 07:16:54 -07006157 def testVpl(self):
6158 """Test that an image with VPL and its device tree can be created"""
6159 # ELF file with a '__bss_size' symbol
6160 self._SetupVplElf()
6161 data = self._DoReadFile('255_u_boot_vpl.dts')
6162 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6163
6164 def testVplNoDtb(self):
6165 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6166 self._SetupVplElf()
6167 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6168 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6169 data[:len(U_BOOT_VPL_NODTB_DATA)])
6170
6171 def testExpandedVpl(self):
6172 """Test that an expanded entry type is selected for TPL when needed"""
6173 self._SetupVplElf()
6174
6175 entry_args = {
6176 'vpl-bss-pad': 'y',
6177 'vpl-dtb': 'y',
6178 }
6179 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6180 entry_args=entry_args)
6181 image = control.images['image']
6182 entries = image.GetEntries()
6183 self.assertEqual(1, len(entries))
6184
6185 # We only have u-boot-vpl, which be expanded
6186 self.assertIn('u-boot-vpl', entries)
6187 entry = entries['u-boot-vpl']
6188 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6189 subent = entry.GetEntries()
6190 self.assertEqual(3, len(subent))
6191 self.assertIn('u-boot-vpl-nodtb', subent)
6192 self.assertIn('u-boot-vpl-bss-pad', subent)
6193 self.assertIn('u-boot-vpl-dtb', subent)
6194
6195 def testVplBssPadMissing(self):
6196 """Test that a missing symbol is detected"""
6197 self._SetupVplElf('u_boot_ucode_ptr')
6198 with self.assertRaises(ValueError) as e:
6199 self._DoReadFile('258_vpl_bss_pad.dts')
6200 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6201 str(e.exception))
6202
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306203 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306204 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306205 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6206 self.assertEqual(0, retcode)
6207 image = control.images['test_image']
6208 fname = tools.get_output_filename('test_image.bin')
6209 sname = tools.get_output_filename('symlink_to_test.bin')
6210 self.assertTrue(os.path.islink(sname))
6211 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006212
Andrew Davis6b463da2023-07-22 00:14:44 +05306213 def testSymlinkOverwrite(self):
6214 """Test that symlinked images can be overwritten"""
6215 testdir = TestFunctional._MakeInputDir('symlinktest')
6216 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6217 # build the same image again in the same directory so that existing symlink is present
6218 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6219 fname = tools.get_output_filename('test_image.bin')
6220 sname = tools.get_output_filename('symlink_to_test.bin')
6221 self.assertTrue(os.path.islink(sname))
6222 self.assertEqual(os.readlink(sname), fname)
6223
Simon Glass37f85de2022-10-20 18:22:47 -06006224 def testSymbolsElf(self):
6225 """Test binman can assign symbols embedded in an ELF file"""
6226 if not elf.ELF_TOOLS:
6227 self.skipTest('Python elftools not available')
6228 self._SetupTplElf('u_boot_binman_syms')
6229 self._SetupVplElf('u_boot_binman_syms')
6230 self._SetupSplElf('u_boot_binman_syms')
6231 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6232 image_fname = tools.get_output_filename('image.bin')
6233
6234 image = control.images['image']
6235 entries = image.GetEntries()
6236
6237 for entry in entries.values():
6238 # No symbols in u-boot and it has faked contents anyway
6239 if entry.name == 'u-boot':
6240 continue
6241 edata = data[entry.image_pos:entry.image_pos + entry.size]
6242 efname = tools.get_output_filename(f'edata-{entry.name}')
6243 tools.write_file(efname, edata)
6244
6245 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6246 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6247 for name, sym in syms.items():
6248 msg = 'test'
6249 val = elf.GetSymbolValue(sym, edata, msg)
6250 entry_m = re_name.match(name)
6251 if entry_m:
6252 ename, prop = entry_m.group(1), entry_m.group(3)
6253 entry, entry_name, prop_name = image.LookupEntry(entries,
6254 name, msg)
6255 if prop_name == 'offset':
6256 expect_val = entry.offset
6257 elif prop_name == 'image_pos':
6258 expect_val = entry.image_pos
6259 elif prop_name == 'size':
6260 expect_val = entry.size
6261 self.assertEqual(expect_val, val)
6262
6263 def testSymbolsElfBad(self):
6264 """Check error when trying to write symbols without the elftools lib"""
6265 if not elf.ELF_TOOLS:
6266 self.skipTest('Python elftools not available')
6267 self._SetupTplElf('u_boot_binman_syms')
6268 self._SetupVplElf('u_boot_binman_syms')
6269 self._SetupSplElf('u_boot_binman_syms')
6270 try:
6271 elf.ELF_TOOLS = False
6272 with self.assertRaises(ValueError) as exc:
6273 self._DoReadFileDtb('260_symbols_elf.dts')
6274 finally:
6275 elf.ELF_TOOLS = True
6276 self.assertIn(
6277 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6278 'Cannot write symbols to an ELF file without Python elftools',
6279 str(exc.exception))
6280
Simon Glassde244162023-01-07 14:07:08 -07006281 def testSectionFilename(self):
6282 """Check writing of section contents to a file"""
6283 data = self._DoReadFile('261_section_fname.dts')
6284 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6285 tools.get_bytes(ord('!'), 7) +
6286 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6287 self.assertEqual(expected, data)
6288
6289 sect_fname = tools.get_output_filename('outfile.bin')
6290 self.assertTrue(os.path.exists(sect_fname))
6291 sect_data = tools.read_file(sect_fname)
6292 self.assertEqual(U_BOOT_DATA, sect_data)
6293
Simon Glass1e9e61c2023-01-07 14:07:12 -07006294 def testAbsent(self):
6295 """Check handling of absent entries"""
6296 data = self._DoReadFile('262_absent.dts')
6297 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6298
Simon Glassad5cfe12023-01-07 14:07:14 -07006299 def testPackTeeOsOptional(self):
6300 """Test that an image with an optional TEE binary can be created"""
6301 entry_args = {
6302 'tee-os-path': 'tee.elf',
6303 }
6304 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6305 entry_args=entry_args)[0]
6306 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6307
6308 def checkFitTee(self, dts, tee_fname):
6309 """Check that a tee-os entry works and returns data
6310
6311 Args:
6312 dts (str): Device tree filename to use
6313 tee_fname (str): filename containing tee-os
6314
6315 Returns:
6316 bytes: Image contents
6317 """
6318 if not elf.ELF_TOOLS:
6319 self.skipTest('Python elftools not available')
6320 entry_args = {
6321 'of-list': 'test-fdt1 test-fdt2',
6322 'default-dt': 'test-fdt2',
6323 'tee-os-path': tee_fname,
6324 }
6325 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6326 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6327 extra_indirs=[test_subdir])[0]
6328 return data
6329
6330 def testFitTeeOsOptionalFit(self):
6331 """Test an image with a FIT with an optional OP-TEE binary"""
6332 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6333
6334 # There should be only one node, holding the data set up in SetUpClass()
6335 # for tee.bin
6336 dtb = fdt.Fdt.FromData(data)
6337 dtb.Scan()
6338 node = dtb.GetNode('/images/tee-1')
6339 self.assertEqual(TEE_ADDR,
6340 fdt_util.fdt32_to_cpu(node.props['load'].value))
6341 self.assertEqual(TEE_ADDR,
6342 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6343 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6344
6345 def testFitTeeOsOptionalFitBad(self):
6346 """Test an image with a FIT with an optional OP-TEE binary"""
6347 with self.assertRaises(ValueError) as exc:
6348 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6349 self.assertIn(
6350 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6351 str(exc.exception))
6352
6353 def testFitTeeOsBad(self):
6354 """Test an OP-TEE binary with wrong formats"""
6355 self.make_tee_bin('tee.bad1', 123)
6356 with self.assertRaises(ValueError) as exc:
6357 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6358 self.assertIn(
6359 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6360 str(exc.exception))
6361
6362 self.make_tee_bin('tee.bad2', 0, b'extra data')
6363 with self.assertRaises(ValueError) as exc:
6364 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6365 self.assertIn(
6366 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6367 str(exc.exception))
6368
Simon Glass63328f12023-01-07 14:07:15 -07006369 def testExtblobOptional(self):
6370 """Test an image with an external blob that is optional"""
6371 with test_util.capture_sys_output() as (stdout, stderr):
6372 data = self._DoReadFile('266_blob_ext_opt.dts')
6373 self.assertEqual(REFCODE_DATA, data)
6374 err = stderr.getvalue()
6375 self.assertRegex(
6376 err,
6377 "Image '.*' is missing external blobs but is still functional: missing")
6378
Simon Glass7447a9d2023-01-11 16:10:12 -07006379 def testSectionInner(self):
6380 """Test an inner section with a size"""
6381 data = self._DoReadFile('267_section_inner.dts')
6382 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6383 self.assertEqual(expected, data)
6384
Simon Glassa4948b22023-01-11 16:10:14 -07006385 def testNull(self):
6386 """Test an image with a null entry"""
6387 data = self._DoReadFile('268_null.dts')
6388 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6389
Simon Glassf1ee03b2023-01-11 16:10:16 -07006390 def testOverlap(self):
6391 """Test an image with a overlapping entry"""
6392 data = self._DoReadFile('269_overlap.dts')
6393 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6394
6395 image = control.images['image']
6396 entries = image.GetEntries()
6397
6398 self.assertIn('inset', entries)
6399 inset = entries['inset']
6400 self.assertEqual(1, inset.offset);
6401 self.assertEqual(1, inset.image_pos);
6402 self.assertEqual(2, inset.size);
6403
6404 def testOverlapNull(self):
6405 """Test an image with a null overlap"""
6406 data = self._DoReadFile('270_overlap_null.dts')
6407 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6408
6409 # Check the FMAP
6410 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6411 self.assertEqual(4, fhdr.nareas)
6412 fiter = iter(fentries)
6413
6414 fentry = next(fiter)
6415 self.assertEqual(b'SECTION', fentry.name)
6416 self.assertEqual(0, fentry.offset)
6417 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6418 self.assertEqual(0, fentry.flags)
6419
6420 fentry = next(fiter)
6421 self.assertEqual(b'U_BOOT', fentry.name)
6422 self.assertEqual(0, fentry.offset)
6423 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6424 self.assertEqual(0, fentry.flags)
6425
6426 # Make sure that the NULL entry appears in the FMAP
6427 fentry = next(fiter)
6428 self.assertEqual(b'NULL', fentry.name)
6429 self.assertEqual(1, fentry.offset)
6430 self.assertEqual(2, fentry.size)
6431 self.assertEqual(0, fentry.flags)
6432
6433 fentry = next(fiter)
6434 self.assertEqual(b'FMAP', fentry.name)
6435 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6436
6437 def testOverlapBad(self):
6438 """Test an image with a bad overlapping entry"""
6439 with self.assertRaises(ValueError) as exc:
6440 self._DoReadFile('271_overlap_bad.dts')
6441 self.assertIn(
6442 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6443 str(exc.exception))
6444
6445 def testOverlapNoOffset(self):
6446 """Test an image with a bad overlapping entry"""
6447 with self.assertRaises(ValueError) as exc:
6448 self._DoReadFile('272_overlap_no_size.dts')
6449 self.assertIn(
6450 "Node '/binman/inset': 'fill' entry is missing properties: size",
6451 str(exc.exception))
6452
Simon Glasse0035c92023-01-11 16:10:17 -07006453 def testBlobSymbol(self):
6454 """Test a blob with symbols read from an ELF file"""
6455 elf_fname = self.ElfTestFile('blob_syms')
6456 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6457 TestFunctional._MakeInputFile('blob_syms.bin',
6458 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6459
6460 data = self._DoReadFile('273_blob_symbol.dts')
6461
6462 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6463 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6464 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6465 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6466 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6467
6468 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6469 expected = sym_values
6470 self.assertEqual(expected, data[:len(expected)])
6471
Simon Glass49e9c002023-01-11 16:10:19 -07006472 def testOffsetFromElf(self):
6473 """Test a blob with symbols read from an ELF file"""
6474 elf_fname = self.ElfTestFile('blob_syms')
6475 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6476 TestFunctional._MakeInputFile('blob_syms.bin',
6477 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6478
6479 data = self._DoReadFile('274_offset_from_elf.dts')
6480
6481 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6482 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6483
6484 image = control.images['image']
6485 entries = image.GetEntries()
6486
6487 self.assertIn('inset', entries)
6488 inset = entries['inset']
6489
6490 self.assertEqual(base + 4, inset.offset);
6491 self.assertEqual(base + 4, inset.image_pos);
6492 self.assertEqual(4, inset.size);
6493
6494 self.assertIn('inset2', entries)
6495 inset = entries['inset2']
6496 self.assertEqual(base + 8, inset.offset);
6497 self.assertEqual(base + 8, inset.image_pos);
6498 self.assertEqual(4, inset.size);
6499
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006500 def testFitAlign(self):
6501 """Test an image with an FIT with aligned external data"""
6502 data = self._DoReadFile('275_fit_align.dts')
6503 self.assertEqual(4096, len(data))
6504
6505 dtb = fdt.Fdt.FromData(data)
6506 dtb.Scan()
6507
6508 props = self._GetPropTree(dtb, ['data-position'])
6509 expected = {
6510 'u-boot:data-position': 1024,
6511 'fdt-1:data-position': 2048,
6512 'fdt-2:data-position': 3072,
6513 }
6514 self.assertEqual(expected, props)
6515
Jonas Karlman490f73c2023-01-21 19:02:12 +00006516 def testFitFirmwareLoadables(self):
6517 """Test an image with an FIT that use fit,firmware"""
6518 if not elf.ELF_TOOLS:
6519 self.skipTest('Python elftools not available')
6520 entry_args = {
6521 'of-list': 'test-fdt1',
6522 'default-dt': 'test-fdt1',
6523 'atf-bl31-path': 'bl31.elf',
6524 'tee-os-path': 'missing.bin',
6525 }
6526 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006527 with test_util.capture_sys_output() as (stdout, stderr):
6528 data = self._DoReadFileDtb(
6529 '276_fit_firmware_loadables.dts',
6530 entry_args=entry_args,
6531 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006532
6533 dtb = fdt.Fdt.FromData(data)
6534 dtb.Scan()
6535
6536 node = dtb.GetNode('/configurations/conf-uboot-1')
6537 self.assertEqual('u-boot', node.props['firmware'].value)
6538 self.assertEqual(['atf-1', 'atf-2'],
6539 fdt_util.GetStringList(node, 'loadables'))
6540
6541 node = dtb.GetNode('/configurations/conf-atf-1')
6542 self.assertEqual('atf-1', node.props['firmware'].value)
6543 self.assertEqual(['u-boot', 'atf-2'],
6544 fdt_util.GetStringList(node, 'loadables'))
6545
6546 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6547 self.assertEqual('u-boot', node.props['firmware'].value)
6548 self.assertEqual(['atf-1', 'atf-2'],
6549 fdt_util.GetStringList(node, 'loadables'))
6550
6551 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6552 self.assertEqual('atf-1', node.props['firmware'].value)
6553 self.assertEqual(['u-boot', 'atf-2'],
6554 fdt_util.GetStringList(node, 'loadables'))
6555
6556 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6557 self.assertEqual('atf-1', node.props['firmware'].value)
6558 self.assertEqual(['u-boot', 'atf-2'],
6559 fdt_util.GetStringList(node, 'loadables'))
6560
Simon Glass9a1c7262023-02-22 12:14:49 -07006561 def testTooldir(self):
6562 """Test that we can specify the tooldir"""
6563 with test_util.capture_sys_output() as (stdout, stderr):
6564 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6565 'tool', '-l'))
6566 self.assertEqual('fred', bintool.Bintool.tooldir)
6567
6568 # Check that the toolpath is updated correctly
6569 self.assertEqual(['fred'], tools.tool_search_paths)
6570
6571 # Try with a few toolpaths; the tooldir should be at the end
6572 with test_util.capture_sys_output() as (stdout, stderr):
6573 self.assertEqual(0, self._DoBinman(
6574 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6575 'tool', '-l'))
6576 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6577
Simon Glass49b77e82023-03-02 17:02:44 -07006578 def testReplaceSectionEntry(self):
6579 """Test replacing an entry in a section"""
6580 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6581 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6582 expect_data, dts='241_replace_section_simple.dts')
6583 self.assertEqual(expect_data, entry_data)
6584
6585 entries = image.GetEntries()
6586 self.assertIn('section', entries)
6587 section = entries['section']
6588
6589 sect_entries = section.GetEntries()
6590 self.assertIn('blob', sect_entries)
6591 entry = sect_entries['blob']
6592 self.assertEqual(len(expect_data), entry.size)
6593
6594 fname = tools.get_output_filename('image-updated.bin')
6595 data = tools.read_file(fname)
6596
6597 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6598 self.assertEqual(expect_data, new_blob_data)
6599
6600 self.assertEqual(U_BOOT_DATA,
6601 data[entry.image_pos + len(expect_data):]
6602 [:len(U_BOOT_DATA)])
6603
6604 def testReplaceSectionDeep(self):
6605 """Test replacing an entry in two levels of sections"""
6606 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6607 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6608 'section/section/blob', expect_data,
6609 dts='278_replace_section_deep.dts')
6610 self.assertEqual(expect_data, entry_data)
6611
6612 entries = image.GetEntries()
6613 self.assertIn('section', entries)
6614 section = entries['section']
6615
6616 subentries = section.GetEntries()
6617 self.assertIn('section', subentries)
6618 section = subentries['section']
6619
6620 sect_entries = section.GetEntries()
6621 self.assertIn('blob', sect_entries)
6622 entry = sect_entries['blob']
6623 self.assertEqual(len(expect_data), entry.size)
6624
6625 fname = tools.get_output_filename('image-updated.bin')
6626 data = tools.read_file(fname)
6627
6628 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6629 self.assertEqual(expect_data, new_blob_data)
6630
6631 self.assertEqual(U_BOOT_DATA,
6632 data[entry.image_pos + len(expect_data):]
6633 [:len(U_BOOT_DATA)])
6634
6635 def testReplaceFitSibling(self):
6636 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006637 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006638 fname = TestFunctional._MakeInputFile('once', b'available once')
6639 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6640 os.remove(fname)
6641
6642 try:
6643 tmpdir, updated_fname = self._SetupImageInTmpdir()
6644
6645 fname = os.path.join(tmpdir, 'update-blob')
6646 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6647 tools.write_file(fname, expected)
6648
6649 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6650 data = tools.read_file(updated_fname)
6651 start = len(U_BOOT_DTB_DATA)
6652 self.assertEqual(expected, data[start:start + len(expected)])
6653 map_fname = os.path.join(tmpdir, 'image-updated.map')
6654 self.assertFalse(os.path.exists(map_fname))
6655 finally:
6656 shutil.rmtree(tmpdir)
6657
Simon Glassc3fe97f2023-03-02 17:02:45 -07006658 def testX509Cert(self):
6659 """Test creating an X509 certificate"""
6660 keyfile = self.TestFile('key.key')
6661 entry_args = {
6662 'keyfile': keyfile,
6663 }
6664 data = self._DoReadFileDtb('279_x509_cert.dts',
6665 entry_args=entry_args)[0]
6666 cert = data[:-4]
6667 self.assertEqual(U_BOOT_DATA, data[-4:])
6668
6669 # TODO: verify the signature
6670
6671 def testX509CertMissing(self):
6672 """Test that binman still produces an image if openssl is missing"""
6673 keyfile = self.TestFile('key.key')
6674 entry_args = {
6675 'keyfile': 'keyfile',
6676 }
6677 with test_util.capture_sys_output() as (_, stderr):
6678 self._DoTestFile('279_x509_cert.dts',
6679 force_missing_bintools='openssl',
6680 entry_args=entry_args)
6681 err = stderr.getvalue()
6682 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6683
Jonas Karlman35305492023-02-25 19:01:33 +00006684 def testPackRockchipTpl(self):
6685 """Test that an image with a Rockchip TPL binary can be created"""
6686 data = self._DoReadFile('277_rockchip_tpl.dts')
6687 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6688
Jonas Karlman1016ec72023-02-25 19:01:35 +00006689 def testMkimageMissingBlobMultiple(self):
6690 """Test missing blob with mkimage entry and multiple-data-files"""
6691 with test_util.capture_sys_output() as (stdout, stderr):
6692 self._DoTestFile('278_mkimage_missing_multiple.dts', allow_missing=True)
6693 err = stderr.getvalue()
6694 self.assertIn("is missing external blobs and is non-functional", err)
6695
6696 with self.assertRaises(ValueError) as e:
6697 self._DoTestFile('278_mkimage_missing_multiple.dts', allow_missing=False)
6698 self.assertIn("not found in input path", str(e.exception))
6699
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006700 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6701 """Prepare sign environment
6702
6703 Create private and public keys, add pubkey into dtb.
6704
6705 Returns:
6706 Tuple:
6707 FIT container
6708 Image name
6709 Private key
6710 DTB
6711 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006712 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006713 data = self._DoReadFileRealDtb(dts)
6714 updated_fname = tools.get_output_filename('image-updated.bin')
6715 tools.write_file(updated_fname, data)
6716 dtb = tools.get_output_filename('source.dtb')
6717 private_key = tools.get_output_filename('test_key.key')
6718 public_key = tools.get_output_filename('test_key.crt')
6719 fit = tools.get_output_filename('fit.fit')
6720 key_dir = tools.get_output_dir()
6721
6722 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6723 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6724 private_key, '-out', public_key)
6725 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6726 '-n', 'test_key', '-r', 'conf', dtb)
6727
6728 return fit, updated_fname, private_key, dtb
6729
6730 def testSignSimple(self):
6731 """Test that a FIT container can be signed in image"""
6732 is_signed = False
6733 fit, fname, private_key, dtb = self._PrepareSignEnv()
6734
6735 # do sign with private key
6736 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6737 ['fit'])
6738 is_signed = self._CheckSign(fit, dtb)
6739
6740 self.assertEqual(is_signed, True)
6741
6742 def testSignExactFIT(self):
6743 """Test that a FIT container can be signed and replaced in image"""
6744 is_signed = False
6745 fit, fname, private_key, dtb = self._PrepareSignEnv()
6746
6747 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6748 args = []
6749 if self.toolpath:
6750 for path in self.toolpath:
6751 args += ['--toolpath', path]
6752
6753 # do sign with private key
6754 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6755 'sha256,rsa4096', '-f', fit, 'fit')
6756 is_signed = self._CheckSign(fit, dtb)
6757
6758 self.assertEqual(is_signed, True)
6759
6760 def testSignNonFit(self):
6761 """Test a non-FIT entry cannot be signed"""
6762 is_signed = False
6763 fit, fname, private_key, _ = self._PrepareSignEnv(
6764 '281_sign_non_fit.dts')
6765
6766 # do sign with private key
6767 with self.assertRaises(ValueError) as e:
6768 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6769 'sha256,rsa4096', '-f', fit, 'u-boot')
6770 self.assertIn(
6771 "Node '/u-boot': Updating signatures is not supported with this entry type",
6772 str(e.exception))
6773
6774 def testSignMissingMkimage(self):
6775 """Test that FIT signing handles a missing mkimage tool"""
6776 fit, fname, private_key, _ = self._PrepareSignEnv()
6777
6778 # try to sign with a missing mkimage tool
6779 bintool.Bintool.set_missing_list(['mkimage'])
6780 with self.assertRaises(ValueError) as e:
6781 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6782 ['fit'])
6783 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6784
Simon Glass4abf7842023-07-18 07:23:54 -06006785 def testSymbolNoWrite(self):
6786 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006787 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006788 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6789 no_write_symbols=True)
6790
6791 def testSymbolNoWriteExpanded(self):
6792 """Test disabling of symbol writing in expanded entries"""
6793 entry_args = {
6794 'spl-dtb': '1',
6795 }
6796 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6797 U_BOOT_SPL_DTB_DATA, 0x38,
6798 entry_args=entry_args, use_expanded=True,
6799 no_write_symbols=True)
6800
Marek Vasutf7413f02023-07-18 07:23:58 -06006801 def testMkimageSpecial(self):
6802 """Test mkimage ignores special hash-1 node"""
6803 data = self._DoReadFile('283_mkimage_special.dts')
6804
6805 # Just check that the data appears in the file somewhere
6806 self.assertIn(U_BOOT_DATA, data)
6807
Simon Glass2d94c422023-07-18 07:23:59 -06006808 def testFitFdtList(self):
6809 """Test an image with an FIT with the fit,fdt-list-val option"""
6810 entry_args = {
6811 'default-dt': 'test-fdt2',
6812 }
6813 data = self._DoReadFileDtb(
6814 '284_fit_fdt_list.dts',
6815 entry_args=entry_args,
6816 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6817 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6818 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6819
Simon Glass83b8bfe2023-07-18 07:24:01 -06006820 def testSplEmptyBss(self):
6821 """Test an expanded SPL with a zero-size BSS"""
6822 # ELF file with a '__bss_size' symbol
6823 self._SetupSplElf(src_fname='bss_data_zero')
6824
6825 entry_args = {
6826 'spl-bss-pad': 'y',
6827 'spl-dtb': 'y',
6828 }
6829 data = self._DoReadFileDtb('285_spl_expand.dts',
6830 use_expanded=True, entry_args=entry_args)[0]
6831
Simon Glassfc792842023-07-18 07:24:04 -06006832 def testTemplate(self):
6833 """Test using a template"""
6834 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6835 data = self._DoReadFile('286_template.dts')
6836 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6837 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6838 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6839
Simon Glass9909c112023-07-18 07:24:05 -06006840 def testTemplateBlobMulti(self):
6841 """Test using a template with 'multiple-images' enabled"""
6842 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6843 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6844 retcode = self._DoTestFile('287_template_multi.dts')
6845
6846 self.assertEqual(0, retcode)
6847 image = control.images['image']
6848 image_fname = tools.get_output_filename('my-image.bin')
6849 data = tools.read_file(image_fname)
6850 self.assertEqual(b'blob@@@@other', data)
6851
Simon Glass5dc511b2023-07-18 07:24:06 -06006852 def testTemplateFit(self):
6853 """Test using a template in a FIT"""
6854 fit_data = self._DoReadFile('288_template_fit.dts')
6855 fname = os.path.join(self._indir, 'fit_data.fit')
6856 tools.write_file(fname, fit_data)
6857 out = tools.run('dumpimage', '-l', fname)
6858
Simon Glassaa6e0552023-07-18 07:24:07 -06006859 def testTemplateSection(self):
6860 """Test using a template in a section (not at top level)"""
6861 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6862 data = self._DoReadFile('289_template_section.dts')
6863 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6864 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6865 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6866
Simon Glassf53a7bc2023-07-18 07:24:08 -06006867 def testMkimageSymbols(self):
6868 """Test using mkimage to build an image with symbols in it"""
6869 self._SetupSplElf('u_boot_binman_syms')
6870 data = self._DoReadFile('290_mkimage_sym.dts')
6871
6872 image = control.images['image']
6873 entries = image.GetEntries()
6874 self.assertIn('u-boot', entries)
6875 u_boot = entries['u-boot']
6876
6877 mkim = entries['mkimage']
6878 mkim_entries = mkim.GetEntries()
6879 self.assertIn('u-boot-spl', mkim_entries)
6880 spl = mkim_entries['u-boot-spl']
6881 self.assertIn('u-boot-spl2', mkim_entries)
6882 spl2 = mkim_entries['u-boot-spl2']
6883
6884 # skip the mkimage header and the area sizes
6885 mk_data = data[mkim.offset + 0x40:]
6886 size, term = struct.unpack('>LL', mk_data[:8])
6887
6888 # There should be only one image, so check that the zero terminator is
6889 # present
6890 self.assertEqual(0, term)
6891
6892 content = mk_data[8:8 + size]
6893
6894 # The image should contain the symbols from u_boot_binman_syms.c
6895 # Note that image_pos is adjusted by the base address of the image,
6896 # which is 0x10 in our test image
6897 spl_data = content[:0x18]
6898 content = content[0x1b:]
6899
6900 # After the header is a table of offsets for each image. There should
6901 # only be one image, then a 0 terminator, so figure out the real start
6902 # of the image data
6903 base = 0x40 + 8
6904
6905 # Check symbols in both u-boot-spl and u-boot-spl2
6906 for i in range(2):
6907 vals = struct.unpack('<LLQLL', spl_data)
6908
6909 # The image should contain the symbols from u_boot_binman_syms.c
6910 # Note that image_pos is adjusted by the base address of the image,
6911 # which is 0x10 in our 'u_boot_binman_syms' test image
6912 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6913 self.assertEqual(base, vals[1])
6914 self.assertEqual(spl2.offset, vals[2])
6915 # figure out the internal positions of its components
6916 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6917
6918 # Check that spl and spl2 are actually at the indicated positions
6919 self.assertEqual(
6920 elf.BINMAN_SYM_MAGIC_VALUE,
6921 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6922 self.assertEqual(
6923 elf.BINMAN_SYM_MAGIC_VALUE,
6924 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6925
6926 self.assertEqual(len(U_BOOT_DATA), vals[4])
6927
6928 # Move to next
6929 spl_data = content[:0x18]
6930
Neha Malcom Francis3b788942023-07-22 00:14:24 +05306931 def testTIBoardConfig(self):
6932 """Test that a schema validated board config file can be generated"""
6933 data = self._DoReadFile('277_ti_board_cfg.dts')
6934 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
6935
6936 def testTIBoardConfigCombined(self):
6937 """Test that a schema validated combined board config file can be generated"""
6938 data = self._DoReadFile('278_ti_board_cfg_combined.dts')
6939 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
6940 self.assertGreater(data, configlen_noheader)
6941
6942 def testTIBoardConfigNoDataType(self):
6943 """Test that error is thrown when data type is not supported"""
6944 with self.assertRaises(ValueError) as e:
6945 data = self._DoReadFile('279_ti_board_cfg_no_type.dts')
6946 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07006947
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05306948 def testPackTiSecure(self):
6949 """Test that an image with a TI secured binary can be created"""
6950 keyfile = self.TestFile('key.key')
6951 entry_args = {
6952 'keyfile': keyfile,
6953 }
6954 data = self._DoReadFileDtb('279_ti_secure.dts',
6955 entry_args=entry_args)[0]
6956 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
6957
6958 def testPackTiSecureMissingTool(self):
6959 """Test that an image with a TI secured binary (non-functional) can be created
6960 when openssl is missing"""
6961 keyfile = self.TestFile('key.key')
6962 entry_args = {
6963 'keyfile': keyfile,
6964 }
6965 with test_util.capture_sys_output() as (_, stderr):
6966 self._DoTestFile('279_ti_secure.dts',
6967 force_missing_bintools='openssl',
6968 entry_args=entry_args)
6969 err = stderr.getvalue()
6970 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6971
6972 def testPackTiSecureROM(self):
6973 """Test that a ROM image with a TI secured binary can be created"""
6974 keyfile = self.TestFile('key.key')
6975 entry_args = {
6976 'keyfile': keyfile,
6977 }
6978 data = self._DoReadFileDtb('280_ti_secure_rom.dts',
6979 entry_args=entry_args)[0]
6980 data_a = self._DoReadFileDtb('288_ti_secure_rom_a.dts',
6981 entry_args=entry_args)[0]
6982 data_b = self._DoReadFileDtb('289_ti_secure_rom_b.dts',
6983 entry_args=entry_args)[0]
6984 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
6985 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
6986 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
6987
6988 def testPackTiSecureROMCombined(self):
6989 """Test that a ROM image with a TI secured binary can be created"""
6990 keyfile = self.TestFile('key.key')
6991 entry_args = {
6992 'keyfile': keyfile,
6993 }
6994 data = self._DoReadFileDtb('281_ti_secure_rom_combined.dts',
6995 entry_args=entry_args)[0]
6996 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
6997
Simon Glassac599912017-11-12 21:52:22 -07006998if __name__ == "__main__":
6999 unittest.main()