blob: 3e8091e832617b304c994b14e5c282f8220be12d [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 = {
5650 'pre-load-key-path': '.',
5651 }
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005652 data, _, _, _ = self._DoReadFileDtb('230_pre_load.dts',
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005653 entry_args=entry_args)
5654 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5655 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5656 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005657 data = self._DoReadFile('230_pre_load.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005658 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5659 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5660 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5661
5662 def testPreLoadPkcs(self):
5663 """Test an image with a pre-load header with padding pkcs"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005664 data = self._DoReadFile('231_pre_load_pkcs.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005665 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5666 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5667 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5668
5669 def testPreLoadPss(self):
5670 """Test an image with a pre-load header with padding pss"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005671 data = self._DoReadFile('232_pre_load_pss.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005672 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5673 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5674 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5675
5676 def testPreLoadInvalidPadding(self):
5677 """Test an image with a pre-load header with an invalid padding"""
5678 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005679 data = self._DoReadFile('233_pre_load_invalid_padding.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005680
5681 def testPreLoadInvalidSha(self):
5682 """Test an image with a pre-load header with an invalid hash"""
5683 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005684 data = self._DoReadFile('234_pre_load_invalid_sha.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005685
5686 def testPreLoadInvalidAlgo(self):
5687 """Test an image with a pre-load header with an invalid algo"""
5688 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005689 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005690
5691 def testPreLoadInvalidKey(self):
5692 """Test an image with a pre-load header with an invalid key"""
5693 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005694 data = self._DoReadFile('236_pre_load_invalid_key.dts')
Roger Quadros5cdcea02022-02-19 20:50:04 +02005695
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005696 def _CheckSafeUniqueNames(self, *images):
5697 """Check all entries of given images for unsafe unique names"""
5698 for image in images:
5699 entries = {}
5700 image._CollectEntries(entries, {}, image)
5701 for entry in entries.values():
5702 uniq = entry.GetUniqueName()
5703
5704 # Used as part of a filename, so must not be absolute paths.
5705 self.assertFalse(os.path.isabs(uniq))
5706
5707 def testSafeUniqueNames(self):
5708 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005709 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005710
5711 orig_image = control.images['image']
5712 image_fname = tools.get_output_filename('image.bin')
5713 image = Image.FromFile(image_fname)
5714
5715 self._CheckSafeUniqueNames(orig_image, image)
5716
5717 def testSafeUniqueNamesMulti(self):
5718 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005719 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005720
5721 orig_image = control.images['image']
5722 image_fname = tools.get_output_filename('image.bin')
5723 image = Image.FromFile(image_fname)
5724
5725 self._CheckSafeUniqueNames(orig_image, image)
5726
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005727 def testReplaceCmdWithBintool(self):
5728 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005729 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005730 expected = U_BOOT_DATA + b'aa'
5731 self.assertEqual(expected, data[:len(expected)])
5732
5733 try:
5734 tmpdir, updated_fname = self._SetupImageInTmpdir()
5735 fname = os.path.join(tmpdir, 'update-testing.bin')
5736 tools.write_file(fname, b'zz')
5737 self._DoBinman('replace', '-i', updated_fname,
5738 '_testing', '-f', fname)
5739
5740 data = tools.read_file(updated_fname)
5741 expected = U_BOOT_DATA + b'zz'
5742 self.assertEqual(expected, data[:len(expected)])
5743 finally:
5744 shutil.rmtree(tmpdir)
5745
5746 def testReplaceCmdOtherWithBintool(self):
5747 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005748 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005749 expected = U_BOOT_DATA + b'aa'
5750 self.assertEqual(expected, data[:len(expected)])
5751
5752 try:
5753 tmpdir, updated_fname = self._SetupImageInTmpdir()
5754 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5755 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5756 self._DoBinman('replace', '-i', updated_fname,
5757 'u-boot', '-f', fname)
5758
5759 data = tools.read_file(updated_fname)
5760 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5761 self.assertEqual(expected, data[:len(expected)])
5762 finally:
5763 shutil.rmtree(tmpdir)
5764
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005765 def testReplaceResizeNoRepackSameSize(self):
5766 """Test replacing entries with same-size data without repacking"""
5767 expected = b'x' * len(U_BOOT_DATA)
5768 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5769 self.assertEqual(expected, data)
5770
5771 path, fdtmap = state.GetFdtContents('fdtmap')
5772 self.assertIsNotNone(path)
5773 self.assertEqual(expected_fdtmap, fdtmap)
5774
5775 def testReplaceResizeNoRepackSmallerSize(self):
5776 """Test replacing entries with smaller-size data without repacking"""
5777 new_data = b'x'
5778 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5779 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5780 self.assertEqual(expected, data)
5781
5782 path, fdtmap = state.GetFdtContents('fdtmap')
5783 self.assertIsNotNone(path)
5784 self.assertEqual(expected_fdtmap, fdtmap)
5785
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005786 def testExtractFit(self):
5787 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005788 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005789 image_fname = tools.get_output_filename('image.bin')
5790
5791 fit_data = control.ReadEntry(image_fname, 'fit')
5792 fit = fdt.Fdt.FromData(fit_data)
5793 fit.Scan()
5794
5795 # Check subentry data inside the extracted fit
5796 for node_path, expected in [
5797 ('/images/kernel', U_BOOT_DATA),
5798 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5799 ('/images/scr-1', COMPRESS_DATA),
5800 ]:
5801 node = fit.GetNode(node_path)
5802 data = fit.GetProps(node)['data'].bytes
5803 self.assertEqual(expected, data)
5804
5805 def testExtractFitSubentries(self):
5806 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005807 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005808 image_fname = tools.get_output_filename('image.bin')
5809
5810 for entry_path, expected in [
5811 ('fit/kernel', U_BOOT_DATA),
5812 ('fit/kernel/u-boot', U_BOOT_DATA),
5813 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5814 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5815 ('fit/scr-1', COMPRESS_DATA),
5816 ('fit/scr-1/blob', COMPRESS_DATA),
5817 ]:
5818 data = control.ReadEntry(image_fname, entry_path)
5819 self.assertEqual(expected, data)
5820
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005821 def testReplaceFitSubentryLeafSameSize(self):
5822 """Test replacing a FIT leaf subentry with same-size data"""
5823 new_data = b'x' * len(U_BOOT_DATA)
5824 data, expected_fdtmap, _ = self._RunReplaceCmd(
5825 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005826 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005827 self.assertEqual(new_data, data)
5828
5829 path, fdtmap = state.GetFdtContents('fdtmap')
5830 self.assertIsNotNone(path)
5831 self.assertEqual(expected_fdtmap, fdtmap)
5832
5833 def testReplaceFitSubentryLeafBiggerSize(self):
5834 """Test replacing a FIT leaf subentry with bigger-size data"""
5835 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5836 data, expected_fdtmap, _ = self._RunReplaceCmd(
5837 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005838 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005839 self.assertEqual(new_data, data)
5840
5841 # Will be repacked, so fdtmap must change
5842 path, fdtmap = state.GetFdtContents('fdtmap')
5843 self.assertIsNotNone(path)
5844 self.assertNotEqual(expected_fdtmap, fdtmap)
5845
5846 def testReplaceFitSubentryLeafSmallerSize(self):
5847 """Test replacing a FIT leaf subentry with smaller-size data"""
5848 new_data = b'x'
5849 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5850 data, expected_fdtmap, _ = self._RunReplaceCmd(
5851 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005852 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005853 self.assertEqual(expected, data)
5854
5855 path, fdtmap = state.GetFdtContents('fdtmap')
5856 self.assertIsNotNone(path)
5857 self.assertEqual(expected_fdtmap, fdtmap)
5858
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005859 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005860 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005861 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005862 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5863 new_data, dts='241_replace_section_simple.dts')
5864 self.assertEqual(new_data, data)
5865
5866 entries = image.GetEntries()
5867 self.assertIn('section', entries)
5868 entry = entries['section']
5869 self.assertEqual(len(new_data), entry.size)
5870
5871 def testReplaceSectionLarger(self):
5872 """Test replacing a simple section with larger data"""
5873 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5874 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5875 new_data, dts='241_replace_section_simple.dts')
5876 self.assertEqual(new_data, data)
5877
5878 entries = image.GetEntries()
5879 self.assertIn('section', entries)
5880 entry = entries['section']
5881 self.assertEqual(len(new_data), entry.size)
5882 fentry = entries['fdtmap']
5883 self.assertEqual(entry.offset + entry.size, fentry.offset)
5884
5885 def testReplaceSectionSmaller(self):
5886 """Test replacing a simple section with smaller data"""
5887 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5888 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5889 new_data, dts='241_replace_section_simple.dts')
5890 self.assertEqual(new_data, data)
5891
5892 # The new size is the same as the old, just with a pad byte at the end
5893 entries = image.GetEntries()
5894 self.assertIn('section', entries)
5895 entry = entries['section']
5896 self.assertEqual(len(new_data), entry.size)
5897
5898 def testReplaceSectionSmallerAllow(self):
5899 """Test failing to replace a simple section with smaller data"""
5900 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5901 try:
5902 state.SetAllowEntryContraction(True)
5903 with self.assertRaises(ValueError) as exc:
5904 self._RunReplaceCmd('section', new_data,
5905 dts='241_replace_section_simple.dts')
5906 finally:
5907 state.SetAllowEntryContraction(False)
5908
5909 # Since we have no information about the position of things within the
5910 # section, we cannot adjust the position of /section-u-boot so it ends
5911 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06005912 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07005913 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5914 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06005915 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005916
Simon Glass8fbca772022-08-13 11:40:48 -06005917 def testMkimageImagename(self):
5918 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005919 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005920 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005921
5922 # Check that the data appears in the file somewhere
5923 self.assertIn(U_BOOT_SPL_DATA, data)
5924
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005925 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005926 name = data[0x20:0x40]
5927
5928 # Build the filename that we expect to be placed in there, by virtue of
5929 # the -n paraameter
5930 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5931
5932 # Check that the image name is set to the temporary filename used
5933 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5934
Simon Glassb1669752022-08-13 11:40:49 -06005935 def testMkimageImage(self):
5936 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005937 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005938 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005939
5940 # Check that the data appears in the file somewhere
5941 self.assertIn(U_BOOT_SPL_DATA, data)
5942
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005943 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06005944 name = data[0x20:0x40]
5945
5946 # Build the filename that we expect to be placed in there, by virtue of
5947 # the -n paraameter
5948 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5949
5950 # Check that the image name is set to the temporary filename used
5951 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5952
5953 # Check the corect data is in the imagename file
5954 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5955
5956 def testMkimageImageNoContent(self):
5957 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005958 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06005959 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005960 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005961 self.assertIn('Could not complete processing of contents',
5962 str(exc.exception))
5963
5964 def testMkimageImageBad(self):
5965 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005966 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06005967 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005968 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005969 self.assertIn('Cannot use both imagename node and data-to-imagename',
5970 str(exc.exception))
5971
Simon Glassbd5cd882022-08-13 11:40:50 -06005972 def testCollectionOther(self):
5973 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005974 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005975 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5976 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5977 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5978 data)
5979
5980 def testMkimageCollection(self):
5981 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005982 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005983 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005984 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5985 self.assertEqual(expect, data[:len(expect)])
5986
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005987 def testCompressDtbPrependInvalid(self):
5988 """Test that invalid header is detected"""
5989 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005990 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005991 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5992 "'u-boot-dtb': 'invalid'", str(e.exception))
5993
5994 def testCompressDtbPrependLength(self):
5995 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005996 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005997 image = control.images['image']
5998 entries = image.GetEntries()
5999 self.assertIn('u-boot-dtb', entries)
6000 u_boot_dtb = entries['u-boot-dtb']
6001 self.assertIn('fdtmap', entries)
6002 fdtmap = entries['fdtmap']
6003
6004 image_fname = tools.get_output_filename('image.bin')
6005 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6006 dtb = fdt.Fdt.FromData(orig)
6007 dtb.Scan()
6008 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6009 expected = {
6010 'u-boot:size': len(U_BOOT_DATA),
6011 'u-boot-dtb:uncomp-size': len(orig),
6012 'u-boot-dtb:size': u_boot_dtb.size,
6013 'fdtmap:size': fdtmap.size,
6014 'size': len(data),
6015 }
6016 self.assertEqual(expected, props)
6017
6018 # Check implementation
6019 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6020 rest = data[len(U_BOOT_DATA):]
6021 comp_data_len = struct.unpack('<I', rest[:4])[0]
6022 comp_data = rest[4:4 + comp_data_len]
6023 orig2 = self._decompress(comp_data)
6024 self.assertEqual(orig, orig2)
6025
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006026 def testInvalidCompress(self):
6027 """Test that invalid compress algorithm is detected"""
6028 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006029 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006030 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6031
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006032 def testCompUtilCompressions(self):
6033 """Test compression algorithms"""
6034 for bintool in self.comp_bintools.values():
6035 self._CheckBintool(bintool)
6036 data = bintool.compress(COMPRESS_DATA)
6037 self.assertNotEqual(COMPRESS_DATA, data)
6038 orig = bintool.decompress(data)
6039 self.assertEquals(COMPRESS_DATA, orig)
6040
6041 def testCompUtilVersions(self):
6042 """Test tool version of compression algorithms"""
6043 for bintool in self.comp_bintools.values():
6044 self._CheckBintool(bintool)
6045 version = bintool.version()
6046 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6047
6048 def testCompUtilPadding(self):
6049 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006050 # Skip zstd because it doesn't support padding
6051 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006052 self._CheckBintool(bintool)
6053 data = bintool.compress(COMPRESS_DATA)
6054 self.assertNotEqual(COMPRESS_DATA, data)
6055 data += tools.get_bytes(0, 64)
6056 orig = bintool.decompress(data)
6057 self.assertEquals(COMPRESS_DATA, orig)
6058
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006059 def testCompressDtbZstd(self):
6060 """Test that zstd compress of device-tree files failed"""
6061 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006062 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006063 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6064 "requires a length header", str(e.exception))
6065
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006066 def testMkimageMultipleDataFiles(self):
6067 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006068 self._SetupSplElf()
6069 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006070 data = self._DoReadFile('252_mkimage_mult_data.dts')
6071 # Size of files are packed in their 4B big-endian format
6072 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6073 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6074 # Size info is always followed by a 4B zero value.
6075 expect += tools.get_bytes(0, 4)
6076 expect += U_BOOT_TPL_DATA
6077 # All but last files are 4B-aligned
6078 align_pad = len(U_BOOT_TPL_DATA) % 4
6079 if align_pad:
6080 expect += tools.get_bytes(0, align_pad)
6081 expect += U_BOOT_SPL_DATA
6082 self.assertEqual(expect, data[-len(expect):])
6083
Marek Vasutf7413f02023-07-18 07:23:58 -06006084 def testMkimageMultipleExpanded(self):
6085 """Test passing multiple files to mkimage in a mkimage entry"""
6086 self._SetupSplElf()
6087 self._SetupTplElf()
6088 entry_args = {
6089 'spl-bss-pad': 'y',
6090 'spl-dtb': 'y',
6091 }
6092 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6093 use_expanded=True, entry_args=entry_args)[0]
6094 pad_len = 10
6095 tpl_expect = U_BOOT_TPL_DATA
6096 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6097 spl_expect += U_BOOT_SPL_DTB_DATA
6098
6099 content = data[0x40:]
6100 lens = struct.unpack('>III', content[:12])
6101
6102 # Size of files are packed in their 4B big-endian format
6103 # Size info is always followed by a 4B zero value.
6104 self.assertEqual(len(tpl_expect), lens[0])
6105 self.assertEqual(len(spl_expect), lens[1])
6106 self.assertEqual(0, lens[2])
6107
6108 rest = content[12:]
6109 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6110
6111 rest = rest[len(tpl_expect):]
6112 align_pad = len(tpl_expect) % 4
6113 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6114 rest = rest[align_pad:]
6115 self.assertEqual(spl_expect, rest)
6116
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006117 def testMkimageMultipleNoContent(self):
6118 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006119 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006120 with self.assertRaises(ValueError) as exc:
6121 self._DoReadFile('253_mkimage_mult_no_content.dts')
6122 self.assertIn('Could not complete processing of contents',
6123 str(exc.exception))
6124
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006125 def testMkimageFilename(self):
6126 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006127 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006128 retcode = self._DoTestFile('254_mkimage_filename.dts')
6129 self.assertEqual(0, retcode)
6130 fname = tools.get_output_filename('mkimage-test.bin')
6131 self.assertTrue(os.path.exists(fname))
6132
Simon Glass56d05412022-02-28 07:16:54 -07006133 def testVpl(self):
6134 """Test that an image with VPL and its device tree can be created"""
6135 # ELF file with a '__bss_size' symbol
6136 self._SetupVplElf()
6137 data = self._DoReadFile('255_u_boot_vpl.dts')
6138 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6139
6140 def testVplNoDtb(self):
6141 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6142 self._SetupVplElf()
6143 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6144 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6145 data[:len(U_BOOT_VPL_NODTB_DATA)])
6146
6147 def testExpandedVpl(self):
6148 """Test that an expanded entry type is selected for TPL when needed"""
6149 self._SetupVplElf()
6150
6151 entry_args = {
6152 'vpl-bss-pad': 'y',
6153 'vpl-dtb': 'y',
6154 }
6155 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6156 entry_args=entry_args)
6157 image = control.images['image']
6158 entries = image.GetEntries()
6159 self.assertEqual(1, len(entries))
6160
6161 # We only have u-boot-vpl, which be expanded
6162 self.assertIn('u-boot-vpl', entries)
6163 entry = entries['u-boot-vpl']
6164 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6165 subent = entry.GetEntries()
6166 self.assertEqual(3, len(subent))
6167 self.assertIn('u-boot-vpl-nodtb', subent)
6168 self.assertIn('u-boot-vpl-bss-pad', subent)
6169 self.assertIn('u-boot-vpl-dtb', subent)
6170
6171 def testVplBssPadMissing(self):
6172 """Test that a missing symbol is detected"""
6173 self._SetupVplElf('u_boot_ucode_ptr')
6174 with self.assertRaises(ValueError) as e:
6175 self._DoReadFile('258_vpl_bss_pad.dts')
6176 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6177 str(e.exception))
6178
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306179 def testSymlink(self):
Andrew Davis6b463da2023-07-22 00:14:44 +05306180 """Test that image files can be symlinked"""
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306181 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6182 self.assertEqual(0, retcode)
6183 image = control.images['test_image']
6184 fname = tools.get_output_filename('test_image.bin')
6185 sname = tools.get_output_filename('symlink_to_test.bin')
6186 self.assertTrue(os.path.islink(sname))
6187 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006188
Andrew Davis6b463da2023-07-22 00:14:44 +05306189 def testSymlinkOverwrite(self):
6190 """Test that symlinked images can be overwritten"""
6191 testdir = TestFunctional._MakeInputDir('symlinktest')
6192 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6193 # build the same image again in the same directory so that existing symlink is present
6194 self._DoTestFile('259_symlink.dts', debug=True, map=True, output_dir=testdir)
6195 fname = tools.get_output_filename('test_image.bin')
6196 sname = tools.get_output_filename('symlink_to_test.bin')
6197 self.assertTrue(os.path.islink(sname))
6198 self.assertEqual(os.readlink(sname), fname)
6199
Simon Glass37f85de2022-10-20 18:22:47 -06006200 def testSymbolsElf(self):
6201 """Test binman can assign symbols embedded in an ELF file"""
6202 if not elf.ELF_TOOLS:
6203 self.skipTest('Python elftools not available')
6204 self._SetupTplElf('u_boot_binman_syms')
6205 self._SetupVplElf('u_boot_binman_syms')
6206 self._SetupSplElf('u_boot_binman_syms')
6207 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6208 image_fname = tools.get_output_filename('image.bin')
6209
6210 image = control.images['image']
6211 entries = image.GetEntries()
6212
6213 for entry in entries.values():
6214 # No symbols in u-boot and it has faked contents anyway
6215 if entry.name == 'u-boot':
6216 continue
6217 edata = data[entry.image_pos:entry.image_pos + entry.size]
6218 efname = tools.get_output_filename(f'edata-{entry.name}')
6219 tools.write_file(efname, edata)
6220
6221 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6222 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6223 for name, sym in syms.items():
6224 msg = 'test'
6225 val = elf.GetSymbolValue(sym, edata, msg)
6226 entry_m = re_name.match(name)
6227 if entry_m:
6228 ename, prop = entry_m.group(1), entry_m.group(3)
6229 entry, entry_name, prop_name = image.LookupEntry(entries,
6230 name, msg)
6231 if prop_name == 'offset':
6232 expect_val = entry.offset
6233 elif prop_name == 'image_pos':
6234 expect_val = entry.image_pos
6235 elif prop_name == 'size':
6236 expect_val = entry.size
6237 self.assertEqual(expect_val, val)
6238
6239 def testSymbolsElfBad(self):
6240 """Check error when trying to write symbols without the elftools lib"""
6241 if not elf.ELF_TOOLS:
6242 self.skipTest('Python elftools not available')
6243 self._SetupTplElf('u_boot_binman_syms')
6244 self._SetupVplElf('u_boot_binman_syms')
6245 self._SetupSplElf('u_boot_binman_syms')
6246 try:
6247 elf.ELF_TOOLS = False
6248 with self.assertRaises(ValueError) as exc:
6249 self._DoReadFileDtb('260_symbols_elf.dts')
6250 finally:
6251 elf.ELF_TOOLS = True
6252 self.assertIn(
6253 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6254 'Cannot write symbols to an ELF file without Python elftools',
6255 str(exc.exception))
6256
Simon Glassde244162023-01-07 14:07:08 -07006257 def testSectionFilename(self):
6258 """Check writing of section contents to a file"""
6259 data = self._DoReadFile('261_section_fname.dts')
6260 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6261 tools.get_bytes(ord('!'), 7) +
6262 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6263 self.assertEqual(expected, data)
6264
6265 sect_fname = tools.get_output_filename('outfile.bin')
6266 self.assertTrue(os.path.exists(sect_fname))
6267 sect_data = tools.read_file(sect_fname)
6268 self.assertEqual(U_BOOT_DATA, sect_data)
6269
Simon Glass1e9e61c2023-01-07 14:07:12 -07006270 def testAbsent(self):
6271 """Check handling of absent entries"""
6272 data = self._DoReadFile('262_absent.dts')
6273 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6274
Simon Glassad5cfe12023-01-07 14:07:14 -07006275 def testPackTeeOsOptional(self):
6276 """Test that an image with an optional TEE binary can be created"""
6277 entry_args = {
6278 'tee-os-path': 'tee.elf',
6279 }
6280 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6281 entry_args=entry_args)[0]
6282 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6283
6284 def checkFitTee(self, dts, tee_fname):
6285 """Check that a tee-os entry works and returns data
6286
6287 Args:
6288 dts (str): Device tree filename to use
6289 tee_fname (str): filename containing tee-os
6290
6291 Returns:
6292 bytes: Image contents
6293 """
6294 if not elf.ELF_TOOLS:
6295 self.skipTest('Python elftools not available')
6296 entry_args = {
6297 'of-list': 'test-fdt1 test-fdt2',
6298 'default-dt': 'test-fdt2',
6299 'tee-os-path': tee_fname,
6300 }
6301 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6302 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6303 extra_indirs=[test_subdir])[0]
6304 return data
6305
6306 def testFitTeeOsOptionalFit(self):
6307 """Test an image with a FIT with an optional OP-TEE binary"""
6308 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6309
6310 # There should be only one node, holding the data set up in SetUpClass()
6311 # for tee.bin
6312 dtb = fdt.Fdt.FromData(data)
6313 dtb.Scan()
6314 node = dtb.GetNode('/images/tee-1')
6315 self.assertEqual(TEE_ADDR,
6316 fdt_util.fdt32_to_cpu(node.props['load'].value))
6317 self.assertEqual(TEE_ADDR,
6318 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6319 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6320
6321 def testFitTeeOsOptionalFitBad(self):
6322 """Test an image with a FIT with an optional OP-TEE binary"""
6323 with self.assertRaises(ValueError) as exc:
6324 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6325 self.assertIn(
6326 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6327 str(exc.exception))
6328
6329 def testFitTeeOsBad(self):
6330 """Test an OP-TEE binary with wrong formats"""
6331 self.make_tee_bin('tee.bad1', 123)
6332 with self.assertRaises(ValueError) as exc:
6333 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6334 self.assertIn(
6335 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6336 str(exc.exception))
6337
6338 self.make_tee_bin('tee.bad2', 0, b'extra data')
6339 with self.assertRaises(ValueError) as exc:
6340 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6341 self.assertIn(
6342 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6343 str(exc.exception))
6344
Simon Glass63328f12023-01-07 14:07:15 -07006345 def testExtblobOptional(self):
6346 """Test an image with an external blob that is optional"""
6347 with test_util.capture_sys_output() as (stdout, stderr):
6348 data = self._DoReadFile('266_blob_ext_opt.dts')
6349 self.assertEqual(REFCODE_DATA, data)
6350 err = stderr.getvalue()
6351 self.assertRegex(
6352 err,
6353 "Image '.*' is missing external blobs but is still functional: missing")
6354
Simon Glass7447a9d2023-01-11 16:10:12 -07006355 def testSectionInner(self):
6356 """Test an inner section with a size"""
6357 data = self._DoReadFile('267_section_inner.dts')
6358 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6359 self.assertEqual(expected, data)
6360
Simon Glassa4948b22023-01-11 16:10:14 -07006361 def testNull(self):
6362 """Test an image with a null entry"""
6363 data = self._DoReadFile('268_null.dts')
6364 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6365
Simon Glassf1ee03b2023-01-11 16:10:16 -07006366 def testOverlap(self):
6367 """Test an image with a overlapping entry"""
6368 data = self._DoReadFile('269_overlap.dts')
6369 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6370
6371 image = control.images['image']
6372 entries = image.GetEntries()
6373
6374 self.assertIn('inset', entries)
6375 inset = entries['inset']
6376 self.assertEqual(1, inset.offset);
6377 self.assertEqual(1, inset.image_pos);
6378 self.assertEqual(2, inset.size);
6379
6380 def testOverlapNull(self):
6381 """Test an image with a null overlap"""
6382 data = self._DoReadFile('270_overlap_null.dts')
6383 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6384
6385 # Check the FMAP
6386 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6387 self.assertEqual(4, fhdr.nareas)
6388 fiter = iter(fentries)
6389
6390 fentry = next(fiter)
6391 self.assertEqual(b'SECTION', fentry.name)
6392 self.assertEqual(0, fentry.offset)
6393 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6394 self.assertEqual(0, fentry.flags)
6395
6396 fentry = next(fiter)
6397 self.assertEqual(b'U_BOOT', fentry.name)
6398 self.assertEqual(0, fentry.offset)
6399 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6400 self.assertEqual(0, fentry.flags)
6401
6402 # Make sure that the NULL entry appears in the FMAP
6403 fentry = next(fiter)
6404 self.assertEqual(b'NULL', fentry.name)
6405 self.assertEqual(1, fentry.offset)
6406 self.assertEqual(2, fentry.size)
6407 self.assertEqual(0, fentry.flags)
6408
6409 fentry = next(fiter)
6410 self.assertEqual(b'FMAP', fentry.name)
6411 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6412
6413 def testOverlapBad(self):
6414 """Test an image with a bad overlapping entry"""
6415 with self.assertRaises(ValueError) as exc:
6416 self._DoReadFile('271_overlap_bad.dts')
6417 self.assertIn(
6418 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6419 str(exc.exception))
6420
6421 def testOverlapNoOffset(self):
6422 """Test an image with a bad overlapping entry"""
6423 with self.assertRaises(ValueError) as exc:
6424 self._DoReadFile('272_overlap_no_size.dts')
6425 self.assertIn(
6426 "Node '/binman/inset': 'fill' entry is missing properties: size",
6427 str(exc.exception))
6428
Simon Glasse0035c92023-01-11 16:10:17 -07006429 def testBlobSymbol(self):
6430 """Test a blob with symbols read from an ELF file"""
6431 elf_fname = self.ElfTestFile('blob_syms')
6432 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6433 TestFunctional._MakeInputFile('blob_syms.bin',
6434 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6435
6436 data = self._DoReadFile('273_blob_symbol.dts')
6437
6438 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6439 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6440 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6441 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6442 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6443
6444 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6445 expected = sym_values
6446 self.assertEqual(expected, data[:len(expected)])
6447
Simon Glass49e9c002023-01-11 16:10:19 -07006448 def testOffsetFromElf(self):
6449 """Test a blob with symbols read from an ELF file"""
6450 elf_fname = self.ElfTestFile('blob_syms')
6451 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6452 TestFunctional._MakeInputFile('blob_syms.bin',
6453 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6454
6455 data = self._DoReadFile('274_offset_from_elf.dts')
6456
6457 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6458 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6459
6460 image = control.images['image']
6461 entries = image.GetEntries()
6462
6463 self.assertIn('inset', entries)
6464 inset = entries['inset']
6465
6466 self.assertEqual(base + 4, inset.offset);
6467 self.assertEqual(base + 4, inset.image_pos);
6468 self.assertEqual(4, inset.size);
6469
6470 self.assertIn('inset2', entries)
6471 inset = entries['inset2']
6472 self.assertEqual(base + 8, inset.offset);
6473 self.assertEqual(base + 8, inset.image_pos);
6474 self.assertEqual(4, inset.size);
6475
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006476 def testFitAlign(self):
6477 """Test an image with an FIT with aligned external data"""
6478 data = self._DoReadFile('275_fit_align.dts')
6479 self.assertEqual(4096, len(data))
6480
6481 dtb = fdt.Fdt.FromData(data)
6482 dtb.Scan()
6483
6484 props = self._GetPropTree(dtb, ['data-position'])
6485 expected = {
6486 'u-boot:data-position': 1024,
6487 'fdt-1:data-position': 2048,
6488 'fdt-2:data-position': 3072,
6489 }
6490 self.assertEqual(expected, props)
6491
Jonas Karlman490f73c2023-01-21 19:02:12 +00006492 def testFitFirmwareLoadables(self):
6493 """Test an image with an FIT that use fit,firmware"""
6494 if not elf.ELF_TOOLS:
6495 self.skipTest('Python elftools not available')
6496 entry_args = {
6497 'of-list': 'test-fdt1',
6498 'default-dt': 'test-fdt1',
6499 'atf-bl31-path': 'bl31.elf',
6500 'tee-os-path': 'missing.bin',
6501 }
6502 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006503 with test_util.capture_sys_output() as (stdout, stderr):
6504 data = self._DoReadFileDtb(
6505 '276_fit_firmware_loadables.dts',
6506 entry_args=entry_args,
6507 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006508
6509 dtb = fdt.Fdt.FromData(data)
6510 dtb.Scan()
6511
6512 node = dtb.GetNode('/configurations/conf-uboot-1')
6513 self.assertEqual('u-boot', node.props['firmware'].value)
6514 self.assertEqual(['atf-1', 'atf-2'],
6515 fdt_util.GetStringList(node, 'loadables'))
6516
6517 node = dtb.GetNode('/configurations/conf-atf-1')
6518 self.assertEqual('atf-1', node.props['firmware'].value)
6519 self.assertEqual(['u-boot', 'atf-2'],
6520 fdt_util.GetStringList(node, 'loadables'))
6521
6522 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6523 self.assertEqual('u-boot', node.props['firmware'].value)
6524 self.assertEqual(['atf-1', 'atf-2'],
6525 fdt_util.GetStringList(node, 'loadables'))
6526
6527 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6528 self.assertEqual('atf-1', node.props['firmware'].value)
6529 self.assertEqual(['u-boot', 'atf-2'],
6530 fdt_util.GetStringList(node, 'loadables'))
6531
6532 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6533 self.assertEqual('atf-1', node.props['firmware'].value)
6534 self.assertEqual(['u-boot', 'atf-2'],
6535 fdt_util.GetStringList(node, 'loadables'))
6536
Simon Glass9a1c7262023-02-22 12:14:49 -07006537 def testTooldir(self):
6538 """Test that we can specify the tooldir"""
6539 with test_util.capture_sys_output() as (stdout, stderr):
6540 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6541 'tool', '-l'))
6542 self.assertEqual('fred', bintool.Bintool.tooldir)
6543
6544 # Check that the toolpath is updated correctly
6545 self.assertEqual(['fred'], tools.tool_search_paths)
6546
6547 # Try with a few toolpaths; the tooldir should be at the end
6548 with test_util.capture_sys_output() as (stdout, stderr):
6549 self.assertEqual(0, self._DoBinman(
6550 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6551 'tool', '-l'))
6552 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6553
Simon Glass49b77e82023-03-02 17:02:44 -07006554 def testReplaceSectionEntry(self):
6555 """Test replacing an entry in a section"""
6556 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6557 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6558 expect_data, dts='241_replace_section_simple.dts')
6559 self.assertEqual(expect_data, entry_data)
6560
6561 entries = image.GetEntries()
6562 self.assertIn('section', entries)
6563 section = entries['section']
6564
6565 sect_entries = section.GetEntries()
6566 self.assertIn('blob', sect_entries)
6567 entry = sect_entries['blob']
6568 self.assertEqual(len(expect_data), entry.size)
6569
6570 fname = tools.get_output_filename('image-updated.bin')
6571 data = tools.read_file(fname)
6572
6573 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6574 self.assertEqual(expect_data, new_blob_data)
6575
6576 self.assertEqual(U_BOOT_DATA,
6577 data[entry.image_pos + len(expect_data):]
6578 [:len(U_BOOT_DATA)])
6579
6580 def testReplaceSectionDeep(self):
6581 """Test replacing an entry in two levels of sections"""
6582 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6583 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6584 'section/section/blob', expect_data,
6585 dts='278_replace_section_deep.dts')
6586 self.assertEqual(expect_data, entry_data)
6587
6588 entries = image.GetEntries()
6589 self.assertIn('section', entries)
6590 section = entries['section']
6591
6592 subentries = section.GetEntries()
6593 self.assertIn('section', subentries)
6594 section = subentries['section']
6595
6596 sect_entries = section.GetEntries()
6597 self.assertIn('blob', sect_entries)
6598 entry = sect_entries['blob']
6599 self.assertEqual(len(expect_data), entry.size)
6600
6601 fname = tools.get_output_filename('image-updated.bin')
6602 data = tools.read_file(fname)
6603
6604 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6605 self.assertEqual(expect_data, new_blob_data)
6606
6607 self.assertEqual(U_BOOT_DATA,
6608 data[entry.image_pos + len(expect_data):]
6609 [:len(U_BOOT_DATA)])
6610
6611 def testReplaceFitSibling(self):
6612 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006613 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006614 fname = TestFunctional._MakeInputFile('once', b'available once')
6615 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6616 os.remove(fname)
6617
6618 try:
6619 tmpdir, updated_fname = self._SetupImageInTmpdir()
6620
6621 fname = os.path.join(tmpdir, 'update-blob')
6622 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6623 tools.write_file(fname, expected)
6624
6625 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6626 data = tools.read_file(updated_fname)
6627 start = len(U_BOOT_DTB_DATA)
6628 self.assertEqual(expected, data[start:start + len(expected)])
6629 map_fname = os.path.join(tmpdir, 'image-updated.map')
6630 self.assertFalse(os.path.exists(map_fname))
6631 finally:
6632 shutil.rmtree(tmpdir)
6633
Simon Glassc3fe97f2023-03-02 17:02:45 -07006634 def testX509Cert(self):
6635 """Test creating an X509 certificate"""
6636 keyfile = self.TestFile('key.key')
6637 entry_args = {
6638 'keyfile': keyfile,
6639 }
6640 data = self._DoReadFileDtb('279_x509_cert.dts',
6641 entry_args=entry_args)[0]
6642 cert = data[:-4]
6643 self.assertEqual(U_BOOT_DATA, data[-4:])
6644
6645 # TODO: verify the signature
6646
6647 def testX509CertMissing(self):
6648 """Test that binman still produces an image if openssl is missing"""
6649 keyfile = self.TestFile('key.key')
6650 entry_args = {
6651 'keyfile': 'keyfile',
6652 }
6653 with test_util.capture_sys_output() as (_, stderr):
6654 self._DoTestFile('279_x509_cert.dts',
6655 force_missing_bintools='openssl',
6656 entry_args=entry_args)
6657 err = stderr.getvalue()
6658 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6659
Jonas Karlman35305492023-02-25 19:01:33 +00006660 def testPackRockchipTpl(self):
6661 """Test that an image with a Rockchip TPL binary can be created"""
6662 data = self._DoReadFile('277_rockchip_tpl.dts')
6663 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6664
Jonas Karlman1016ec72023-02-25 19:01:35 +00006665 def testMkimageMissingBlobMultiple(self):
6666 """Test missing blob with mkimage entry and multiple-data-files"""
6667 with test_util.capture_sys_output() as (stdout, stderr):
6668 self._DoTestFile('278_mkimage_missing_multiple.dts', allow_missing=True)
6669 err = stderr.getvalue()
6670 self.assertIn("is missing external blobs and is non-functional", err)
6671
6672 with self.assertRaises(ValueError) as e:
6673 self._DoTestFile('278_mkimage_missing_multiple.dts', allow_missing=False)
6674 self.assertIn("not found in input path", str(e.exception))
6675
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006676 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6677 """Prepare sign environment
6678
6679 Create private and public keys, add pubkey into dtb.
6680
6681 Returns:
6682 Tuple:
6683 FIT container
6684 Image name
6685 Private key
6686 DTB
6687 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006688 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006689 data = self._DoReadFileRealDtb(dts)
6690 updated_fname = tools.get_output_filename('image-updated.bin')
6691 tools.write_file(updated_fname, data)
6692 dtb = tools.get_output_filename('source.dtb')
6693 private_key = tools.get_output_filename('test_key.key')
6694 public_key = tools.get_output_filename('test_key.crt')
6695 fit = tools.get_output_filename('fit.fit')
6696 key_dir = tools.get_output_dir()
6697
6698 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6699 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6700 private_key, '-out', public_key)
6701 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6702 '-n', 'test_key', '-r', 'conf', dtb)
6703
6704 return fit, updated_fname, private_key, dtb
6705
6706 def testSignSimple(self):
6707 """Test that a FIT container can be signed in image"""
6708 is_signed = False
6709 fit, fname, private_key, dtb = self._PrepareSignEnv()
6710
6711 # do sign with private key
6712 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6713 ['fit'])
6714 is_signed = self._CheckSign(fit, dtb)
6715
6716 self.assertEqual(is_signed, True)
6717
6718 def testSignExactFIT(self):
6719 """Test that a FIT container can be signed and replaced in image"""
6720 is_signed = False
6721 fit, fname, private_key, dtb = self._PrepareSignEnv()
6722
6723 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6724 args = []
6725 if self.toolpath:
6726 for path in self.toolpath:
6727 args += ['--toolpath', path]
6728
6729 # do sign with private key
6730 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6731 'sha256,rsa4096', '-f', fit, 'fit')
6732 is_signed = self._CheckSign(fit, dtb)
6733
6734 self.assertEqual(is_signed, True)
6735
6736 def testSignNonFit(self):
6737 """Test a non-FIT entry cannot be signed"""
6738 is_signed = False
6739 fit, fname, private_key, _ = self._PrepareSignEnv(
6740 '281_sign_non_fit.dts')
6741
6742 # do sign with private key
6743 with self.assertRaises(ValueError) as e:
6744 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6745 'sha256,rsa4096', '-f', fit, 'u-boot')
6746 self.assertIn(
6747 "Node '/u-boot': Updating signatures is not supported with this entry type",
6748 str(e.exception))
6749
6750 def testSignMissingMkimage(self):
6751 """Test that FIT signing handles a missing mkimage tool"""
6752 fit, fname, private_key, _ = self._PrepareSignEnv()
6753
6754 # try to sign with a missing mkimage tool
6755 bintool.Bintool.set_missing_list(['mkimage'])
6756 with self.assertRaises(ValueError) as e:
6757 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6758 ['fit'])
6759 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6760
Simon Glass4abf7842023-07-18 07:23:54 -06006761 def testSymbolNoWrite(self):
6762 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006763 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006764 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6765 no_write_symbols=True)
6766
6767 def testSymbolNoWriteExpanded(self):
6768 """Test disabling of symbol writing in expanded entries"""
6769 entry_args = {
6770 'spl-dtb': '1',
6771 }
6772 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6773 U_BOOT_SPL_DTB_DATA, 0x38,
6774 entry_args=entry_args, use_expanded=True,
6775 no_write_symbols=True)
6776
Marek Vasutf7413f02023-07-18 07:23:58 -06006777 def testMkimageSpecial(self):
6778 """Test mkimage ignores special hash-1 node"""
6779 data = self._DoReadFile('283_mkimage_special.dts')
6780
6781 # Just check that the data appears in the file somewhere
6782 self.assertIn(U_BOOT_DATA, data)
6783
Simon Glass2d94c422023-07-18 07:23:59 -06006784 def testFitFdtList(self):
6785 """Test an image with an FIT with the fit,fdt-list-val option"""
6786 entry_args = {
6787 'default-dt': 'test-fdt2',
6788 }
6789 data = self._DoReadFileDtb(
6790 '284_fit_fdt_list.dts',
6791 entry_args=entry_args,
6792 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6793 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6794 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6795
Simon Glass83b8bfe2023-07-18 07:24:01 -06006796 def testSplEmptyBss(self):
6797 """Test an expanded SPL with a zero-size BSS"""
6798 # ELF file with a '__bss_size' symbol
6799 self._SetupSplElf(src_fname='bss_data_zero')
6800
6801 entry_args = {
6802 'spl-bss-pad': 'y',
6803 'spl-dtb': 'y',
6804 }
6805 data = self._DoReadFileDtb('285_spl_expand.dts',
6806 use_expanded=True, entry_args=entry_args)[0]
6807
Simon Glassfc792842023-07-18 07:24:04 -06006808 def testTemplate(self):
6809 """Test using a template"""
6810 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6811 data = self._DoReadFile('286_template.dts')
6812 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6813 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6814 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6815
Simon Glass9909c112023-07-18 07:24:05 -06006816 def testTemplateBlobMulti(self):
6817 """Test using a template with 'multiple-images' enabled"""
6818 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6819 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6820 retcode = self._DoTestFile('287_template_multi.dts')
6821
6822 self.assertEqual(0, retcode)
6823 image = control.images['image']
6824 image_fname = tools.get_output_filename('my-image.bin')
6825 data = tools.read_file(image_fname)
6826 self.assertEqual(b'blob@@@@other', data)
6827
Simon Glass5dc511b2023-07-18 07:24:06 -06006828 def testTemplateFit(self):
6829 """Test using a template in a FIT"""
6830 fit_data = self._DoReadFile('288_template_fit.dts')
6831 fname = os.path.join(self._indir, 'fit_data.fit')
6832 tools.write_file(fname, fit_data)
6833 out = tools.run('dumpimage', '-l', fname)
6834
Simon Glassaa6e0552023-07-18 07:24:07 -06006835 def testTemplateSection(self):
6836 """Test using a template in a section (not at top level)"""
6837 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6838 data = self._DoReadFile('289_template_section.dts')
6839 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6840 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6841 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6842
Simon Glassf53a7bc2023-07-18 07:24:08 -06006843 def testMkimageSymbols(self):
6844 """Test using mkimage to build an image with symbols in it"""
6845 self._SetupSplElf('u_boot_binman_syms')
6846 data = self._DoReadFile('290_mkimage_sym.dts')
6847
6848 image = control.images['image']
6849 entries = image.GetEntries()
6850 self.assertIn('u-boot', entries)
6851 u_boot = entries['u-boot']
6852
6853 mkim = entries['mkimage']
6854 mkim_entries = mkim.GetEntries()
6855 self.assertIn('u-boot-spl', mkim_entries)
6856 spl = mkim_entries['u-boot-spl']
6857 self.assertIn('u-boot-spl2', mkim_entries)
6858 spl2 = mkim_entries['u-boot-spl2']
6859
6860 # skip the mkimage header and the area sizes
6861 mk_data = data[mkim.offset + 0x40:]
6862 size, term = struct.unpack('>LL', mk_data[:8])
6863
6864 # There should be only one image, so check that the zero terminator is
6865 # present
6866 self.assertEqual(0, term)
6867
6868 content = mk_data[8:8 + size]
6869
6870 # The image should contain the symbols from u_boot_binman_syms.c
6871 # Note that image_pos is adjusted by the base address of the image,
6872 # which is 0x10 in our test image
6873 spl_data = content[:0x18]
6874 content = content[0x1b:]
6875
6876 # After the header is a table of offsets for each image. There should
6877 # only be one image, then a 0 terminator, so figure out the real start
6878 # of the image data
6879 base = 0x40 + 8
6880
6881 # Check symbols in both u-boot-spl and u-boot-spl2
6882 for i in range(2):
6883 vals = struct.unpack('<LLQLL', spl_data)
6884
6885 # The image should contain the symbols from u_boot_binman_syms.c
6886 # Note that image_pos is adjusted by the base address of the image,
6887 # which is 0x10 in our 'u_boot_binman_syms' test image
6888 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6889 self.assertEqual(base, vals[1])
6890 self.assertEqual(spl2.offset, vals[2])
6891 # figure out the internal positions of its components
6892 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6893
6894 # Check that spl and spl2 are actually at the indicated positions
6895 self.assertEqual(
6896 elf.BINMAN_SYM_MAGIC_VALUE,
6897 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6898 self.assertEqual(
6899 elf.BINMAN_SYM_MAGIC_VALUE,
6900 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6901
6902 self.assertEqual(len(U_BOOT_DATA), vals[4])
6903
6904 # Move to next
6905 spl_data = content[:0x18]
6906
Neha Malcom Francis3b788942023-07-22 00:14:24 +05306907 def testTIBoardConfig(self):
6908 """Test that a schema validated board config file can be generated"""
6909 data = self._DoReadFile('277_ti_board_cfg.dts')
6910 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
6911
6912 def testTIBoardConfigCombined(self):
6913 """Test that a schema validated combined board config file can be generated"""
6914 data = self._DoReadFile('278_ti_board_cfg_combined.dts')
6915 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
6916 self.assertGreater(data, configlen_noheader)
6917
6918 def testTIBoardConfigNoDataType(self):
6919 """Test that error is thrown when data type is not supported"""
6920 with self.assertRaises(ValueError) as e:
6921 data = self._DoReadFile('279_ti_board_cfg_no_type.dts')
6922 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07006923
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05306924 def testPackTiSecure(self):
6925 """Test that an image with a TI secured binary can be created"""
6926 keyfile = self.TestFile('key.key')
6927 entry_args = {
6928 'keyfile': keyfile,
6929 }
6930 data = self._DoReadFileDtb('279_ti_secure.dts',
6931 entry_args=entry_args)[0]
6932 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
6933
6934 def testPackTiSecureMissingTool(self):
6935 """Test that an image with a TI secured binary (non-functional) can be created
6936 when openssl is missing"""
6937 keyfile = self.TestFile('key.key')
6938 entry_args = {
6939 'keyfile': keyfile,
6940 }
6941 with test_util.capture_sys_output() as (_, stderr):
6942 self._DoTestFile('279_ti_secure.dts',
6943 force_missing_bintools='openssl',
6944 entry_args=entry_args)
6945 err = stderr.getvalue()
6946 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6947
6948 def testPackTiSecureROM(self):
6949 """Test that a ROM 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('280_ti_secure_rom.dts',
6955 entry_args=entry_args)[0]
6956 data_a = self._DoReadFileDtb('288_ti_secure_rom_a.dts',
6957 entry_args=entry_args)[0]
6958 data_b = self._DoReadFileDtb('289_ti_secure_rom_b.dts',
6959 entry_args=entry_args)[0]
6960 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
6961 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
6962 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
6963
6964 def testPackTiSecureROMCombined(self):
6965 """Test that a ROM image with a TI secured binary can be created"""
6966 keyfile = self.TestFile('key.key')
6967 entry_args = {
6968 'keyfile': keyfile,
6969 }
6970 data = self._DoReadFileDtb('281_ti_secure_rom_combined.dts',
6971 entry_args=entry_args)[0]
6972 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
6973
Simon Glassac599912017-11-12 21:52:22 -07006974if __name__ == "__main__":
6975 unittest.main()