blob: 5b136238e67f6d393a29b5f4e339affb308d28e4 [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,
Simon Glass6bce5dc2022-11-09 19:14:42 -0700356 force_missing_bintools='', ignore_missing=False):
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
Simon Glass9a798402021-11-03 21:09:17 -0600387
388 Returns:
389 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700390 """
Simon Glassf46732a2019-07-08 14:25:29 -0600391 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700392 if debug:
393 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600394 if verbosity is not None:
395 args.append('-v%d' % verbosity)
396 elif self.verbosity:
397 args.append('-v%d' % self.verbosity)
398 if self.toolpath:
399 for path in self.toolpath:
400 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600401 if threads is not None:
402 args.append('-T%d' % threads)
403 if test_section_timeout:
404 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600405 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600406 if map:
407 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600408 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600409 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600410 if not use_real_dtb:
411 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300412 if not use_expanded:
413 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600414 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600415 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600416 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600417 if allow_missing:
418 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700419 if ignore_missing:
420 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100421 if allow_fake_blobs:
422 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700423 if force_missing_bintools:
424 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600425 if update_fdt_in_elf:
426 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600427 if images:
428 for image in images:
429 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600430 if extra_indirs:
431 for indir in extra_indirs:
432 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700433 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700434
435 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700436 """Set up a new test device-tree file
437
438 The given file is compiled and set up as the device tree to be used
439 for ths test.
440
441 Args:
442 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600443 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700444
445 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600446 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700447 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600448 tmpdir = tempfile.mkdtemp(prefix='binmant.')
449 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600450 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700451 data = fd.read()
452 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600453 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600454 return data
Simon Glass57454f42016-11-25 20:15:52 -0700455
Simon Glass56d05412022-02-28 07:16:54 -0700456 def _GetDtbContentsForSpls(self, dtb_data, name):
457 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600458
459 For testing we don't actually have different versions of the DTB. With
460 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
461 we don't normally have any unwanted nodes.
462
463 We still want the DTBs for SPL and TPL to be different though, since
464 otherwise it is confusing to know which one we are looking at. So add
465 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600466
467 Args:
468 dtb_data: dtb data to modify (this should be a value devicetree)
469 name: Name of a new property to add
470
471 Returns:
472 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600473 """
474 dtb = fdt.Fdt.FromData(dtb_data)
475 dtb.Scan()
476 dtb.GetNode('/binman').AddZeroProp(name)
477 dtb.Sync(auto_resize=True)
478 dtb.Pack()
479 return dtb.GetContents()
480
Simon Glassed930672021-03-18 20:25:05 +1300481 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
482 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600483 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700484 """Run binman and return the resulting image
485
486 This runs binman with a given test file and then reads the resulting
487 output file. It is a shortcut function since most tests need to do
488 these steps.
489
490 Raises an assertion failure if binman returns a non-zero exit code.
491
492 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600493 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700494 use_real_dtb: True to use the test file as the contents of
495 the u-boot-dtb entry. Normally this is not needed and the
496 test contents (the U_BOOT_DTB_DATA string) can be used.
497 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300498 use_expanded: True to use expanded entries where available, e.g.
499 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600500 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600501 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600502 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600503 entry_args: Dict of entry args to supply to binman
504 key: arg name
505 value: value of that arg
506 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
507 function. If reset_dtbs is True, then the original test dtb
508 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600509 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600510 threads: Number of threads to use (None for default, 0 for
511 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700512
513 Returns:
514 Tuple:
515 Resulting image contents
516 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600517 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600518 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700519 """
Simon Glass72232452016-11-25 20:15:53 -0700520 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700521 # Use the compiled test file as the u-boot-dtb input
522 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700523 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600524
525 # For testing purposes, make a copy of the DT for SPL and TPL. Add
526 # a node indicating which it is, so aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700527 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600528 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
529 outfile = os.path.join(self._indir, dtb_fname)
530 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700531 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700532
533 try:
Simon Glass91710b32018-07-17 13:25:32 -0600534 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600535 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600536 use_expanded=use_expanded, extra_indirs=extra_indirs,
537 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700538 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700539 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700540
541 # Find the (only) image, read it and return its contents
542 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700543 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600544 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600545 if map:
Simon Glass80025522022-01-29 14:14:04 -0700546 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600547 with open(map_fname) as fd:
548 map_data = fd.read()
549 else:
550 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600551 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600552 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700553 finally:
554 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600555 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600556 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700557
Simon Glass5b4bce32019-07-08 14:25:26 -0600558 def _DoReadFileRealDtb(self, fname):
559 """Run binman with a real .dtb file and return the resulting data
560
561 Args:
562 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
563
564 Returns:
565 Resulting image contents
566 """
567 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
568
Simon Glass72232452016-11-25 20:15:53 -0700569 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600570 """Helper function which discards the device-tree binary
571
572 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600573 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600574 use_real_dtb: True to use the test file as the contents of
575 the u-boot-dtb entry. Normally this is not needed and the
576 test contents (the U_BOOT_DTB_DATA string) can be used.
577 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600578
579 Returns:
580 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600581 """
Simon Glass72232452016-11-25 20:15:53 -0700582 return self._DoReadFileDtb(fname, use_real_dtb)[0]
583
Simon Glass57454f42016-11-25 20:15:52 -0700584 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600585 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700586 """Create a new test input file, creating directories as needed
587
588 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600589 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700590 contents: File contents to write in to the file
591 Returns:
592 Full pathname of file created
593 """
Simon Glass862f8e22019-08-24 07:22:43 -0600594 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700595 dirname = os.path.dirname(pathname)
596 if dirname and not os.path.exists(dirname):
597 os.makedirs(dirname)
598 with open(pathname, 'wb') as fd:
599 fd.write(contents)
600 return pathname
601
602 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600603 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600604 """Create a new test input directory, creating directories as needed
605
606 Args:
607 dirname: Directory name to create
608
609 Returns:
610 Full pathname of directory created
611 """
Simon Glass862f8e22019-08-24 07:22:43 -0600612 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600613 if not os.path.exists(pathname):
614 os.makedirs(pathname)
615 return pathname
616
617 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600618 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600619 """Set up an ELF file with a '_dt_ucode_base_size' symbol
620
621 Args:
622 Filename of ELF file to use as SPL
623 """
Simon Glass93a806f2019-08-24 07:22:59 -0600624 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700625 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600626
627 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600628 def _SetupTplElf(cls, src_fname='bss_data'):
629 """Set up an ELF file with a '_dt_ucode_base_size' symbol
630
631 Args:
632 Filename of ELF file to use as TPL
633 """
634 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700635 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600636
637 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700638 def _SetupVplElf(cls, src_fname='bss_data'):
639 """Set up an ELF file with a '_dt_ucode_base_size' symbol
640
641 Args:
642 Filename of ELF file to use as VPL
643 """
644 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
645 tools.read_file(cls.ElfTestFile(src_fname)))
646
647 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600648 def _SetupDescriptor(cls):
649 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
650 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
651
652 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600653 def TestFile(cls, fname):
654 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700655
Simon Glassf6290892019-08-24 07:22:53 -0600656 @classmethod
657 def ElfTestFile(cls, fname):
658 return os.path.join(cls._elf_testdir, fname)
659
Simon Glassad5cfe12023-01-07 14:07:14 -0700660 @classmethod
661 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
662 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
663 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
664 dummy, paged_sz) + U_BOOT_DATA
665 data += extra_data
666 TestFunctional._MakeInputFile(fname, data)
667
Simon Glass57454f42016-11-25 20:15:52 -0700668 def AssertInList(self, grep_list, target):
669 """Assert that at least one of a list of things is in a target
670
671 Args:
672 grep_list: List of strings to check
673 target: Target string
674 """
675 for grep in grep_list:
676 if grep in target:
677 return
Simon Glass848cdb52019-05-17 22:00:50 -0600678 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700679
680 def CheckNoGaps(self, entries):
681 """Check that all entries fit together without gaps
682
683 Args:
684 entries: List of entries to check
685 """
Simon Glasse8561af2018-08-01 15:22:37 -0600686 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700687 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600688 self.assertEqual(offset, entry.offset)
689 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700690
Simon Glass72232452016-11-25 20:15:53 -0700691 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600692 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700693
694 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600695 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700696
697 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600698 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700699 """
700 return struct.unpack('>L', dtb[4:8])[0]
701
Simon Glass0f621332019-07-08 14:25:27 -0600702 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600703 def AddNode(node, path):
704 if node.name != '/':
705 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600706 for prop in node.props.values():
707 if prop.name in prop_names:
708 prop_path = path + ':' + prop.name
709 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
710 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600711 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600712 AddNode(subnode, path)
713
714 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600715 AddNode(dtb.GetRoot(), '')
716 return tree
717
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000718 def _CheckSign(self, fit, key):
719 try:
720 tools.run('fit_check_sign', '-k', key, '-f', fit)
721 except:
722 self.fail('Expected signed FIT container')
723 return False
724 return True
725
Simon Glass57454f42016-11-25 20:15:52 -0700726 def testRun(self):
727 """Test a basic run with valid args"""
728 result = self._RunBinman('-h')
729
730 def testFullHelp(self):
731 """Test that the full help is displayed with -H"""
732 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300733 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500734 # Remove possible extraneous strings
735 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
736 gothelp = result.stdout.replace(extra, '')
737 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700738 self.assertEqual(0, len(result.stderr))
739 self.assertEqual(0, result.return_code)
740
741 def testFullHelpInternal(self):
742 """Test that the full help is displayed with -H"""
743 try:
744 command.test_result = command.CommandResult()
745 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300746 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700747 finally:
748 command.test_result = None
749
750 def testHelp(self):
751 """Test that the basic help is displayed with -h"""
752 result = self._RunBinman('-h')
753 self.assertTrue(len(result.stdout) > 200)
754 self.assertEqual(0, len(result.stderr))
755 self.assertEqual(0, result.return_code)
756
Simon Glass57454f42016-11-25 20:15:52 -0700757 def testBoard(self):
758 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600759 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700760 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300761 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700762 self.assertEqual(0, result)
763
764 def testNeedBoard(self):
765 """Test that we get an error when no board ius supplied"""
766 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600767 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700768 self.assertIn("Must provide a board to process (use -b <board>)",
769 str(e.exception))
770
771 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600772 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700773 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600774 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700775 # We get one error from libfdt, and a different one from fdtget.
776 self.AssertInList(["Couldn't open blob from 'missing_file'",
777 'No such file or directory'], str(e.exception))
778
779 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600780 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700781
782 Since this is a source file it should be compiled and the error
783 will come from the device-tree compiler (dtc).
784 """
785 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600786 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700787 self.assertIn("FATAL ERROR: Unable to parse input tree",
788 str(e.exception))
789
790 def testMissingNode(self):
791 """Test that a device tree without a 'binman' node generates an error"""
792 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600793 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700794 self.assertIn("does not have a 'binman' node", str(e.exception))
795
796 def testEmpty(self):
797 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600798 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700799 self.assertEqual(0, len(result.stderr))
800 self.assertEqual(0, result.return_code)
801
802 def testInvalidEntry(self):
803 """Test that an invalid entry is flagged"""
804 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600805 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600806 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700807 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
808 "'/binman/not-a-valid-type'", str(e.exception))
809
810 def testSimple(self):
811 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600812 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700813 self.assertEqual(U_BOOT_DATA, data)
814
Simon Glass075a45c2017-11-13 18:55:00 -0700815 def testSimpleDebug(self):
816 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600817 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700818
Simon Glass57454f42016-11-25 20:15:52 -0700819 def testDual(self):
820 """Test that we can handle creating two images
821
822 This also tests image padding.
823 """
Simon Glass511f6582018-10-01 12:22:30 -0600824 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700825 self.assertEqual(0, retcode)
826
827 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600828 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700829 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700830 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600831 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700832 data = fd.read()
833 self.assertEqual(U_BOOT_DATA, data)
834
835 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600836 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700837 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700838 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600839 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700840 data = fd.read()
841 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700842 self.assertEqual(tools.get_bytes(0, 3), data[:3])
843 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700844
845 def testBadAlign(self):
846 """Test that an invalid alignment value is detected"""
847 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600848 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700849 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
850 "of two", str(e.exception))
851
852 def testPackSimple(self):
853 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600854 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700855 self.assertEqual(0, retcode)
856 self.assertIn('image', control.images)
857 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600858 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700859 self.assertEqual(5, len(entries))
860
861 # First u-boot
862 self.assertIn('u-boot', entries)
863 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600864 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700865 self.assertEqual(len(U_BOOT_DATA), entry.size)
866
867 # Second u-boot, aligned to 16-byte boundary
868 self.assertIn('u-boot-align', entries)
869 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600870 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700871 self.assertEqual(len(U_BOOT_DATA), entry.size)
872
873 # Third u-boot, size 23 bytes
874 self.assertIn('u-boot-size', entries)
875 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600876 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700877 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
878 self.assertEqual(23, entry.size)
879
880 # Fourth u-boot, placed immediate after the above
881 self.assertIn('u-boot-next', entries)
882 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600883 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700884 self.assertEqual(len(U_BOOT_DATA), entry.size)
885
Simon Glasse8561af2018-08-01 15:22:37 -0600886 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700887 self.assertIn('u-boot-fixed', entries)
888 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600889 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700890 self.assertEqual(len(U_BOOT_DATA), entry.size)
891
Simon Glass39dd2152019-07-08 14:25:47 -0600892 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700893
894 def testPackExtra(self):
895 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600896 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
897 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700898
Simon Glass57454f42016-11-25 20:15:52 -0700899 self.assertIn('image', control.images)
900 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600901 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600902 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700903
Samuel Hollande2574022023-01-21 17:25:16 -0600904 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700905 self.assertIn('u-boot', entries)
906 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600907 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700908 self.assertEqual(3, entry.pad_before)
909 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600910 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700911 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
912 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600913 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700914
915 # Second u-boot has an aligned size, but it has no effect
916 self.assertIn('u-boot-align-size-nop', entries)
917 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600918 self.assertEqual(pos, entry.offset)
919 self.assertEqual(len(U_BOOT_DATA), entry.size)
920 self.assertEqual(U_BOOT_DATA, entry.data)
921 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
922 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700923
924 # Third u-boot has an aligned size too
925 self.assertIn('u-boot-align-size', entries)
926 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600927 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700928 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600929 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700930 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600931 data[pos:pos + entry.size])
932 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700933
934 # Fourth u-boot has an aligned end
935 self.assertIn('u-boot-align-end', entries)
936 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600937 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700938 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600939 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700940 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600941 data[pos:pos + entry.size])
942 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700943
944 # Fifth u-boot immediately afterwards
945 self.assertIn('u-boot-align-both', entries)
946 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600947 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700948 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600949 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700950 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600951 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700952
Samuel Hollande2574022023-01-21 17:25:16 -0600953 # Sixth u-boot with both minimum size and aligned size
954 self.assertIn('u-boot-min-size', entries)
955 entry = entries['u-boot-min-size']
956 self.assertEqual(128, entry.offset)
957 self.assertEqual(32, entry.size)
958 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
959 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
960 data[pos:pos + entry.size])
961
Simon Glass57454f42016-11-25 20:15:52 -0700962 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -0600963 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700964
Simon Glassafb9caa2020-10-26 17:40:10 -0600965 dtb = fdt.Fdt(out_dtb_fname)
966 dtb.Scan()
967 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
968 expected = {
969 'image-pos': 0,
970 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -0600971 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -0600972
973 'u-boot:image-pos': 0,
974 'u-boot:offset': 0,
975 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
976
977 'u-boot-align-size-nop:image-pos': 12,
978 'u-boot-align-size-nop:offset': 12,
979 'u-boot-align-size-nop:size': 4,
980
981 'u-boot-align-size:image-pos': 16,
982 'u-boot-align-size:offset': 16,
983 'u-boot-align-size:size': 32,
984
985 'u-boot-align-end:image-pos': 48,
986 'u-boot-align-end:offset': 48,
987 'u-boot-align-end:size': 16,
988
989 'u-boot-align-both:image-pos': 64,
990 'u-boot-align-both:offset': 64,
991 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -0600992
993 'u-boot-min-size:image-pos': 128,
994 'u-boot-min-size:offset': 128,
995 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -0600996 }
997 self.assertEqual(expected, props)
998
Simon Glass57454f42016-11-25 20:15:52 -0700999 def testPackAlignPowerOf2(self):
1000 """Test that invalid entry alignment is detected"""
1001 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001002 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001003 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
1004 "of two", str(e.exception))
1005
1006 def testPackAlignSizePowerOf2(self):
1007 """Test that invalid entry size alignment is detected"""
1008 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001009 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001010 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1011 "power of two", str(e.exception))
1012
1013 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001014 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001015 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001016 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001017 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001018 "align 0x4 (4)", str(e.exception))
1019
1020 def testPackInvalidSizeAlign(self):
1021 """Test that invalid entry size alignment is detected"""
1022 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001023 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001024 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1025 "align-size 0x4 (4)", str(e.exception))
1026
1027 def testPackOverlap(self):
1028 """Test that overlapping regions are detected"""
1029 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001030 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001031 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001032 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1033 str(e.exception))
1034
1035 def testPackEntryOverflow(self):
1036 """Test that entries that overflow their size are detected"""
1037 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001038 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001039 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1040 "but entry size is 0x3 (3)", str(e.exception))
1041
1042 def testPackImageOverflow(self):
1043 """Test that entries which overflow the image size are detected"""
1044 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001045 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001046 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001047 "size 0x3 (3)", str(e.exception))
1048
1049 def testPackImageSize(self):
1050 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001051 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001052 self.assertEqual(0, retcode)
1053 self.assertIn('image', control.images)
1054 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001055 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001056
1057 def testPackImageSizeAlign(self):
1058 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001059 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001060 self.assertEqual(0, retcode)
1061 self.assertIn('image', control.images)
1062 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001063 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001064
1065 def testPackInvalidImageAlign(self):
1066 """Test that invalid image alignment is detected"""
1067 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001068 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001069 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001070 "align-size 0x8 (8)", str(e.exception))
1071
Simon Glass2a0fa982022-02-11 13:23:21 -07001072 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001073 """Test that invalid image alignment is detected"""
1074 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001075 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001076 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001077 "two", str(e.exception))
1078
1079 def testImagePadByte(self):
1080 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001081 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001082 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001083 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001084 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001085
1086 def testImageName(self):
1087 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001088 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001089 self.assertEqual(0, retcode)
1090 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001091 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001092 self.assertTrue(os.path.exists(fname))
1093
1094 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001095 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001096 self.assertTrue(os.path.exists(fname))
1097
1098 def testBlobFilename(self):
1099 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001100 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001101 self.assertEqual(BLOB_DATA, data)
1102
1103 def testPackSorted(self):
1104 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001105 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001106 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001107 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1108 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001109
Simon Glasse8561af2018-08-01 15:22:37 -06001110 def testPackZeroOffset(self):
1111 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001112 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001113 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001114 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001115 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001116 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1117 str(e.exception))
1118
1119 def testPackUbootDtb(self):
1120 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001121 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001122 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001123
1124 def testPackX86RomNoSize(self):
1125 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001126 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001127 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001128 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001129 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001130 "using end-at-4gb", str(e.exception))
1131
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301132 def test4gbAndSkipAtStartTogether(self):
1133 """Test that the end-at-4gb and skip-at-size property can't be used
1134 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001135 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301136 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001137 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001138 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301139 "'skip-at-start'", str(e.exception))
1140
Simon Glass72232452016-11-25 20:15:53 -07001141 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001142 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001143 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001144 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001145 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001146 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1147 "is outside the section '/binman' starting at "
1148 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001149 str(e.exception))
1150
1151 def testPackX86Rom(self):
1152 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001153 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001154 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001155 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1156 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001157
1158 def testPackX86RomMeNoDesc(self):
1159 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001160 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001161 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001162 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001163 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001164 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1165 str(e.exception))
1166 finally:
1167 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001168
1169 def testPackX86RomBadDesc(self):
1170 """Test that the Intel requires a descriptor entry"""
1171 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001172 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001173 self.assertIn("Node '/binman/intel-me': No offset set with "
1174 "offset-unset: should another entry provide this correct "
1175 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001176
1177 def testPackX86RomMe(self):
1178 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001179 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001180 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001181 if data[:0x1000] != expected_desc:
1182 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001183 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1184
1185 def testPackVga(self):
1186 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001187 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001188 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1189
1190 def testPackStart16(self):
1191 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001192 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001193 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1194
Jagdish Gediya311d4842018-09-03 21:35:08 +05301195 def testPackPowerpcMpc85xxBootpgResetvec(self):
1196 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1197 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001198 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301199 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1200
Simon Glass6ba679c2018-07-06 10:27:17 -06001201 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001202 """Handle running a test for insertion of microcode
1203
1204 Args:
1205 dts_fname: Name of test .dts file
1206 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001207 ucode_second: True if the microsecond entry is second instead of
1208 third
Simon Glass820af1d2018-07-06 10:27:16 -06001209
1210 Returns:
1211 Tuple:
1212 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001213 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001214 in the above (two 4-byte words)
1215 """
Simon Glass3d274232017-11-12 21:52:27 -07001216 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001217
1218 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001219 if ucode_second:
1220 ucode_content = data[len(nodtb_data):]
1221 ucode_pos = len(nodtb_data)
1222 dtb_with_ucode = ucode_content[16:]
1223 fdt_len = self.GetFdtLen(dtb_with_ucode)
1224 else:
1225 dtb_with_ucode = data[len(nodtb_data):]
1226 fdt_len = self.GetFdtLen(dtb_with_ucode)
1227 ucode_content = dtb_with_ucode[fdt_len:]
1228 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001229 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001230 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001231 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001232 dtb = fdt.FdtScan(fname)
1233 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001234 self.assertTrue(ucode)
1235 for node in ucode.subnodes:
1236 self.assertFalse(node.props.get('data'))
1237
Simon Glass72232452016-11-25 20:15:53 -07001238 # Check that the microcode appears immediately after the Fdt
1239 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001240 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001241 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1242 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001243 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001244
1245 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001246 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001247 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1248 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001249 u_boot = data[:len(nodtb_data)]
1250 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001251
1252 def testPackUbootMicrocode(self):
1253 """Test that x86 microcode can be handled correctly
1254
1255 We expect to see the following in the image, in order:
1256 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1257 place
1258 u-boot.dtb with the microcode removed
1259 the microcode
1260 """
Simon Glass511f6582018-10-01 12:22:30 -06001261 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001262 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001263 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1264 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001265
Simon Glassbac25c82017-05-27 07:38:26 -06001266 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001267 """Test that x86 microcode can be handled correctly
1268
1269 We expect to see the following in the image, in order:
1270 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1271 place
1272 u-boot.dtb with the microcode
1273 an empty microcode region
1274 """
1275 # We need the libfdt library to run this test since only that allows
1276 # finding the offset of a property. This is required by
1277 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001278 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001279
1280 second = data[len(U_BOOT_NODTB_DATA):]
1281
1282 fdt_len = self.GetFdtLen(second)
1283 third = second[fdt_len:]
1284 second = second[:fdt_len]
1285
Simon Glassbac25c82017-05-27 07:38:26 -06001286 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1287 self.assertIn(ucode_data, second)
1288 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001289
Simon Glassbac25c82017-05-27 07:38:26 -06001290 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001291 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001292 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1293 len(ucode_data))
1294 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001295 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1296 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001297
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001298 def testPackUbootSingleMicrocode(self):
1299 """Test that x86 microcode can be handled correctly with fdt_normal.
1300 """
Simon Glassbac25c82017-05-27 07:38:26 -06001301 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001302
Simon Glass996021e2016-11-25 20:15:54 -07001303 def testUBootImg(self):
1304 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001305 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001306 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001307
1308 def testNoMicrocode(self):
1309 """Test that a missing microcode region is detected"""
1310 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001311 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001312 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1313 "node found in ", str(e.exception))
1314
1315 def testMicrocodeWithoutNode(self):
1316 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1317 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001318 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001319 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1320 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1321
1322 def testMicrocodeWithoutNode2(self):
1323 """Test that a missing u-boot-ucode node is detected"""
1324 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001325 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001326 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1327 "microcode region u-boot-ucode", str(e.exception))
1328
1329 def testMicrocodeWithoutPtrInElf(self):
1330 """Test that a U-Boot binary without the microcode symbol is detected"""
1331 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001332 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001333 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001334 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001335
1336 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001337 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001338 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1339 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1340
1341 finally:
1342 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001343 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001344 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001345
1346 def testMicrocodeNotInImage(self):
1347 """Test that microcode must be placed within the image"""
1348 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001349 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001350 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1351 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001352 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001353
1354 def testWithoutMicrocode(self):
1355 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001356 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001357 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001358 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001359
1360 # Now check the device tree has no microcode
1361 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1362 second = data[len(U_BOOT_NODTB_DATA):]
1363
1364 fdt_len = self.GetFdtLen(second)
1365 self.assertEqual(dtb, second[:fdt_len])
1366
1367 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1368 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001369 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001370
1371 def testUnknownPosSize(self):
1372 """Test that microcode must be placed within the image"""
1373 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001374 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001375 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001376 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001377
1378 def testPackFsp(self):
1379 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001380 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001381 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1382
1383 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001384 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001385 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001386 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001387
1388 def testPackVbt(self):
1389 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001390 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001391 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001392
Simon Glass7f94e832017-11-12 21:52:25 -07001393 def testSplBssPad(self):
1394 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001395 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001396 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001397 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001398 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001399 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001400
Simon Glass04cda032018-10-01 21:12:42 -06001401 def testSplBssPadMissing(self):
1402 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001403 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001404 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001405 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001406 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1407 str(e.exception))
1408
Simon Glasse83679d2017-11-12 21:52:26 -07001409 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001410 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001411 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001412 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1413
Simon Glass6ba679c2018-07-06 10:27:17 -06001414 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1415 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001416
1417 We expect to see the following in the image, in order:
1418 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1419 correct place
1420 u-boot.dtb with the microcode removed
1421 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001422
1423 Args:
1424 dts: Device tree file to use for test
1425 ucode_second: True if the microsecond entry is second instead of
1426 third
Simon Glass3d274232017-11-12 21:52:27 -07001427 """
Simon Glass7057d022018-10-01 21:12:47 -06001428 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001429 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1430 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001431 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1432 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001433
Simon Glass6ba679c2018-07-06 10:27:17 -06001434 def testPackUbootSplMicrocode(self):
1435 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001436 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001437 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001438
1439 def testPackUbootSplMicrocodeReorder(self):
1440 """Test that order doesn't matter for microcode entries
1441
1442 This is the same as testPackUbootSplMicrocode but when we process the
1443 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1444 entry, so we reply on binman to try later.
1445 """
Simon Glass511f6582018-10-01 12:22:30 -06001446 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001447 ucode_second=True)
1448
Simon Glassa409c932017-11-12 21:52:28 -07001449 def testPackMrc(self):
1450 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001451 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001452 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1453
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001454 def testSplDtb(self):
1455 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001456 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001457 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001458 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1459
Simon Glass0a6da312017-11-13 18:54:56 -07001460 def testSplNoDtb(self):
1461 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001462 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001463 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001464 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1465
Simon Glass7098b7f2021-03-21 18:24:30 +13001466 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4abf7842023-07-18 07:23:54 -06001467 use_expanded=False, no_write_symbols=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001468 """Check the image contains the expected symbol values
1469
1470 Args:
1471 dts: Device tree file to use for test
1472 base_data: Data before and after 'u-boot' section
1473 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001474 entry_args: Dict of entry args to supply to binman
1475 key: arg name
1476 value: value of that arg
1477 use_expanded: True to use expanded entries where available, e.g.
1478 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001479 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001480 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001481 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1482 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001483 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001484 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001485 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001486
Simon Glass7057d022018-10-01 21:12:47 -06001487 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001488 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1489 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001490 # The image should contain the symbols from u_boot_binman_syms.c
1491 # Note that image_pos is adjusted by the base address of the image,
1492 # which is 0x10 in our test image
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001493 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1494 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glass31e04cb2021-03-18 20:24:56 +13001495 0x10 + u_boot_offset, 0x04)
Simon Glass4abf7842023-07-18 07:23:54 -06001496 if no_write_symbols:
1497 expected = (base_data +
1498 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1499 U_BOOT_DATA + base_data)
1500 else:
1501 expected = (sym_values + base_data[24:] +
1502 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1503 base_data[24:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001504 self.assertEqual(expected, data)
1505
Simon Glass31e04cb2021-03-18 20:24:56 +13001506 def testSymbols(self):
1507 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001508 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001509
1510 def testSymbolsNoDtb(self):
1511 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001512 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001513 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1514 0x38)
1515
Simon Glasse76a3e62018-06-01 09:38:11 -06001516 def testPackUnitAddress(self):
1517 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001518 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001519 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1520
Simon Glassa91e1152018-06-01 09:38:16 -06001521 def testSections(self):
1522 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001523 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001524 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1525 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1526 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001527 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001528
Simon Glass30732662018-06-01 09:38:20 -06001529 def testMap(self):
1530 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001531 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001532 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700153300000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600153400000000 00000000 00000010 section@0
153500000000 00000000 00000004 u-boot
153600000010 00000010 00000010 section@1
153700000010 00000000 00000004 u-boot
153800000020 00000020 00000004 section@2
153900000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001540''', map_data)
1541
Simon Glass3b78d532018-06-01 09:38:21 -06001542 def testNamePrefix(self):
1543 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001544 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001545 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700154600000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600154700000000 00000000 00000010 section@0
154800000000 00000000 00000004 ro-u-boot
154900000010 00000010 00000010 section@1
155000000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001551''', map_data)
1552
Simon Glass6ba679c2018-07-06 10:27:17 -06001553 def testUnknownContents(self):
1554 """Test that obtaining the contents works as expected"""
1555 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001556 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001557 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001558 "processing of contents: remaining ["
1559 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001560
Simon Glass2e1169f2018-07-06 10:27:19 -06001561 def testBadChangeSize(self):
1562 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001563 try:
1564 state.SetAllowEntryExpansion(False)
1565 with self.assertRaises(ValueError) as e:
1566 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001567 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001568 str(e.exception))
1569 finally:
1570 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001571
Simon Glassa87014e2018-07-06 10:27:42 -06001572 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001573 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001574 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001575 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001576 dtb = fdt.Fdt(out_dtb_fname)
1577 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001578 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001579 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001580 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001581 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001582 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001583 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001584 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001585 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001586 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001587 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001588 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001589 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001590 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001591
Simon Glasse8561af2018-08-01 15:22:37 -06001592 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001593 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001594 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001595 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001596 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001597 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001598 'size': 40
1599 }, props)
1600
1601 def testUpdateFdtBad(self):
1602 """Test that we detect when ProcessFdt never completes"""
1603 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001604 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001605 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001606 '[<binman.etype._testing.Entry__testing',
1607 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001608
Simon Glass91710b32018-07-17 13:25:32 -06001609 def testEntryArgs(self):
1610 """Test passing arguments to entries from the command line"""
1611 entry_args = {
1612 'test-str-arg': 'test1',
1613 'test-int-arg': '456',
1614 }
Simon Glass511f6582018-10-01 12:22:30 -06001615 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001616 self.assertIn('image', control.images)
1617 entry = control.images['image'].GetEntries()['_testing']
1618 self.assertEqual('test0', entry.test_str_fdt)
1619 self.assertEqual('test1', entry.test_str_arg)
1620 self.assertEqual(123, entry.test_int_fdt)
1621 self.assertEqual(456, entry.test_int_arg)
1622
1623 def testEntryArgsMissing(self):
1624 """Test missing arguments and properties"""
1625 entry_args = {
1626 'test-int-arg': '456',
1627 }
Simon Glass511f6582018-10-01 12:22:30 -06001628 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001629 entry = control.images['image'].GetEntries()['_testing']
1630 self.assertEqual('test0', entry.test_str_fdt)
1631 self.assertEqual(None, entry.test_str_arg)
1632 self.assertEqual(None, entry.test_int_fdt)
1633 self.assertEqual(456, entry.test_int_arg)
1634
1635 def testEntryArgsRequired(self):
1636 """Test missing arguments and properties"""
1637 entry_args = {
1638 'test-int-arg': '456',
1639 }
1640 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001641 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001642 self.assertIn("Node '/binman/_testing': "
1643 'Missing required properties/entry args: test-str-arg, '
1644 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001645 str(e.exception))
1646
1647 def testEntryArgsInvalidFormat(self):
1648 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001649 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1650 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001651 with self.assertRaises(ValueError) as e:
1652 self._DoBinman(*args)
1653 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1654
1655 def testEntryArgsInvalidInteger(self):
1656 """Test that an invalid entry-argument integer is detected"""
1657 entry_args = {
1658 'test-int-arg': 'abc',
1659 }
1660 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001661 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001662 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1663 "'test-int-arg' (value 'abc') to integer",
1664 str(e.exception))
1665
1666 def testEntryArgsInvalidDatatype(self):
1667 """Test that an invalid entry-argument datatype is detected
1668
1669 This test could be written in entry_test.py except that it needs
1670 access to control.entry_args, which seems more than that module should
1671 be able to see.
1672 """
1673 entry_args = {
1674 'test-bad-datatype-arg': '12',
1675 }
1676 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001677 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001678 entry_args=entry_args)
1679 self.assertIn('GetArg() internal error: Unknown data type ',
1680 str(e.exception))
1681
Simon Glass2ca52032018-07-17 13:25:33 -06001682 def testText(self):
1683 """Test for a text entry type"""
1684 entry_args = {
1685 'test-id': TEXT_DATA,
1686 'test-id2': TEXT_DATA2,
1687 'test-id3': TEXT_DATA3,
1688 }
Simon Glass511f6582018-10-01 12:22:30 -06001689 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001690 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001691 expected = (tools.to_bytes(TEXT_DATA) +
1692 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1693 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001694 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001695 self.assertEqual(expected, data)
1696
Simon Glass969616c2018-07-17 13:25:36 -06001697 def testEntryDocs(self):
1698 """Test for creation of entry documentation"""
1699 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001700 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001701 self.assertTrue(len(stdout.getvalue()) > 0)
1702
1703 def testEntryDocsMissing(self):
1704 """Test handling of missing entry documentation"""
1705 with self.assertRaises(ValueError) as e:
1706 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001707 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001708 self.assertIn('Documentation is missing for modules: u_boot',
1709 str(e.exception))
1710
Simon Glass704784b2018-07-17 13:25:38 -06001711 def testFmap(self):
1712 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001713 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001714 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001715 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1716 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001717 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001718 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001719 self.assertEqual(1, fhdr.ver_major)
1720 self.assertEqual(0, fhdr.ver_minor)
1721 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001722 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001723 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001724 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001725 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001726 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001727
Simon Glass82059c22021-04-03 11:05:09 +13001728 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001729 self.assertEqual(b'SECTION0', fentry.name)
1730 self.assertEqual(0, fentry.offset)
1731 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001732 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001733
1734 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001735 self.assertEqual(b'RO_U_BOOT', fentry.name)
1736 self.assertEqual(0, fentry.offset)
1737 self.assertEqual(4, fentry.size)
1738 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001739
Simon Glass82059c22021-04-03 11:05:09 +13001740 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001741 self.assertEqual(b'SECTION1', fentry.name)
1742 self.assertEqual(16, fentry.offset)
1743 self.assertEqual(16, fentry.size)
1744 self.assertEqual(0, fentry.flags)
1745
1746 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001747 self.assertEqual(b'RW_U_BOOT', fentry.name)
1748 self.assertEqual(16, fentry.offset)
1749 self.assertEqual(4, fentry.size)
1750 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001751
Simon Glass82059c22021-04-03 11:05:09 +13001752 fentry = next(fiter)
1753 self.assertEqual(b'FMAP', fentry.name)
1754 self.assertEqual(32, fentry.offset)
1755 self.assertEqual(expect_size, fentry.size)
1756 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001757
Simon Glassdb168d42018-07-17 13:25:39 -06001758 def testBlobNamedByArg(self):
1759 """Test we can add a blob with the filename coming from an entry arg"""
1760 entry_args = {
1761 'cros-ec-rw-path': 'ecrw.bin',
1762 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001763 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001764
Simon Glass53f53992018-07-17 13:25:40 -06001765 def testFill(self):
1766 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001767 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001768 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001769 self.assertEqual(expected, data)
1770
1771 def testFillNoSize(self):
1772 """Test for an fill entry type with no size"""
1773 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001774 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001775 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001776 str(e.exception))
1777
Simon Glassc1ae83c2018-07-17 13:25:44 -06001778 def _HandleGbbCommand(self, pipe_list):
1779 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001780 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001781 fname = pipe_list[0][-1]
1782 # Append our GBB data to the file, which will happen every time the
1783 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001784 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001785 fd.write(GBB_DATA)
1786 return command.CommandResult()
1787
1788 def testGbb(self):
1789 """Test for the Chromium OS Google Binary Block"""
1790 command.test_result = self._HandleGbbCommand
1791 entry_args = {
1792 'keydir': 'devkeys',
1793 'bmpblk': 'bmpblk.bin',
1794 }
Simon Glass511f6582018-10-01 12:22:30 -06001795 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001796
1797 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001798 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1799 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001800 self.assertEqual(expected, data)
1801
1802 def testGbbTooSmall(self):
1803 """Test for the Chromium OS Google Binary Block being large enough"""
1804 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001805 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001806 self.assertIn("Node '/binman/gbb': GBB is too small",
1807 str(e.exception))
1808
1809 def testGbbNoSize(self):
1810 """Test for the Chromium OS Google Binary Block having a size"""
1811 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001812 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001813 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1814 str(e.exception))
1815
Simon Glass66152ce2022-01-09 20:14:09 -07001816 def testGbbMissing(self):
1817 """Test that binman still produces an image if futility is missing"""
1818 entry_args = {
1819 'keydir': 'devkeys',
1820 }
1821 with test_util.capture_sys_output() as (_, stderr):
1822 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1823 entry_args=entry_args)
1824 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001825 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001826
Simon Glass5c350162018-07-17 13:25:47 -06001827 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001828 """Fake calls to the futility utility
1829
1830 The expected pipe is:
1831
1832 [('futility', 'vbutil_firmware', '--vblock',
1833 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1834 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1835 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1836 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1837
1838 This writes to the output file (here, 'vblock.vblock'). If
1839 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1840 of the input data (here, 'input.vblock').
1841 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001842 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001843 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001844 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001845 if self._hash_data:
1846 infile = pipe_list[0][11]
1847 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001848 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001849 m.update(data)
1850 fd.write(m.digest())
1851 else:
1852 fd.write(VBLOCK_DATA)
1853
Simon Glass5c350162018-07-17 13:25:47 -06001854 return command.CommandResult()
1855
1856 def testVblock(self):
1857 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001858 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001859 command.test_result = self._HandleVblockCommand
1860 entry_args = {
1861 'keydir': 'devkeys',
1862 }
Simon Glass511f6582018-10-01 12:22:30 -06001863 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001864 entry_args=entry_args)
1865 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1866 self.assertEqual(expected, data)
1867
1868 def testVblockNoContent(self):
1869 """Test we detect a vblock which has no content to sign"""
1870 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001871 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001872 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001873 'property', str(e.exception))
1874
1875 def testVblockBadPhandle(self):
1876 """Test that we detect a vblock with an invalid phandle in contents"""
1877 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001878 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001879 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1880 '1000', str(e.exception))
1881
1882 def testVblockBadEntry(self):
1883 """Test that we detect an entry that points to a non-entry"""
1884 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001885 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001886 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1887 "'other'", str(e.exception))
1888
Simon Glass220c6222021-01-06 21:35:17 -07001889 def testVblockContent(self):
1890 """Test that the vblock signs the right data"""
1891 self._hash_data = True
1892 command.test_result = self._HandleVblockCommand
1893 entry_args = {
1894 'keydir': 'devkeys',
1895 }
1896 data = self._DoReadFileDtb(
1897 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1898 entry_args=entry_args)[0]
1899 hashlen = 32 # SHA256 hash is 32 bytes
1900 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1901 hashval = data[-hashlen:]
1902 dtb = data[len(U_BOOT_DATA):-hashlen]
1903
1904 expected_data = U_BOOT_DATA + dtb
1905
1906 # The hashval should be a hash of the dtb
1907 m = hashlib.sha256()
1908 m.update(expected_data)
1909 expected_hashval = m.digest()
1910 self.assertEqual(expected_hashval, hashval)
1911
Simon Glass66152ce2022-01-09 20:14:09 -07001912 def testVblockMissing(self):
1913 """Test that binman still produces an image if futility is missing"""
1914 entry_args = {
1915 'keydir': 'devkeys',
1916 }
1917 with test_util.capture_sys_output() as (_, stderr):
1918 self._DoTestFile('074_vblock.dts',
1919 force_missing_bintools='futility',
1920 entry_args=entry_args)
1921 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001922 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001923
Simon Glass8425a1f2018-07-17 13:25:48 -06001924 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001925 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001926 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001927 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001928 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001929 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1930
Simon Glass24b97442018-07-17 13:25:51 -06001931 def testUsesPos(self):
1932 """Test that the 'pos' property cannot be used anymore"""
1933 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001934 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001935 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1936 "'pos'", str(e.exception))
1937
Simon Glass274bf092018-09-14 04:57:08 -06001938 def testFillZero(self):
1939 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001940 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001941 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001942
Simon Glass267de432018-09-14 04:57:09 -06001943 def testTextMissing(self):
1944 """Test for a text entry type where there is no text"""
1945 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001946 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001947 self.assertIn("Node '/binman/text': No value provided for text label "
1948 "'test-id'", str(e.exception))
1949
Simon Glassed40e962018-09-14 04:57:10 -06001950 def testPackStart16Tpl(self):
1951 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001952 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001953 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1954
Simon Glass3b376c32018-09-14 04:57:12 -06001955 def testSelectImage(self):
1956 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001957 expected = 'Skipping images: image1'
1958
1959 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001960 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001961 with test_util.capture_sys_output() as (stdout, stderr):
1962 retcode = self._DoTestFile('006_dual_image.dts',
1963 verbosity=verbosity,
1964 images=['image2'])
1965 self.assertEqual(0, retcode)
1966 if verbosity:
1967 self.assertIn(expected, stdout.getvalue())
1968 else:
1969 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001970
Simon Glass80025522022-01-29 14:14:04 -07001971 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1972 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001973 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001974
Simon Glasse219aa42018-09-14 04:57:24 -06001975 def testUpdateFdtAll(self):
1976 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001977 self._SetupSplElf()
1978 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06001979 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001980
1981 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06001982 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001983 'image-pos': 0,
1984 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06001985 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001986 'section:image-pos': 0,
1987 'section:size': 565,
1988 'section/u-boot-dtb:offset': 0,
1989 'section/u-boot-dtb:image-pos': 0,
1990 'section/u-boot-dtb:size': 565,
1991 'u-boot-spl-dtb:offset': 565,
1992 'u-boot-spl-dtb:image-pos': 565,
1993 'u-boot-spl-dtb:size': 585,
1994 'u-boot-tpl-dtb:offset': 1150,
1995 'u-boot-tpl-dtb:image-pos': 1150,
1996 'u-boot-tpl-dtb:size': 585,
1997 'u-boot-vpl-dtb:image-pos': 1735,
1998 'u-boot-vpl-dtb:offset': 1735,
1999 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06002000 }
2001
2002 # We expect three device-tree files in the output, one after the other.
2003 # Read them in sequence. We look for an 'spl' property in the SPL tree,
2004 # and 'tpl' in the TPL tree, to make sure they are distinct from the
2005 # main U-Boot tree. All three should have the same postions and offset.
2006 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002007 self.maxDiff = None
2008 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002009 dtb = fdt.Fdt.FromData(data[start:])
2010 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002011 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002012 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002013 expected = dict(base_expected)
2014 if item:
2015 expected[item] = 0
2016 self.assertEqual(expected, props)
2017 start += dtb._fdt_obj.totalsize()
2018
2019 def testUpdateFdtOutput(self):
2020 """Test that output DTB files are updated"""
2021 try:
Simon Glass511f6582018-10-01 12:22:30 -06002022 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002023 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2024
2025 # Unfortunately, compiling a source file always results in a file
2026 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002027 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002028 # binman as a file called u-boot.dtb. To fix this, copy the file
2029 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002030 start = 0
2031 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002032 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002033 dtb = fdt.Fdt.FromData(data[start:])
2034 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002035 pathname = tools.get_output_filename(os.path.split(fname)[1])
2036 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002037 name = os.path.split(fname)[0]
2038
2039 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002040 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002041 else:
2042 orig_indata = dtb_data
2043 self.assertNotEqual(outdata, orig_indata,
2044 "Expected output file '%s' be updated" % pathname)
2045 self.assertEqual(outdata, data[start:start + size],
2046 "Expected output file '%s' to match output image" %
2047 pathname)
2048 start += size
2049 finally:
2050 self._ResetDtbs()
2051
Simon Glass7ba33592018-09-14 04:57:26 -06002052 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002053 bintool = self.comp_bintools['lz4']
2054 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002055
2056 def testCompress(self):
2057 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002058 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002059 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002060 use_real_dtb=True, update_dtb=True)
2061 dtb = fdt.Fdt(out_dtb_fname)
2062 dtb.Scan()
2063 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2064 orig = self._decompress(data)
2065 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002066
2067 # Do a sanity check on various fields
2068 image = control.images['image']
2069 entries = image.GetEntries()
2070 self.assertEqual(1, len(entries))
2071
2072 entry = entries['blob']
2073 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2074 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2075 orig = self._decompress(entry.data)
2076 self.assertEqual(orig, entry.uncomp_data)
2077
Simon Glass72eeff12020-10-26 17:40:16 -06002078 self.assertEqual(image.data, entry.data)
2079
Simon Glass7ba33592018-09-14 04:57:26 -06002080 expected = {
2081 'blob:uncomp-size': len(COMPRESS_DATA),
2082 'blob:size': len(data),
2083 'size': len(data),
2084 }
2085 self.assertEqual(expected, props)
2086
Simon Glassac6328c2018-09-14 04:57:28 -06002087 def testFiles(self):
2088 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002089 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002090 self.assertEqual(FILES_DATA, data)
2091
2092 def testFilesCompress(self):
2093 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002094 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002095 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002096
2097 image = control.images['image']
2098 entries = image.GetEntries()
2099 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002100 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002101
Simon Glass303f62f2019-05-17 22:00:46 -06002102 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002103 for i in range(1, 3):
2104 key = '%d.dat' % i
2105 start = entries[key].image_pos
2106 len = entries[key].size
2107 chunk = data[start:start + len]
2108 orig += self._decompress(chunk)
2109
2110 self.assertEqual(FILES_DATA, orig)
2111
2112 def testFilesMissing(self):
2113 """Test missing files"""
2114 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002115 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002116 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2117 'no files', str(e.exception))
2118
2119 def testFilesNoPattern(self):
2120 """Test missing files"""
2121 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002122 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002123 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2124 str(e.exception))
2125
Simon Glassdd156a42022-03-05 20:18:59 -07002126 def testExtendSize(self):
2127 """Test an extending entry"""
2128 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002129 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002130 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2131 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2132 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2133 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002134 self.assertEqual(expect, data)
2135 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700213600000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600213700000000 00000000 00000008 fill
213800000008 00000008 00000004 u-boot
21390000000c 0000000c 00000004 section
21400000000c 00000000 00000003 intel-mrc
214100000010 00000010 00000004 u-boot2
214200000014 00000014 0000000c section2
214300000014 00000000 00000008 fill
21440000001c 00000008 00000004 u-boot
214500000020 00000020 00000008 fill2
2146''', map_data)
2147
Simon Glassdd156a42022-03-05 20:18:59 -07002148 def testExtendSizeBad(self):
2149 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002150 with test_util.capture_sys_output() as (stdout, stderr):
2151 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002152 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002153 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2154 'expanding entry', str(e.exception))
2155
Simon Glassae7cf032018-09-14 04:57:31 -06002156 def testHash(self):
2157 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002158 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002159 use_real_dtb=True, update_dtb=True)
2160 dtb = fdt.Fdt(out_dtb_fname)
2161 dtb.Scan()
2162 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2163 m = hashlib.sha256()
2164 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002165 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002166
2167 def testHashNoAlgo(self):
2168 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002169 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002170 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2171 'hash node', str(e.exception))
2172
2173 def testHashBadAlgo(self):
2174 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002175 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002176 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002177 str(e.exception))
2178
2179 def testHashSection(self):
2180 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002181 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002182 use_real_dtb=True, update_dtb=True)
2183 dtb = fdt.Fdt(out_dtb_fname)
2184 dtb.Scan()
2185 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2186 m = hashlib.sha256()
2187 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002188 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002189 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002190
Simon Glass3fb4f422018-09-14 04:57:32 -06002191 def testPackUBootTplMicrocode(self):
2192 """Test that x86 microcode can be handled correctly in TPL
2193
2194 We expect to see the following in the image, in order:
2195 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2196 place
2197 u-boot-tpl.dtb with the microcode removed
2198 the microcode
2199 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002200 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002201 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002202 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002203 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2204 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002205
Simon Glassc64aea52018-09-14 04:57:34 -06002206 def testFmapX86(self):
2207 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002208 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002209 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002210 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002211 self.assertEqual(expected, data[:32])
2212 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2213
2214 self.assertEqual(0x100, fhdr.image_size)
2215
2216 self.assertEqual(0, fentries[0].offset)
2217 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002218 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002219
2220 self.assertEqual(4, fentries[1].offset)
2221 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002222 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002223
2224 self.assertEqual(32, fentries[2].offset)
2225 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2226 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002227 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002228
2229 def testFmapX86Section(self):
2230 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002231 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002232 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002233 self.assertEqual(expected, data[:32])
2234 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2235
Simon Glassb1d414c2021-04-03 11:05:10 +13002236 self.assertEqual(0x180, fhdr.image_size)
2237 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002238 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002239
Simon Glass82059c22021-04-03 11:05:09 +13002240 fentry = next(fiter)
2241 self.assertEqual(b'U_BOOT', fentry.name)
2242 self.assertEqual(0, fentry.offset)
2243 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002244
Simon Glass82059c22021-04-03 11:05:09 +13002245 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002246 self.assertEqual(b'SECTION', fentry.name)
2247 self.assertEqual(4, fentry.offset)
2248 self.assertEqual(0x20 + expect_size, fentry.size)
2249
2250 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002251 self.assertEqual(b'INTEL_MRC', fentry.name)
2252 self.assertEqual(4, fentry.offset)
2253 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002254
Simon Glass82059c22021-04-03 11:05:09 +13002255 fentry = next(fiter)
2256 self.assertEqual(b'FMAP', fentry.name)
2257 self.assertEqual(36, fentry.offset)
2258 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002259
Simon Glassb1714232018-09-14 04:57:35 -06002260 def testElf(self):
2261 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002262 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002263 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002264 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002265 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002266 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002267
Simon Glass0d673792019-07-08 13:18:25 -06002268 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002269 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002270 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002271 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002272 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002273 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002274
Simon Glasscd817d52018-09-14 04:57:36 -06002275 def testPackOverlapMap(self):
2276 """Test that overlapping regions are detected"""
2277 with test_util.capture_sys_output() as (stdout, stderr):
2278 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002279 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002280 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002281 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2282 stdout.getvalue())
2283
2284 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002285 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002286 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002287 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002288 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002289<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002290<none> 00000000 00000004 u-boot
2291<none> 00000003 00000004 u-boot-align
2292''', map_data)
2293
Simon Glass0d673792019-07-08 13:18:25 -06002294 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002295 """Test that an image with an Intel Reference code binary works"""
2296 data = self._DoReadFile('100_intel_refcode.dts')
2297 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2298
Simon Glasseb023b32019-04-25 21:58:39 -06002299 def testSectionOffset(self):
2300 """Tests use of a section with an offset"""
2301 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2302 map=True)
2303 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700230400000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600230500000004 00000004 00000010 section@0
230600000004 00000000 00000004 u-boot
230700000018 00000018 00000010 section@1
230800000018 00000000 00000004 u-boot
23090000002c 0000002c 00000004 section@2
23100000002c 00000000 00000004 u-boot
2311''', map_data)
2312 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002313 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2314 tools.get_bytes(0x21, 12) +
2315 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2316 tools.get_bytes(0x61, 12) +
2317 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2318 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002319
Simon Glass1de34482019-07-08 13:18:53 -06002320 def testCbfsRaw(self):
2321 """Test base handling of a Coreboot Filesystem (CBFS)
2322
2323 The exact contents of the CBFS is verified by similar tests in
2324 cbfs_util_test.py. The tests here merely check that the files added to
2325 the CBFS can be found in the final image.
2326 """
2327 data = self._DoReadFile('102_cbfs_raw.dts')
2328 size = 0xb0
2329
2330 cbfs = cbfs_util.CbfsReader(data)
2331 self.assertEqual(size, cbfs.rom_size)
2332
2333 self.assertIn('u-boot-dtb', cbfs.files)
2334 cfile = cbfs.files['u-boot-dtb']
2335 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2336
2337 def testCbfsArch(self):
2338 """Test on non-x86 architecture"""
2339 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2340 size = 0x100
2341
2342 cbfs = cbfs_util.CbfsReader(data)
2343 self.assertEqual(size, cbfs.rom_size)
2344
2345 self.assertIn('u-boot-dtb', cbfs.files)
2346 cfile = cbfs.files['u-boot-dtb']
2347 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2348
2349 def testCbfsStage(self):
2350 """Tests handling of a Coreboot Filesystem (CBFS)"""
2351 if not elf.ELF_TOOLS:
2352 self.skipTest('Python elftools not available')
2353 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2354 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2355 size = 0xb0
2356
2357 data = self._DoReadFile('104_cbfs_stage.dts')
2358 cbfs = cbfs_util.CbfsReader(data)
2359 self.assertEqual(size, cbfs.rom_size)
2360
2361 self.assertIn('u-boot', cbfs.files)
2362 cfile = cbfs.files['u-boot']
2363 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2364
2365 def testCbfsRawCompress(self):
2366 """Test handling of compressing raw files"""
2367 self._CheckLz4()
2368 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2369 size = 0x140
2370
2371 cbfs = cbfs_util.CbfsReader(data)
2372 self.assertIn('u-boot', cbfs.files)
2373 cfile = cbfs.files['u-boot']
2374 self.assertEqual(COMPRESS_DATA, cfile.data)
2375
2376 def testCbfsBadArch(self):
2377 """Test handling of a bad architecture"""
2378 with self.assertRaises(ValueError) as e:
2379 self._DoReadFile('106_cbfs_bad_arch.dts')
2380 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2381
2382 def testCbfsNoSize(self):
2383 """Test handling of a missing size property"""
2384 with self.assertRaises(ValueError) as e:
2385 self._DoReadFile('107_cbfs_no_size.dts')
2386 self.assertIn('entry must have a size property', str(e.exception))
2387
Simon Glass3e28f4f2021-11-23 11:03:54 -07002388 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002389 """Test handling of a CBFS entry which does not provide contentsy"""
2390 with self.assertRaises(ValueError) as e:
2391 self._DoReadFile('108_cbfs_no_contents.dts')
2392 self.assertIn('Could not complete processing of contents',
2393 str(e.exception))
2394
2395 def testCbfsBadCompress(self):
2396 """Test handling of a bad architecture"""
2397 with self.assertRaises(ValueError) as e:
2398 self._DoReadFile('109_cbfs_bad_compress.dts')
2399 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2400 str(e.exception))
2401
2402 def testCbfsNamedEntries(self):
2403 """Test handling of named entries"""
2404 data = self._DoReadFile('110_cbfs_name.dts')
2405
2406 cbfs = cbfs_util.CbfsReader(data)
2407 self.assertIn('FRED', cbfs.files)
2408 cfile1 = cbfs.files['FRED']
2409 self.assertEqual(U_BOOT_DATA, cfile1.data)
2410
2411 self.assertIn('hello', cbfs.files)
2412 cfile2 = cbfs.files['hello']
2413 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2414
Simon Glass759af872019-07-08 13:18:54 -06002415 def _SetupIfwi(self, fname):
2416 """Set up to run an IFWI test
2417
2418 Args:
2419 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2420 """
2421 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002422 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002423
2424 # Intel Integrated Firmware Image (IFWI) file
2425 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2426 data = fd.read()
2427 TestFunctional._MakeInputFile(fname,data)
2428
2429 def _CheckIfwi(self, data):
2430 """Check that an image with an IFWI contains the correct output
2431
2432 Args:
2433 data: Conents of output file
2434 """
Simon Glass80025522022-01-29 14:14:04 -07002435 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002436 if data[:0x1000] != expected_desc:
2437 self.fail('Expected descriptor binary at start of image')
2438
2439 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002440 image_fname = tools.get_output_filename('image.bin')
2441 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002442 ifwitool = bintool.Bintool.create('ifwitool')
2443 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002444
Simon Glass80025522022-01-29 14:14:04 -07002445 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002446 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002447
2448 def testPackX86RomIfwi(self):
2449 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2450 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002451 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002452 self._CheckIfwi(data)
2453
2454 def testPackX86RomIfwiNoDesc(self):
2455 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2456 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002457 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002458 self._CheckIfwi(data)
2459
2460 def testPackX86RomIfwiNoData(self):
2461 """Test that an x86 ROM with IFWI handles missing data"""
2462 self._SetupIfwi('ifwi.bin')
2463 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002464 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002465 self.assertIn('Could not complete processing of contents',
2466 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002467
Simon Glass66152ce2022-01-09 20:14:09 -07002468 def testIfwiMissing(self):
2469 """Test that binman still produces an image if ifwitool is missing"""
2470 self._SetupIfwi('fitimage.bin')
2471 with test_util.capture_sys_output() as (_, stderr):
2472 self._DoTestFile('111_x86_rom_ifwi.dts',
2473 force_missing_bintools='ifwitool')
2474 err = stderr.getvalue()
2475 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002476 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002477
Simon Glassc2f1aed2019-07-08 13:18:56 -06002478 def testCbfsOffset(self):
2479 """Test a CBFS with files at particular offsets
2480
2481 Like all CFBS tests, this is just checking the logic that calls
2482 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2483 """
2484 data = self._DoReadFile('114_cbfs_offset.dts')
2485 size = 0x200
2486
2487 cbfs = cbfs_util.CbfsReader(data)
2488 self.assertEqual(size, cbfs.rom_size)
2489
2490 self.assertIn('u-boot', cbfs.files)
2491 cfile = cbfs.files['u-boot']
2492 self.assertEqual(U_BOOT_DATA, cfile.data)
2493 self.assertEqual(0x40, cfile.cbfs_offset)
2494
2495 self.assertIn('u-boot-dtb', cbfs.files)
2496 cfile2 = cbfs.files['u-boot-dtb']
2497 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2498 self.assertEqual(0x140, cfile2.cbfs_offset)
2499
Simon Glass0f621332019-07-08 14:25:27 -06002500 def testFdtmap(self):
2501 """Test an FDT map can be inserted in the image"""
2502 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2503 fdtmap_data = data[len(U_BOOT_DATA):]
2504 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002505 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002506 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002507
2508 fdt_data = fdtmap_data[16:]
2509 dtb = fdt.Fdt.FromData(fdt_data)
2510 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002511 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002512 self.assertEqual({
2513 'image-pos': 0,
2514 'offset': 0,
2515 'u-boot:offset': 0,
2516 'u-boot:size': len(U_BOOT_DATA),
2517 'u-boot:image-pos': 0,
2518 'fdtmap:image-pos': 4,
2519 'fdtmap:offset': 4,
2520 'fdtmap:size': len(fdtmap_data),
2521 'size': len(data),
2522 }, props)
2523
2524 def testFdtmapNoMatch(self):
2525 """Check handling of an FDT map when the section cannot be found"""
2526 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2527
2528 # Mangle the section name, which should cause a mismatch between the
2529 # correct FDT path and the one expected by the section
2530 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002531 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002532 entries = image.GetEntries()
2533 fdtmap = entries['fdtmap']
2534 with self.assertRaises(ValueError) as e:
2535 fdtmap._GetFdtmap()
2536 self.assertIn("Cannot locate node for path '/binman-suffix'",
2537 str(e.exception))
2538
Simon Glasscec34ba2019-07-08 14:25:28 -06002539 def testFdtmapHeader(self):
2540 """Test an FDT map and image header can be inserted in the image"""
2541 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2542 fdtmap_pos = len(U_BOOT_DATA)
2543 fdtmap_data = data[fdtmap_pos:]
2544 fdt_data = fdtmap_data[16:]
2545 dtb = fdt.Fdt.FromData(fdt_data)
2546 fdt_size = dtb.GetFdtObj().totalsize()
2547 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002548 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002549 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2550 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2551
2552 def testFdtmapHeaderStart(self):
2553 """Test an image header can be inserted at the image start"""
2554 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2555 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2556 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002557 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002558 offset = struct.unpack('<I', hdr_data[4:])[0]
2559 self.assertEqual(fdtmap_pos, offset)
2560
2561 def testFdtmapHeaderPos(self):
2562 """Test an image header can be inserted at a chosen position"""
2563 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2564 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2565 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002566 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002567 offset = struct.unpack('<I', hdr_data[4:])[0]
2568 self.assertEqual(fdtmap_pos, offset)
2569
2570 def testHeaderMissingFdtmap(self):
2571 """Test an image header requires an fdtmap"""
2572 with self.assertRaises(ValueError) as e:
2573 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2574 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2575 str(e.exception))
2576
2577 def testHeaderNoLocation(self):
2578 """Test an image header with a no specified location is detected"""
2579 with self.assertRaises(ValueError) as e:
2580 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2581 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2582 str(e.exception))
2583
Simon Glasse61b6f62019-07-08 14:25:37 -06002584 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002585 """Test extending an entry after it is packed"""
2586 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002587 self.assertEqual(b'aaa', data[:3])
2588 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2589 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002590
Simon Glassdd156a42022-03-05 20:18:59 -07002591 def testEntryExtendBad(self):
2592 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002593 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002594 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002595 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002596 str(e.exception))
2597
Simon Glassdd156a42022-03-05 20:18:59 -07002598 def testEntryExtendSection(self):
2599 """Test extending an entry within a section after it is packed"""
2600 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002601 self.assertEqual(b'aaa', data[:3])
2602 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2603 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002604
Simon Glass90d29682019-07-08 14:25:38 -06002605 def testCompressDtb(self):
2606 """Test that compress of device-tree files is supported"""
2607 self._CheckLz4()
2608 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2609 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2610 comp_data = data[len(U_BOOT_DATA):]
2611 orig = self._decompress(comp_data)
2612 dtb = fdt.Fdt.FromData(orig)
2613 dtb.Scan()
2614 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2615 expected = {
2616 'u-boot:size': len(U_BOOT_DATA),
2617 'u-boot-dtb:uncomp-size': len(orig),
2618 'u-boot-dtb:size': len(comp_data),
2619 'size': len(data),
2620 }
2621 self.assertEqual(expected, props)
2622
Simon Glass151bbbf2019-07-08 14:25:41 -06002623 def testCbfsUpdateFdt(self):
2624 """Test that we can update the device tree with CBFS offset/size info"""
2625 self._CheckLz4()
2626 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2627 update_dtb=True)
2628 dtb = fdt.Fdt(out_dtb_fname)
2629 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002630 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002631 del props['cbfs/u-boot:size']
2632 self.assertEqual({
2633 'offset': 0,
2634 'size': len(data),
2635 'image-pos': 0,
2636 'cbfs:offset': 0,
2637 'cbfs:size': len(data),
2638 'cbfs:image-pos': 0,
2639 'cbfs/u-boot:offset': 0x38,
2640 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2641 'cbfs/u-boot:image-pos': 0x38,
2642 'cbfs/u-boot-dtb:offset': 0xb8,
2643 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2644 'cbfs/u-boot-dtb:image-pos': 0xb8,
2645 }, props)
2646
Simon Glass3c9b4f22019-07-08 14:25:42 -06002647 def testCbfsBadType(self):
2648 """Test an image header with a no specified location is detected"""
2649 with self.assertRaises(ValueError) as e:
2650 self._DoReadFile('126_cbfs_bad_type.dts')
2651 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2652
Simon Glass6b156f82019-07-08 14:25:43 -06002653 def testList(self):
2654 """Test listing the files in an image"""
2655 self._CheckLz4()
2656 data = self._DoReadFile('127_list.dts')
2657 image = control.images['image']
2658 entries = image.BuildEntryList()
2659 self.assertEqual(7, len(entries))
2660
2661 ent = entries[0]
2662 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002663 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002664 self.assertEqual('section', ent.etype)
2665 self.assertEqual(len(data), ent.size)
2666 self.assertEqual(0, ent.image_pos)
2667 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002668 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002669
2670 ent = entries[1]
2671 self.assertEqual(1, ent.indent)
2672 self.assertEqual('u-boot', ent.name)
2673 self.assertEqual('u-boot', ent.etype)
2674 self.assertEqual(len(U_BOOT_DATA), ent.size)
2675 self.assertEqual(0, ent.image_pos)
2676 self.assertEqual(None, ent.uncomp_size)
2677 self.assertEqual(0, ent.offset)
2678
2679 ent = entries[2]
2680 self.assertEqual(1, ent.indent)
2681 self.assertEqual('section', ent.name)
2682 self.assertEqual('section', ent.etype)
2683 section_size = ent.size
2684 self.assertEqual(0x100, ent.image_pos)
2685 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002686 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002687
2688 ent = entries[3]
2689 self.assertEqual(2, ent.indent)
2690 self.assertEqual('cbfs', ent.name)
2691 self.assertEqual('cbfs', ent.etype)
2692 self.assertEqual(0x400, ent.size)
2693 self.assertEqual(0x100, ent.image_pos)
2694 self.assertEqual(None, ent.uncomp_size)
2695 self.assertEqual(0, ent.offset)
2696
2697 ent = entries[4]
2698 self.assertEqual(3, ent.indent)
2699 self.assertEqual('u-boot', ent.name)
2700 self.assertEqual('u-boot', ent.etype)
2701 self.assertEqual(len(U_BOOT_DATA), ent.size)
2702 self.assertEqual(0x138, ent.image_pos)
2703 self.assertEqual(None, ent.uncomp_size)
2704 self.assertEqual(0x38, ent.offset)
2705
2706 ent = entries[5]
2707 self.assertEqual(3, ent.indent)
2708 self.assertEqual('u-boot-dtb', ent.name)
2709 self.assertEqual('text', ent.etype)
2710 self.assertGreater(len(COMPRESS_DATA), ent.size)
2711 self.assertEqual(0x178, ent.image_pos)
2712 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2713 self.assertEqual(0x78, ent.offset)
2714
2715 ent = entries[6]
2716 self.assertEqual(2, ent.indent)
2717 self.assertEqual('u-boot-dtb', ent.name)
2718 self.assertEqual('u-boot-dtb', ent.etype)
2719 self.assertEqual(0x500, ent.image_pos)
2720 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2721 dtb_size = ent.size
2722 # Compressing this data expands it since headers are added
2723 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2724 self.assertEqual(0x400, ent.offset)
2725
2726 self.assertEqual(len(data), 0x100 + section_size)
2727 self.assertEqual(section_size, 0x400 + dtb_size)
2728
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002729 def testFindFdtmap(self):
2730 """Test locating an FDT map in an image"""
2731 self._CheckLz4()
2732 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2733 image = control.images['image']
2734 entries = image.GetEntries()
2735 entry = entries['fdtmap']
2736 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2737
2738 def testFindFdtmapMissing(self):
2739 """Test failing to locate an FDP map"""
2740 data = self._DoReadFile('005_simple.dts')
2741 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2742
Simon Glassed39a3c2019-07-08 14:25:45 -06002743 def testFindImageHeader(self):
2744 """Test locating a image header"""
2745 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002746 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002747 image = control.images['image']
2748 entries = image.GetEntries()
2749 entry = entries['fdtmap']
2750 # The header should point to the FDT map
2751 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2752
2753 def testFindImageHeaderStart(self):
2754 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002755 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002756 image = control.images['image']
2757 entries = image.GetEntries()
2758 entry = entries['fdtmap']
2759 # The header should point to the FDT map
2760 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2761
2762 def testFindImageHeaderMissing(self):
2763 """Test failing to locate an image header"""
2764 data = self._DoReadFile('005_simple.dts')
2765 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2766
Simon Glassb8424fa2019-07-08 14:25:46 -06002767 def testReadImage(self):
2768 """Test reading an image and accessing its FDT map"""
2769 self._CheckLz4()
2770 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002771 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002772 orig_image = control.images['image']
2773 image = Image.FromFile(image_fname)
2774 self.assertEqual(orig_image.GetEntries().keys(),
2775 image.GetEntries().keys())
2776
2777 orig_entry = orig_image.GetEntries()['fdtmap']
2778 entry = image.GetEntries()['fdtmap']
2779 self.assertEquals(orig_entry.offset, entry.offset)
2780 self.assertEquals(orig_entry.size, entry.size)
2781 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2782
2783 def testReadImageNoHeader(self):
2784 """Test accessing an image's FDT map without an image header"""
2785 self._CheckLz4()
2786 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002787 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002788 image = Image.FromFile(image_fname)
2789 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002790 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002791
2792 def testReadImageFail(self):
2793 """Test failing to read an image image's FDT map"""
2794 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002795 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002796 with self.assertRaises(ValueError) as e:
2797 image = Image.FromFile(image_fname)
2798 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002799
Simon Glassb2fd11d2019-07-08 14:25:48 -06002800 def testListCmd(self):
2801 """Test listing the files in an image using an Fdtmap"""
2802 self._CheckLz4()
2803 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2804
2805 # lz4 compression size differs depending on the version
2806 image = control.images['image']
2807 entries = image.GetEntries()
2808 section_size = entries['section'].size
2809 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2810 fdtmap_offset = entries['fdtmap'].offset
2811
Simon Glassb3d6fc72019-07-20 12:24:10 -06002812 try:
2813 tmpdir, updated_fname = self._SetupImageInTmpdir()
2814 with test_util.capture_sys_output() as (stdout, stderr):
2815 self._DoBinman('ls', '-i', updated_fname)
2816 finally:
2817 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002818 lines = stdout.getvalue().splitlines()
2819 expected = [
2820'Name Image-pos Size Entry-type Offset Uncomp-size',
2821'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002822'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002823' u-boot 0 4 u-boot 0',
2824' section 100 %x section 100' % section_size,
2825' cbfs 100 400 cbfs 0',
2826' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002827' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002828' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002829' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002830 (fdtmap_offset, fdtmap_offset),
2831' image-header bf8 8 image-header bf8',
2832 ]
2833 self.assertEqual(expected, lines)
2834
2835 def testListCmdFail(self):
2836 """Test failing to list an image"""
2837 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002838 try:
2839 tmpdir, updated_fname = self._SetupImageInTmpdir()
2840 with self.assertRaises(ValueError) as e:
2841 self._DoBinman('ls', '-i', updated_fname)
2842 finally:
2843 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002844 self.assertIn("Cannot find FDT map in image", str(e.exception))
2845
2846 def _RunListCmd(self, paths, expected):
2847 """List out entries and check the result
2848
2849 Args:
2850 paths: List of paths to pass to the list command
2851 expected: Expected list of filenames to be returned, in order
2852 """
2853 self._CheckLz4()
2854 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002855 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002856 image = Image.FromFile(image_fname)
2857 lines = image.GetListEntries(paths)[1]
2858 files = [line[0].strip() for line in lines[1:]]
2859 self.assertEqual(expected, files)
2860
2861 def testListCmdSection(self):
2862 """Test listing the files in a section"""
2863 self._RunListCmd(['section'],
2864 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2865
2866 def testListCmdFile(self):
2867 """Test listing a particular file"""
2868 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2869
2870 def testListCmdWildcard(self):
2871 """Test listing a wildcarded file"""
2872 self._RunListCmd(['*boot*'],
2873 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2874
2875 def testListCmdWildcardMulti(self):
2876 """Test listing a wildcarded file"""
2877 self._RunListCmd(['*cb*', '*head*'],
2878 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2879
2880 def testListCmdEmpty(self):
2881 """Test listing a wildcarded file"""
2882 self._RunListCmd(['nothing'], [])
2883
2884 def testListCmdPath(self):
2885 """Test listing the files in a sub-entry of a section"""
2886 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2887
Simon Glass4c613bf2019-07-08 14:25:50 -06002888 def _RunExtractCmd(self, entry_name, decomp=True):
2889 """Extract an entry from an image
2890
2891 Args:
2892 entry_name: Entry name to extract
2893 decomp: True to decompress the data if compressed, False to leave
2894 it in its raw uncompressed format
2895
2896 Returns:
2897 data from entry
2898 """
2899 self._CheckLz4()
2900 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002901 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002902 return control.ReadEntry(image_fname, entry_name, decomp)
2903
2904 def testExtractSimple(self):
2905 """Test extracting a single file"""
2906 data = self._RunExtractCmd('u-boot')
2907 self.assertEqual(U_BOOT_DATA, data)
2908
Simon Glass980a2842019-07-08 14:25:52 -06002909 def testExtractSection(self):
2910 """Test extracting the files in a section"""
2911 data = self._RunExtractCmd('section')
2912 cbfs_data = data[:0x400]
2913 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002914 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002915 dtb_data = data[0x400:]
2916 dtb = self._decompress(dtb_data)
2917 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2918
2919 def testExtractCompressed(self):
2920 """Test extracting compressed data"""
2921 data = self._RunExtractCmd('section/u-boot-dtb')
2922 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2923
2924 def testExtractRaw(self):
2925 """Test extracting compressed data without decompressing it"""
2926 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2927 dtb = self._decompress(data)
2928 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2929
2930 def testExtractCbfs(self):
2931 """Test extracting CBFS data"""
2932 data = self._RunExtractCmd('section/cbfs/u-boot')
2933 self.assertEqual(U_BOOT_DATA, data)
2934
2935 def testExtractCbfsCompressed(self):
2936 """Test extracting CBFS compressed data"""
2937 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2938 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2939
2940 def testExtractCbfsRaw(self):
2941 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002942 bintool = self.comp_bintools['lzma_alone']
2943 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06002944 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002945 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06002946 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2947
Simon Glass4c613bf2019-07-08 14:25:50 -06002948 def testExtractBadEntry(self):
2949 """Test extracting a bad section path"""
2950 with self.assertRaises(ValueError) as e:
2951 self._RunExtractCmd('section/does-not-exist')
2952 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2953 str(e.exception))
2954
2955 def testExtractMissingFile(self):
2956 """Test extracting file that does not exist"""
2957 with self.assertRaises(IOError) as e:
2958 control.ReadEntry('missing-file', 'name')
2959
2960 def testExtractBadFile(self):
2961 """Test extracting an invalid file"""
2962 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002963 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002964 with self.assertRaises(ValueError) as e:
2965 control.ReadEntry(fname, 'name')
2966
Simon Glass980a2842019-07-08 14:25:52 -06002967 def testExtractCmd(self):
2968 """Test extracting a file fron an image on the command line"""
2969 self._CheckLz4()
2970 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002971 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002972 try:
2973 tmpdir, updated_fname = self._SetupImageInTmpdir()
2974 with test_util.capture_sys_output() as (stdout, stderr):
2975 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2976 '-f', fname)
2977 finally:
2978 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07002979 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002980 self.assertEqual(U_BOOT_DATA, data)
2981
2982 def testExtractOneEntry(self):
2983 """Test extracting a single entry fron an image """
2984 self._CheckLz4()
2985 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002986 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002987 fname = os.path.join(self._indir, 'output.extact')
2988 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07002989 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002990 self.assertEqual(U_BOOT_DATA, data)
2991
2992 def _CheckExtractOutput(self, decomp):
2993 """Helper to test file output with and without decompression
2994
2995 Args:
2996 decomp: True to decompress entry data, False to output it raw
2997 """
2998 def _CheckPresent(entry_path, expect_data, expect_size=None):
2999 """Check and remove expected file
3000
3001 This checks the data/size of a file and removes the file both from
3002 the outfiles set and from the output directory. Once all files are
3003 processed, both the set and directory should be empty.
3004
3005 Args:
3006 entry_path: Entry path
3007 expect_data: Data to expect in file, or None to skip check
3008 expect_size: Size of data to expect in file, or None to skip
3009 """
3010 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003011 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003012 os.remove(path)
3013 if expect_data:
3014 self.assertEqual(expect_data, data)
3015 elif expect_size:
3016 self.assertEqual(expect_size, len(data))
3017 outfiles.remove(path)
3018
3019 def _CheckDirPresent(name):
3020 """Remove expected directory
3021
3022 This gives an error if the directory does not exist as expected
3023
3024 Args:
3025 name: Name of directory to remove
3026 """
3027 path = os.path.join(outdir, name)
3028 os.rmdir(path)
3029
3030 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003031 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003032 outdir = os.path.join(self._indir, 'extract')
3033 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3034
3035 # Create a set of all file that were output (should be 9)
3036 outfiles = set()
3037 for root, dirs, files in os.walk(outdir):
3038 outfiles |= set([os.path.join(root, fname) for fname in files])
3039 self.assertEqual(9, len(outfiles))
3040 self.assertEqual(9, len(einfos))
3041
3042 image = control.images['image']
3043 entries = image.GetEntries()
3044
3045 # Check the 9 files in various ways
3046 section = entries['section']
3047 section_entries = section.GetEntries()
3048 cbfs_entries = section_entries['cbfs'].GetEntries()
3049 _CheckPresent('u-boot', U_BOOT_DATA)
3050 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3051 dtb_len = EXTRACT_DTB_SIZE
3052 if not decomp:
3053 dtb_len = cbfs_entries['u-boot-dtb'].size
3054 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3055 if not decomp:
3056 dtb_len = section_entries['u-boot-dtb'].size
3057 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3058
3059 fdtmap = entries['fdtmap']
3060 _CheckPresent('fdtmap', fdtmap.data)
3061 hdr = entries['image-header']
3062 _CheckPresent('image-header', hdr.data)
3063
3064 _CheckPresent('section/root', section.data)
3065 cbfs = section_entries['cbfs']
3066 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003067 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003068 _CheckPresent('root', data)
3069
3070 # There should be no files left. Remove all the directories to check.
3071 # If there are any files/dirs remaining, one of these checks will fail.
3072 self.assertEqual(0, len(outfiles))
3073 _CheckDirPresent('section/cbfs')
3074 _CheckDirPresent('section')
3075 _CheckDirPresent('')
3076 self.assertFalse(os.path.exists(outdir))
3077
3078 def testExtractAllEntries(self):
3079 """Test extracting all entries"""
3080 self._CheckLz4()
3081 self._CheckExtractOutput(decomp=True)
3082
3083 def testExtractAllEntriesRaw(self):
3084 """Test extracting all entries without decompressing them"""
3085 self._CheckLz4()
3086 self._CheckExtractOutput(decomp=False)
3087
3088 def testExtractSelectedEntries(self):
3089 """Test extracting some entries"""
3090 self._CheckLz4()
3091 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003092 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003093 outdir = os.path.join(self._indir, 'extract')
3094 einfos = control.ExtractEntries(image_fname, None, outdir,
3095 ['*cb*', '*head*'])
3096
3097 # File output is tested by testExtractAllEntries(), so just check that
3098 # the expected entries are selected
3099 names = [einfo.name for einfo in einfos]
3100 self.assertEqual(names,
3101 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3102
3103 def testExtractNoEntryPaths(self):
3104 """Test extracting some entries"""
3105 self._CheckLz4()
3106 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003107 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003108 with self.assertRaises(ValueError) as e:
3109 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003110 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003111 str(e.exception))
3112
3113 def testExtractTooManyEntryPaths(self):
3114 """Test extracting some entries"""
3115 self._CheckLz4()
3116 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003117 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003118 with self.assertRaises(ValueError) as e:
3119 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003120 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003121 str(e.exception))
3122
Simon Glass52d06212019-07-08 14:25:53 -06003123 def testPackAlignSection(self):
3124 """Test that sections can have alignment"""
3125 self._DoReadFile('131_pack_align_section.dts')
3126
3127 self.assertIn('image', control.images)
3128 image = control.images['image']
3129 entries = image.GetEntries()
3130 self.assertEqual(3, len(entries))
3131
3132 # First u-boot
3133 self.assertIn('u-boot', entries)
3134 entry = entries['u-boot']
3135 self.assertEqual(0, entry.offset)
3136 self.assertEqual(0, entry.image_pos)
3137 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3138 self.assertEqual(len(U_BOOT_DATA), entry.size)
3139
3140 # Section0
3141 self.assertIn('section0', entries)
3142 section0 = entries['section0']
3143 self.assertEqual(0x10, section0.offset)
3144 self.assertEqual(0x10, section0.image_pos)
3145 self.assertEqual(len(U_BOOT_DATA), section0.size)
3146
3147 # Second u-boot
3148 section_entries = section0.GetEntries()
3149 self.assertIn('u-boot', section_entries)
3150 entry = section_entries['u-boot']
3151 self.assertEqual(0, entry.offset)
3152 self.assertEqual(0x10, entry.image_pos)
3153 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3154 self.assertEqual(len(U_BOOT_DATA), entry.size)
3155
3156 # Section1
3157 self.assertIn('section1', entries)
3158 section1 = entries['section1']
3159 self.assertEqual(0x14, section1.offset)
3160 self.assertEqual(0x14, section1.image_pos)
3161 self.assertEqual(0x20, section1.size)
3162
3163 # Second u-boot
3164 section_entries = section1.GetEntries()
3165 self.assertIn('u-boot', section_entries)
3166 entry = section_entries['u-boot']
3167 self.assertEqual(0, entry.offset)
3168 self.assertEqual(0x14, entry.image_pos)
3169 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3170 self.assertEqual(len(U_BOOT_DATA), entry.size)
3171
3172 # Section2
3173 self.assertIn('section2', section_entries)
3174 section2 = section_entries['section2']
3175 self.assertEqual(0x4, section2.offset)
3176 self.assertEqual(0x18, section2.image_pos)
3177 self.assertEqual(4, section2.size)
3178
3179 # Third u-boot
3180 section_entries = section2.GetEntries()
3181 self.assertIn('u-boot', section_entries)
3182 entry = section_entries['u-boot']
3183 self.assertEqual(0, entry.offset)
3184 self.assertEqual(0x18, entry.image_pos)
3185 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3186 self.assertEqual(len(U_BOOT_DATA), entry.size)
3187
Simon Glassf8a54bc2019-07-20 12:23:56 -06003188 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3189 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003190 """Replace an entry in an image
3191
3192 This writes the entry data to update it, then opens the updated file and
3193 returns the value that it now finds there.
3194
3195 Args:
3196 entry_name: Entry name to replace
3197 data: Data to replace it with
3198 decomp: True to compress the data if needed, False if data is
3199 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003200 allow_resize: True to allow entries to change size, False to raise
3201 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003202
3203 Returns:
3204 Tuple:
3205 data from entry
3206 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003207 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003208 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003209 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003210 update_dtb=True)[1]
3211
3212 self.assertIn('image', control.images)
3213 image = control.images['image']
3214 entries = image.GetEntries()
3215 orig_dtb_data = entries['u-boot-dtb'].data
3216 orig_fdtmap_data = entries['fdtmap'].data
3217
Simon Glass80025522022-01-29 14:14:04 -07003218 image_fname = tools.get_output_filename('image.bin')
3219 updated_fname = tools.get_output_filename('image-updated.bin')
3220 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003221 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3222 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003223 data = control.ReadEntry(updated_fname, entry_name, decomp)
3224
Simon Glassf8a54bc2019-07-20 12:23:56 -06003225 # The DT data should not change unless resized:
3226 if not allow_resize:
3227 new_dtb_data = entries['u-boot-dtb'].data
3228 self.assertEqual(new_dtb_data, orig_dtb_data)
3229 new_fdtmap_data = entries['fdtmap'].data
3230 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003231
Simon Glassf8a54bc2019-07-20 12:23:56 -06003232 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003233
3234 def testReplaceSimple(self):
3235 """Test replacing a single file"""
3236 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003237 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3238 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003239 self.assertEqual(expected, data)
3240
3241 # Test that the state looks right. There should be an FDT for the fdtmap
3242 # that we jsut read back in, and it should match what we find in the
3243 # 'control' tables. Checking for an FDT that does not exist should
3244 # return None.
3245 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003246 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003247 self.assertEqual(expected_fdtmap, fdtmap)
3248
3249 dtb = state.GetFdtForEtype('fdtmap')
3250 self.assertEqual(dtb.GetContents(), fdtmap)
3251
3252 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3253 self.assertIsNone(missing_path)
3254 self.assertIsNone(missing_fdtmap)
3255
3256 missing_dtb = state.GetFdtForEtype('missing')
3257 self.assertIsNone(missing_dtb)
3258
3259 self.assertEqual('/binman', state.fdt_path_prefix)
3260
3261 def testReplaceResizeFail(self):
3262 """Test replacing a file by something larger"""
3263 expected = U_BOOT_DATA + b'x'
3264 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003265 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3266 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003267 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3268 str(e.exception))
3269
3270 def testReplaceMulti(self):
3271 """Test replacing entry data where multiple images are generated"""
3272 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3273 update_dtb=True)[0]
3274 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003275 updated_fname = tools.get_output_filename('image-updated.bin')
3276 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003277 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003278 control.WriteEntry(updated_fname, entry_name, expected,
3279 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003280 data = control.ReadEntry(updated_fname, entry_name)
3281 self.assertEqual(expected, data)
3282
3283 # Check the state looks right.
3284 self.assertEqual('/binman/image', state.fdt_path_prefix)
3285
3286 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003287 image_fname = tools.get_output_filename('first-image.bin')
3288 updated_fname = tools.get_output_filename('first-updated.bin')
3289 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003290 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003291 control.WriteEntry(updated_fname, entry_name, expected,
3292 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003293 data = control.ReadEntry(updated_fname, entry_name)
3294 self.assertEqual(expected, data)
3295
3296 # Check the state looks right.
3297 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003298
Simon Glassfb30e292019-07-20 12:23:51 -06003299 def testUpdateFdtAllRepack(self):
3300 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003301 self._SetupSplElf()
3302 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003303 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3304 SECTION_SIZE = 0x300
3305 DTB_SIZE = 602
3306 FDTMAP_SIZE = 608
3307 base_expected = {
3308 'offset': 0,
3309 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3310 'image-pos': 0,
3311 'section:offset': 0,
3312 'section:size': SECTION_SIZE,
3313 'section:image-pos': 0,
3314 'section/u-boot-dtb:offset': 4,
3315 'section/u-boot-dtb:size': 636,
3316 'section/u-boot-dtb:image-pos': 4,
3317 'u-boot-spl-dtb:offset': SECTION_SIZE,
3318 'u-boot-spl-dtb:size': DTB_SIZE,
3319 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3320 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3321 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3322 'u-boot-tpl-dtb:size': DTB_SIZE,
3323 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3324 'fdtmap:size': FDTMAP_SIZE,
3325 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3326 }
3327 main_expected = {
3328 'section:orig-size': SECTION_SIZE,
3329 'section/u-boot-dtb:orig-offset': 4,
3330 }
3331
3332 # We expect three device-tree files in the output, with the first one
3333 # within a fixed-size section.
3334 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3335 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3336 # main U-Boot tree. All three should have the same positions and offset
3337 # except that the main tree should include the main_expected properties
3338 start = 4
3339 for item in ['', 'spl', 'tpl', None]:
3340 if item is None:
3341 start += 16 # Move past fdtmap header
3342 dtb = fdt.Fdt.FromData(data[start:])
3343 dtb.Scan()
3344 props = self._GetPropTree(dtb,
3345 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3346 prefix='/' if item is None else '/binman/')
3347 expected = dict(base_expected)
3348 if item:
3349 expected[item] = 0
3350 else:
3351 # Main DTB and fdtdec should include the 'orig-' properties
3352 expected.update(main_expected)
3353 # Helpful for debugging:
3354 #for prop in sorted(props):
3355 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3356 self.assertEqual(expected, props)
3357 if item == '':
3358 start = SECTION_SIZE
3359 else:
3360 start += dtb._fdt_obj.totalsize()
3361
Simon Glass11453762019-07-20 12:23:55 -06003362 def testFdtmapHeaderMiddle(self):
3363 """Test an FDT map in the middle of an image when it should be at end"""
3364 with self.assertRaises(ValueError) as e:
3365 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3366 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3367 str(e.exception))
3368
3369 def testFdtmapHeaderStartBad(self):
3370 """Test an FDT map in middle of an image when it should be at start"""
3371 with self.assertRaises(ValueError) as e:
3372 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3373 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3374 str(e.exception))
3375
3376 def testFdtmapHeaderEndBad(self):
3377 """Test an FDT map at the start of an image when it should be at end"""
3378 with self.assertRaises(ValueError) as e:
3379 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3380 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3381 str(e.exception))
3382
3383 def testFdtmapHeaderNoSize(self):
3384 """Test an image header at the end of an image with undefined size"""
3385 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3386
Simon Glassf8a54bc2019-07-20 12:23:56 -06003387 def testReplaceResize(self):
3388 """Test replacing a single file in an entry with a larger file"""
3389 expected = U_BOOT_DATA + b'x'
3390 data, _, image = self._RunReplaceCmd('u-boot', expected,
3391 dts='139_replace_repack.dts')
3392 self.assertEqual(expected, data)
3393
3394 entries = image.GetEntries()
3395 dtb_data = entries['u-boot-dtb'].data
3396 dtb = fdt.Fdt.FromData(dtb_data)
3397 dtb.Scan()
3398
3399 # The u-boot section should now be larger in the dtb
3400 node = dtb.GetNode('/binman/u-boot')
3401 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3402
3403 # Same for the fdtmap
3404 fdata = entries['fdtmap'].data
3405 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3406 fdtb.Scan()
3407 fnode = fdtb.GetNode('/u-boot')
3408 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3409
3410 def testReplaceResizeNoRepack(self):
3411 """Test replacing an entry with a larger file when not allowed"""
3412 expected = U_BOOT_DATA + b'x'
3413 with self.assertRaises(ValueError) as e:
3414 self._RunReplaceCmd('u-boot', expected)
3415 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3416 str(e.exception))
3417
Simon Glass9d8ee322019-07-20 12:23:58 -06003418 def testEntryShrink(self):
3419 """Test contracting an entry after it is packed"""
3420 try:
3421 state.SetAllowEntryContraction(True)
3422 data = self._DoReadFileDtb('140_entry_shrink.dts',
3423 update_dtb=True)[0]
3424 finally:
3425 state.SetAllowEntryContraction(False)
3426 self.assertEqual(b'a', data[:1])
3427 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3428 self.assertEqual(b'a', data[-1:])
3429
3430 def testEntryShrinkFail(self):
3431 """Test not being allowed to contract an entry after it is packed"""
3432 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3433
3434 # In this case there is a spare byte at the end of the data. The size of
3435 # the contents is only 1 byte but we still have the size before it
3436 # shrunk.
3437 self.assertEqual(b'a\0', data[:2])
3438 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3439 self.assertEqual(b'a\0', data[-2:])
3440
Simon Glass70e32982019-07-20 12:24:01 -06003441 def testDescriptorOffset(self):
3442 """Test that the Intel descriptor is always placed at at the start"""
3443 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3444 image = control.images['image']
3445 entries = image.GetEntries()
3446 desc = entries['intel-descriptor']
3447 self.assertEqual(0xff800000, desc.offset);
3448 self.assertEqual(0xff800000, desc.image_pos);
3449
Simon Glass37fdd142019-07-20 12:24:06 -06003450 def testReplaceCbfs(self):
3451 """Test replacing a single file in CBFS without changing the size"""
3452 self._CheckLz4()
3453 expected = b'x' * len(U_BOOT_DATA)
3454 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003455 updated_fname = tools.get_output_filename('image-updated.bin')
3456 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003457 entry_name = 'section/cbfs/u-boot'
3458 control.WriteEntry(updated_fname, entry_name, expected,
3459 allow_resize=True)
3460 data = control.ReadEntry(updated_fname, entry_name)
3461 self.assertEqual(expected, data)
3462
3463 def testReplaceResizeCbfs(self):
3464 """Test replacing a single file in CBFS with one of a different size"""
3465 self._CheckLz4()
3466 expected = U_BOOT_DATA + b'x'
3467 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003468 updated_fname = tools.get_output_filename('image-updated.bin')
3469 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003470 entry_name = 'section/cbfs/u-boot'
3471 control.WriteEntry(updated_fname, entry_name, expected,
3472 allow_resize=True)
3473 data = control.ReadEntry(updated_fname, entry_name)
3474 self.assertEqual(expected, data)
3475
Simon Glass30033c22019-07-20 12:24:15 -06003476 def _SetupForReplace(self):
3477 """Set up some files to use to replace entries
3478
3479 This generates an image, copies it to a new file, extracts all the files
3480 in it and updates some of them
3481
3482 Returns:
3483 List
3484 Image filename
3485 Output directory
3486 Expected values for updated entries, each a string
3487 """
3488 data = self._DoReadFileRealDtb('143_replace_all.dts')
3489
Simon Glass80025522022-01-29 14:14:04 -07003490 updated_fname = tools.get_output_filename('image-updated.bin')
3491 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003492
3493 outdir = os.path.join(self._indir, 'extract')
3494 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3495
3496 expected1 = b'x' + U_BOOT_DATA + b'y'
3497 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003498 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003499
3500 expected2 = b'a' + U_BOOT_DATA + b'b'
3501 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003502 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003503
3504 expected_text = b'not the same text'
3505 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003506 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003507
3508 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3509 dtb = fdt.FdtScan(dtb_fname)
3510 node = dtb.GetNode('/binman/text')
3511 node.AddString('my-property', 'the value')
3512 dtb.Sync(auto_resize=True)
3513 dtb.Flush()
3514
3515 return updated_fname, outdir, expected1, expected2, expected_text
3516
3517 def _CheckReplaceMultiple(self, entry_paths):
3518 """Handle replacing the contents of multiple entries
3519
3520 Args:
3521 entry_paths: List of entry paths to replace
3522
3523 Returns:
3524 List
3525 Dict of entries in the image:
3526 key: Entry name
3527 Value: Entry object
3528 Expected values for updated entries, each a string
3529 """
3530 updated_fname, outdir, expected1, expected2, expected_text = (
3531 self._SetupForReplace())
3532 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3533
3534 image = Image.FromFile(updated_fname)
3535 image.LoadData()
3536 return image.GetEntries(), expected1, expected2, expected_text
3537
3538 def testReplaceAll(self):
3539 """Test replacing the contents of all entries"""
3540 entries, expected1, expected2, expected_text = (
3541 self._CheckReplaceMultiple([]))
3542 data = entries['u-boot'].data
3543 self.assertEqual(expected1, data)
3544
3545 data = entries['u-boot2'].data
3546 self.assertEqual(expected2, data)
3547
3548 data = entries['text'].data
3549 self.assertEqual(expected_text, data)
3550
3551 # Check that the device tree is updated
3552 data = entries['u-boot-dtb'].data
3553 dtb = fdt.Fdt.FromData(data)
3554 dtb.Scan()
3555 node = dtb.GetNode('/binman/text')
3556 self.assertEqual('the value', node.props['my-property'].value)
3557
3558 def testReplaceSome(self):
3559 """Test replacing the contents of a few entries"""
3560 entries, expected1, expected2, expected_text = (
3561 self._CheckReplaceMultiple(['u-boot2', 'text']))
3562
3563 # This one should not change
3564 data = entries['u-boot'].data
3565 self.assertEqual(U_BOOT_DATA, data)
3566
3567 data = entries['u-boot2'].data
3568 self.assertEqual(expected2, data)
3569
3570 data = entries['text'].data
3571 self.assertEqual(expected_text, data)
3572
3573 def testReplaceCmd(self):
3574 """Test replacing a file fron an image on the command line"""
3575 self._DoReadFileRealDtb('143_replace_all.dts')
3576
3577 try:
3578 tmpdir, updated_fname = self._SetupImageInTmpdir()
3579
3580 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3581 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003582 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003583
3584 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003585 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003586 self.assertEqual(expected, data[:len(expected)])
3587 map_fname = os.path.join(tmpdir, 'image-updated.map')
3588 self.assertFalse(os.path.exists(map_fname))
3589 finally:
3590 shutil.rmtree(tmpdir)
3591
3592 def testReplaceCmdSome(self):
3593 """Test replacing some files fron an image on the command line"""
3594 updated_fname, outdir, expected1, expected2, expected_text = (
3595 self._SetupForReplace())
3596
3597 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3598 'u-boot2', 'text')
3599
Simon Glass80025522022-01-29 14:14:04 -07003600 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003601 image = Image.FromFile(updated_fname)
3602 image.LoadData()
3603 entries = image.GetEntries()
3604
3605 # This one should not change
3606 data = entries['u-boot'].data
3607 self.assertEqual(U_BOOT_DATA, data)
3608
3609 data = entries['u-boot2'].data
3610 self.assertEqual(expected2, data)
3611
3612 data = entries['text'].data
3613 self.assertEqual(expected_text, data)
3614
3615 def testReplaceMissing(self):
3616 """Test replacing entries where the file is missing"""
3617 updated_fname, outdir, expected1, expected2, expected_text = (
3618 self._SetupForReplace())
3619
3620 # Remove one of the files, to generate a warning
3621 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3622 os.remove(u_boot_fname1)
3623
3624 with test_util.capture_sys_output() as (stdout, stderr):
3625 control.ReplaceEntries(updated_fname, None, outdir, [])
3626 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003627 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003628
3629 def testReplaceCmdMap(self):
3630 """Test replacing a file fron an image on the command line"""
3631 self._DoReadFileRealDtb('143_replace_all.dts')
3632
3633 try:
3634 tmpdir, updated_fname = self._SetupImageInTmpdir()
3635
3636 fname = os.path.join(self._indir, 'update-u-boot.bin')
3637 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003638 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003639
3640 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3641 '-f', fname, '-m')
3642 map_fname = os.path.join(tmpdir, 'image-updated.map')
3643 self.assertTrue(os.path.exists(map_fname))
3644 finally:
3645 shutil.rmtree(tmpdir)
3646
3647 def testReplaceNoEntryPaths(self):
3648 """Test replacing an entry without an entry path"""
3649 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003650 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003651 with self.assertRaises(ValueError) as e:
3652 control.ReplaceEntries(image_fname, 'fname', None, [])
3653 self.assertIn('Must specify an entry path to read with -f',
3654 str(e.exception))
3655
3656 def testReplaceTooManyEntryPaths(self):
3657 """Test extracting some entries"""
3658 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003659 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003660 with self.assertRaises(ValueError) as e:
3661 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3662 self.assertIn('Must specify exactly one entry path to write with -f',
3663 str(e.exception))
3664
Simon Glass0b074d62019-08-24 07:22:48 -06003665 def testPackReset16(self):
3666 """Test that an image with an x86 reset16 region can be created"""
3667 data = self._DoReadFile('144_x86_reset16.dts')
3668 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3669
3670 def testPackReset16Spl(self):
3671 """Test that an image with an x86 reset16-spl region can be created"""
3672 data = self._DoReadFile('145_x86_reset16_spl.dts')
3673 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3674
3675 def testPackReset16Tpl(self):
3676 """Test that an image with an x86 reset16-tpl region can be created"""
3677 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3678 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3679
Simon Glass232f90c2019-08-24 07:22:50 -06003680 def testPackIntelFit(self):
3681 """Test that an image with an Intel FIT and pointer can be created"""
3682 data = self._DoReadFile('147_intel_fit.dts')
3683 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3684 fit = data[16:32];
3685 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3686 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3687
3688 image = control.images['image']
3689 entries = image.GetEntries()
3690 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3691 self.assertEqual(expected_ptr, ptr)
3692
3693 def testPackIntelFitMissing(self):
3694 """Test detection of a FIT pointer with not FIT region"""
3695 with self.assertRaises(ValueError) as e:
3696 self._DoReadFile('148_intel_fit_missing.dts')
3697 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3698 str(e.exception))
3699
Simon Glass72555fa2019-11-06 17:22:44 -07003700 def _CheckSymbolsTplSection(self, dts, expected_vals):
3701 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003702 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003703 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003704 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003705 self.assertEqual(expected1, data[:upto1])
3706
3707 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003708 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003709 self.assertEqual(expected2, data[upto1:upto2])
3710
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003711 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003712 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003713 self.assertEqual(expected3, data[upto2:upto3])
3714
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003715 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003716 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3717
3718 def testSymbolsTplSection(self):
3719 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3720 self._SetupSplElf('u_boot_binman_syms')
3721 self._SetupTplElf('u_boot_binman_syms')
3722 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003723 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003724
3725 def testSymbolsTplSectionX86(self):
3726 """Test binman can assign symbols in a section with end-at-4gb"""
3727 self._SetupSplElf('u_boot_binman_syms_x86')
3728 self._SetupTplElf('u_boot_binman_syms_x86')
3729 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003730 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003731 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003732
Simon Glass98c59572019-08-24 07:23:03 -06003733 def testPackX86RomIfwiSectiom(self):
3734 """Test that a section can be placed in an IFWI region"""
3735 self._SetupIfwi('fitimage.bin')
3736 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3737 self._CheckIfwi(data)
3738
Simon Glassba7985d2019-08-24 07:23:07 -06003739 def testPackFspM(self):
3740 """Test that an image with a FSP memory-init binary can be created"""
3741 data = self._DoReadFile('152_intel_fsp_m.dts')
3742 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3743
Simon Glass4d9086d2019-10-20 21:31:35 -06003744 def testPackFspS(self):
3745 """Test that an image with a FSP silicon-init binary can be created"""
3746 data = self._DoReadFile('153_intel_fsp_s.dts')
3747 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003748
Simon Glass9ea87b22019-10-20 21:31:36 -06003749 def testPackFspT(self):
3750 """Test that an image with a FSP temp-ram-init binary can be created"""
3751 data = self._DoReadFile('154_intel_fsp_t.dts')
3752 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3753
Simon Glass48f3aad2020-07-09 18:39:31 -06003754 def testMkimage(self):
3755 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003756 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003757 data = self._DoReadFile('156_mkimage.dts')
3758
3759 # Just check that the data appears in the file somewhere
3760 self.assertIn(U_BOOT_SPL_DATA, data)
3761
Simon Glass66152ce2022-01-09 20:14:09 -07003762 def testMkimageMissing(self):
3763 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003764 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003765 with test_util.capture_sys_output() as (_, stderr):
3766 self._DoTestFile('156_mkimage.dts',
3767 force_missing_bintools='mkimage')
3768 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003769 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003770
Simon Glass5e560182020-07-09 18:39:36 -06003771 def testExtblob(self):
3772 """Test an image with an external blob"""
3773 data = self._DoReadFile('157_blob_ext.dts')
3774 self.assertEqual(REFCODE_DATA, data)
3775
3776 def testExtblobMissing(self):
3777 """Test an image with a missing external blob"""
3778 with self.assertRaises(ValueError) as e:
3779 self._DoReadFile('158_blob_ext_missing.dts')
3780 self.assertIn("Filename 'missing-file' not found in input path",
3781 str(e.exception))
3782
Simon Glass5d94cc62020-07-09 18:39:38 -06003783 def testExtblobMissingOk(self):
3784 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003785 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003786 ret = self._DoTestFile('158_blob_ext_missing.dts',
3787 allow_missing=True)
3788 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003789 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003790 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003791 self.assertIn('Some images are invalid', err)
3792
3793 def testExtblobMissingOkFlag(self):
3794 """Test an image with an missing external blob allowed with -W"""
3795 with test_util.capture_sys_output() as (stdout, stderr):
3796 ret = self._DoTestFile('158_blob_ext_missing.dts',
3797 allow_missing=True, ignore_missing=True)
3798 self.assertEqual(0, ret)
3799 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003800 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003801 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003802
3803 def testExtblobMissingOkSect(self):
3804 """Test an image with an missing external blob that is allowed"""
3805 with test_util.capture_sys_output() as (stdout, stderr):
3806 self._DoTestFile('159_blob_ext_missing_sect.dts',
3807 allow_missing=True)
3808 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003809 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003810
Simon Glasse88cef92020-07-09 18:39:41 -06003811 def testPackX86RomMeMissingDesc(self):
3812 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003813 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003814 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003815 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003816 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003817
3818 def testPackX86RomMissingIfwi(self):
3819 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3820 self._SetupIfwi('fitimage.bin')
3821 pathname = os.path.join(self._indir, 'fitimage.bin')
3822 os.remove(pathname)
3823 with test_util.capture_sys_output() as (stdout, stderr):
3824 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3825 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003826 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003827
Simon Glass2a0fa982022-02-11 13:23:21 -07003828 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003829 """Test that zero-size overlapping regions are ignored"""
3830 self._DoTestFile('160_pack_overlap_zero.dts')
3831
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003832 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003833 # The data should be inside the FIT
3834 dtb = fdt.Fdt.FromData(fit_data)
3835 dtb.Scan()
3836 fnode = dtb.GetNode('/images/kernel')
3837 self.assertIn('data', fnode.props)
3838
3839 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003840 tools.write_file(fname, fit_data)
3841 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003842
3843 # Check a few features to make sure the plumbing works. We don't need
3844 # to test the operation of mkimage or dumpimage here. First convert the
3845 # output into a dict where the keys are the fields printed by dumpimage
3846 # and the values are a list of values for each field
3847 lines = out.splitlines()
3848
3849 # Converts "Compression: gzip compressed" into two groups:
3850 # 'Compression' and 'gzip compressed'
3851 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3852 vals = collections.defaultdict(list)
3853 for line in lines:
3854 mat = re_line.match(line)
3855 vals[mat.group(1)].append(mat.group(2))
3856
3857 self.assertEquals('FIT description: test-desc', lines[0])
3858 self.assertIn('Created:', lines[1])
3859 self.assertIn('Image 0 (kernel)', vals)
3860 self.assertIn('Hash value', vals)
3861 data_sizes = vals.get('Data Size')
3862 self.assertIsNotNone(data_sizes)
3863 self.assertEqual(2, len(data_sizes))
3864 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003865 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3866 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3867
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003868 # Check if entry listing correctly omits /images/
3869 image = control.images['image']
3870 fit_entry = image.GetEntries()['fit']
3871 subentries = list(fit_entry.GetEntries().keys())
3872 expected = ['kernel', 'fdt-1']
3873 self.assertEqual(expected, subentries)
3874
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003875 def testSimpleFit(self):
3876 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003877 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003878 data = self._DoReadFile('161_fit.dts')
3879 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3880 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3881 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3882
3883 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3884
3885 def testSimpleFitExpandsSubentries(self):
3886 """Test that FIT images expand their subentries"""
3887 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3888 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3889 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3890 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3891
3892 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003893
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003894 def testSimpleFitImagePos(self):
3895 """Test that we have correct image-pos for FIT subentries"""
3896 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3897 update_dtb=True)
3898 dtb = fdt.Fdt(out_dtb_fname)
3899 dtb.Scan()
3900 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3901
Simon Glassb7bad182022-03-05 20:19:01 -07003902 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003903 self.assertEqual({
3904 'image-pos': 0,
3905 'offset': 0,
3906 'size': 1890,
3907
3908 'u-boot:image-pos': 0,
3909 'u-boot:offset': 0,
3910 'u-boot:size': 4,
3911
3912 'fit:image-pos': 4,
3913 'fit:offset': 4,
3914 'fit:size': 1840,
3915
Simon Glassb7bad182022-03-05 20:19:01 -07003916 'fit/images/kernel:image-pos': 304,
3917 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003918 'fit/images/kernel:size': 4,
3919
Simon Glassb7bad182022-03-05 20:19:01 -07003920 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003921 'fit/images/kernel/u-boot:offset': 0,
3922 'fit/images/kernel/u-boot:size': 4,
3923
Simon Glassb7bad182022-03-05 20:19:01 -07003924 'fit/images/fdt-1:image-pos': 552,
3925 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003926 'fit/images/fdt-1:size': 6,
3927
Simon Glassb7bad182022-03-05 20:19:01 -07003928 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003929 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3930 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3931
3932 'u-boot-nodtb:image-pos': 1844,
3933 'u-boot-nodtb:offset': 1844,
3934 'u-boot-nodtb:size': 46,
3935 }, props)
3936
3937 # Actually check the data is where we think it is
3938 for node, expected in [
3939 ("u-boot", U_BOOT_DATA),
3940 ("fit/images/kernel", U_BOOT_DATA),
3941 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3942 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3943 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3944 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3945 ]:
3946 image_pos = props[f"{node}:image-pos"]
3947 size = props[f"{node}:size"]
3948 self.assertEqual(len(expected), size)
3949 self.assertEqual(expected, data[image_pos:image_pos+size])
3950
Simon Glass45d556d2020-07-09 18:39:45 -06003951 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003952 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003953 data = self._DoReadFile('162_fit_external.dts')
3954 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3955
Simon Glass7932c882022-01-09 20:13:39 -07003956 # Size of the external-data region as set up by mkimage
3957 external_data_size = len(U_BOOT_DATA) + 2
3958 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003959 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003960 len(U_BOOT_NODTB_DATA))
3961
Simon Glass45d556d2020-07-09 18:39:45 -06003962 # The data should be outside the FIT
3963 dtb = fdt.Fdt.FromData(fit_data)
3964 dtb.Scan()
3965 fnode = dtb.GetNode('/images/kernel')
3966 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003967 self.assertEqual(len(U_BOOT_DATA),
3968 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3969 fit_pos = 0x400;
3970 self.assertEqual(
3971 fit_pos,
3972 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3973
3974 self.assertEquals(expected_size, len(data))
3975 actual_pos = len(U_BOOT_DATA) + fit_pos
3976 self.assertEqual(U_BOOT_DATA + b'aa',
3977 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003978
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003979 def testFitExternalImagePos(self):
3980 """Test that we have correct image-pos for external FIT subentries"""
3981 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3982 update_dtb=True)
3983 dtb = fdt.Fdt(out_dtb_fname)
3984 dtb.Scan()
3985 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3986
3987 self.assertEqual({
3988 'image-pos': 0,
3989 'offset': 0,
3990 'size': 1082,
3991
3992 'u-boot:image-pos': 0,
3993 'u-boot:offset': 0,
3994 'u-boot:size': 4,
3995
3996 'fit:size': 1032,
3997 'fit:offset': 4,
3998 'fit:image-pos': 4,
3999
4000 'fit/images/kernel:size': 4,
4001 'fit/images/kernel:offset': 1024,
4002 'fit/images/kernel:image-pos': 1028,
4003
4004 'fit/images/kernel/u-boot:size': 4,
4005 'fit/images/kernel/u-boot:offset': 0,
4006 'fit/images/kernel/u-boot:image-pos': 1028,
4007
4008 'fit/images/fdt-1:size': 2,
4009 'fit/images/fdt-1:offset': 1028,
4010 'fit/images/fdt-1:image-pos': 1032,
4011
4012 'fit/images/fdt-1/_testing:size': 2,
4013 'fit/images/fdt-1/_testing:offset': 0,
4014 'fit/images/fdt-1/_testing:image-pos': 1032,
4015
4016 'u-boot-nodtb:image-pos': 1036,
4017 'u-boot-nodtb:offset': 1036,
4018 'u-boot-nodtb:size': 46,
4019 }, props)
4020
4021 # Actually check the data is where we think it is
4022 for node, expected in [
4023 ("u-boot", U_BOOT_DATA),
4024 ("fit/images/kernel", U_BOOT_DATA),
4025 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4026 ("fit/images/fdt-1", b'aa'),
4027 ("fit/images/fdt-1/_testing", b'aa'),
4028 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4029 ]:
4030 image_pos = props[f"{node}:image-pos"]
4031 size = props[f"{node}:size"]
4032 self.assertEqual(len(expected), size)
4033 self.assertEqual(expected, data[image_pos:image_pos+size])
4034
Simon Glass66152ce2022-01-09 20:14:09 -07004035 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004036 """Test that binman complains if mkimage is missing"""
4037 with self.assertRaises(ValueError) as e:
4038 self._DoTestFile('162_fit_external.dts',
4039 force_missing_bintools='mkimage')
4040 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4041 str(e.exception))
4042
4043 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004044 """Test that binman still produces a FIT image if mkimage is missing"""
4045 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004046 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004047 force_missing_bintools='mkimage')
4048 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004049 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004050
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004051 def testSectionIgnoreHashSignature(self):
4052 """Test that sections ignore hash, signature nodes for its data"""
4053 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4054 expected = (U_BOOT_DATA + U_BOOT_DATA)
4055 self.assertEqual(expected, data)
4056
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004057 def testPadInSections(self):
4058 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004059 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4060 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004061 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4062 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004063 U_BOOT_DATA)
4064 self.assertEqual(expected, data)
4065
Simon Glassd12599d2020-10-26 17:40:09 -06004066 dtb = fdt.Fdt(out_dtb_fname)
4067 dtb.Scan()
4068 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4069 expected = {
4070 'image-pos': 0,
4071 'offset': 0,
4072 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4073
4074 'section:image-pos': 0,
4075 'section:offset': 0,
4076 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4077
4078 'section/before:image-pos': 0,
4079 'section/before:offset': 0,
4080 'section/before:size': len(U_BOOT_DATA),
4081
4082 'section/u-boot:image-pos': 4,
4083 'section/u-boot:offset': 4,
4084 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4085
4086 'section/after:image-pos': 26,
4087 'section/after:offset': 26,
4088 'section/after:size': len(U_BOOT_DATA),
4089 }
4090 self.assertEqual(expected, props)
4091
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004092 def testFitImageSubentryAlignment(self):
4093 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004094 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004095 entry_args = {
4096 'test-id': TEXT_DATA,
4097 }
4098 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4099 entry_args=entry_args)
4100 dtb = fdt.Fdt.FromData(data)
4101 dtb.Scan()
4102
4103 node = dtb.GetNode('/images/kernel')
4104 data = dtb.GetProps(node)["data"].bytes
4105 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004106 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4107 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004108 self.assertEqual(expected, data)
4109
4110 node = dtb.GetNode('/images/fdt-1')
4111 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004112 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4113 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004114 U_BOOT_DTB_DATA)
4115 self.assertEqual(expected, data)
4116
4117 def testFitExtblobMissingOk(self):
4118 """Test a FIT with a missing external blob that is allowed"""
4119 with test_util.capture_sys_output() as (stdout, stderr):
4120 self._DoTestFile('168_fit_missing_blob.dts',
4121 allow_missing=True)
4122 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004123 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004124
Simon Glass21db0ff2020-09-01 05:13:54 -06004125 def testBlobNamedByArgMissing(self):
4126 """Test handling of a missing entry arg"""
4127 with self.assertRaises(ValueError) as e:
4128 self._DoReadFile('068_blob_named_by_arg.dts')
4129 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4130 str(e.exception))
4131
Simon Glass559c4de2020-09-01 05:13:58 -06004132 def testPackBl31(self):
4133 """Test that an image with an ATF BL31 binary can be created"""
4134 data = self._DoReadFile('169_atf_bl31.dts')
4135 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4136
Samuel Holland9d8cc632020-10-21 21:12:15 -05004137 def testPackScp(self):
4138 """Test that an image with an SCP binary can be created"""
4139 data = self._DoReadFile('172_scp.dts')
4140 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4141
Simon Glassa435cd12020-09-01 05:13:59 -06004142 def testFitFdt(self):
4143 """Test an image with an FIT with multiple FDT images"""
4144 def _CheckFdt(seq, expected_data):
4145 """Check the FDT nodes
4146
4147 Args:
4148 seq: Sequence number to check (0 or 1)
4149 expected_data: Expected contents of 'data' property
4150 """
4151 name = 'fdt-%d' % seq
4152 fnode = dtb.GetNode('/images/%s' % name)
4153 self.assertIsNotNone(fnode)
4154 self.assertEqual({'description','type', 'compression', 'data'},
4155 set(fnode.props.keys()))
4156 self.assertEqual(expected_data, fnode.props['data'].bytes)
4157 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4158 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004159 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004160
4161 def _CheckConfig(seq, expected_data):
4162 """Check the configuration nodes
4163
4164 Args:
4165 seq: Sequence number to check (0 or 1)
4166 expected_data: Expected contents of 'data' property
4167 """
4168 cnode = dtb.GetNode('/configurations')
4169 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004170 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004171
4172 name = 'config-%d' % seq
4173 fnode = dtb.GetNode('/configurations/%s' % name)
4174 self.assertIsNotNone(fnode)
4175 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4176 set(fnode.props.keys()))
4177 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4178 fnode.props['description'].value)
4179 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4180
4181 entry_args = {
4182 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004183 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004184 }
4185 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004186 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004187 entry_args=entry_args,
4188 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4189 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4190 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4191
4192 dtb = fdt.Fdt.FromData(fit_data)
4193 dtb.Scan()
4194 fnode = dtb.GetNode('/images/kernel')
4195 self.assertIn('data', fnode.props)
4196
4197 # Check all the properties in fdt-1 and fdt-2
4198 _CheckFdt(1, TEST_FDT1_DATA)
4199 _CheckFdt(2, TEST_FDT2_DATA)
4200
4201 # Check configurations
4202 _CheckConfig(1, TEST_FDT1_DATA)
4203 _CheckConfig(2, TEST_FDT2_DATA)
4204
4205 def testFitFdtMissingList(self):
4206 """Test handling of a missing 'of-list' entry arg"""
4207 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004208 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004209 self.assertIn("Generator node requires 'of-list' entry argument",
4210 str(e.exception))
4211
4212 def testFitFdtEmptyList(self):
4213 """Test handling of an empty 'of-list' entry arg"""
4214 entry_args = {
4215 'of-list': '',
4216 }
4217 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4218
4219 def testFitFdtMissingProp(self):
4220 """Test handling of a missing 'fit,fdt-list' property"""
4221 with self.assertRaises(ValueError) as e:
4222 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4223 self.assertIn("Generator node requires 'fit,fdt-list' property",
4224 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004225
Simon Glass1032acc2020-09-06 10:39:08 -06004226 def testFitFdtMissing(self):
4227 """Test handling of a missing 'default-dt' entry arg"""
4228 entry_args = {
4229 'of-list': 'test-fdt1 test-fdt2',
4230 }
4231 with self.assertRaises(ValueError) as e:
4232 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004233 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004234 entry_args=entry_args,
4235 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4236 self.assertIn("Generated 'default' node requires default-dt entry argument",
4237 str(e.exception))
4238
4239 def testFitFdtNotInList(self):
4240 """Test handling of a default-dt that is not in the of-list"""
4241 entry_args = {
4242 'of-list': 'test-fdt1 test-fdt2',
4243 'default-dt': 'test-fdt3',
4244 }
4245 with self.assertRaises(ValueError) as e:
4246 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004247 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004248 entry_args=entry_args,
4249 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4250 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4251 str(e.exception))
4252
Simon Glassa820af72020-09-06 10:39:09 -06004253 def testFitExtblobMissingHelp(self):
4254 """Test display of help messages when an external blob is missing"""
4255 control.missing_blob_help = control._ReadMissingBlobHelp()
4256 control.missing_blob_help['wibble'] = 'Wibble test'
4257 control.missing_blob_help['another'] = 'Another test'
4258 with test_util.capture_sys_output() as (stdout, stderr):
4259 self._DoTestFile('168_fit_missing_blob.dts',
4260 allow_missing=True)
4261 err = stderr.getvalue()
4262
4263 # We can get the tag from the name, the type or the missing-msg
4264 # property. Check all three.
4265 self.assertIn('You may need to build ARM Trusted', err)
4266 self.assertIn('Wibble test', err)
4267 self.assertIn('Another test', err)
4268
Simon Glass6f1f4d42020-09-06 10:35:32 -06004269 def testMissingBlob(self):
4270 """Test handling of a blob containing a missing file"""
4271 with self.assertRaises(ValueError) as e:
4272 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4273 self.assertIn("Filename 'missing' not found in input path",
4274 str(e.exception))
4275
Simon Glassa0729502020-09-06 10:35:33 -06004276 def testEnvironment(self):
4277 """Test adding a U-Boot environment"""
4278 data = self._DoReadFile('174_env.dts')
4279 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4280 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4281 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4282 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4283 env)
4284
4285 def testEnvironmentNoSize(self):
4286 """Test that a missing 'size' property is detected"""
4287 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004288 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004289 self.assertIn("'u-boot-env' entry must have a size property",
4290 str(e.exception))
4291
4292 def testEnvironmentTooSmall(self):
4293 """Test handling of an environment that does not fit"""
4294 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004295 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004296
4297 # checksum, start byte, environment with \0 terminator, final \0
4298 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4299 short = need - 0x8
4300 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4301 str(e.exception))
4302
Simon Glassd1fdf752020-10-26 17:40:01 -06004303 def testSkipAtStart(self):
4304 """Test handling of skip-at-start section"""
4305 data = self._DoReadFile('177_skip_at_start.dts')
4306 self.assertEqual(U_BOOT_DATA, data)
4307
4308 image = control.images['image']
4309 entries = image.GetEntries()
4310 section = entries['section']
4311 self.assertEqual(0, section.offset)
4312 self.assertEqual(len(U_BOOT_DATA), section.size)
4313 self.assertEqual(U_BOOT_DATA, section.GetData())
4314
4315 entry = section.GetEntries()['u-boot']
4316 self.assertEqual(16, entry.offset)
4317 self.assertEqual(len(U_BOOT_DATA), entry.size)
4318 self.assertEqual(U_BOOT_DATA, entry.data)
4319
4320 def testSkipAtStartPad(self):
4321 """Test handling of skip-at-start section with padded entry"""
4322 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004323 before = tools.get_bytes(0, 8)
4324 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004325 all = before + U_BOOT_DATA + after
4326 self.assertEqual(all, data)
4327
4328 image = control.images['image']
4329 entries = image.GetEntries()
4330 section = entries['section']
4331 self.assertEqual(0, section.offset)
4332 self.assertEqual(len(all), section.size)
4333 self.assertEqual(all, section.GetData())
4334
4335 entry = section.GetEntries()['u-boot']
4336 self.assertEqual(16, entry.offset)
4337 self.assertEqual(len(all), entry.size)
4338 self.assertEqual(U_BOOT_DATA, entry.data)
4339
4340 def testSkipAtStartSectionPad(self):
4341 """Test handling of skip-at-start section with padding"""
4342 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004343 before = tools.get_bytes(0, 8)
4344 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004345 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004346 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004347
4348 image = control.images['image']
4349 entries = image.GetEntries()
4350 section = entries['section']
4351 self.assertEqual(0, section.offset)
4352 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004353 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004354 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004355
4356 entry = section.GetEntries()['u-boot']
4357 self.assertEqual(16, entry.offset)
4358 self.assertEqual(len(U_BOOT_DATA), entry.size)
4359 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004360
Simon Glassbb395742020-10-26 17:40:14 -06004361 def testSectionPad(self):
4362 """Testing padding with sections"""
4363 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004364 expected = (tools.get_bytes(ord('&'), 3) +
4365 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004366 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004367 tools.get_bytes(ord('!'), 1) +
4368 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004369 self.assertEqual(expected, data)
4370
4371 def testSectionAlign(self):
4372 """Testing alignment with sections"""
4373 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4374 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004375 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004376 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004377 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004378 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004379 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4380 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004381 self.assertEqual(expected, data)
4382
Simon Glassd92c8362020-10-26 17:40:25 -06004383 def testCompressImage(self):
4384 """Test compression of the entire image"""
4385 self._CheckLz4()
4386 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4387 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4388 dtb = fdt.Fdt(out_dtb_fname)
4389 dtb.Scan()
4390 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4391 'uncomp-size'])
4392 orig = self._decompress(data)
4393 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4394
4395 # Do a sanity check on various fields
4396 image = control.images['image']
4397 entries = image.GetEntries()
4398 self.assertEqual(2, len(entries))
4399
4400 entry = entries['blob']
4401 self.assertEqual(COMPRESS_DATA, entry.data)
4402 self.assertEqual(len(COMPRESS_DATA), entry.size)
4403
4404 entry = entries['u-boot']
4405 self.assertEqual(U_BOOT_DATA, entry.data)
4406 self.assertEqual(len(U_BOOT_DATA), entry.size)
4407
4408 self.assertEqual(len(data), image.size)
4409 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4410 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4411 orig = self._decompress(image.data)
4412 self.assertEqual(orig, image.uncomp_data)
4413
4414 expected = {
4415 'blob:offset': 0,
4416 'blob:size': len(COMPRESS_DATA),
4417 'u-boot:offset': len(COMPRESS_DATA),
4418 'u-boot:size': len(U_BOOT_DATA),
4419 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4420 'offset': 0,
4421 'image-pos': 0,
4422 'size': len(data),
4423 }
4424 self.assertEqual(expected, props)
4425
4426 def testCompressImageLess(self):
4427 """Test compression where compression reduces the image size"""
4428 self._CheckLz4()
4429 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4430 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4431 dtb = fdt.Fdt(out_dtb_fname)
4432 dtb.Scan()
4433 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4434 'uncomp-size'])
4435 orig = self._decompress(data)
4436
4437 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4438
4439 # Do a sanity check on various fields
4440 image = control.images['image']
4441 entries = image.GetEntries()
4442 self.assertEqual(2, len(entries))
4443
4444 entry = entries['blob']
4445 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4446 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4447
4448 entry = entries['u-boot']
4449 self.assertEqual(U_BOOT_DATA, entry.data)
4450 self.assertEqual(len(U_BOOT_DATA), entry.size)
4451
4452 self.assertEqual(len(data), image.size)
4453 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4454 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4455 image.uncomp_size)
4456 orig = self._decompress(image.data)
4457 self.assertEqual(orig, image.uncomp_data)
4458
4459 expected = {
4460 'blob:offset': 0,
4461 'blob:size': len(COMPRESS_DATA_BIG),
4462 'u-boot:offset': len(COMPRESS_DATA_BIG),
4463 'u-boot:size': len(U_BOOT_DATA),
4464 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4465 'offset': 0,
4466 'image-pos': 0,
4467 'size': len(data),
4468 }
4469 self.assertEqual(expected, props)
4470
4471 def testCompressSectionSize(self):
4472 """Test compression of a section with a fixed size"""
4473 self._CheckLz4()
4474 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4475 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4476 dtb = fdt.Fdt(out_dtb_fname)
4477 dtb.Scan()
4478 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4479 'uncomp-size'])
4480 orig = self._decompress(data)
4481 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4482 expected = {
4483 'section/blob:offset': 0,
4484 'section/blob:size': len(COMPRESS_DATA),
4485 'section/u-boot:offset': len(COMPRESS_DATA),
4486 'section/u-boot:size': len(U_BOOT_DATA),
4487 'section:offset': 0,
4488 'section:image-pos': 0,
4489 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4490 'section:size': 0x30,
4491 'offset': 0,
4492 'image-pos': 0,
4493 'size': 0x30,
4494 }
4495 self.assertEqual(expected, props)
4496
4497 def testCompressSection(self):
4498 """Test compression of a section with no fixed size"""
4499 self._CheckLz4()
4500 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4501 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4502 dtb = fdt.Fdt(out_dtb_fname)
4503 dtb.Scan()
4504 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4505 'uncomp-size'])
4506 orig = self._decompress(data)
4507 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4508 expected = {
4509 'section/blob:offset': 0,
4510 'section/blob:size': len(COMPRESS_DATA),
4511 'section/u-boot:offset': len(COMPRESS_DATA),
4512 'section/u-boot:size': len(U_BOOT_DATA),
4513 'section:offset': 0,
4514 'section:image-pos': 0,
4515 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4516 'section:size': len(data),
4517 'offset': 0,
4518 'image-pos': 0,
4519 'size': len(data),
4520 }
4521 self.assertEqual(expected, props)
4522
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004523 def testLz4Missing(self):
4524 """Test that binman still produces an image if lz4 is missing"""
4525 with test_util.capture_sys_output() as (_, stderr):
4526 self._DoTestFile('185_compress_section.dts',
4527 force_missing_bintools='lz4')
4528 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004529 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004530
Simon Glassd92c8362020-10-26 17:40:25 -06004531 def testCompressExtra(self):
4532 """Test compression of a section with no fixed size"""
4533 self._CheckLz4()
4534 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4535 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4536 dtb = fdt.Fdt(out_dtb_fname)
4537 dtb.Scan()
4538 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4539 'uncomp-size'])
4540
4541 base = data[len(U_BOOT_DATA):]
4542 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4543 rest = base[len(U_BOOT_DATA):]
4544
4545 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004546 bintool = self.comp_bintools['lz4']
4547 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004548 data1 = rest[:len(expect1)]
4549 section1 = self._decompress(data1)
4550 self.assertEquals(expect1, data1)
Simon Glassd92c8362020-10-26 17:40:25 -06004551 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4552 rest1 = rest[len(expect1):]
4553
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004554 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004555 data2 = rest1[:len(expect2)]
4556 section2 = self._decompress(data2)
4557 self.assertEquals(expect2, data2)
Simon Glassd92c8362020-10-26 17:40:25 -06004558 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4559 rest2 = rest1[len(expect2):]
4560
4561 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4562 len(expect2) + len(U_BOOT_DATA))
4563 #self.assertEquals(expect_size, len(data))
4564
4565 #self.assertEquals(U_BOOT_DATA, rest2)
4566
4567 self.maxDiff = None
4568 expected = {
4569 'u-boot:offset': 0,
4570 'u-boot:image-pos': 0,
4571 'u-boot:size': len(U_BOOT_DATA),
4572
4573 'base:offset': len(U_BOOT_DATA),
4574 'base:image-pos': len(U_BOOT_DATA),
4575 'base:size': len(data) - len(U_BOOT_DATA),
4576 'base/u-boot:offset': 0,
4577 'base/u-boot:image-pos': len(U_BOOT_DATA),
4578 'base/u-boot:size': len(U_BOOT_DATA),
4579 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4580 len(expect2),
4581 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4582 len(expect2),
4583 'base/u-boot2:size': len(U_BOOT_DATA),
4584
4585 'base/section:offset': len(U_BOOT_DATA),
4586 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4587 'base/section:size': len(expect1),
4588 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4589 'base/section/blob:offset': 0,
4590 'base/section/blob:size': len(COMPRESS_DATA),
4591 'base/section/u-boot:offset': len(COMPRESS_DATA),
4592 'base/section/u-boot:size': len(U_BOOT_DATA),
4593
4594 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4595 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4596 'base/section2:size': len(expect2),
4597 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4598 'base/section2/blob:offset': 0,
4599 'base/section2/blob:size': len(COMPRESS_DATA),
4600 'base/section2/blob2:offset': len(COMPRESS_DATA),
4601 'base/section2/blob2:size': len(COMPRESS_DATA),
4602
4603 'offset': 0,
4604 'image-pos': 0,
4605 'size': len(data),
4606 }
4607 self.assertEqual(expected, props)
4608
Simon Glassecbe4732021-01-06 21:35:15 -07004609 def testSymbolsSubsection(self):
4610 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004611 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004612
Simon Glass3fb25402021-01-06 21:35:16 -07004613 def testReadImageEntryArg(self):
4614 """Test reading an image that would need an entry arg to generate"""
4615 entry_args = {
4616 'cros-ec-rw-path': 'ecrw.bin',
4617 }
4618 data = self.data = self._DoReadFileDtb(
4619 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4620 entry_args=entry_args)
4621
Simon Glass80025522022-01-29 14:14:04 -07004622 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004623 orig_image = control.images['image']
4624
4625 # This should not generate an error about the missing 'cros-ec-rw-path'
4626 # since we are reading the image from a file. Compare with
4627 # testEntryArgsRequired()
4628 image = Image.FromFile(image_fname)
4629 self.assertEqual(orig_image.GetEntries().keys(),
4630 image.GetEntries().keys())
4631
Simon Glassa2af7302021-01-06 21:35:18 -07004632 def testFilesAlign(self):
4633 """Test alignment with files"""
4634 data = self._DoReadFile('190_files_align.dts')
4635
4636 # The first string is 15 bytes so will align to 16
4637 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4638 self.assertEqual(expect, data)
4639
Simon Glassdb84b562021-01-06 21:35:19 -07004640 def testReadImageSkip(self):
4641 """Test reading an image and accessing its FDT map"""
4642 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004643 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004644 orig_image = control.images['image']
4645 image = Image.FromFile(image_fname)
4646 self.assertEqual(orig_image.GetEntries().keys(),
4647 image.GetEntries().keys())
4648
4649 orig_entry = orig_image.GetEntries()['fdtmap']
4650 entry = image.GetEntries()['fdtmap']
4651 self.assertEqual(orig_entry.offset, entry.offset)
4652 self.assertEqual(orig_entry.size, entry.size)
4653 self.assertEqual(16, entry.image_pos)
4654
4655 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4656
4657 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4658
Simon Glassc98de972021-03-18 20:24:57 +13004659 def testTplNoDtb(self):
4660 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004661 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004662 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4663 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4664 data[:len(U_BOOT_TPL_NODTB_DATA)])
4665
Simon Glass63f41d42021-03-18 20:24:58 +13004666 def testTplBssPad(self):
4667 """Test that we can pad TPL's BSS with zeros"""
4668 # ELF file with a '__bss_size' symbol
4669 self._SetupTplElf()
4670 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004671 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004672 data)
4673
4674 def testTplBssPadMissing(self):
4675 """Test that a missing symbol is detected"""
4676 self._SetupTplElf('u_boot_ucode_ptr')
4677 with self.assertRaises(ValueError) as e:
4678 self._DoReadFile('193_tpl_bss_pad.dts')
4679 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4680 str(e.exception))
4681
Simon Glass718b5292021-03-18 20:25:07 +13004682 def checkDtbSizes(self, data, pad_len, start):
4683 """Check the size arguments in a dtb embedded in an image
4684
4685 Args:
4686 data: The image data
4687 pad_len: Length of the pad section in the image, in bytes
4688 start: Start offset of the devicetree to examine, within the image
4689
4690 Returns:
4691 Size of the devicetree in bytes
4692 """
4693 dtb_data = data[start:]
4694 dtb = fdt.Fdt.FromData(dtb_data)
4695 fdt_size = dtb.GetFdtObj().totalsize()
4696 dtb.Scan()
4697 props = self._GetPropTree(dtb, 'size')
4698 self.assertEqual({
4699 'size': len(data),
4700 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4701 'u-boot-spl/u-boot-spl-dtb:size': 801,
4702 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4703 'u-boot-spl:size': 860,
4704 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4705 'u-boot/u-boot-dtb:size': 781,
4706 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4707 'u-boot:size': 827,
4708 }, props)
4709 return fdt_size
4710
4711 def testExpanded(self):
4712 """Test that an expanded entry type is selected when needed"""
4713 self._SetupSplElf()
4714 self._SetupTplElf()
4715
4716 # SPL has a devicetree, TPL does not
4717 entry_args = {
4718 'spl-dtb': '1',
4719 'spl-bss-pad': 'y',
4720 'tpl-dtb': '',
4721 }
4722 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4723 entry_args=entry_args)
4724 image = control.images['image']
4725 entries = image.GetEntries()
4726 self.assertEqual(3, len(entries))
4727
4728 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4729 self.assertIn('u-boot', entries)
4730 entry = entries['u-boot']
4731 self.assertEqual('u-boot-expanded', entry.etype)
4732 subent = entry.GetEntries()
4733 self.assertEqual(2, len(subent))
4734 self.assertIn('u-boot-nodtb', subent)
4735 self.assertIn('u-boot-dtb', subent)
4736
4737 # Second, u-boot-spl, which should be expanded into three parts
4738 self.assertIn('u-boot-spl', entries)
4739 entry = entries['u-boot-spl']
4740 self.assertEqual('u-boot-spl-expanded', entry.etype)
4741 subent = entry.GetEntries()
4742 self.assertEqual(3, len(subent))
4743 self.assertIn('u-boot-spl-nodtb', subent)
4744 self.assertIn('u-boot-spl-bss-pad', subent)
4745 self.assertIn('u-boot-spl-dtb', subent)
4746
4747 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4748 # devicetree
4749 self.assertIn('u-boot-tpl', entries)
4750 entry = entries['u-boot-tpl']
4751 self.assertEqual('u-boot-tpl', entry.etype)
4752 self.assertEqual(None, entry.GetEntries())
4753
4754 def testExpandedTpl(self):
4755 """Test that an expanded entry type is selected for TPL when needed"""
4756 self._SetupTplElf()
4757
4758 entry_args = {
4759 'tpl-bss-pad': 'y',
4760 'tpl-dtb': 'y',
4761 }
4762 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4763 entry_args=entry_args)
4764 image = control.images['image']
4765 entries = image.GetEntries()
4766 self.assertEqual(1, len(entries))
4767
4768 # We only have u-boot-tpl, which be expanded
4769 self.assertIn('u-boot-tpl', entries)
4770 entry = entries['u-boot-tpl']
4771 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4772 subent = entry.GetEntries()
4773 self.assertEqual(3, len(subent))
4774 self.assertIn('u-boot-tpl-nodtb', subent)
4775 self.assertIn('u-boot-tpl-bss-pad', subent)
4776 self.assertIn('u-boot-tpl-dtb', subent)
4777
4778 def testExpandedNoPad(self):
4779 """Test an expanded entry without BSS pad enabled"""
4780 self._SetupSplElf()
4781 self._SetupTplElf()
4782
4783 # SPL has a devicetree, TPL does not
4784 entry_args = {
4785 'spl-dtb': 'something',
4786 'spl-bss-pad': 'n',
4787 'tpl-dtb': '',
4788 }
4789 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4790 entry_args=entry_args)
4791 image = control.images['image']
4792 entries = image.GetEntries()
4793
4794 # Just check u-boot-spl, which should be expanded into two parts
4795 self.assertIn('u-boot-spl', entries)
4796 entry = entries['u-boot-spl']
4797 self.assertEqual('u-boot-spl-expanded', entry.etype)
4798 subent = entry.GetEntries()
4799 self.assertEqual(2, len(subent))
4800 self.assertIn('u-boot-spl-nodtb', subent)
4801 self.assertIn('u-boot-spl-dtb', subent)
4802
4803 def testExpandedTplNoPad(self):
4804 """Test that an expanded entry type with padding disabled in TPL"""
4805 self._SetupTplElf()
4806
4807 entry_args = {
4808 'tpl-bss-pad': '',
4809 'tpl-dtb': 'y',
4810 }
4811 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4812 entry_args=entry_args)
4813 image = control.images['image']
4814 entries = image.GetEntries()
4815 self.assertEqual(1, len(entries))
4816
4817 # We only have u-boot-tpl, which be expanded
4818 self.assertIn('u-boot-tpl', entries)
4819 entry = entries['u-boot-tpl']
4820 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4821 subent = entry.GetEntries()
4822 self.assertEqual(2, len(subent))
4823 self.assertIn('u-boot-tpl-nodtb', subent)
4824 self.assertIn('u-boot-tpl-dtb', subent)
4825
4826 def testFdtInclude(self):
4827 """Test that an Fdt is update within all binaries"""
4828 self._SetupSplElf()
4829 self._SetupTplElf()
4830
4831 # SPL has a devicetree, TPL does not
4832 self.maxDiff = None
4833 entry_args = {
4834 'spl-dtb': '1',
4835 'spl-bss-pad': 'y',
4836 'tpl-dtb': '',
4837 }
4838 # Build the image. It includes two separate devicetree binaries, each
4839 # with their own contents, but all contain the binman definition.
4840 data = self._DoReadFileDtb(
4841 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4842 update_dtb=True, entry_args=entry_args)[0]
4843 pad_len = 10
4844
4845 # Check the U-Boot dtb
4846 start = len(U_BOOT_NODTB_DATA)
4847 fdt_size = self.checkDtbSizes(data, pad_len, start)
4848
4849 # Now check SPL
4850 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4851 fdt_size = self.checkDtbSizes(data, pad_len, start)
4852
4853 # TPL has no devicetree
4854 start += fdt_size + len(U_BOOT_TPL_DATA)
4855 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004856
Simon Glass7098b7f2021-03-21 18:24:30 +13004857 def testSymbolsExpanded(self):
4858 """Test binman can assign symbols in expanded entries"""
4859 entry_args = {
4860 'spl-dtb': '1',
4861 }
4862 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4863 U_BOOT_SPL_DTB_DATA, 0x38,
4864 entry_args=entry_args, use_expanded=True)
4865
Simon Glasse1915782021-03-21 18:24:31 +13004866 def testCollection(self):
4867 """Test a collection"""
4868 data = self._DoReadFile('198_collection.dts')
4869 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004870 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4871 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004872 data)
4873
Simon Glass27a7f772021-03-21 18:24:32 +13004874 def testCollectionSection(self):
4875 """Test a collection where a section must be built first"""
4876 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004877 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004878 # building the contents, producing an error is anything is still
4879 # missing.
4880 data = self._DoReadFile('199_collection_section.dts')
4881 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004882 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4883 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004884 data)
4885
Simon Glassf427c5f2021-03-21 18:24:33 +13004886 def testAlignDefault(self):
4887 """Test that default alignment works on sections"""
4888 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004889 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004890 U_BOOT_DATA)
4891 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004892 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004893 # No alignment within the nested section
4894 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4895 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004896 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004897 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004898
Bin Mengc0b15742021-05-10 20:23:33 +08004899 def testPackOpenSBI(self):
4900 """Test that an image with an OpenSBI binary can be created"""
4901 data = self._DoReadFile('201_opensbi.dts')
4902 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4903
Simon Glass76f496d2021-07-06 10:36:37 -06004904 def testSectionsSingleThread(self):
4905 """Test sections without multithreading"""
4906 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004907 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4908 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4909 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004910 self.assertEqual(expected, data)
4911
4912 def testThreadTimeout(self):
4913 """Test handling a thread that takes too long"""
4914 with self.assertRaises(ValueError) as e:
4915 self._DoTestFile('202_section_timeout.dts',
4916 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004917 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004918
Simon Glass748a1d42021-07-06 10:36:41 -06004919 def testTiming(self):
4920 """Test output of timing information"""
4921 data = self._DoReadFile('055_sections.dts')
4922 with test_util.capture_sys_output() as (stdout, stderr):
4923 state.TimingShow()
4924 self.assertIn('read:', stdout.getvalue())
4925 self.assertIn('compress:', stdout.getvalue())
4926
Simon Glassadfb8492021-11-03 21:09:18 -06004927 def testUpdateFdtInElf(self):
4928 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004929 if not elf.ELF_TOOLS:
4930 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004931 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4932 outfile = os.path.join(self._indir, 'u-boot.out')
4933 begin_sym = 'dtb_embed_begin'
4934 end_sym = 'dtb_embed_end'
4935 retcode = self._DoTestFile(
4936 '060_fdt_update.dts', update_dtb=True,
4937 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4938 self.assertEqual(0, retcode)
4939
4940 # Check that the output file does in fact contact a dtb with the binman
4941 # definition in the correct place
4942 syms = elf.GetSymbolFileOffset(infile,
4943 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004944 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004945 dtb_data = data[syms['dtb_embed_begin'].offset:
4946 syms['dtb_embed_end'].offset]
4947
4948 dtb = fdt.Fdt.FromData(dtb_data)
4949 dtb.Scan()
4950 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4951 self.assertEqual({
4952 'image-pos': 0,
4953 'offset': 0,
4954 '_testing:offset': 32,
4955 '_testing:size': 2,
4956 '_testing:image-pos': 32,
4957 'section@0/u-boot:offset': 0,
4958 'section@0/u-boot:size': len(U_BOOT_DATA),
4959 'section@0/u-boot:image-pos': 0,
4960 'section@0:offset': 0,
4961 'section@0:size': 16,
4962 'section@0:image-pos': 0,
4963
4964 'section@1/u-boot:offset': 0,
4965 'section@1/u-boot:size': len(U_BOOT_DATA),
4966 'section@1/u-boot:image-pos': 16,
4967 'section@1:offset': 16,
4968 'section@1:size': 16,
4969 'section@1:image-pos': 16,
4970 'size': 40
4971 }, props)
4972
4973 def testUpdateFdtInElfInvalid(self):
4974 """Test that invalid args are detected with --update-fdt-in-elf"""
4975 with self.assertRaises(ValueError) as e:
4976 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4977 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4978 str(e.exception))
4979
4980 def testUpdateFdtInElfNoSyms(self):
4981 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004982 if not elf.ELF_TOOLS:
4983 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004984 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4985 outfile = ''
4986 begin_sym = 'wrong_begin'
4987 end_sym = 'wrong_end'
4988 with self.assertRaises(ValueError) as e:
4989 self._DoTestFile(
4990 '060_fdt_update.dts',
4991 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4992 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4993 str(e.exception))
4994
4995 def testUpdateFdtInElfTooSmall(self):
4996 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004997 if not elf.ELF_TOOLS:
4998 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004999 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
5000 outfile = os.path.join(self._indir, 'u-boot.out')
5001 begin_sym = 'dtb_embed_begin'
5002 end_sym = 'dtb_embed_end'
5003 with self.assertRaises(ValueError) as e:
5004 self._DoTestFile(
5005 '060_fdt_update.dts', update_dtb=True,
5006 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5007 self.assertRegex(
5008 str(e.exception),
5009 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5010
Simon Glass88e04da2021-11-23 11:03:42 -07005011 def testVersion(self):
5012 """Test we can get the binman version"""
5013 version = '(unreleased)'
5014 self.assertEqual(version, state.GetVersion(self._indir))
5015
5016 with self.assertRaises(SystemExit):
5017 with test_util.capture_sys_output() as (_, stderr):
5018 self._DoBinman('-V')
5019 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5020
5021 # Try running the tool too, just to be safe
5022 result = self._RunBinman('-V')
5023 self.assertEqual('Binman %s\n' % version, result.stderr)
5024
5025 # Set up a version file to make sure that works
5026 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005027 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005028 binary=False)
5029 self.assertEqual(version, state.GetVersion(self._indir))
5030
Simon Glass637958f2021-11-23 21:09:50 -07005031 def testAltFormat(self):
5032 """Test that alternative formats can be used to extract"""
5033 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5034
5035 try:
5036 tmpdir, updated_fname = self._SetupImageInTmpdir()
5037 with test_util.capture_sys_output() as (stdout, _):
5038 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5039 self.assertEqual(
5040 '''Flag (-F) Entry type Description
5041fdt fdtmap Extract the devicetree blob from the fdtmap
5042''',
5043 stdout.getvalue())
5044
5045 dtb = os.path.join(tmpdir, 'fdt.dtb')
5046 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5047 dtb, 'fdtmap')
5048
5049 # Check that we can read it and it can be scanning, meaning it does
5050 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005051 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005052 dtb = fdt.Fdt.FromData(data)
5053 dtb.Scan()
5054
5055 # Now check u-boot which has no alt_format
5056 fname = os.path.join(tmpdir, 'fdt.dtb')
5057 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5058 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005059 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005060 self.assertEqual(U_BOOT_DATA, data)
5061
5062 finally:
5063 shutil.rmtree(tmpdir)
5064
Simon Glass0b00ae62021-11-23 21:09:52 -07005065 def testExtblobList(self):
5066 """Test an image with an external blob list"""
5067 data = self._DoReadFile('215_blob_ext_list.dts')
5068 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5069
5070 def testExtblobListMissing(self):
5071 """Test an image with a missing external blob"""
5072 with self.assertRaises(ValueError) as e:
5073 self._DoReadFile('216_blob_ext_list_missing.dts')
5074 self.assertIn("Filename 'missing-file' not found in input path",
5075 str(e.exception))
5076
5077 def testExtblobListMissingOk(self):
5078 """Test an image with an missing external blob that is allowed"""
5079 with test_util.capture_sys_output() as (stdout, stderr):
5080 self._DoTestFile('216_blob_ext_list_missing.dts',
5081 allow_missing=True)
5082 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005083 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005084
Simon Glass3efb2972021-11-23 21:08:59 -07005085 def testFip(self):
5086 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5087 data = self._DoReadFile('203_fip.dts')
5088 hdr, fents = fip_util.decode_fip(data)
5089 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5090 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5091 self.assertEqual(0x123, hdr.flags)
5092
5093 self.assertEqual(2, len(fents))
5094
5095 fent = fents[0]
5096 self.assertEqual(
5097 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5098 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5099 self.assertEqual('soc-fw', fent.fip_type)
5100 self.assertEqual(0x88, fent.offset)
5101 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5102 self.assertEqual(0x123456789abcdef, fent.flags)
5103 self.assertEqual(ATF_BL31_DATA, fent.data)
5104 self.assertEqual(True, fent.valid)
5105
5106 fent = fents[1]
5107 self.assertEqual(
5108 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5109 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5110 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5111 self.assertEqual(0x8c, fent.offset)
5112 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5113 self.assertEqual(0, fent.flags)
5114 self.assertEqual(ATF_BL2U_DATA, fent.data)
5115 self.assertEqual(True, fent.valid)
5116
5117 def testFipOther(self):
5118 """Basic FIP with something that isn't a external blob"""
5119 data = self._DoReadFile('204_fip_other.dts')
5120 hdr, fents = fip_util.decode_fip(data)
5121
5122 self.assertEqual(2, len(fents))
5123 fent = fents[1]
5124 self.assertEqual('rot-cert', fent.fip_type)
5125 self.assertEqual(b'aa', fent.data)
5126
Simon Glass3efb2972021-11-23 21:08:59 -07005127 def testFipNoType(self):
5128 """FIP with an entry of an unknown type"""
5129 with self.assertRaises(ValueError) as e:
5130 self._DoReadFile('205_fip_no_type.dts')
5131 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5132 str(e.exception))
5133
5134 def testFipUuid(self):
5135 """Basic FIP with a manual uuid"""
5136 data = self._DoReadFile('206_fip_uuid.dts')
5137 hdr, fents = fip_util.decode_fip(data)
5138
5139 self.assertEqual(2, len(fents))
5140 fent = fents[1]
5141 self.assertEqual(None, fent.fip_type)
5142 self.assertEqual(
5143 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5144 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5145 fent.uuid)
5146 self.assertEqual(U_BOOT_DATA, fent.data)
5147
5148 def testFipLs(self):
5149 """Test listing a FIP"""
5150 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5151 hdr, fents = fip_util.decode_fip(data)
5152
5153 try:
5154 tmpdir, updated_fname = self._SetupImageInTmpdir()
5155 with test_util.capture_sys_output() as (stdout, stderr):
5156 self._DoBinman('ls', '-i', updated_fname)
5157 finally:
5158 shutil.rmtree(tmpdir)
5159 lines = stdout.getvalue().splitlines()
5160 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005161'Name Image-pos Size Entry-type Offset Uncomp-size',
5162'--------------------------------------------------------------',
5163'image 0 2d3 section 0',
5164' atf-fip 0 90 atf-fip 0',
5165' soc-fw 88 4 blob-ext 88',
5166' u-boot 8c 4 u-boot 8c',
5167' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005168]
5169 self.assertEqual(expected, lines)
5170
5171 image = control.images['image']
5172 entries = image.GetEntries()
5173 fdtmap = entries['fdtmap']
5174
5175 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5176 magic = fdtmap_data[:8]
5177 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005178 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005179
5180 fdt_data = fdtmap_data[16:]
5181 dtb = fdt.Fdt.FromData(fdt_data)
5182 dtb.Scan()
5183 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5184 self.assertEqual({
5185 'atf-fip/soc-fw:image-pos': 136,
5186 'atf-fip/soc-fw:offset': 136,
5187 'atf-fip/soc-fw:size': 4,
5188 'atf-fip/u-boot:image-pos': 140,
5189 'atf-fip/u-boot:offset': 140,
5190 'atf-fip/u-boot:size': 4,
5191 'atf-fip:image-pos': 0,
5192 'atf-fip:offset': 0,
5193 'atf-fip:size': 144,
5194 'image-pos': 0,
5195 'offset': 0,
5196 'fdtmap:image-pos': fdtmap.image_pos,
5197 'fdtmap:offset': fdtmap.offset,
5198 'fdtmap:size': len(fdtmap_data),
5199 'size': len(data),
5200 }, props)
5201
5202 def testFipExtractOneEntry(self):
5203 """Test extracting a single entry fron an FIP"""
5204 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005205 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005206 fname = os.path.join(self._indir, 'output.extact')
5207 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005208 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005209 self.assertEqual(U_BOOT_DATA, data)
5210
5211 def testFipReplace(self):
5212 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005213 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005214 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005215 updated_fname = tools.get_output_filename('image-updated.bin')
5216 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005217 entry_name = 'atf-fip/u-boot'
5218 control.WriteEntry(updated_fname, entry_name, expected,
5219 allow_resize=True)
5220 actual = control.ReadEntry(updated_fname, entry_name)
5221 self.assertEqual(expected, actual)
5222
Simon Glass80025522022-01-29 14:14:04 -07005223 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005224 hdr, fents = fip_util.decode_fip(new_data)
5225
5226 self.assertEqual(2, len(fents))
5227
5228 # Check that the FIP entry is updated
5229 fent = fents[1]
5230 self.assertEqual(0x8c, fent.offset)
5231 self.assertEqual(len(expected), fent.size)
5232 self.assertEqual(0, fent.flags)
5233 self.assertEqual(expected, fent.data)
5234 self.assertEqual(True, fent.valid)
5235
5236 def testFipMissing(self):
5237 with test_util.capture_sys_output() as (stdout, stderr):
5238 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5239 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005240 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005241
5242 def testFipSize(self):
5243 """Test a FIP with a size property"""
5244 data = self._DoReadFile('210_fip_size.dts')
5245 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5246 hdr, fents = fip_util.decode_fip(data)
5247 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5248 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5249
5250 self.assertEqual(1, len(fents))
5251
5252 fent = fents[0]
5253 self.assertEqual('soc-fw', fent.fip_type)
5254 self.assertEqual(0x60, fent.offset)
5255 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5256 self.assertEqual(ATF_BL31_DATA, fent.data)
5257 self.assertEqual(True, fent.valid)
5258
5259 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005260 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005261
5262 def testFipBadAlign(self):
5263 """Test that an invalid alignment value in a FIP is detected"""
5264 with self.assertRaises(ValueError) as e:
5265 self._DoTestFile('211_fip_bad_align.dts')
5266 self.assertIn(
5267 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5268 str(e.exception))
5269
5270 def testFipCollection(self):
5271 """Test using a FIP in a collection"""
5272 data = self._DoReadFile('212_fip_collection.dts')
5273 entry1 = control.images['image'].GetEntries()['collection']
5274 data1 = data[:entry1.size]
5275 hdr1, fents2 = fip_util.decode_fip(data1)
5276
5277 entry2 = control.images['image'].GetEntries()['atf-fip']
5278 data2 = data[entry2.offset:entry2.offset + entry2.size]
5279 hdr1, fents2 = fip_util.decode_fip(data2)
5280
5281 # The 'collection' entry should have U-Boot included at the end
5282 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5283 self.assertEqual(data1, data2 + U_BOOT_DATA)
5284 self.assertEqual(U_BOOT_DATA, data1[-4:])
5285
5286 # There should be a U-Boot after the final FIP
5287 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005288
Simon Glassccae6862022-01-12 13:10:35 -07005289 def testFakeBlob(self):
5290 """Test handling of faking an external blob"""
5291 with test_util.capture_sys_output() as (stdout, stderr):
5292 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5293 allow_fake_blobs=True)
5294 err = stderr.getvalue()
5295 self.assertRegex(
5296 err,
5297 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005298
Simon Glassceb5f912022-01-09 20:13:46 -07005299 def testExtblobListFaked(self):
5300 """Test an extblob with missing external blob that are faked"""
5301 with test_util.capture_sys_output() as (stdout, stderr):
5302 self._DoTestFile('216_blob_ext_list_missing.dts',
5303 allow_fake_blobs=True)
5304 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005305 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005306
Simon Glass162017b2022-01-09 20:13:57 -07005307 def testListBintools(self):
5308 args = ['tool', '--list']
5309 with test_util.capture_sys_output() as (stdout, _):
5310 self._DoBinman(*args)
5311 out = stdout.getvalue().splitlines()
5312 self.assertTrue(len(out) >= 2)
5313
5314 def testFetchBintools(self):
5315 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005316 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005317 raise urllib.error.URLError('my error')
5318
5319 args = ['tool']
5320 with self.assertRaises(ValueError) as e:
5321 self._DoBinman(*args)
5322 self.assertIn("Invalid arguments to 'tool' subcommand",
5323 str(e.exception))
5324
5325 args = ['tool', '--fetch']
5326 with self.assertRaises(ValueError) as e:
5327 self._DoBinman(*args)
5328 self.assertIn('Please specify bintools to fetch', str(e.exception))
5329
5330 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005331 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005332 side_effect=fail_download):
5333 with test_util.capture_sys_output() as (stdout, _):
5334 self._DoBinman(*args)
5335 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5336
Simon Glass620c4462022-01-09 20:14:11 -07005337 def testBintoolDocs(self):
5338 """Test for creation of bintool documentation"""
5339 with test_util.capture_sys_output() as (stdout, stderr):
5340 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5341 self.assertTrue(len(stdout.getvalue()) > 0)
5342
5343 def testBintoolDocsMissing(self):
5344 """Test handling of missing bintool documentation"""
5345 with self.assertRaises(ValueError) as e:
5346 with test_util.capture_sys_output() as (stdout, stderr):
5347 control.write_bintool_docs(
5348 control.bintool.Bintool.get_tool_list(), 'mkimage')
5349 self.assertIn('Documentation is missing for modules: mkimage',
5350 str(e.exception))
5351
Jan Kiszka58c407f2022-01-28 20:37:53 +01005352 def testListWithGenNode(self):
5353 """Check handling of an FDT map when the section cannot be found"""
5354 entry_args = {
5355 'of-list': 'test-fdt1 test-fdt2',
5356 }
5357 data = self._DoReadFileDtb(
5358 '219_fit_gennode.dts',
5359 entry_args=entry_args,
5360 use_real_dtb=True,
5361 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5362
5363 try:
5364 tmpdir, updated_fname = self._SetupImageInTmpdir()
5365 with test_util.capture_sys_output() as (stdout, stderr):
5366 self._RunBinman('ls', '-i', updated_fname)
5367 finally:
5368 shutil.rmtree(tmpdir)
5369
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005370 def testFitSubentryUsesBintool(self):
5371 """Test that binman FIT subentries can use bintools"""
5372 command.test_result = self._HandleGbbCommand
5373 entry_args = {
5374 'keydir': 'devkeys',
5375 'bmpblk': 'bmpblk.bin',
5376 }
5377 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5378 entry_args=entry_args)
5379
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005380 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5381 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005382 self.assertIn(expected, data)
5383
5384 def testFitSubentryMissingBintool(self):
5385 """Test that binman reports missing bintools for FIT subentries"""
5386 entry_args = {
5387 'keydir': 'devkeys',
5388 }
5389 with test_util.capture_sys_output() as (_, stderr):
5390 self._DoTestFile('220_fit_subentry_bintool.dts',
5391 force_missing_bintools='futility', entry_args=entry_args)
5392 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005393 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005394
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005395 def testFitSubentryHashSubnode(self):
5396 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005397 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005398 data, _, _, out_dtb_name = self._DoReadFileDtb(
5399 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5400
5401 mkimage_dtb = fdt.Fdt.FromData(data)
5402 mkimage_dtb.Scan()
5403 binman_dtb = fdt.Fdt(out_dtb_name)
5404 binman_dtb.Scan()
5405
5406 # Check that binman didn't add hash values
5407 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5408 self.assertNotIn('value', fnode.props)
5409
5410 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5411 self.assertNotIn('value', fnode.props)
5412
5413 # Check that mkimage added hash values
5414 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5415 self.assertIn('value', fnode.props)
5416
5417 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5418 self.assertIn('value', fnode.props)
5419
Roger Quadros5cdcea02022-02-19 20:50:04 +02005420 def testPackTeeOs(self):
5421 """Test that an image with an TEE binary can be created"""
5422 data = self._DoReadFile('222_tee_os.dts')
5423 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5424
Simon Glass912339f2022-02-08 11:50:03 -07005425 def testFitFdtOper(self):
5426 """Check handling of a specified FIT operation"""
5427 entry_args = {
5428 'of-list': 'test-fdt1 test-fdt2',
5429 'default-dt': 'test-fdt2',
5430 }
5431 self._DoReadFileDtb(
5432 '223_fit_fdt_oper.dts',
5433 entry_args=entry_args,
5434 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5435
5436 def testFitFdtBadOper(self):
5437 """Check handling of an FDT map when the section cannot be found"""
5438 with self.assertRaises(ValueError) as exc:
5439 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005440 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005441 str(exc.exception))
5442
Simon Glassdd156a42022-03-05 20:18:59 -07005443 def test_uses_expand_size(self):
5444 """Test that the 'expand-size' property cannot be used anymore"""
5445 with self.assertRaises(ValueError) as e:
5446 data = self._DoReadFile('225_expand_size_bad.dts')
5447 self.assertIn(
5448 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5449 str(e.exception))
5450
Simon Glass5f423422022-03-05 20:19:12 -07005451 def testFitSplitElf(self):
5452 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005453 if not elf.ELF_TOOLS:
5454 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005455 entry_args = {
5456 'of-list': 'test-fdt1 test-fdt2',
5457 'default-dt': 'test-fdt2',
5458 'atf-bl31-path': 'bl31.elf',
5459 'tee-os-path': 'tee.elf',
5460 }
5461 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5462 data = self._DoReadFileDtb(
5463 '226_fit_split_elf.dts',
5464 entry_args=entry_args,
5465 extra_indirs=[test_subdir])[0]
5466
5467 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5468 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5469
5470 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5471 'data', 'load'}
5472 dtb = fdt.Fdt.FromData(fit_data)
5473 dtb.Scan()
5474
5475 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5476 segments, entry = elf.read_loadable_segments(elf_data)
5477
5478 # We assume there are two segments
5479 self.assertEquals(2, len(segments))
5480
5481 atf1 = dtb.GetNode('/images/atf-1')
5482 _, start, data = segments[0]
5483 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5484 self.assertEqual(entry,
5485 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5486 self.assertEqual(start,
5487 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5488 self.assertEqual(data, atf1.props['data'].bytes)
5489
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005490 hash_node = atf1.FindNode('hash')
5491 self.assertIsNotNone(hash_node)
5492 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5493
Simon Glass5f423422022-03-05 20:19:12 -07005494 atf2 = dtb.GetNode('/images/atf-2')
5495 self.assertEqual(base_keys, atf2.props.keys())
5496 _, start, data = segments[1]
5497 self.assertEqual(start,
5498 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5499 self.assertEqual(data, atf2.props['data'].bytes)
5500
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005501 hash_node = atf2.FindNode('hash')
5502 self.assertIsNotNone(hash_node)
5503 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5504
5505 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5506 self.assertIsNotNone(hash_node)
5507 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5508
Simon Glass5f423422022-03-05 20:19:12 -07005509 conf = dtb.GetNode('/configurations')
5510 self.assertEqual({'default'}, conf.props.keys())
5511
5512 for subnode in conf.subnodes:
5513 self.assertEqual({'description', 'fdt', 'loadables'},
5514 subnode.props.keys())
5515 self.assertEqual(
5516 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5517 fdt_util.GetStringList(subnode, 'loadables'))
5518
5519 def _check_bad_fit(self, dts):
5520 """Check a bad FIT
5521
5522 This runs with the given dts and returns the assertion raised
5523
5524 Args:
5525 dts (str): dts filename to use
5526
5527 Returns:
5528 str: Assertion string raised
5529 """
5530 entry_args = {
5531 'of-list': 'test-fdt1 test-fdt2',
5532 'default-dt': 'test-fdt2',
5533 'atf-bl31-path': 'bl31.elf',
5534 'tee-os-path': 'tee.elf',
5535 }
5536 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5537 with self.assertRaises(ValueError) as exc:
5538 self._DoReadFileDtb(dts, entry_args=entry_args,
5539 extra_indirs=[test_subdir])[0]
5540 return str(exc.exception)
5541
5542 def testFitSplitElfBadElf(self):
5543 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005544 if not elf.ELF_TOOLS:
5545 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005546 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5547 entry_args = {
5548 'of-list': 'test-fdt1 test-fdt2',
5549 'default-dt': 'test-fdt2',
5550 'atf-bl31-path': 'bad.elf',
5551 'tee-os-path': 'tee.elf',
5552 }
5553 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5554 with self.assertRaises(ValueError) as exc:
5555 self._DoReadFileDtb(
5556 '226_fit_split_elf.dts',
5557 entry_args=entry_args,
5558 extra_indirs=[test_subdir])[0]
5559 self.assertIn(
5560 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5561 str(exc.exception))
5562
Simon Glass5f423422022-03-05 20:19:12 -07005563 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005564 """Test an split-elf FIT with a missing ELF file
5565
5566 Args:
5567 kwargs (dict of str): Arguments to pass to _DoTestFile()
5568
5569 Returns:
5570 tuple:
5571 str: stdout result
5572 str: stderr result
5573 """
Simon Glass5f423422022-03-05 20:19:12 -07005574 entry_args = {
5575 'of-list': 'test-fdt1 test-fdt2',
5576 'default-dt': 'test-fdt2',
5577 'atf-bl31-path': 'bl31.elf',
5578 'tee-os-path': 'missing.elf',
5579 }
5580 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5581 with test_util.capture_sys_output() as (stdout, stderr):
5582 self._DoTestFile(
5583 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005584 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5585 out = stdout.getvalue()
5586 err = stderr.getvalue()
5587 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005588
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005589 def testFitSplitElfBadDirective(self):
5590 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5591 if not elf.ELF_TOOLS:
5592 self.skipTest('Python elftools not available')
5593 err = self._check_bad_fit('227_fit_bad_dir.dts')
5594 self.assertIn(
5595 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5596 err)
5597
5598 def testFitSplitElfBadDirectiveConfig(self):
5599 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5600 if not elf.ELF_TOOLS:
5601 self.skipTest('Python elftools not available')
5602 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5603 self.assertEqual(
5604 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5605 err)
5606
5607
Simon Glass5f423422022-03-05 20:19:12 -07005608 def testFitSplitElfMissing(self):
5609 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005610 if not elf.ELF_TOOLS:
5611 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005612 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005613 self.assertRegex(
5614 err,
5615 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005616 self.assertNotRegex(out, '.*Faked blob.*')
5617 fname = tools.get_output_filename('binman-fake/missing.elf')
5618 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005619
5620 def testFitSplitElfFaked(self):
5621 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005622 if not elf.ELF_TOOLS:
5623 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005624 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005625 self.assertRegex(
5626 err,
5627 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005628 self.assertRegex(
5629 out,
5630 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5631 fname = tools.get_output_filename('binman-fake/missing.elf')
5632 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005633
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005634 def testMkimageMissingBlob(self):
5635 """Test using mkimage to build an image"""
5636 with test_util.capture_sys_output() as (stdout, stderr):
5637 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5638 allow_fake_blobs=True)
5639 err = stderr.getvalue()
5640 self.assertRegex(
5641 err,
5642 "Image '.*' has faked external blobs and is non-functional: .*")
5643
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005644 def testPreLoad(self):
5645 """Test an image with a pre-load header"""
5646 entry_args = {
5647 'pre-load-key-path': '.',
5648 }
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005649 data, _, _, _ = self._DoReadFileDtb('230_pre_load.dts',
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005650 entry_args=entry_args)
5651 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5652 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5653 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005654 data = self._DoReadFile('230_pre_load.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005655 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5656 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5657 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5658
5659 def testPreLoadPkcs(self):
5660 """Test an image with a pre-load header with padding pkcs"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005661 data = self._DoReadFile('231_pre_load_pkcs.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005662 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5663 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5664 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5665
5666 def testPreLoadPss(self):
5667 """Test an image with a pre-load header with padding pss"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005668 data = self._DoReadFile('232_pre_load_pss.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005669 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5670 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5671 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5672
5673 def testPreLoadInvalidPadding(self):
5674 """Test an image with a pre-load header with an invalid padding"""
5675 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005676 data = self._DoReadFile('233_pre_load_invalid_padding.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005677
5678 def testPreLoadInvalidSha(self):
5679 """Test an image with a pre-load header with an invalid hash"""
5680 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005681 data = self._DoReadFile('234_pre_load_invalid_sha.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005682
5683 def testPreLoadInvalidAlgo(self):
5684 """Test an image with a pre-load header with an invalid algo"""
5685 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005686 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005687
5688 def testPreLoadInvalidKey(self):
5689 """Test an image with a pre-load header with an invalid key"""
5690 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005691 data = self._DoReadFile('236_pre_load_invalid_key.dts')
Roger Quadros5cdcea02022-02-19 20:50:04 +02005692
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005693 def _CheckSafeUniqueNames(self, *images):
5694 """Check all entries of given images for unsafe unique names"""
5695 for image in images:
5696 entries = {}
5697 image._CollectEntries(entries, {}, image)
5698 for entry in entries.values():
5699 uniq = entry.GetUniqueName()
5700
5701 # Used as part of a filename, so must not be absolute paths.
5702 self.assertFalse(os.path.isabs(uniq))
5703
5704 def testSafeUniqueNames(self):
5705 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005706 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005707
5708 orig_image = control.images['image']
5709 image_fname = tools.get_output_filename('image.bin')
5710 image = Image.FromFile(image_fname)
5711
5712 self._CheckSafeUniqueNames(orig_image, image)
5713
5714 def testSafeUniqueNamesMulti(self):
5715 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005716 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005717
5718 orig_image = control.images['image']
5719 image_fname = tools.get_output_filename('image.bin')
5720 image = Image.FromFile(image_fname)
5721
5722 self._CheckSafeUniqueNames(orig_image, image)
5723
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005724 def testReplaceCmdWithBintool(self):
5725 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005726 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005727 expected = U_BOOT_DATA + b'aa'
5728 self.assertEqual(expected, data[:len(expected)])
5729
5730 try:
5731 tmpdir, updated_fname = self._SetupImageInTmpdir()
5732 fname = os.path.join(tmpdir, 'update-testing.bin')
5733 tools.write_file(fname, b'zz')
5734 self._DoBinman('replace', '-i', updated_fname,
5735 '_testing', '-f', fname)
5736
5737 data = tools.read_file(updated_fname)
5738 expected = U_BOOT_DATA + b'zz'
5739 self.assertEqual(expected, data[:len(expected)])
5740 finally:
5741 shutil.rmtree(tmpdir)
5742
5743 def testReplaceCmdOtherWithBintool(self):
5744 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005745 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005746 expected = U_BOOT_DATA + b'aa'
5747 self.assertEqual(expected, data[:len(expected)])
5748
5749 try:
5750 tmpdir, updated_fname = self._SetupImageInTmpdir()
5751 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5752 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5753 self._DoBinman('replace', '-i', updated_fname,
5754 'u-boot', '-f', fname)
5755
5756 data = tools.read_file(updated_fname)
5757 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5758 self.assertEqual(expected, data[:len(expected)])
5759 finally:
5760 shutil.rmtree(tmpdir)
5761
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005762 def testReplaceResizeNoRepackSameSize(self):
5763 """Test replacing entries with same-size data without repacking"""
5764 expected = b'x' * len(U_BOOT_DATA)
5765 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5766 self.assertEqual(expected, data)
5767
5768 path, fdtmap = state.GetFdtContents('fdtmap')
5769 self.assertIsNotNone(path)
5770 self.assertEqual(expected_fdtmap, fdtmap)
5771
5772 def testReplaceResizeNoRepackSmallerSize(self):
5773 """Test replacing entries with smaller-size data without repacking"""
5774 new_data = b'x'
5775 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5776 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5777 self.assertEqual(expected, data)
5778
5779 path, fdtmap = state.GetFdtContents('fdtmap')
5780 self.assertIsNotNone(path)
5781 self.assertEqual(expected_fdtmap, fdtmap)
5782
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005783 def testExtractFit(self):
5784 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005785 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005786 image_fname = tools.get_output_filename('image.bin')
5787
5788 fit_data = control.ReadEntry(image_fname, 'fit')
5789 fit = fdt.Fdt.FromData(fit_data)
5790 fit.Scan()
5791
5792 # Check subentry data inside the extracted fit
5793 for node_path, expected in [
5794 ('/images/kernel', U_BOOT_DATA),
5795 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5796 ('/images/scr-1', COMPRESS_DATA),
5797 ]:
5798 node = fit.GetNode(node_path)
5799 data = fit.GetProps(node)['data'].bytes
5800 self.assertEqual(expected, data)
5801
5802 def testExtractFitSubentries(self):
5803 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005804 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005805 image_fname = tools.get_output_filename('image.bin')
5806
5807 for entry_path, expected in [
5808 ('fit/kernel', U_BOOT_DATA),
5809 ('fit/kernel/u-boot', U_BOOT_DATA),
5810 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5811 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5812 ('fit/scr-1', COMPRESS_DATA),
5813 ('fit/scr-1/blob', COMPRESS_DATA),
5814 ]:
5815 data = control.ReadEntry(image_fname, entry_path)
5816 self.assertEqual(expected, data)
5817
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005818 def testReplaceFitSubentryLeafSameSize(self):
5819 """Test replacing a FIT leaf subentry with same-size data"""
5820 new_data = b'x' * len(U_BOOT_DATA)
5821 data, expected_fdtmap, _ = self._RunReplaceCmd(
5822 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005823 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005824 self.assertEqual(new_data, data)
5825
5826 path, fdtmap = state.GetFdtContents('fdtmap')
5827 self.assertIsNotNone(path)
5828 self.assertEqual(expected_fdtmap, fdtmap)
5829
5830 def testReplaceFitSubentryLeafBiggerSize(self):
5831 """Test replacing a FIT leaf subentry with bigger-size data"""
5832 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5833 data, expected_fdtmap, _ = self._RunReplaceCmd(
5834 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005835 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005836 self.assertEqual(new_data, data)
5837
5838 # Will be repacked, so fdtmap must change
5839 path, fdtmap = state.GetFdtContents('fdtmap')
5840 self.assertIsNotNone(path)
5841 self.assertNotEqual(expected_fdtmap, fdtmap)
5842
5843 def testReplaceFitSubentryLeafSmallerSize(self):
5844 """Test replacing a FIT leaf subentry with smaller-size data"""
5845 new_data = b'x'
5846 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5847 data, expected_fdtmap, _ = self._RunReplaceCmd(
5848 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005849 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005850 self.assertEqual(expected, data)
5851
5852 path, fdtmap = state.GetFdtContents('fdtmap')
5853 self.assertIsNotNone(path)
5854 self.assertEqual(expected_fdtmap, fdtmap)
5855
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005856 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005857 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005858 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005859 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5860 new_data, dts='241_replace_section_simple.dts')
5861 self.assertEqual(new_data, data)
5862
5863 entries = image.GetEntries()
5864 self.assertIn('section', entries)
5865 entry = entries['section']
5866 self.assertEqual(len(new_data), entry.size)
5867
5868 def testReplaceSectionLarger(self):
5869 """Test replacing a simple section with larger data"""
5870 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5871 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5872 new_data, dts='241_replace_section_simple.dts')
5873 self.assertEqual(new_data, data)
5874
5875 entries = image.GetEntries()
5876 self.assertIn('section', entries)
5877 entry = entries['section']
5878 self.assertEqual(len(new_data), entry.size)
5879 fentry = entries['fdtmap']
5880 self.assertEqual(entry.offset + entry.size, fentry.offset)
5881
5882 def testReplaceSectionSmaller(self):
5883 """Test replacing a simple section with smaller data"""
5884 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5885 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5886 new_data, dts='241_replace_section_simple.dts')
5887 self.assertEqual(new_data, data)
5888
5889 # The new size is the same as the old, just with a pad byte at the end
5890 entries = image.GetEntries()
5891 self.assertIn('section', entries)
5892 entry = entries['section']
5893 self.assertEqual(len(new_data), entry.size)
5894
5895 def testReplaceSectionSmallerAllow(self):
5896 """Test failing to replace a simple section with smaller data"""
5897 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5898 try:
5899 state.SetAllowEntryContraction(True)
5900 with self.assertRaises(ValueError) as exc:
5901 self._RunReplaceCmd('section', new_data,
5902 dts='241_replace_section_simple.dts')
5903 finally:
5904 state.SetAllowEntryContraction(False)
5905
5906 # Since we have no information about the position of things within the
5907 # section, we cannot adjust the position of /section-u-boot so it ends
5908 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06005909 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07005910 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5911 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06005912 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005913
Simon Glass8fbca772022-08-13 11:40:48 -06005914 def testMkimageImagename(self):
5915 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005916 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005917 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005918
5919 # Check that the data appears in the file somewhere
5920 self.assertIn(U_BOOT_SPL_DATA, data)
5921
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005922 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005923 name = data[0x20:0x40]
5924
5925 # Build the filename that we expect to be placed in there, by virtue of
5926 # the -n paraameter
5927 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5928
5929 # Check that the image name is set to the temporary filename used
5930 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5931
Simon Glassb1669752022-08-13 11:40:49 -06005932 def testMkimageImage(self):
5933 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005934 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005935 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005936
5937 # Check that the data appears in the file somewhere
5938 self.assertIn(U_BOOT_SPL_DATA, data)
5939
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005940 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06005941 name = data[0x20:0x40]
5942
5943 # Build the filename that we expect to be placed in there, by virtue of
5944 # the -n paraameter
5945 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5946
5947 # Check that the image name is set to the temporary filename used
5948 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5949
5950 # Check the corect data is in the imagename file
5951 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5952
5953 def testMkimageImageNoContent(self):
5954 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005955 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06005956 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005957 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005958 self.assertIn('Could not complete processing of contents',
5959 str(exc.exception))
5960
5961 def testMkimageImageBad(self):
5962 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005963 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06005964 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005965 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005966 self.assertIn('Cannot use both imagename node and data-to-imagename',
5967 str(exc.exception))
5968
Simon Glassbd5cd882022-08-13 11:40:50 -06005969 def testCollectionOther(self):
5970 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005971 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005972 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5973 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5974 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5975 data)
5976
5977 def testMkimageCollection(self):
5978 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005979 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005980 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005981 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5982 self.assertEqual(expect, data[:len(expect)])
5983
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005984 def testCompressDtbPrependInvalid(self):
5985 """Test that invalid header is detected"""
5986 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005987 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005988 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5989 "'u-boot-dtb': 'invalid'", str(e.exception))
5990
5991 def testCompressDtbPrependLength(self):
5992 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005993 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005994 image = control.images['image']
5995 entries = image.GetEntries()
5996 self.assertIn('u-boot-dtb', entries)
5997 u_boot_dtb = entries['u-boot-dtb']
5998 self.assertIn('fdtmap', entries)
5999 fdtmap = entries['fdtmap']
6000
6001 image_fname = tools.get_output_filename('image.bin')
6002 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
6003 dtb = fdt.Fdt.FromData(orig)
6004 dtb.Scan()
6005 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6006 expected = {
6007 'u-boot:size': len(U_BOOT_DATA),
6008 'u-boot-dtb:uncomp-size': len(orig),
6009 'u-boot-dtb:size': u_boot_dtb.size,
6010 'fdtmap:size': fdtmap.size,
6011 'size': len(data),
6012 }
6013 self.assertEqual(expected, props)
6014
6015 # Check implementation
6016 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6017 rest = data[len(U_BOOT_DATA):]
6018 comp_data_len = struct.unpack('<I', rest[:4])[0]
6019 comp_data = rest[4:4 + comp_data_len]
6020 orig2 = self._decompress(comp_data)
6021 self.assertEqual(orig, orig2)
6022
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006023 def testInvalidCompress(self):
6024 """Test that invalid compress algorithm is detected"""
6025 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006026 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006027 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6028
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006029 def testCompUtilCompressions(self):
6030 """Test compression algorithms"""
6031 for bintool in self.comp_bintools.values():
6032 self._CheckBintool(bintool)
6033 data = bintool.compress(COMPRESS_DATA)
6034 self.assertNotEqual(COMPRESS_DATA, data)
6035 orig = bintool.decompress(data)
6036 self.assertEquals(COMPRESS_DATA, orig)
6037
6038 def testCompUtilVersions(self):
6039 """Test tool version of compression algorithms"""
6040 for bintool in self.comp_bintools.values():
6041 self._CheckBintool(bintool)
6042 version = bintool.version()
6043 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6044
6045 def testCompUtilPadding(self):
6046 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006047 # Skip zstd because it doesn't support padding
6048 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006049 self._CheckBintool(bintool)
6050 data = bintool.compress(COMPRESS_DATA)
6051 self.assertNotEqual(COMPRESS_DATA, data)
6052 data += tools.get_bytes(0, 64)
6053 orig = bintool.decompress(data)
6054 self.assertEquals(COMPRESS_DATA, orig)
6055
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006056 def testCompressDtbZstd(self):
6057 """Test that zstd compress of device-tree files failed"""
6058 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006059 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006060 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6061 "requires a length header", str(e.exception))
6062
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006063 def testMkimageMultipleDataFiles(self):
6064 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006065 self._SetupSplElf()
6066 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006067 data = self._DoReadFile('252_mkimage_mult_data.dts')
6068 # Size of files are packed in their 4B big-endian format
6069 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6070 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6071 # Size info is always followed by a 4B zero value.
6072 expect += tools.get_bytes(0, 4)
6073 expect += U_BOOT_TPL_DATA
6074 # All but last files are 4B-aligned
6075 align_pad = len(U_BOOT_TPL_DATA) % 4
6076 if align_pad:
6077 expect += tools.get_bytes(0, align_pad)
6078 expect += U_BOOT_SPL_DATA
6079 self.assertEqual(expect, data[-len(expect):])
6080
Marek Vasutf7413f02023-07-18 07:23:58 -06006081 def testMkimageMultipleExpanded(self):
6082 """Test passing multiple files to mkimage in a mkimage entry"""
6083 self._SetupSplElf()
6084 self._SetupTplElf()
6085 entry_args = {
6086 'spl-bss-pad': 'y',
6087 'spl-dtb': 'y',
6088 }
6089 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6090 use_expanded=True, entry_args=entry_args)[0]
6091 pad_len = 10
6092 tpl_expect = U_BOOT_TPL_DATA
6093 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6094 spl_expect += U_BOOT_SPL_DTB_DATA
6095
6096 content = data[0x40:]
6097 lens = struct.unpack('>III', content[:12])
6098
6099 # Size of files are packed in their 4B big-endian format
6100 # Size info is always followed by a 4B zero value.
6101 self.assertEqual(len(tpl_expect), lens[0])
6102 self.assertEqual(len(spl_expect), lens[1])
6103 self.assertEqual(0, lens[2])
6104
6105 rest = content[12:]
6106 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6107
6108 rest = rest[len(tpl_expect):]
6109 align_pad = len(tpl_expect) % 4
6110 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6111 rest = rest[align_pad:]
6112 self.assertEqual(spl_expect, rest)
6113
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006114 def testMkimageMultipleNoContent(self):
6115 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006116 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006117 with self.assertRaises(ValueError) as exc:
6118 self._DoReadFile('253_mkimage_mult_no_content.dts')
6119 self.assertIn('Could not complete processing of contents',
6120 str(exc.exception))
6121
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006122 def testMkimageFilename(self):
6123 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006124 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006125 retcode = self._DoTestFile('254_mkimage_filename.dts')
6126 self.assertEqual(0, retcode)
6127 fname = tools.get_output_filename('mkimage-test.bin')
6128 self.assertTrue(os.path.exists(fname))
6129
Simon Glass56d05412022-02-28 07:16:54 -07006130 def testVpl(self):
6131 """Test that an image with VPL and its device tree can be created"""
6132 # ELF file with a '__bss_size' symbol
6133 self._SetupVplElf()
6134 data = self._DoReadFile('255_u_boot_vpl.dts')
6135 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6136
6137 def testVplNoDtb(self):
6138 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6139 self._SetupVplElf()
6140 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6141 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6142 data[:len(U_BOOT_VPL_NODTB_DATA)])
6143
6144 def testExpandedVpl(self):
6145 """Test that an expanded entry type is selected for TPL when needed"""
6146 self._SetupVplElf()
6147
6148 entry_args = {
6149 'vpl-bss-pad': 'y',
6150 'vpl-dtb': 'y',
6151 }
6152 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6153 entry_args=entry_args)
6154 image = control.images['image']
6155 entries = image.GetEntries()
6156 self.assertEqual(1, len(entries))
6157
6158 # We only have u-boot-vpl, which be expanded
6159 self.assertIn('u-boot-vpl', entries)
6160 entry = entries['u-boot-vpl']
6161 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6162 subent = entry.GetEntries()
6163 self.assertEqual(3, len(subent))
6164 self.assertIn('u-boot-vpl-nodtb', subent)
6165 self.assertIn('u-boot-vpl-bss-pad', subent)
6166 self.assertIn('u-boot-vpl-dtb', subent)
6167
6168 def testVplBssPadMissing(self):
6169 """Test that a missing symbol is detected"""
6170 self._SetupVplElf('u_boot_ucode_ptr')
6171 with self.assertRaises(ValueError) as e:
6172 self._DoReadFile('258_vpl_bss_pad.dts')
6173 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6174 str(e.exception))
6175
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306176 def testSymlink(self):
6177 """Test that image files can be named"""
6178 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6179 self.assertEqual(0, retcode)
6180 image = control.images['test_image']
6181 fname = tools.get_output_filename('test_image.bin')
6182 sname = tools.get_output_filename('symlink_to_test.bin')
6183 self.assertTrue(os.path.islink(sname))
6184 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006185
Simon Glass37f85de2022-10-20 18:22:47 -06006186 def testSymbolsElf(self):
6187 """Test binman can assign symbols embedded in an ELF file"""
6188 if not elf.ELF_TOOLS:
6189 self.skipTest('Python elftools not available')
6190 self._SetupTplElf('u_boot_binman_syms')
6191 self._SetupVplElf('u_boot_binman_syms')
6192 self._SetupSplElf('u_boot_binman_syms')
6193 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6194 image_fname = tools.get_output_filename('image.bin')
6195
6196 image = control.images['image']
6197 entries = image.GetEntries()
6198
6199 for entry in entries.values():
6200 # No symbols in u-boot and it has faked contents anyway
6201 if entry.name == 'u-boot':
6202 continue
6203 edata = data[entry.image_pos:entry.image_pos + entry.size]
6204 efname = tools.get_output_filename(f'edata-{entry.name}')
6205 tools.write_file(efname, edata)
6206
6207 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6208 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6209 for name, sym in syms.items():
6210 msg = 'test'
6211 val = elf.GetSymbolValue(sym, edata, msg)
6212 entry_m = re_name.match(name)
6213 if entry_m:
6214 ename, prop = entry_m.group(1), entry_m.group(3)
6215 entry, entry_name, prop_name = image.LookupEntry(entries,
6216 name, msg)
6217 if prop_name == 'offset':
6218 expect_val = entry.offset
6219 elif prop_name == 'image_pos':
6220 expect_val = entry.image_pos
6221 elif prop_name == 'size':
6222 expect_val = entry.size
6223 self.assertEqual(expect_val, val)
6224
6225 def testSymbolsElfBad(self):
6226 """Check error when trying to write symbols without the elftools lib"""
6227 if not elf.ELF_TOOLS:
6228 self.skipTest('Python elftools not available')
6229 self._SetupTplElf('u_boot_binman_syms')
6230 self._SetupVplElf('u_boot_binman_syms')
6231 self._SetupSplElf('u_boot_binman_syms')
6232 try:
6233 elf.ELF_TOOLS = False
6234 with self.assertRaises(ValueError) as exc:
6235 self._DoReadFileDtb('260_symbols_elf.dts')
6236 finally:
6237 elf.ELF_TOOLS = True
6238 self.assertIn(
6239 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6240 'Cannot write symbols to an ELF file without Python elftools',
6241 str(exc.exception))
6242
Simon Glassde244162023-01-07 14:07:08 -07006243 def testSectionFilename(self):
6244 """Check writing of section contents to a file"""
6245 data = self._DoReadFile('261_section_fname.dts')
6246 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6247 tools.get_bytes(ord('!'), 7) +
6248 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6249 self.assertEqual(expected, data)
6250
6251 sect_fname = tools.get_output_filename('outfile.bin')
6252 self.assertTrue(os.path.exists(sect_fname))
6253 sect_data = tools.read_file(sect_fname)
6254 self.assertEqual(U_BOOT_DATA, sect_data)
6255
Simon Glass1e9e61c2023-01-07 14:07:12 -07006256 def testAbsent(self):
6257 """Check handling of absent entries"""
6258 data = self._DoReadFile('262_absent.dts')
6259 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6260
Simon Glassad5cfe12023-01-07 14:07:14 -07006261 def testPackTeeOsOptional(self):
6262 """Test that an image with an optional TEE binary can be created"""
6263 entry_args = {
6264 'tee-os-path': 'tee.elf',
6265 }
6266 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6267 entry_args=entry_args)[0]
6268 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6269
6270 def checkFitTee(self, dts, tee_fname):
6271 """Check that a tee-os entry works and returns data
6272
6273 Args:
6274 dts (str): Device tree filename to use
6275 tee_fname (str): filename containing tee-os
6276
6277 Returns:
6278 bytes: Image contents
6279 """
6280 if not elf.ELF_TOOLS:
6281 self.skipTest('Python elftools not available')
6282 entry_args = {
6283 'of-list': 'test-fdt1 test-fdt2',
6284 'default-dt': 'test-fdt2',
6285 'tee-os-path': tee_fname,
6286 }
6287 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6288 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6289 extra_indirs=[test_subdir])[0]
6290 return data
6291
6292 def testFitTeeOsOptionalFit(self):
6293 """Test an image with a FIT with an optional OP-TEE binary"""
6294 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6295
6296 # There should be only one node, holding the data set up in SetUpClass()
6297 # for tee.bin
6298 dtb = fdt.Fdt.FromData(data)
6299 dtb.Scan()
6300 node = dtb.GetNode('/images/tee-1')
6301 self.assertEqual(TEE_ADDR,
6302 fdt_util.fdt32_to_cpu(node.props['load'].value))
6303 self.assertEqual(TEE_ADDR,
6304 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6305 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6306
6307 def testFitTeeOsOptionalFitBad(self):
6308 """Test an image with a FIT with an optional OP-TEE binary"""
6309 with self.assertRaises(ValueError) as exc:
6310 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6311 self.assertIn(
6312 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6313 str(exc.exception))
6314
6315 def testFitTeeOsBad(self):
6316 """Test an OP-TEE binary with wrong formats"""
6317 self.make_tee_bin('tee.bad1', 123)
6318 with self.assertRaises(ValueError) as exc:
6319 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6320 self.assertIn(
6321 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6322 str(exc.exception))
6323
6324 self.make_tee_bin('tee.bad2', 0, b'extra data')
6325 with self.assertRaises(ValueError) as exc:
6326 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6327 self.assertIn(
6328 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6329 str(exc.exception))
6330
Simon Glass63328f12023-01-07 14:07:15 -07006331 def testExtblobOptional(self):
6332 """Test an image with an external blob that is optional"""
6333 with test_util.capture_sys_output() as (stdout, stderr):
6334 data = self._DoReadFile('266_blob_ext_opt.dts')
6335 self.assertEqual(REFCODE_DATA, data)
6336 err = stderr.getvalue()
6337 self.assertRegex(
6338 err,
6339 "Image '.*' is missing external blobs but is still functional: missing")
6340
Simon Glass7447a9d2023-01-11 16:10:12 -07006341 def testSectionInner(self):
6342 """Test an inner section with a size"""
6343 data = self._DoReadFile('267_section_inner.dts')
6344 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6345 self.assertEqual(expected, data)
6346
Simon Glassa4948b22023-01-11 16:10:14 -07006347 def testNull(self):
6348 """Test an image with a null entry"""
6349 data = self._DoReadFile('268_null.dts')
6350 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6351
Simon Glassf1ee03b2023-01-11 16:10:16 -07006352 def testOverlap(self):
6353 """Test an image with a overlapping entry"""
6354 data = self._DoReadFile('269_overlap.dts')
6355 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6356
6357 image = control.images['image']
6358 entries = image.GetEntries()
6359
6360 self.assertIn('inset', entries)
6361 inset = entries['inset']
6362 self.assertEqual(1, inset.offset);
6363 self.assertEqual(1, inset.image_pos);
6364 self.assertEqual(2, inset.size);
6365
6366 def testOverlapNull(self):
6367 """Test an image with a null overlap"""
6368 data = self._DoReadFile('270_overlap_null.dts')
6369 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6370
6371 # Check the FMAP
6372 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6373 self.assertEqual(4, fhdr.nareas)
6374 fiter = iter(fentries)
6375
6376 fentry = next(fiter)
6377 self.assertEqual(b'SECTION', fentry.name)
6378 self.assertEqual(0, fentry.offset)
6379 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6380 self.assertEqual(0, fentry.flags)
6381
6382 fentry = next(fiter)
6383 self.assertEqual(b'U_BOOT', fentry.name)
6384 self.assertEqual(0, fentry.offset)
6385 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6386 self.assertEqual(0, fentry.flags)
6387
6388 # Make sure that the NULL entry appears in the FMAP
6389 fentry = next(fiter)
6390 self.assertEqual(b'NULL', fentry.name)
6391 self.assertEqual(1, fentry.offset)
6392 self.assertEqual(2, fentry.size)
6393 self.assertEqual(0, fentry.flags)
6394
6395 fentry = next(fiter)
6396 self.assertEqual(b'FMAP', fentry.name)
6397 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6398
6399 def testOverlapBad(self):
6400 """Test an image with a bad overlapping entry"""
6401 with self.assertRaises(ValueError) as exc:
6402 self._DoReadFile('271_overlap_bad.dts')
6403 self.assertIn(
6404 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6405 str(exc.exception))
6406
6407 def testOverlapNoOffset(self):
6408 """Test an image with a bad overlapping entry"""
6409 with self.assertRaises(ValueError) as exc:
6410 self._DoReadFile('272_overlap_no_size.dts')
6411 self.assertIn(
6412 "Node '/binman/inset': 'fill' entry is missing properties: size",
6413 str(exc.exception))
6414
Simon Glasse0035c92023-01-11 16:10:17 -07006415 def testBlobSymbol(self):
6416 """Test a blob with symbols read from an ELF file"""
6417 elf_fname = self.ElfTestFile('blob_syms')
6418 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6419 TestFunctional._MakeInputFile('blob_syms.bin',
6420 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6421
6422 data = self._DoReadFile('273_blob_symbol.dts')
6423
6424 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6425 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6426 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6427 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6428 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6429
6430 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6431 expected = sym_values
6432 self.assertEqual(expected, data[:len(expected)])
6433
Simon Glass49e9c002023-01-11 16:10:19 -07006434 def testOffsetFromElf(self):
6435 """Test a blob with symbols read from an ELF file"""
6436 elf_fname = self.ElfTestFile('blob_syms')
6437 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6438 TestFunctional._MakeInputFile('blob_syms.bin',
6439 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6440
6441 data = self._DoReadFile('274_offset_from_elf.dts')
6442
6443 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6444 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6445
6446 image = control.images['image']
6447 entries = image.GetEntries()
6448
6449 self.assertIn('inset', entries)
6450 inset = entries['inset']
6451
6452 self.assertEqual(base + 4, inset.offset);
6453 self.assertEqual(base + 4, inset.image_pos);
6454 self.assertEqual(4, inset.size);
6455
6456 self.assertIn('inset2', entries)
6457 inset = entries['inset2']
6458 self.assertEqual(base + 8, inset.offset);
6459 self.assertEqual(base + 8, inset.image_pos);
6460 self.assertEqual(4, inset.size);
6461
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006462 def testFitAlign(self):
6463 """Test an image with an FIT with aligned external data"""
6464 data = self._DoReadFile('275_fit_align.dts')
6465 self.assertEqual(4096, len(data))
6466
6467 dtb = fdt.Fdt.FromData(data)
6468 dtb.Scan()
6469
6470 props = self._GetPropTree(dtb, ['data-position'])
6471 expected = {
6472 'u-boot:data-position': 1024,
6473 'fdt-1:data-position': 2048,
6474 'fdt-2:data-position': 3072,
6475 }
6476 self.assertEqual(expected, props)
6477
Jonas Karlman490f73c2023-01-21 19:02:12 +00006478 def testFitFirmwareLoadables(self):
6479 """Test an image with an FIT that use fit,firmware"""
6480 if not elf.ELF_TOOLS:
6481 self.skipTest('Python elftools not available')
6482 entry_args = {
6483 'of-list': 'test-fdt1',
6484 'default-dt': 'test-fdt1',
6485 'atf-bl31-path': 'bl31.elf',
6486 'tee-os-path': 'missing.bin',
6487 }
6488 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006489 with test_util.capture_sys_output() as (stdout, stderr):
6490 data = self._DoReadFileDtb(
6491 '276_fit_firmware_loadables.dts',
6492 entry_args=entry_args,
6493 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006494
6495 dtb = fdt.Fdt.FromData(data)
6496 dtb.Scan()
6497
6498 node = dtb.GetNode('/configurations/conf-uboot-1')
6499 self.assertEqual('u-boot', node.props['firmware'].value)
6500 self.assertEqual(['atf-1', 'atf-2'],
6501 fdt_util.GetStringList(node, 'loadables'))
6502
6503 node = dtb.GetNode('/configurations/conf-atf-1')
6504 self.assertEqual('atf-1', node.props['firmware'].value)
6505 self.assertEqual(['u-boot', 'atf-2'],
6506 fdt_util.GetStringList(node, 'loadables'))
6507
6508 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6509 self.assertEqual('u-boot', node.props['firmware'].value)
6510 self.assertEqual(['atf-1', 'atf-2'],
6511 fdt_util.GetStringList(node, 'loadables'))
6512
6513 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6514 self.assertEqual('atf-1', node.props['firmware'].value)
6515 self.assertEqual(['u-boot', 'atf-2'],
6516 fdt_util.GetStringList(node, 'loadables'))
6517
6518 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6519 self.assertEqual('atf-1', node.props['firmware'].value)
6520 self.assertEqual(['u-boot', 'atf-2'],
6521 fdt_util.GetStringList(node, 'loadables'))
6522
Simon Glass9a1c7262023-02-22 12:14:49 -07006523 def testTooldir(self):
6524 """Test that we can specify the tooldir"""
6525 with test_util.capture_sys_output() as (stdout, stderr):
6526 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6527 'tool', '-l'))
6528 self.assertEqual('fred', bintool.Bintool.tooldir)
6529
6530 # Check that the toolpath is updated correctly
6531 self.assertEqual(['fred'], tools.tool_search_paths)
6532
6533 # Try with a few toolpaths; the tooldir should be at the end
6534 with test_util.capture_sys_output() as (stdout, stderr):
6535 self.assertEqual(0, self._DoBinman(
6536 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6537 'tool', '-l'))
6538 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6539
Simon Glass49b77e82023-03-02 17:02:44 -07006540 def testReplaceSectionEntry(self):
6541 """Test replacing an entry in a section"""
6542 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6543 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6544 expect_data, dts='241_replace_section_simple.dts')
6545 self.assertEqual(expect_data, entry_data)
6546
6547 entries = image.GetEntries()
6548 self.assertIn('section', entries)
6549 section = entries['section']
6550
6551 sect_entries = section.GetEntries()
6552 self.assertIn('blob', sect_entries)
6553 entry = sect_entries['blob']
6554 self.assertEqual(len(expect_data), entry.size)
6555
6556 fname = tools.get_output_filename('image-updated.bin')
6557 data = tools.read_file(fname)
6558
6559 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6560 self.assertEqual(expect_data, new_blob_data)
6561
6562 self.assertEqual(U_BOOT_DATA,
6563 data[entry.image_pos + len(expect_data):]
6564 [:len(U_BOOT_DATA)])
6565
6566 def testReplaceSectionDeep(self):
6567 """Test replacing an entry in two levels of sections"""
6568 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6569 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6570 'section/section/blob', expect_data,
6571 dts='278_replace_section_deep.dts')
6572 self.assertEqual(expect_data, entry_data)
6573
6574 entries = image.GetEntries()
6575 self.assertIn('section', entries)
6576 section = entries['section']
6577
6578 subentries = section.GetEntries()
6579 self.assertIn('section', subentries)
6580 section = subentries['section']
6581
6582 sect_entries = section.GetEntries()
6583 self.assertIn('blob', sect_entries)
6584 entry = sect_entries['blob']
6585 self.assertEqual(len(expect_data), entry.size)
6586
6587 fname = tools.get_output_filename('image-updated.bin')
6588 data = tools.read_file(fname)
6589
6590 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6591 self.assertEqual(expect_data, new_blob_data)
6592
6593 self.assertEqual(U_BOOT_DATA,
6594 data[entry.image_pos + len(expect_data):]
6595 [:len(U_BOOT_DATA)])
6596
6597 def testReplaceFitSibling(self):
6598 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006599 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006600 fname = TestFunctional._MakeInputFile('once', b'available once')
6601 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6602 os.remove(fname)
6603
6604 try:
6605 tmpdir, updated_fname = self._SetupImageInTmpdir()
6606
6607 fname = os.path.join(tmpdir, 'update-blob')
6608 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6609 tools.write_file(fname, expected)
6610
6611 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6612 data = tools.read_file(updated_fname)
6613 start = len(U_BOOT_DTB_DATA)
6614 self.assertEqual(expected, data[start:start + len(expected)])
6615 map_fname = os.path.join(tmpdir, 'image-updated.map')
6616 self.assertFalse(os.path.exists(map_fname))
6617 finally:
6618 shutil.rmtree(tmpdir)
6619
Simon Glassc3fe97f2023-03-02 17:02:45 -07006620 def testX509Cert(self):
6621 """Test creating an X509 certificate"""
6622 keyfile = self.TestFile('key.key')
6623 entry_args = {
6624 'keyfile': keyfile,
6625 }
6626 data = self._DoReadFileDtb('279_x509_cert.dts',
6627 entry_args=entry_args)[0]
6628 cert = data[:-4]
6629 self.assertEqual(U_BOOT_DATA, data[-4:])
6630
6631 # TODO: verify the signature
6632
6633 def testX509CertMissing(self):
6634 """Test that binman still produces an image if openssl is missing"""
6635 keyfile = self.TestFile('key.key')
6636 entry_args = {
6637 'keyfile': 'keyfile',
6638 }
6639 with test_util.capture_sys_output() as (_, stderr):
6640 self._DoTestFile('279_x509_cert.dts',
6641 force_missing_bintools='openssl',
6642 entry_args=entry_args)
6643 err = stderr.getvalue()
6644 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6645
Jonas Karlman35305492023-02-25 19:01:33 +00006646 def testPackRockchipTpl(self):
6647 """Test that an image with a Rockchip TPL binary can be created"""
6648 data = self._DoReadFile('277_rockchip_tpl.dts')
6649 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6650
Jonas Karlman1016ec72023-02-25 19:01:35 +00006651 def testMkimageMissingBlobMultiple(self):
6652 """Test missing blob with mkimage entry and multiple-data-files"""
6653 with test_util.capture_sys_output() as (stdout, stderr):
6654 self._DoTestFile('278_mkimage_missing_multiple.dts', allow_missing=True)
6655 err = stderr.getvalue()
6656 self.assertIn("is missing external blobs and is non-functional", err)
6657
6658 with self.assertRaises(ValueError) as e:
6659 self._DoTestFile('278_mkimage_missing_multiple.dts', allow_missing=False)
6660 self.assertIn("not found in input path", str(e.exception))
6661
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006662 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6663 """Prepare sign environment
6664
6665 Create private and public keys, add pubkey into dtb.
6666
6667 Returns:
6668 Tuple:
6669 FIT container
6670 Image name
6671 Private key
6672 DTB
6673 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006674 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006675 data = self._DoReadFileRealDtb(dts)
6676 updated_fname = tools.get_output_filename('image-updated.bin')
6677 tools.write_file(updated_fname, data)
6678 dtb = tools.get_output_filename('source.dtb')
6679 private_key = tools.get_output_filename('test_key.key')
6680 public_key = tools.get_output_filename('test_key.crt')
6681 fit = tools.get_output_filename('fit.fit')
6682 key_dir = tools.get_output_dir()
6683
6684 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6685 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6686 private_key, '-out', public_key)
6687 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6688 '-n', 'test_key', '-r', 'conf', dtb)
6689
6690 return fit, updated_fname, private_key, dtb
6691
6692 def testSignSimple(self):
6693 """Test that a FIT container can be signed in image"""
6694 is_signed = False
6695 fit, fname, private_key, dtb = self._PrepareSignEnv()
6696
6697 # do sign with private key
6698 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6699 ['fit'])
6700 is_signed = self._CheckSign(fit, dtb)
6701
6702 self.assertEqual(is_signed, True)
6703
6704 def testSignExactFIT(self):
6705 """Test that a FIT container can be signed and replaced in image"""
6706 is_signed = False
6707 fit, fname, private_key, dtb = self._PrepareSignEnv()
6708
6709 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6710 args = []
6711 if self.toolpath:
6712 for path in self.toolpath:
6713 args += ['--toolpath', path]
6714
6715 # do sign with private key
6716 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6717 'sha256,rsa4096', '-f', fit, 'fit')
6718 is_signed = self._CheckSign(fit, dtb)
6719
6720 self.assertEqual(is_signed, True)
6721
6722 def testSignNonFit(self):
6723 """Test a non-FIT entry cannot be signed"""
6724 is_signed = False
6725 fit, fname, private_key, _ = self._PrepareSignEnv(
6726 '281_sign_non_fit.dts')
6727
6728 # do sign with private key
6729 with self.assertRaises(ValueError) as e:
6730 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6731 'sha256,rsa4096', '-f', fit, 'u-boot')
6732 self.assertIn(
6733 "Node '/u-boot': Updating signatures is not supported with this entry type",
6734 str(e.exception))
6735
6736 def testSignMissingMkimage(self):
6737 """Test that FIT signing handles a missing mkimage tool"""
6738 fit, fname, private_key, _ = self._PrepareSignEnv()
6739
6740 # try to sign with a missing mkimage tool
6741 bintool.Bintool.set_missing_list(['mkimage'])
6742 with self.assertRaises(ValueError) as e:
6743 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6744 ['fit'])
6745 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6746
Simon Glass4abf7842023-07-18 07:23:54 -06006747 def testSymbolNoWrite(self):
6748 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006749 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006750 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6751 no_write_symbols=True)
6752
6753 def testSymbolNoWriteExpanded(self):
6754 """Test disabling of symbol writing in expanded entries"""
6755 entry_args = {
6756 'spl-dtb': '1',
6757 }
6758 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6759 U_BOOT_SPL_DTB_DATA, 0x38,
6760 entry_args=entry_args, use_expanded=True,
6761 no_write_symbols=True)
6762
Marek Vasutf7413f02023-07-18 07:23:58 -06006763 def testMkimageSpecial(self):
6764 """Test mkimage ignores special hash-1 node"""
6765 data = self._DoReadFile('283_mkimage_special.dts')
6766
6767 # Just check that the data appears in the file somewhere
6768 self.assertIn(U_BOOT_DATA, data)
6769
Simon Glass2d94c422023-07-18 07:23:59 -06006770 def testFitFdtList(self):
6771 """Test an image with an FIT with the fit,fdt-list-val option"""
6772 entry_args = {
6773 'default-dt': 'test-fdt2',
6774 }
6775 data = self._DoReadFileDtb(
6776 '284_fit_fdt_list.dts',
6777 entry_args=entry_args,
6778 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6779 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6780 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6781
Simon Glass83b8bfe2023-07-18 07:24:01 -06006782 def testSplEmptyBss(self):
6783 """Test an expanded SPL with a zero-size BSS"""
6784 # ELF file with a '__bss_size' symbol
6785 self._SetupSplElf(src_fname='bss_data_zero')
6786
6787 entry_args = {
6788 'spl-bss-pad': 'y',
6789 'spl-dtb': 'y',
6790 }
6791 data = self._DoReadFileDtb('285_spl_expand.dts',
6792 use_expanded=True, entry_args=entry_args)[0]
6793
Simon Glassfc792842023-07-18 07:24:04 -06006794 def testTemplate(self):
6795 """Test using a template"""
6796 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6797 data = self._DoReadFile('286_template.dts')
6798 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6799 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6800 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6801
Simon Glass9909c112023-07-18 07:24:05 -06006802 def testTemplateBlobMulti(self):
6803 """Test using a template with 'multiple-images' enabled"""
6804 TestFunctional._MakeInputFile('my-blob.bin', b'blob')
6805 TestFunctional._MakeInputFile('my-blob2.bin', b'other')
6806 retcode = self._DoTestFile('287_template_multi.dts')
6807
6808 self.assertEqual(0, retcode)
6809 image = control.images['image']
6810 image_fname = tools.get_output_filename('my-image.bin')
6811 data = tools.read_file(image_fname)
6812 self.assertEqual(b'blob@@@@other', data)
6813
Simon Glass5dc511b2023-07-18 07:24:06 -06006814 def testTemplateFit(self):
6815 """Test using a template in a FIT"""
6816 fit_data = self._DoReadFile('288_template_fit.dts')
6817 fname = os.path.join(self._indir, 'fit_data.fit')
6818 tools.write_file(fname, fit_data)
6819 out = tools.run('dumpimage', '-l', fname)
6820
Simon Glassaa6e0552023-07-18 07:24:07 -06006821 def testTemplateSection(self):
6822 """Test using a template in a section (not at top level)"""
6823 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6824 data = self._DoReadFile('289_template_section.dts')
6825 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6826 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6827 self.assertEqual(U_BOOT_IMG_DATA + first + second + first, data)
6828
Simon Glassf53a7bc2023-07-18 07:24:08 -06006829 def testMkimageSymbols(self):
6830 """Test using mkimage to build an image with symbols in it"""
6831 self._SetupSplElf('u_boot_binman_syms')
6832 data = self._DoReadFile('290_mkimage_sym.dts')
6833
6834 image = control.images['image']
6835 entries = image.GetEntries()
6836 self.assertIn('u-boot', entries)
6837 u_boot = entries['u-boot']
6838
6839 mkim = entries['mkimage']
6840 mkim_entries = mkim.GetEntries()
6841 self.assertIn('u-boot-spl', mkim_entries)
6842 spl = mkim_entries['u-boot-spl']
6843 self.assertIn('u-boot-spl2', mkim_entries)
6844 spl2 = mkim_entries['u-boot-spl2']
6845
6846 # skip the mkimage header and the area sizes
6847 mk_data = data[mkim.offset + 0x40:]
6848 size, term = struct.unpack('>LL', mk_data[:8])
6849
6850 # There should be only one image, so check that the zero terminator is
6851 # present
6852 self.assertEqual(0, term)
6853
6854 content = mk_data[8:8 + size]
6855
6856 # The image should contain the symbols from u_boot_binman_syms.c
6857 # Note that image_pos is adjusted by the base address of the image,
6858 # which is 0x10 in our test image
6859 spl_data = content[:0x18]
6860 content = content[0x1b:]
6861
6862 # After the header is a table of offsets for each image. There should
6863 # only be one image, then a 0 terminator, so figure out the real start
6864 # of the image data
6865 base = 0x40 + 8
6866
6867 # Check symbols in both u-boot-spl and u-boot-spl2
6868 for i in range(2):
6869 vals = struct.unpack('<LLQLL', spl_data)
6870
6871 # The image should contain the symbols from u_boot_binman_syms.c
6872 # Note that image_pos is adjusted by the base address of the image,
6873 # which is 0x10 in our 'u_boot_binman_syms' test image
6874 self.assertEqual(elf.BINMAN_SYM_MAGIC_VALUE, vals[0])
6875 self.assertEqual(base, vals[1])
6876 self.assertEqual(spl2.offset, vals[2])
6877 # figure out the internal positions of its components
6878 self.assertEqual(0x10 + u_boot.image_pos, vals[3])
6879
6880 # Check that spl and spl2 are actually at the indicated positions
6881 self.assertEqual(
6882 elf.BINMAN_SYM_MAGIC_VALUE,
6883 struct.unpack('<I', data[spl.image_pos:spl.image_pos + 4])[0])
6884 self.assertEqual(
6885 elf.BINMAN_SYM_MAGIC_VALUE,
6886 struct.unpack('<I', data[spl2.image_pos:spl2.image_pos + 4])[0])
6887
6888 self.assertEqual(len(U_BOOT_DATA), vals[4])
6889
6890 # Move to next
6891 spl_data = content[:0x18]
6892
Neha Malcom Francis3b788942023-07-22 00:14:24 +05306893 def testTIBoardConfig(self):
6894 """Test that a schema validated board config file can be generated"""
6895 data = self._DoReadFile('277_ti_board_cfg.dts')
6896 self.assertEqual(TI_BOARD_CONFIG_DATA, data)
6897
6898 def testTIBoardConfigCombined(self):
6899 """Test that a schema validated combined board config file can be generated"""
6900 data = self._DoReadFile('278_ti_board_cfg_combined.dts')
6901 configlen_noheader = TI_BOARD_CONFIG_DATA * 4
6902 self.assertGreater(data, configlen_noheader)
6903
6904 def testTIBoardConfigNoDataType(self):
6905 """Test that error is thrown when data type is not supported"""
6906 with self.assertRaises(ValueError) as e:
6907 data = self._DoReadFile('279_ti_board_cfg_no_type.dts')
6908 self.assertIn("Schema validation error", str(e.exception))
Simon Glassde244162023-01-07 14:07:08 -07006909
Neha Malcom Francis5f5f0a62023-07-22 00:14:25 +05306910 def testPackTiSecure(self):
6911 """Test that an image with a TI secured binary can be created"""
6912 keyfile = self.TestFile('key.key')
6913 entry_args = {
6914 'keyfile': keyfile,
6915 }
6916 data = self._DoReadFileDtb('279_ti_secure.dts',
6917 entry_args=entry_args)[0]
6918 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
6919
6920 def testPackTiSecureMissingTool(self):
6921 """Test that an image with a TI secured binary (non-functional) can be created
6922 when openssl is missing"""
6923 keyfile = self.TestFile('key.key')
6924 entry_args = {
6925 'keyfile': keyfile,
6926 }
6927 with test_util.capture_sys_output() as (_, stderr):
6928 self._DoTestFile('279_ti_secure.dts',
6929 force_missing_bintools='openssl',
6930 entry_args=entry_args)
6931 err = stderr.getvalue()
6932 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6933
6934 def testPackTiSecureROM(self):
6935 """Test that a ROM image with a TI secured binary can be created"""
6936 keyfile = self.TestFile('key.key')
6937 entry_args = {
6938 'keyfile': keyfile,
6939 }
6940 data = self._DoReadFileDtb('280_ti_secure_rom.dts',
6941 entry_args=entry_args)[0]
6942 data_a = self._DoReadFileDtb('288_ti_secure_rom_a.dts',
6943 entry_args=entry_args)[0]
6944 data_b = self._DoReadFileDtb('289_ti_secure_rom_b.dts',
6945 entry_args=entry_args)[0]
6946 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
6947 self.assertGreater(len(data_a), len(TI_UNSECURE_DATA))
6948 self.assertGreater(len(data_b), len(TI_UNSECURE_DATA))
6949
6950 def testPackTiSecureROMCombined(self):
6951 """Test that a ROM image with a TI secured binary can be created"""
6952 keyfile = self.TestFile('key.key')
6953 entry_args = {
6954 'keyfile': keyfile,
6955 }
6956 data = self._DoReadFileDtb('281_ti_secure_rom_combined.dts',
6957 entry_args=entry_args)[0]
6958 self.assertGreater(len(data), len(TI_UNSECURE_DATA))
6959
Simon Glassac599912017-11-12 21:52:22 -07006960if __name__ == "__main__":
6961 unittest.main()