blob: fc5d8a839e6b2608e3aebe544c8edd0ce3769344 [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')
Simon Glassa435cd12020-09-01 05:13:59 -0600100
101# Subdirectory of the input dir to use to put test FDTs
102TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600103
Simon Glass2c6adba2019-07-20 12:23:47 -0600104# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600105EXTRACT_DTB_SIZE = 0x3c9
106
Simon Glass2c6adba2019-07-20 12:23:47 -0600107# Properties expected to be in the device tree when update_dtb is used
108BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
109
Simon Glassfb30e292019-07-20 12:23:51 -0600110# Extra properties expected to be in the device tree when allow-repack is used
111REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
112
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200113# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200114COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700115
Simon Glassad5cfe12023-01-07 14:07:14 -0700116TEE_ADDR = 0x5678
117
Simon Glass57454f42016-11-25 20:15:52 -0700118class TestFunctional(unittest.TestCase):
119 """Functional tests for binman
120
121 Most of these use a sample .dts file to build an image and then check
122 that it looks correct. The sample files are in the test/ subdirectory
123 and are numbered.
124
125 For each entry type a very small test file is created using fixed
126 string contents. This makes it easy to test that things look right, and
127 debug problems.
128
129 In some cases a 'real' file must be used - these are also supplied in
130 the test/ diurectory.
131 """
132 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600133 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700134 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600135 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700136
Simon Glass57454f42016-11-25 20:15:52 -0700137 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600138 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
139 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700140
141 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600142 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700143
144 # Create some test files
145 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
146 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
147 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600148 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700149 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700150 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700151 TestFunctional._MakeInputFile('me.bin', ME_DATA)
152 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600153 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600154
Jagdish Gediya311d4842018-09-03 21:35:08 +0530155 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600156
Simon Glassabab18c2019-08-24 07:22:49 -0600157 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
158 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700159 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600160 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600161 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600162
163 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
164 X86_RESET16_DATA)
165 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
166 X86_RESET16_SPL_DATA)
167 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
168 X86_RESET16_TPL_DATA)
169
Simon Glass57454f42016-11-25 20:15:52 -0700170 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700171 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
172 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600173 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
174 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700175 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
176 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700177 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
178 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700179 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700180 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600181 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600182 TestFunctional._MakeInputDir('devkeys')
183 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600184 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600185 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600186 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600187 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700188
Simon Glassf6290892019-08-24 07:22:53 -0600189 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
190 elf_test.BuildElfTestFiles(cls._elf_testdir)
191
Simon Glass72232452016-11-25 20:15:53 -0700192 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600193 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700194 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700195
196 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600197 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700198
Simon Glass862f8e22019-08-24 07:22:43 -0600199 shutil.copytree(cls.TestFile('files'),
200 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600201
Simon Glass7ba33592018-09-14 04:57:26 -0600202 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600203 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600204 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200205 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700206 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800207 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500208 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Jonas Karlman35305492023-02-25 19:01:33 +0000209 TestFunctional._MakeInputFile('rockchip-tpl.bin', ROCKCHIP_TPL_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600210
Simon Glassa435cd12020-09-01 05:13:59 -0600211 # Add a few .dtb files for testing
212 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
213 TEST_FDT1_DATA)
214 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
215 TEST_FDT2_DATA)
216
Simon Glassa0729502020-09-06 10:35:33 -0600217 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
218
Simon Glass5f423422022-03-05 20:19:12 -0700219 # ELF file with two sections in different parts of memory, used for both
220 # ATF and OP_TEE
221 TestFunctional._MakeInputFile('bl31.elf',
222 tools.read_file(cls.ElfTestFile('elf_sections')))
223 TestFunctional._MakeInputFile('tee.elf',
224 tools.read_file(cls.ElfTestFile('elf_sections')))
225
Simon Glassad5cfe12023-01-07 14:07:14 -0700226 # Newer OP_TEE file in v1 binary format
227 cls.make_tee_bin('tee.bin')
228
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200229 cls.comp_bintools = {}
230 for name in COMP_BINTOOLS:
231 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600232
Simon Glass57454f42016-11-25 20:15:52 -0700233 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600234 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700235 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600236 if cls.preserve_indir:
237 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600238 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600239 if cls._indir:
240 shutil.rmtree(cls._indir)
241 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700242
Simon Glass1c420c92019-07-08 13:18:49 -0600243 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600244 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600245 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600246 """Accept arguments controlling test execution
247
248 Args:
249 preserve_indir: Preserve the shared input directory used by all
250 tests in this class.
251 preserve_outdir: Preserve the output directories used by tests. Each
252 test has its own, so this is normally only useful when running a
253 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600254 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600255 """
256 cls.preserve_indir = preserve_indir
257 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600258 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600259 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600260
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200261 def _CheckBintool(self, bintool):
262 if not bintool.is_present():
263 self.skipTest('%s not available' % bintool.name)
264
Simon Glass1de34482019-07-08 13:18:53 -0600265 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200266 bintool = self.comp_bintools['lz4']
267 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600268
Simon Glassee9d10d2019-07-20 12:24:09 -0600269 def _CleanupOutputDir(self):
270 """Remove the temporary output directory"""
271 if self.preserve_outdirs:
272 print('Preserving output dir: %s' % tools.outdir)
273 else:
Simon Glass80025522022-01-29 14:14:04 -0700274 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600275
Simon Glass57454f42016-11-25 20:15:52 -0700276 def setUp(self):
277 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700278 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700279 command.test_result = None
280
281 def tearDown(self):
282 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600283 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700284
Simon Glassb3d6fc72019-07-20 12:24:10 -0600285 def _SetupImageInTmpdir(self):
286 """Set up the output image in a new temporary directory
287
288 This is used when an image has been generated in the output directory,
289 but we want to run binman again. This will create a new output
290 directory and fail to delete the original one.
291
292 This creates a new temporary directory, copies the image to it (with a
293 new name) and removes the old output directory.
294
295 Returns:
296 Tuple:
297 Temporary directory to use
298 New image filename
299 """
Simon Glass80025522022-01-29 14:14:04 -0700300 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600301 tmpdir = tempfile.mkdtemp(prefix='binman.')
302 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700303 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600304 self._CleanupOutputDir()
305 return tmpdir, updated_fname
306
Simon Glass8425a1f2018-07-17 13:25:48 -0600307 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600308 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600309 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
310 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
311 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700312 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600313
Simon Glass57454f42016-11-25 20:15:52 -0700314 def _RunBinman(self, *args, **kwargs):
315 """Run binman using the command line
316
317 Args:
318 Arguments to pass, as a list of strings
319 kwargs: Arguments to pass to Command.RunPipe()
320 """
Simon Glass840be732022-01-29 14:14:05 -0700321 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700322 capture=True, capture_stderr=True, raise_on_error=False)
323 if result.return_code and kwargs.get('raise_on_error', True):
324 raise Exception("Error running '%s': %s" % (' '.join(args),
325 result.stdout + result.stderr))
326 return result
327
Simon Glassf46732a2019-07-08 14:25:29 -0600328 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700329 """Run binman using directly (in the same process)
330
331 Args:
332 Arguments to pass, as a list of strings
333 Returns:
334 Return value (0 for success)
335 """
Simon Glassf46732a2019-07-08 14:25:29 -0600336 argv = list(argv)
337 args = cmdline.ParseArgs(argv)
338 args.pager = 'binman-invalid-pager'
339 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700340
341 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600342 # args.verbosity = tout.DEBUG
343 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700344
Simon Glass91710b32018-07-17 13:25:32 -0600345 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600346 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300347 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100348 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700349 test_section_timeout=False, update_fdt_in_elf=None,
Simon Glass6bce5dc2022-11-09 19:14:42 -0700350 force_missing_bintools='', ignore_missing=False):
Simon Glass57454f42016-11-25 20:15:52 -0700351 """Run binman with a given test file
352
353 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600354 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600355 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600356 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600357 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600358 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600359 entry_args: Dict of entry args to supply to binman
360 key: arg name
361 value: value of that arg
362 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600363 use_real_dtb: True to use the test file as the contents of
364 the u-boot-dtb entry. Normally this is not needed and the
365 test contents (the U_BOOT_DTB_DATA string) can be used.
366 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300367 use_expanded: True to use expanded entries where available, e.g.
368 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600369 verbosity: Verbosity level to use (0-3, None=don't set it)
370 allow_missing: Set the '--allow-missing' flag so that missing
371 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100372 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600373 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600374 threads: Number of threads to use (None for default, 0 for
375 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600376 test_section_timeout: True to force the first time to timeout, as
377 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600378 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass66152ce2022-01-09 20:14:09 -0700379 force_missing_tools (str): comma-separated list of bintools to
380 regard as missing
Simon Glass9a798402021-11-03 21:09:17 -0600381
382 Returns:
383 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700384 """
Simon Glassf46732a2019-07-08 14:25:29 -0600385 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700386 if debug:
387 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600388 if verbosity is not None:
389 args.append('-v%d' % verbosity)
390 elif self.verbosity:
391 args.append('-v%d' % self.verbosity)
392 if self.toolpath:
393 for path in self.toolpath:
394 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600395 if threads is not None:
396 args.append('-T%d' % threads)
397 if test_section_timeout:
398 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600399 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600400 if map:
401 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600402 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600403 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600404 if not use_real_dtb:
405 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300406 if not use_expanded:
407 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600408 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600409 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600410 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600411 if allow_missing:
412 args.append('-M')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700413 if ignore_missing:
414 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100415 if allow_fake_blobs:
416 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700417 if force_missing_bintools:
418 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600419 if update_fdt_in_elf:
420 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600421 if images:
422 for image in images:
423 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600424 if extra_indirs:
425 for indir in extra_indirs:
426 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700427 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700428
429 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700430 """Set up a new test device-tree file
431
432 The given file is compiled and set up as the device tree to be used
433 for ths test.
434
435 Args:
436 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600437 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700438
439 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600440 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700441 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600442 tmpdir = tempfile.mkdtemp(prefix='binmant.')
443 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600444 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700445 data = fd.read()
446 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600447 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600448 return data
Simon Glass57454f42016-11-25 20:15:52 -0700449
Simon Glass56d05412022-02-28 07:16:54 -0700450 def _GetDtbContentsForSpls(self, dtb_data, name):
451 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600452
453 For testing we don't actually have different versions of the DTB. With
454 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
455 we don't normally have any unwanted nodes.
456
457 We still want the DTBs for SPL and TPL to be different though, since
458 otherwise it is confusing to know which one we are looking at. So add
459 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600460
461 Args:
462 dtb_data: dtb data to modify (this should be a value devicetree)
463 name: Name of a new property to add
464
465 Returns:
466 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600467 """
468 dtb = fdt.Fdt.FromData(dtb_data)
469 dtb.Scan()
470 dtb.GetNode('/binman').AddZeroProp(name)
471 dtb.Sync(auto_resize=True)
472 dtb.Pack()
473 return dtb.GetContents()
474
Simon Glassed930672021-03-18 20:25:05 +1300475 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
476 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600477 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700478 """Run binman and return the resulting image
479
480 This runs binman with a given test file and then reads the resulting
481 output file. It is a shortcut function since most tests need to do
482 these steps.
483
484 Raises an assertion failure if binman returns a non-zero exit code.
485
486 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600487 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700488 use_real_dtb: True to use the test file as the contents of
489 the u-boot-dtb entry. Normally this is not needed and the
490 test contents (the U_BOOT_DTB_DATA string) can be used.
491 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300492 use_expanded: True to use expanded entries where available, e.g.
493 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600494 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600495 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600496 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600497 entry_args: Dict of entry args to supply to binman
498 key: arg name
499 value: value of that arg
500 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
501 function. If reset_dtbs is True, then the original test dtb
502 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600503 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600504 threads: Number of threads to use (None for default, 0 for
505 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700506
507 Returns:
508 Tuple:
509 Resulting image contents
510 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600511 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600512 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700513 """
Simon Glass72232452016-11-25 20:15:53 -0700514 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700515 # Use the compiled test file as the u-boot-dtb input
516 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700517 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600518
519 # For testing purposes, make a copy of the DT for SPL and TPL. Add
520 # a node indicating which it is, so aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700521 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600522 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
523 outfile = os.path.join(self._indir, dtb_fname)
524 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700525 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700526
527 try:
Simon Glass91710b32018-07-17 13:25:32 -0600528 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600529 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600530 use_expanded=use_expanded, extra_indirs=extra_indirs,
531 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700532 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700533 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700534
535 # Find the (only) image, read it and return its contents
536 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700537 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600538 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600539 if map:
Simon Glass80025522022-01-29 14:14:04 -0700540 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600541 with open(map_fname) as fd:
542 map_data = fd.read()
543 else:
544 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600545 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600546 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700547 finally:
548 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600549 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600550 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700551
Simon Glass5b4bce32019-07-08 14:25:26 -0600552 def _DoReadFileRealDtb(self, fname):
553 """Run binman with a real .dtb file and return the resulting data
554
555 Args:
556 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
557
558 Returns:
559 Resulting image contents
560 """
561 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
562
Simon Glass72232452016-11-25 20:15:53 -0700563 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600564 """Helper function which discards the device-tree binary
565
566 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600567 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600568 use_real_dtb: True to use the test file as the contents of
569 the u-boot-dtb entry. Normally this is not needed and the
570 test contents (the U_BOOT_DTB_DATA string) can be used.
571 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600572
573 Returns:
574 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600575 """
Simon Glass72232452016-11-25 20:15:53 -0700576 return self._DoReadFileDtb(fname, use_real_dtb)[0]
577
Simon Glass57454f42016-11-25 20:15:52 -0700578 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600579 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700580 """Create a new test input file, creating directories as needed
581
582 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600583 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700584 contents: File contents to write in to the file
585 Returns:
586 Full pathname of file created
587 """
Simon Glass862f8e22019-08-24 07:22:43 -0600588 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700589 dirname = os.path.dirname(pathname)
590 if dirname and not os.path.exists(dirname):
591 os.makedirs(dirname)
592 with open(pathname, 'wb') as fd:
593 fd.write(contents)
594 return pathname
595
596 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600597 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600598 """Create a new test input directory, creating directories as needed
599
600 Args:
601 dirname: Directory name to create
602
603 Returns:
604 Full pathname of directory created
605 """
Simon Glass862f8e22019-08-24 07:22:43 -0600606 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600607 if not os.path.exists(pathname):
608 os.makedirs(pathname)
609 return pathname
610
611 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600612 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600613 """Set up an ELF file with a '_dt_ucode_base_size' symbol
614
615 Args:
616 Filename of ELF file to use as SPL
617 """
Simon Glass93a806f2019-08-24 07:22:59 -0600618 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700619 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600620
621 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600622 def _SetupTplElf(cls, src_fname='bss_data'):
623 """Set up an ELF file with a '_dt_ucode_base_size' symbol
624
625 Args:
626 Filename of ELF file to use as TPL
627 """
628 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700629 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600630
631 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700632 def _SetupVplElf(cls, src_fname='bss_data'):
633 """Set up an ELF file with a '_dt_ucode_base_size' symbol
634
635 Args:
636 Filename of ELF file to use as VPL
637 """
638 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
639 tools.read_file(cls.ElfTestFile(src_fname)))
640
641 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600642 def _SetupDescriptor(cls):
643 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
644 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
645
646 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600647 def TestFile(cls, fname):
648 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700649
Simon Glassf6290892019-08-24 07:22:53 -0600650 @classmethod
651 def ElfTestFile(cls, fname):
652 return os.path.join(cls._elf_testdir, fname)
653
Simon Glassad5cfe12023-01-07 14:07:14 -0700654 @classmethod
655 def make_tee_bin(cls, fname, paged_sz=0, extra_data=b''):
656 init_sz, start_hi, start_lo, dummy = (len(U_BOOT_DATA), 0, TEE_ADDR, 0)
657 data = b'OPTE\x01xxx' + struct.pack('<5I', init_sz, start_hi, start_lo,
658 dummy, paged_sz) + U_BOOT_DATA
659 data += extra_data
660 TestFunctional._MakeInputFile(fname, data)
661
Simon Glass57454f42016-11-25 20:15:52 -0700662 def AssertInList(self, grep_list, target):
663 """Assert that at least one of a list of things is in a target
664
665 Args:
666 grep_list: List of strings to check
667 target: Target string
668 """
669 for grep in grep_list:
670 if grep in target:
671 return
Simon Glass848cdb52019-05-17 22:00:50 -0600672 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700673
674 def CheckNoGaps(self, entries):
675 """Check that all entries fit together without gaps
676
677 Args:
678 entries: List of entries to check
679 """
Simon Glasse8561af2018-08-01 15:22:37 -0600680 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700681 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600682 self.assertEqual(offset, entry.offset)
683 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700684
Simon Glass72232452016-11-25 20:15:53 -0700685 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600686 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700687
688 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600689 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700690
691 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600692 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700693 """
694 return struct.unpack('>L', dtb[4:8])[0]
695
Simon Glass0f621332019-07-08 14:25:27 -0600696 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600697 def AddNode(node, path):
698 if node.name != '/':
699 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600700 for prop in node.props.values():
701 if prop.name in prop_names:
702 prop_path = path + ':' + prop.name
703 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
704 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600705 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600706 AddNode(subnode, path)
707
708 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600709 AddNode(dtb.GetRoot(), '')
710 return tree
711
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +0000712 def _CheckSign(self, fit, key):
713 try:
714 tools.run('fit_check_sign', '-k', key, '-f', fit)
715 except:
716 self.fail('Expected signed FIT container')
717 return False
718 return True
719
Simon Glass57454f42016-11-25 20:15:52 -0700720 def testRun(self):
721 """Test a basic run with valid args"""
722 result = self._RunBinman('-h')
723
724 def testFullHelp(self):
725 """Test that the full help is displayed with -H"""
726 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300727 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500728 # Remove possible extraneous strings
729 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
730 gothelp = result.stdout.replace(extra, '')
731 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700732 self.assertEqual(0, len(result.stderr))
733 self.assertEqual(0, result.return_code)
734
735 def testFullHelpInternal(self):
736 """Test that the full help is displayed with -H"""
737 try:
738 command.test_result = command.CommandResult()
739 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300740 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700741 finally:
742 command.test_result = None
743
744 def testHelp(self):
745 """Test that the basic help is displayed with -h"""
746 result = self._RunBinman('-h')
747 self.assertTrue(len(result.stdout) > 200)
748 self.assertEqual(0, len(result.stderr))
749 self.assertEqual(0, result.return_code)
750
Simon Glass57454f42016-11-25 20:15:52 -0700751 def testBoard(self):
752 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600753 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700754 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300755 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700756 self.assertEqual(0, result)
757
758 def testNeedBoard(self):
759 """Test that we get an error when no board ius supplied"""
760 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600761 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700762 self.assertIn("Must provide a board to process (use -b <board>)",
763 str(e.exception))
764
765 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600766 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700767 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600768 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700769 # We get one error from libfdt, and a different one from fdtget.
770 self.AssertInList(["Couldn't open blob from 'missing_file'",
771 'No such file or directory'], str(e.exception))
772
773 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600774 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700775
776 Since this is a source file it should be compiled and the error
777 will come from the device-tree compiler (dtc).
778 """
779 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600780 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700781 self.assertIn("FATAL ERROR: Unable to parse input tree",
782 str(e.exception))
783
784 def testMissingNode(self):
785 """Test that a device tree without a 'binman' node generates an error"""
786 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600787 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700788 self.assertIn("does not have a 'binman' node", str(e.exception))
789
790 def testEmpty(self):
791 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600792 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700793 self.assertEqual(0, len(result.stderr))
794 self.assertEqual(0, result.return_code)
795
796 def testInvalidEntry(self):
797 """Test that an invalid entry is flagged"""
798 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600799 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600800 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700801 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
802 "'/binman/not-a-valid-type'", str(e.exception))
803
804 def testSimple(self):
805 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600806 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700807 self.assertEqual(U_BOOT_DATA, data)
808
Simon Glass075a45c2017-11-13 18:55:00 -0700809 def testSimpleDebug(self):
810 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600811 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700812
Simon Glass57454f42016-11-25 20:15:52 -0700813 def testDual(self):
814 """Test that we can handle creating two images
815
816 This also tests image padding.
817 """
Simon Glass511f6582018-10-01 12:22:30 -0600818 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700819 self.assertEqual(0, retcode)
820
821 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600822 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700823 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700824 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600825 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700826 data = fd.read()
827 self.assertEqual(U_BOOT_DATA, data)
828
829 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600830 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700831 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700832 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600833 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700834 data = fd.read()
835 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700836 self.assertEqual(tools.get_bytes(0, 3), data[:3])
837 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700838
839 def testBadAlign(self):
840 """Test that an invalid alignment value is detected"""
841 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600842 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700843 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
844 "of two", str(e.exception))
845
846 def testPackSimple(self):
847 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600848 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700849 self.assertEqual(0, retcode)
850 self.assertIn('image', control.images)
851 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600852 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700853 self.assertEqual(5, len(entries))
854
855 # First u-boot
856 self.assertIn('u-boot', entries)
857 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600858 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700859 self.assertEqual(len(U_BOOT_DATA), entry.size)
860
861 # Second u-boot, aligned to 16-byte boundary
862 self.assertIn('u-boot-align', entries)
863 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600864 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700865 self.assertEqual(len(U_BOOT_DATA), entry.size)
866
867 # Third u-boot, size 23 bytes
868 self.assertIn('u-boot-size', entries)
869 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600870 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700871 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
872 self.assertEqual(23, entry.size)
873
874 # Fourth u-boot, placed immediate after the above
875 self.assertIn('u-boot-next', entries)
876 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600877 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700878 self.assertEqual(len(U_BOOT_DATA), entry.size)
879
Simon Glasse8561af2018-08-01 15:22:37 -0600880 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700881 self.assertIn('u-boot-fixed', entries)
882 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600883 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700884 self.assertEqual(len(U_BOOT_DATA), entry.size)
885
Simon Glass39dd2152019-07-08 14:25:47 -0600886 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700887
888 def testPackExtra(self):
889 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600890 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
891 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700892
Simon Glass57454f42016-11-25 20:15:52 -0700893 self.assertIn('image', control.images)
894 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600895 entries = image.GetEntries()
Samuel Hollande2574022023-01-21 17:25:16 -0600896 self.assertEqual(6, len(entries))
Simon Glass57454f42016-11-25 20:15:52 -0700897
Samuel Hollande2574022023-01-21 17:25:16 -0600898 # First u-boot with padding before and after (included in minimum size)
Simon Glass57454f42016-11-25 20:15:52 -0700899 self.assertIn('u-boot', entries)
900 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600901 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700902 self.assertEqual(3, entry.pad_before)
903 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600904 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700905 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
906 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600907 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700908
909 # Second u-boot has an aligned size, but it has no effect
910 self.assertIn('u-boot-align-size-nop', entries)
911 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600912 self.assertEqual(pos, entry.offset)
913 self.assertEqual(len(U_BOOT_DATA), entry.size)
914 self.assertEqual(U_BOOT_DATA, entry.data)
915 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
916 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700917
918 # Third u-boot has an aligned size too
919 self.assertIn('u-boot-align-size', entries)
920 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600921 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700922 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600923 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700924 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600925 data[pos:pos + entry.size])
926 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700927
928 # Fourth u-boot has an aligned end
929 self.assertIn('u-boot-align-end', entries)
930 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600931 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700932 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600933 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700934 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600935 data[pos:pos + entry.size])
936 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700937
938 # Fifth u-boot immediately afterwards
939 self.assertIn('u-boot-align-both', entries)
940 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600941 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700942 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600943 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700944 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600945 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700946
Samuel Hollande2574022023-01-21 17:25:16 -0600947 # Sixth u-boot with both minimum size and aligned size
948 self.assertIn('u-boot-min-size', entries)
949 entry = entries['u-boot-min-size']
950 self.assertEqual(128, entry.offset)
951 self.assertEqual(32, entry.size)
952 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
953 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
954 data[pos:pos + entry.size])
955
Simon Glass57454f42016-11-25 20:15:52 -0700956 self.CheckNoGaps(entries)
Samuel Hollande2574022023-01-21 17:25:16 -0600957 self.assertEqual(160, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700958
Simon Glassafb9caa2020-10-26 17:40:10 -0600959 dtb = fdt.Fdt(out_dtb_fname)
960 dtb.Scan()
961 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
962 expected = {
963 'image-pos': 0,
964 'offset': 0,
Samuel Hollande2574022023-01-21 17:25:16 -0600965 'size': 160,
Simon Glassafb9caa2020-10-26 17:40:10 -0600966
967 'u-boot:image-pos': 0,
968 'u-boot:offset': 0,
969 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
970
971 'u-boot-align-size-nop:image-pos': 12,
972 'u-boot-align-size-nop:offset': 12,
973 'u-boot-align-size-nop:size': 4,
974
975 'u-boot-align-size:image-pos': 16,
976 'u-boot-align-size:offset': 16,
977 'u-boot-align-size:size': 32,
978
979 'u-boot-align-end:image-pos': 48,
980 'u-boot-align-end:offset': 48,
981 'u-boot-align-end:size': 16,
982
983 'u-boot-align-both:image-pos': 64,
984 'u-boot-align-both:offset': 64,
985 'u-boot-align-both:size': 64,
Samuel Hollande2574022023-01-21 17:25:16 -0600986
987 'u-boot-min-size:image-pos': 128,
988 'u-boot-min-size:offset': 128,
989 'u-boot-min-size:size': 32,
Simon Glassafb9caa2020-10-26 17:40:10 -0600990 }
991 self.assertEqual(expected, props)
992
Simon Glass57454f42016-11-25 20:15:52 -0700993 def testPackAlignPowerOf2(self):
994 """Test that invalid entry alignment is detected"""
995 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600996 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700997 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
998 "of two", str(e.exception))
999
1000 def testPackAlignSizePowerOf2(self):
1001 """Test that invalid entry size alignment is detected"""
1002 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001003 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001004 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
1005 "power of two", str(e.exception))
1006
1007 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001008 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -07001009 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001010 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001011 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001012 "align 0x4 (4)", str(e.exception))
1013
1014 def testPackInvalidSizeAlign(self):
1015 """Test that invalid entry size alignment is detected"""
1016 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001017 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001018 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
1019 "align-size 0x4 (4)", str(e.exception))
1020
1021 def testPackOverlap(self):
1022 """Test that overlapping regions are detected"""
1023 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001024 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001025 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001026 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1027 str(e.exception))
1028
1029 def testPackEntryOverflow(self):
1030 """Test that entries that overflow their size are detected"""
1031 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001032 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001033 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
1034 "but entry size is 0x3 (3)", str(e.exception))
1035
1036 def testPackImageOverflow(self):
1037 """Test that entries which overflow the image size are detected"""
1038 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001039 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001040 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001041 "size 0x3 (3)", str(e.exception))
1042
1043 def testPackImageSize(self):
1044 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001045 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001046 self.assertEqual(0, retcode)
1047 self.assertIn('image', control.images)
1048 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001049 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001050
1051 def testPackImageSizeAlign(self):
1052 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001053 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001054 self.assertEqual(0, retcode)
1055 self.assertIn('image', control.images)
1056 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001057 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001058
1059 def testPackInvalidImageAlign(self):
1060 """Test that invalid image alignment is detected"""
1061 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001062 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001063 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001064 "align-size 0x8 (8)", str(e.exception))
1065
Simon Glass2a0fa982022-02-11 13:23:21 -07001066 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001067 """Test that invalid image alignment is detected"""
1068 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001069 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001070 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001071 "two", str(e.exception))
1072
1073 def testImagePadByte(self):
1074 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001075 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001076 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001077 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001078 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001079
1080 def testImageName(self):
1081 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001082 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001083 self.assertEqual(0, retcode)
1084 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001085 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001086 self.assertTrue(os.path.exists(fname))
1087
1088 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001089 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001090 self.assertTrue(os.path.exists(fname))
1091
1092 def testBlobFilename(self):
1093 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001094 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001095 self.assertEqual(BLOB_DATA, data)
1096
1097 def testPackSorted(self):
1098 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001099 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001100 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001101 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1102 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001103
Simon Glasse8561af2018-08-01 15:22:37 -06001104 def testPackZeroOffset(self):
1105 """Test that an entry at offset 0 is not given a new offset"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001106 self._SetupSplElf()
Simon Glass57454f42016-11-25 20:15:52 -07001107 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001108 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001109 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001110 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1111 str(e.exception))
1112
1113 def testPackUbootDtb(self):
1114 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001115 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001116 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001117
1118 def testPackX86RomNoSize(self):
1119 """Test that the end-at-4gb property requires a size property"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001120 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001121 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001122 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001123 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001124 "using end-at-4gb", str(e.exception))
1125
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301126 def test4gbAndSkipAtStartTogether(self):
1127 """Test that the end-at-4gb and skip-at-size property can't be used
1128 together"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001129 self._SetupSplElf()
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301130 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001131 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001132 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301133 "'skip-at-start'", str(e.exception))
1134
Simon Glass72232452016-11-25 20:15:53 -07001135 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001136 """Test that the end-at-4gb property checks for offset boundaries"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001137 self._SetupSplElf()
Simon Glass72232452016-11-25 20:15:53 -07001138 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001139 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001140 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1141 "is outside the section '/binman' starting at "
1142 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001143 str(e.exception))
1144
1145 def testPackX86Rom(self):
1146 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001147 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001148 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001149 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1150 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001151
1152 def testPackX86RomMeNoDesc(self):
1153 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001154 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001155 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001156 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001157 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001158 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1159 str(e.exception))
1160 finally:
1161 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001162
1163 def testPackX86RomBadDesc(self):
1164 """Test that the Intel requires a descriptor entry"""
1165 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001166 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001167 self.assertIn("Node '/binman/intel-me': No offset set with "
1168 "offset-unset: should another entry provide this correct "
1169 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001170
1171 def testPackX86RomMe(self):
1172 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001173 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001174 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001175 if data[:0x1000] != expected_desc:
1176 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001177 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1178
1179 def testPackVga(self):
1180 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001181 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001182 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1183
1184 def testPackStart16(self):
1185 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001186 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001187 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1188
Jagdish Gediya311d4842018-09-03 21:35:08 +05301189 def testPackPowerpcMpc85xxBootpgResetvec(self):
1190 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1191 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001192 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301193 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1194
Simon Glass6ba679c2018-07-06 10:27:17 -06001195 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001196 """Handle running a test for insertion of microcode
1197
1198 Args:
1199 dts_fname: Name of test .dts file
1200 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001201 ucode_second: True if the microsecond entry is second instead of
1202 third
Simon Glass820af1d2018-07-06 10:27:16 -06001203
1204 Returns:
1205 Tuple:
1206 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001207 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001208 in the above (two 4-byte words)
1209 """
Simon Glass3d274232017-11-12 21:52:27 -07001210 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001211
1212 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001213 if ucode_second:
1214 ucode_content = data[len(nodtb_data):]
1215 ucode_pos = len(nodtb_data)
1216 dtb_with_ucode = ucode_content[16:]
1217 fdt_len = self.GetFdtLen(dtb_with_ucode)
1218 else:
1219 dtb_with_ucode = data[len(nodtb_data):]
1220 fdt_len = self.GetFdtLen(dtb_with_ucode)
1221 ucode_content = dtb_with_ucode[fdt_len:]
1222 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001223 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001224 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001225 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001226 dtb = fdt.FdtScan(fname)
1227 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001228 self.assertTrue(ucode)
1229 for node in ucode.subnodes:
1230 self.assertFalse(node.props.get('data'))
1231
Simon Glass72232452016-11-25 20:15:53 -07001232 # Check that the microcode appears immediately after the Fdt
1233 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001234 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001235 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1236 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001237 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001238
1239 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001240 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001241 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1242 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001243 u_boot = data[:len(nodtb_data)]
1244 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001245
1246 def testPackUbootMicrocode(self):
1247 """Test that x86 microcode can be handled correctly
1248
1249 We expect to see the following in the image, in order:
1250 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1251 place
1252 u-boot.dtb with the microcode removed
1253 the microcode
1254 """
Simon Glass511f6582018-10-01 12:22:30 -06001255 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001256 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001257 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1258 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001259
Simon Glassbac25c82017-05-27 07:38:26 -06001260 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001261 """Test that x86 microcode can be handled correctly
1262
1263 We expect to see the following in the image, in order:
1264 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1265 place
1266 u-boot.dtb with the microcode
1267 an empty microcode region
1268 """
1269 # We need the libfdt library to run this test since only that allows
1270 # finding the offset of a property. This is required by
1271 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001272 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001273
1274 second = data[len(U_BOOT_NODTB_DATA):]
1275
1276 fdt_len = self.GetFdtLen(second)
1277 third = second[fdt_len:]
1278 second = second[:fdt_len]
1279
Simon Glassbac25c82017-05-27 07:38:26 -06001280 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1281 self.assertIn(ucode_data, second)
1282 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001283
Simon Glassbac25c82017-05-27 07:38:26 -06001284 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001285 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001286 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1287 len(ucode_data))
1288 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001289 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1290 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001291
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001292 def testPackUbootSingleMicrocode(self):
1293 """Test that x86 microcode can be handled correctly with fdt_normal.
1294 """
Simon Glassbac25c82017-05-27 07:38:26 -06001295 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001296
Simon Glass996021e2016-11-25 20:15:54 -07001297 def testUBootImg(self):
1298 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001299 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001300 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001301
1302 def testNoMicrocode(self):
1303 """Test that a missing microcode region is detected"""
1304 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001305 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001306 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1307 "node found in ", str(e.exception))
1308
1309 def testMicrocodeWithoutNode(self):
1310 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1311 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001312 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001313 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1314 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1315
1316 def testMicrocodeWithoutNode2(self):
1317 """Test that a missing u-boot-ucode node is detected"""
1318 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001319 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001320 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1321 "microcode region u-boot-ucode", str(e.exception))
1322
1323 def testMicrocodeWithoutPtrInElf(self):
1324 """Test that a U-Boot binary without the microcode symbol is detected"""
1325 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001326 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001327 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001328 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001329
1330 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001331 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001332 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1333 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1334
1335 finally:
1336 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001337 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001338 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001339
1340 def testMicrocodeNotInImage(self):
1341 """Test that microcode must be placed within the image"""
1342 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001343 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001344 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1345 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001346 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001347
1348 def testWithoutMicrocode(self):
1349 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001350 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001351 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001352 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001353
1354 # Now check the device tree has no microcode
1355 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1356 second = data[len(U_BOOT_NODTB_DATA):]
1357
1358 fdt_len = self.GetFdtLen(second)
1359 self.assertEqual(dtb, second[:fdt_len])
1360
1361 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1362 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001363 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001364
1365 def testUnknownPosSize(self):
1366 """Test that microcode must be placed within the image"""
1367 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001368 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001369 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001370 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001371
1372 def testPackFsp(self):
1373 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001374 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001375 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1376
1377 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001378 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001379 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001380 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001381
1382 def testPackVbt(self):
1383 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001384 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001385 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001386
Simon Glass7f94e832017-11-12 21:52:25 -07001387 def testSplBssPad(self):
1388 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001389 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001390 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001391 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001392 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001393 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001394
Simon Glass04cda032018-10-01 21:12:42 -06001395 def testSplBssPadMissing(self):
1396 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001397 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001398 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001399 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001400 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1401 str(e.exception))
1402
Simon Glasse83679d2017-11-12 21:52:26 -07001403 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001404 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001405 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001406 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1407
Simon Glass6ba679c2018-07-06 10:27:17 -06001408 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1409 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001410
1411 We expect to see the following in the image, in order:
1412 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1413 correct place
1414 u-boot.dtb with the microcode removed
1415 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001416
1417 Args:
1418 dts: Device tree file to use for test
1419 ucode_second: True if the microsecond entry is second instead of
1420 third
Simon Glass3d274232017-11-12 21:52:27 -07001421 """
Simon Glass7057d022018-10-01 21:12:47 -06001422 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001423 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1424 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001425 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1426 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001427
Simon Glass6ba679c2018-07-06 10:27:17 -06001428 def testPackUbootSplMicrocode(self):
1429 """Test that x86 microcode can be handled correctly in SPL"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001430 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001431 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001432
1433 def testPackUbootSplMicrocodeReorder(self):
1434 """Test that order doesn't matter for microcode entries
1435
1436 This is the same as testPackUbootSplMicrocode but when we process the
1437 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1438 entry, so we reply on binman to try later.
1439 """
Simon Glass511f6582018-10-01 12:22:30 -06001440 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001441 ucode_second=True)
1442
Simon Glassa409c932017-11-12 21:52:28 -07001443 def testPackMrc(self):
1444 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001445 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001446 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1447
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001448 def testSplDtb(self):
1449 """Test that an image with spl/u-boot-spl.dtb can be created"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001450 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001451 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001452 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1453
Simon Glass0a6da312017-11-13 18:54:56 -07001454 def testSplNoDtb(self):
1455 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001456 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001457 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001458 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1459
Simon Glass7098b7f2021-03-21 18:24:30 +13001460 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4abf7842023-07-18 07:23:54 -06001461 use_expanded=False, no_write_symbols=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001462 """Check the image contains the expected symbol values
1463
1464 Args:
1465 dts: Device tree file to use for test
1466 base_data: Data before and after 'u-boot' section
1467 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001468 entry_args: Dict of entry args to supply to binman
1469 key: arg name
1470 value: value of that arg
1471 use_expanded: True to use expanded entries where available, e.g.
1472 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001473 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001474 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001475 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1476 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001477 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001478 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001479 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001480
Simon Glass7057d022018-10-01 21:12:47 -06001481 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001482 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1483 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001484 # The image should contain the symbols from u_boot_binman_syms.c
1485 # Note that image_pos is adjusted by the base address of the image,
1486 # which is 0x10 in our test image
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001487 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1488 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glass31e04cb2021-03-18 20:24:56 +13001489 0x10 + u_boot_offset, 0x04)
Simon Glass4abf7842023-07-18 07:23:54 -06001490 if no_write_symbols:
1491 expected = (base_data +
1492 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1493 U_BOOT_DATA + base_data)
1494 else:
1495 expected = (sym_values + base_data[24:] +
1496 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1497 base_data[24:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001498 self.assertEqual(expected, data)
1499
Simon Glass31e04cb2021-03-18 20:24:56 +13001500 def testSymbols(self):
1501 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001502 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001503
1504 def testSymbolsNoDtb(self):
1505 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001506 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001507 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1508 0x38)
1509
Simon Glasse76a3e62018-06-01 09:38:11 -06001510 def testPackUnitAddress(self):
1511 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001512 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001513 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1514
Simon Glassa91e1152018-06-01 09:38:16 -06001515 def testSections(self):
1516 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001517 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001518 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1519 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1520 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001521 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001522
Simon Glass30732662018-06-01 09:38:20 -06001523 def testMap(self):
1524 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001525 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001526 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700152700000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600152800000000 00000000 00000010 section@0
152900000000 00000000 00000004 u-boot
153000000010 00000010 00000010 section@1
153100000010 00000000 00000004 u-boot
153200000020 00000020 00000004 section@2
153300000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001534''', map_data)
1535
Simon Glass3b78d532018-06-01 09:38:21 -06001536 def testNamePrefix(self):
1537 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001538 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001539 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700154000000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600154100000000 00000000 00000010 section@0
154200000000 00000000 00000004 ro-u-boot
154300000010 00000010 00000010 section@1
154400000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001545''', map_data)
1546
Simon Glass6ba679c2018-07-06 10:27:17 -06001547 def testUnknownContents(self):
1548 """Test that obtaining the contents works as expected"""
1549 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001550 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001551 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001552 "processing of contents: remaining ["
1553 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001554
Simon Glass2e1169f2018-07-06 10:27:19 -06001555 def testBadChangeSize(self):
1556 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001557 try:
1558 state.SetAllowEntryExpansion(False)
1559 with self.assertRaises(ValueError) as e:
1560 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001561 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001562 str(e.exception))
1563 finally:
1564 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001565
Simon Glassa87014e2018-07-06 10:27:42 -06001566 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001567 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001568 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001569 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001570 dtb = fdt.Fdt(out_dtb_fname)
1571 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001572 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001573 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001574 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001575 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001576 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001577 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001578 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001579 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001580 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001581 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001582 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001583 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001584 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001585
Simon Glasse8561af2018-08-01 15:22:37 -06001586 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001587 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001588 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001589 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001590 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001591 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001592 'size': 40
1593 }, props)
1594
1595 def testUpdateFdtBad(self):
1596 """Test that we detect when ProcessFdt never completes"""
1597 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001598 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001599 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001600 '[<binman.etype._testing.Entry__testing',
1601 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001602
Simon Glass91710b32018-07-17 13:25:32 -06001603 def testEntryArgs(self):
1604 """Test passing arguments to entries from the command line"""
1605 entry_args = {
1606 'test-str-arg': 'test1',
1607 'test-int-arg': '456',
1608 }
Simon Glass511f6582018-10-01 12:22:30 -06001609 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001610 self.assertIn('image', control.images)
1611 entry = control.images['image'].GetEntries()['_testing']
1612 self.assertEqual('test0', entry.test_str_fdt)
1613 self.assertEqual('test1', entry.test_str_arg)
1614 self.assertEqual(123, entry.test_int_fdt)
1615 self.assertEqual(456, entry.test_int_arg)
1616
1617 def testEntryArgsMissing(self):
1618 """Test missing arguments and properties"""
1619 entry_args = {
1620 'test-int-arg': '456',
1621 }
Simon Glass511f6582018-10-01 12:22:30 -06001622 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001623 entry = control.images['image'].GetEntries()['_testing']
1624 self.assertEqual('test0', entry.test_str_fdt)
1625 self.assertEqual(None, entry.test_str_arg)
1626 self.assertEqual(None, entry.test_int_fdt)
1627 self.assertEqual(456, entry.test_int_arg)
1628
1629 def testEntryArgsRequired(self):
1630 """Test missing arguments and properties"""
1631 entry_args = {
1632 'test-int-arg': '456',
1633 }
1634 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001635 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001636 self.assertIn("Node '/binman/_testing': "
1637 'Missing required properties/entry args: test-str-arg, '
1638 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001639 str(e.exception))
1640
1641 def testEntryArgsInvalidFormat(self):
1642 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001643 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1644 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001645 with self.assertRaises(ValueError) as e:
1646 self._DoBinman(*args)
1647 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1648
1649 def testEntryArgsInvalidInteger(self):
1650 """Test that an invalid entry-argument integer is detected"""
1651 entry_args = {
1652 'test-int-arg': 'abc',
1653 }
1654 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001655 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001656 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1657 "'test-int-arg' (value 'abc') to integer",
1658 str(e.exception))
1659
1660 def testEntryArgsInvalidDatatype(self):
1661 """Test that an invalid entry-argument datatype is detected
1662
1663 This test could be written in entry_test.py except that it needs
1664 access to control.entry_args, which seems more than that module should
1665 be able to see.
1666 """
1667 entry_args = {
1668 'test-bad-datatype-arg': '12',
1669 }
1670 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001671 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001672 entry_args=entry_args)
1673 self.assertIn('GetArg() internal error: Unknown data type ',
1674 str(e.exception))
1675
Simon Glass2ca52032018-07-17 13:25:33 -06001676 def testText(self):
1677 """Test for a text entry type"""
1678 entry_args = {
1679 'test-id': TEXT_DATA,
1680 'test-id2': TEXT_DATA2,
1681 'test-id3': TEXT_DATA3,
1682 }
Simon Glass511f6582018-10-01 12:22:30 -06001683 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001684 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001685 expected = (tools.to_bytes(TEXT_DATA) +
1686 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1687 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001688 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001689 self.assertEqual(expected, data)
1690
Simon Glass969616c2018-07-17 13:25:36 -06001691 def testEntryDocs(self):
1692 """Test for creation of entry documentation"""
1693 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001694 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001695 self.assertTrue(len(stdout.getvalue()) > 0)
1696
1697 def testEntryDocsMissing(self):
1698 """Test handling of missing entry documentation"""
1699 with self.assertRaises(ValueError) as e:
1700 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001701 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001702 self.assertIn('Documentation is missing for modules: u_boot',
1703 str(e.exception))
1704
Simon Glass704784b2018-07-17 13:25:38 -06001705 def testFmap(self):
1706 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001707 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001708 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001709 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1710 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001711 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001712 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001713 self.assertEqual(1, fhdr.ver_major)
1714 self.assertEqual(0, fhdr.ver_minor)
1715 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001716 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001717 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001718 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001719 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001720 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001721
Simon Glass82059c22021-04-03 11:05:09 +13001722 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001723 self.assertEqual(b'SECTION0', fentry.name)
1724 self.assertEqual(0, fentry.offset)
1725 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001726 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001727
1728 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001729 self.assertEqual(b'RO_U_BOOT', fentry.name)
1730 self.assertEqual(0, fentry.offset)
1731 self.assertEqual(4, fentry.size)
1732 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001733
Simon Glass82059c22021-04-03 11:05:09 +13001734 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001735 self.assertEqual(b'SECTION1', fentry.name)
1736 self.assertEqual(16, fentry.offset)
1737 self.assertEqual(16, fentry.size)
1738 self.assertEqual(0, fentry.flags)
1739
1740 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001741 self.assertEqual(b'RW_U_BOOT', fentry.name)
1742 self.assertEqual(16, fentry.offset)
1743 self.assertEqual(4, fentry.size)
1744 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001745
Simon Glass82059c22021-04-03 11:05:09 +13001746 fentry = next(fiter)
1747 self.assertEqual(b'FMAP', fentry.name)
1748 self.assertEqual(32, fentry.offset)
1749 self.assertEqual(expect_size, fentry.size)
1750 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001751
Simon Glassdb168d42018-07-17 13:25:39 -06001752 def testBlobNamedByArg(self):
1753 """Test we can add a blob with the filename coming from an entry arg"""
1754 entry_args = {
1755 'cros-ec-rw-path': 'ecrw.bin',
1756 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001757 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001758
Simon Glass53f53992018-07-17 13:25:40 -06001759 def testFill(self):
1760 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001761 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001762 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001763 self.assertEqual(expected, data)
1764
1765 def testFillNoSize(self):
1766 """Test for an fill entry type with no size"""
1767 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001768 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001769 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001770 str(e.exception))
1771
Simon Glassc1ae83c2018-07-17 13:25:44 -06001772 def _HandleGbbCommand(self, pipe_list):
1773 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001774 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001775 fname = pipe_list[0][-1]
1776 # Append our GBB data to the file, which will happen every time the
1777 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001778 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001779 fd.write(GBB_DATA)
1780 return command.CommandResult()
1781
1782 def testGbb(self):
1783 """Test for the Chromium OS Google Binary Block"""
1784 command.test_result = self._HandleGbbCommand
1785 entry_args = {
1786 'keydir': 'devkeys',
1787 'bmpblk': 'bmpblk.bin',
1788 }
Simon Glass511f6582018-10-01 12:22:30 -06001789 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001790
1791 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001792 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1793 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001794 self.assertEqual(expected, data)
1795
1796 def testGbbTooSmall(self):
1797 """Test for the Chromium OS Google Binary Block being large enough"""
1798 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001799 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001800 self.assertIn("Node '/binman/gbb': GBB is too small",
1801 str(e.exception))
1802
1803 def testGbbNoSize(self):
1804 """Test for the Chromium OS Google Binary Block having a size"""
1805 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001806 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001807 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1808 str(e.exception))
1809
Simon Glass66152ce2022-01-09 20:14:09 -07001810 def testGbbMissing(self):
1811 """Test that binman still produces an image if futility is missing"""
1812 entry_args = {
1813 'keydir': 'devkeys',
1814 }
1815 with test_util.capture_sys_output() as (_, stderr):
1816 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1817 entry_args=entry_args)
1818 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001819 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001820
Simon Glass5c350162018-07-17 13:25:47 -06001821 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001822 """Fake calls to the futility utility
1823
1824 The expected pipe is:
1825
1826 [('futility', 'vbutil_firmware', '--vblock',
1827 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1828 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1829 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1830 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1831
1832 This writes to the output file (here, 'vblock.vblock'). If
1833 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1834 of the input data (here, 'input.vblock').
1835 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001836 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001837 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001838 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001839 if self._hash_data:
1840 infile = pipe_list[0][11]
1841 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001842 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001843 m.update(data)
1844 fd.write(m.digest())
1845 else:
1846 fd.write(VBLOCK_DATA)
1847
Simon Glass5c350162018-07-17 13:25:47 -06001848 return command.CommandResult()
1849
1850 def testVblock(self):
1851 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001852 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001853 command.test_result = self._HandleVblockCommand
1854 entry_args = {
1855 'keydir': 'devkeys',
1856 }
Simon Glass511f6582018-10-01 12:22:30 -06001857 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001858 entry_args=entry_args)
1859 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1860 self.assertEqual(expected, data)
1861
1862 def testVblockNoContent(self):
1863 """Test we detect a vblock which has no content to sign"""
1864 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001865 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001866 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001867 'property', str(e.exception))
1868
1869 def testVblockBadPhandle(self):
1870 """Test that we detect a vblock with an invalid phandle in contents"""
1871 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001872 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001873 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1874 '1000', str(e.exception))
1875
1876 def testVblockBadEntry(self):
1877 """Test that we detect an entry that points to a non-entry"""
1878 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001879 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001880 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1881 "'other'", str(e.exception))
1882
Simon Glass220c6222021-01-06 21:35:17 -07001883 def testVblockContent(self):
1884 """Test that the vblock signs the right data"""
1885 self._hash_data = True
1886 command.test_result = self._HandleVblockCommand
1887 entry_args = {
1888 'keydir': 'devkeys',
1889 }
1890 data = self._DoReadFileDtb(
1891 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1892 entry_args=entry_args)[0]
1893 hashlen = 32 # SHA256 hash is 32 bytes
1894 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1895 hashval = data[-hashlen:]
1896 dtb = data[len(U_BOOT_DATA):-hashlen]
1897
1898 expected_data = U_BOOT_DATA + dtb
1899
1900 # The hashval should be a hash of the dtb
1901 m = hashlib.sha256()
1902 m.update(expected_data)
1903 expected_hashval = m.digest()
1904 self.assertEqual(expected_hashval, hashval)
1905
Simon Glass66152ce2022-01-09 20:14:09 -07001906 def testVblockMissing(self):
1907 """Test that binman still produces an image if futility is missing"""
1908 entry_args = {
1909 'keydir': 'devkeys',
1910 }
1911 with test_util.capture_sys_output() as (_, stderr):
1912 self._DoTestFile('074_vblock.dts',
1913 force_missing_bintools='futility',
1914 entry_args=entry_args)
1915 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001916 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001917
Simon Glass8425a1f2018-07-17 13:25:48 -06001918 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001919 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001920 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001921 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001922 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001923 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1924
Simon Glass24b97442018-07-17 13:25:51 -06001925 def testUsesPos(self):
1926 """Test that the 'pos' property cannot be used anymore"""
1927 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001928 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001929 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1930 "'pos'", str(e.exception))
1931
Simon Glass274bf092018-09-14 04:57:08 -06001932 def testFillZero(self):
1933 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001934 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001935 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001936
Simon Glass267de432018-09-14 04:57:09 -06001937 def testTextMissing(self):
1938 """Test for a text entry type where there is no text"""
1939 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001940 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001941 self.assertIn("Node '/binman/text': No value provided for text label "
1942 "'test-id'", str(e.exception))
1943
Simon Glassed40e962018-09-14 04:57:10 -06001944 def testPackStart16Tpl(self):
1945 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001946 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001947 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1948
Simon Glass3b376c32018-09-14 04:57:12 -06001949 def testSelectImage(self):
1950 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001951 expected = 'Skipping images: image1'
1952
1953 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001954 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001955 with test_util.capture_sys_output() as (stdout, stderr):
1956 retcode = self._DoTestFile('006_dual_image.dts',
1957 verbosity=verbosity,
1958 images=['image2'])
1959 self.assertEqual(0, retcode)
1960 if verbosity:
1961 self.assertIn(expected, stdout.getvalue())
1962 else:
1963 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001964
Simon Glass80025522022-01-29 14:14:04 -07001965 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1966 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001967 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001968
Simon Glasse219aa42018-09-14 04:57:24 -06001969 def testUpdateFdtAll(self):
1970 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06001971 self._SetupSplElf()
1972 self._SetupTplElf()
Simon Glass5b4bce32019-07-08 14:25:26 -06001973 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001974
1975 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06001976 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001977 'image-pos': 0,
1978 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06001979 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001980 'section:image-pos': 0,
1981 'section:size': 565,
1982 'section/u-boot-dtb:offset': 0,
1983 'section/u-boot-dtb:image-pos': 0,
1984 'section/u-boot-dtb:size': 565,
1985 'u-boot-spl-dtb:offset': 565,
1986 'u-boot-spl-dtb:image-pos': 565,
1987 'u-boot-spl-dtb:size': 585,
1988 'u-boot-tpl-dtb:offset': 1150,
1989 'u-boot-tpl-dtb:image-pos': 1150,
1990 'u-boot-tpl-dtb:size': 585,
1991 'u-boot-vpl-dtb:image-pos': 1735,
1992 'u-boot-vpl-dtb:offset': 1735,
1993 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06001994 }
1995
1996 # We expect three device-tree files in the output, one after the other.
1997 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1998 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1999 # main U-Boot tree. All three should have the same postions and offset.
2000 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07002001 self.maxDiff = None
2002 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06002003 dtb = fdt.Fdt.FromData(data[start:])
2004 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06002005 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07002006 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06002007 expected = dict(base_expected)
2008 if item:
2009 expected[item] = 0
2010 self.assertEqual(expected, props)
2011 start += dtb._fdt_obj.totalsize()
2012
2013 def testUpdateFdtOutput(self):
2014 """Test that output DTB files are updated"""
2015 try:
Simon Glass511f6582018-10-01 12:22:30 -06002016 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002017 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2018
2019 # Unfortunately, compiling a source file always results in a file
2020 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002021 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002022 # binman as a file called u-boot.dtb. To fix this, copy the file
2023 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002024 start = 0
2025 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002026 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002027 dtb = fdt.Fdt.FromData(data[start:])
2028 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002029 pathname = tools.get_output_filename(os.path.split(fname)[1])
2030 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002031 name = os.path.split(fname)[0]
2032
2033 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002034 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002035 else:
2036 orig_indata = dtb_data
2037 self.assertNotEqual(outdata, orig_indata,
2038 "Expected output file '%s' be updated" % pathname)
2039 self.assertEqual(outdata, data[start:start + size],
2040 "Expected output file '%s' to match output image" %
2041 pathname)
2042 start += size
2043 finally:
2044 self._ResetDtbs()
2045
Simon Glass7ba33592018-09-14 04:57:26 -06002046 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002047 bintool = self.comp_bintools['lz4']
2048 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002049
2050 def testCompress(self):
2051 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002052 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002053 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002054 use_real_dtb=True, update_dtb=True)
2055 dtb = fdt.Fdt(out_dtb_fname)
2056 dtb.Scan()
2057 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2058 orig = self._decompress(data)
2059 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002060
2061 # Do a sanity check on various fields
2062 image = control.images['image']
2063 entries = image.GetEntries()
2064 self.assertEqual(1, len(entries))
2065
2066 entry = entries['blob']
2067 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2068 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2069 orig = self._decompress(entry.data)
2070 self.assertEqual(orig, entry.uncomp_data)
2071
Simon Glass72eeff12020-10-26 17:40:16 -06002072 self.assertEqual(image.data, entry.data)
2073
Simon Glass7ba33592018-09-14 04:57:26 -06002074 expected = {
2075 'blob:uncomp-size': len(COMPRESS_DATA),
2076 'blob:size': len(data),
2077 'size': len(data),
2078 }
2079 self.assertEqual(expected, props)
2080
Simon Glassac6328c2018-09-14 04:57:28 -06002081 def testFiles(self):
2082 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002083 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002084 self.assertEqual(FILES_DATA, data)
2085
2086 def testFilesCompress(self):
2087 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002088 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002089 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002090
2091 image = control.images['image']
2092 entries = image.GetEntries()
2093 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002094 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002095
Simon Glass303f62f2019-05-17 22:00:46 -06002096 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002097 for i in range(1, 3):
2098 key = '%d.dat' % i
2099 start = entries[key].image_pos
2100 len = entries[key].size
2101 chunk = data[start:start + len]
2102 orig += self._decompress(chunk)
2103
2104 self.assertEqual(FILES_DATA, orig)
2105
2106 def testFilesMissing(self):
2107 """Test missing files"""
2108 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002109 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002110 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2111 'no files', str(e.exception))
2112
2113 def testFilesNoPattern(self):
2114 """Test missing files"""
2115 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002116 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002117 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2118 str(e.exception))
2119
Simon Glassdd156a42022-03-05 20:18:59 -07002120 def testExtendSize(self):
2121 """Test an extending entry"""
2122 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002123 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002124 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2125 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2126 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2127 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002128 self.assertEqual(expect, data)
2129 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700213000000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600213100000000 00000000 00000008 fill
213200000008 00000008 00000004 u-boot
21330000000c 0000000c 00000004 section
21340000000c 00000000 00000003 intel-mrc
213500000010 00000010 00000004 u-boot2
213600000014 00000014 0000000c section2
213700000014 00000000 00000008 fill
21380000001c 00000008 00000004 u-boot
213900000020 00000020 00000008 fill2
2140''', map_data)
2141
Simon Glassdd156a42022-03-05 20:18:59 -07002142 def testExtendSizeBad(self):
2143 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002144 with test_util.capture_sys_output() as (stdout, stderr):
2145 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002146 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002147 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2148 'expanding entry', str(e.exception))
2149
Simon Glassae7cf032018-09-14 04:57:31 -06002150 def testHash(self):
2151 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002152 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002153 use_real_dtb=True, update_dtb=True)
2154 dtb = fdt.Fdt(out_dtb_fname)
2155 dtb.Scan()
2156 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2157 m = hashlib.sha256()
2158 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002159 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002160
2161 def testHashNoAlgo(self):
2162 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002163 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002164 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2165 'hash node', str(e.exception))
2166
2167 def testHashBadAlgo(self):
2168 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002169 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002170 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002171 str(e.exception))
2172
2173 def testHashSection(self):
2174 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002175 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002176 use_real_dtb=True, update_dtb=True)
2177 dtb = fdt.Fdt(out_dtb_fname)
2178 dtb.Scan()
2179 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2180 m = hashlib.sha256()
2181 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002182 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002183 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002184
Simon Glass3fb4f422018-09-14 04:57:32 -06002185 def testPackUBootTplMicrocode(self):
2186 """Test that x86 microcode can be handled correctly in TPL
2187
2188 We expect to see the following in the image, in order:
2189 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2190 place
2191 u-boot-tpl.dtb with the microcode removed
2192 the microcode
2193 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002194 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002195 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002196 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002197 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2198 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002199
Simon Glassc64aea52018-09-14 04:57:34 -06002200 def testFmapX86(self):
2201 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002202 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002203 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002204 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002205 self.assertEqual(expected, data[:32])
2206 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2207
2208 self.assertEqual(0x100, fhdr.image_size)
2209
2210 self.assertEqual(0, fentries[0].offset)
2211 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002212 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002213
2214 self.assertEqual(4, fentries[1].offset)
2215 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002216 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002217
2218 self.assertEqual(32, fentries[2].offset)
2219 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2220 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002221 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002222
2223 def testFmapX86Section(self):
2224 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002225 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002226 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002227 self.assertEqual(expected, data[:32])
2228 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2229
Simon Glassb1d414c2021-04-03 11:05:10 +13002230 self.assertEqual(0x180, fhdr.image_size)
2231 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002232 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002233
Simon Glass82059c22021-04-03 11:05:09 +13002234 fentry = next(fiter)
2235 self.assertEqual(b'U_BOOT', fentry.name)
2236 self.assertEqual(0, fentry.offset)
2237 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002238
Simon Glass82059c22021-04-03 11:05:09 +13002239 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002240 self.assertEqual(b'SECTION', fentry.name)
2241 self.assertEqual(4, fentry.offset)
2242 self.assertEqual(0x20 + expect_size, fentry.size)
2243
2244 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002245 self.assertEqual(b'INTEL_MRC', fentry.name)
2246 self.assertEqual(4, fentry.offset)
2247 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002248
Simon Glass82059c22021-04-03 11:05:09 +13002249 fentry = next(fiter)
2250 self.assertEqual(b'FMAP', fentry.name)
2251 self.assertEqual(36, fentry.offset)
2252 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002253
Simon Glassb1714232018-09-14 04:57:35 -06002254 def testElf(self):
2255 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002256 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002257 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002258 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002259 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002260 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002261
Simon Glass0d673792019-07-08 13:18:25 -06002262 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002263 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002264 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002265 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002266 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002267 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002268
Simon Glasscd817d52018-09-14 04:57:36 -06002269 def testPackOverlapMap(self):
2270 """Test that overlapping regions are detected"""
2271 with test_util.capture_sys_output() as (stdout, stderr):
2272 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002273 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002274 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002275 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2276 stdout.getvalue())
2277
2278 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002279 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002280 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002281 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002282 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002283<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002284<none> 00000000 00000004 u-boot
2285<none> 00000003 00000004 u-boot-align
2286''', map_data)
2287
Simon Glass0d673792019-07-08 13:18:25 -06002288 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002289 """Test that an image with an Intel Reference code binary works"""
2290 data = self._DoReadFile('100_intel_refcode.dts')
2291 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2292
Simon Glasseb023b32019-04-25 21:58:39 -06002293 def testSectionOffset(self):
2294 """Tests use of a section with an offset"""
2295 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2296 map=True)
2297 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700229800000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600229900000004 00000004 00000010 section@0
230000000004 00000000 00000004 u-boot
230100000018 00000018 00000010 section@1
230200000018 00000000 00000004 u-boot
23030000002c 0000002c 00000004 section@2
23040000002c 00000000 00000004 u-boot
2305''', map_data)
2306 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002307 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2308 tools.get_bytes(0x21, 12) +
2309 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2310 tools.get_bytes(0x61, 12) +
2311 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2312 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002313
Simon Glass1de34482019-07-08 13:18:53 -06002314 def testCbfsRaw(self):
2315 """Test base handling of a Coreboot Filesystem (CBFS)
2316
2317 The exact contents of the CBFS is verified by similar tests in
2318 cbfs_util_test.py. The tests here merely check that the files added to
2319 the CBFS can be found in the final image.
2320 """
2321 data = self._DoReadFile('102_cbfs_raw.dts')
2322 size = 0xb0
2323
2324 cbfs = cbfs_util.CbfsReader(data)
2325 self.assertEqual(size, cbfs.rom_size)
2326
2327 self.assertIn('u-boot-dtb', cbfs.files)
2328 cfile = cbfs.files['u-boot-dtb']
2329 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2330
2331 def testCbfsArch(self):
2332 """Test on non-x86 architecture"""
2333 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2334 size = 0x100
2335
2336 cbfs = cbfs_util.CbfsReader(data)
2337 self.assertEqual(size, cbfs.rom_size)
2338
2339 self.assertIn('u-boot-dtb', cbfs.files)
2340 cfile = cbfs.files['u-boot-dtb']
2341 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2342
2343 def testCbfsStage(self):
2344 """Tests handling of a Coreboot Filesystem (CBFS)"""
2345 if not elf.ELF_TOOLS:
2346 self.skipTest('Python elftools not available')
2347 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2348 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2349 size = 0xb0
2350
2351 data = self._DoReadFile('104_cbfs_stage.dts')
2352 cbfs = cbfs_util.CbfsReader(data)
2353 self.assertEqual(size, cbfs.rom_size)
2354
2355 self.assertIn('u-boot', cbfs.files)
2356 cfile = cbfs.files['u-boot']
2357 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2358
2359 def testCbfsRawCompress(self):
2360 """Test handling of compressing raw files"""
2361 self._CheckLz4()
2362 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2363 size = 0x140
2364
2365 cbfs = cbfs_util.CbfsReader(data)
2366 self.assertIn('u-boot', cbfs.files)
2367 cfile = cbfs.files['u-boot']
2368 self.assertEqual(COMPRESS_DATA, cfile.data)
2369
2370 def testCbfsBadArch(self):
2371 """Test handling of a bad architecture"""
2372 with self.assertRaises(ValueError) as e:
2373 self._DoReadFile('106_cbfs_bad_arch.dts')
2374 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2375
2376 def testCbfsNoSize(self):
2377 """Test handling of a missing size property"""
2378 with self.assertRaises(ValueError) as e:
2379 self._DoReadFile('107_cbfs_no_size.dts')
2380 self.assertIn('entry must have a size property', str(e.exception))
2381
Simon Glass3e28f4f2021-11-23 11:03:54 -07002382 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002383 """Test handling of a CBFS entry which does not provide contentsy"""
2384 with self.assertRaises(ValueError) as e:
2385 self._DoReadFile('108_cbfs_no_contents.dts')
2386 self.assertIn('Could not complete processing of contents',
2387 str(e.exception))
2388
2389 def testCbfsBadCompress(self):
2390 """Test handling of a bad architecture"""
2391 with self.assertRaises(ValueError) as e:
2392 self._DoReadFile('109_cbfs_bad_compress.dts')
2393 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2394 str(e.exception))
2395
2396 def testCbfsNamedEntries(self):
2397 """Test handling of named entries"""
2398 data = self._DoReadFile('110_cbfs_name.dts')
2399
2400 cbfs = cbfs_util.CbfsReader(data)
2401 self.assertIn('FRED', cbfs.files)
2402 cfile1 = cbfs.files['FRED']
2403 self.assertEqual(U_BOOT_DATA, cfile1.data)
2404
2405 self.assertIn('hello', cbfs.files)
2406 cfile2 = cbfs.files['hello']
2407 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2408
Simon Glass759af872019-07-08 13:18:54 -06002409 def _SetupIfwi(self, fname):
2410 """Set up to run an IFWI test
2411
2412 Args:
2413 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2414 """
2415 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002416 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002417
2418 # Intel Integrated Firmware Image (IFWI) file
2419 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2420 data = fd.read()
2421 TestFunctional._MakeInputFile(fname,data)
2422
2423 def _CheckIfwi(self, data):
2424 """Check that an image with an IFWI contains the correct output
2425
2426 Args:
2427 data: Conents of output file
2428 """
Simon Glass80025522022-01-29 14:14:04 -07002429 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002430 if data[:0x1000] != expected_desc:
2431 self.fail('Expected descriptor binary at start of image')
2432
2433 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002434 image_fname = tools.get_output_filename('image.bin')
2435 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002436 ifwitool = bintool.Bintool.create('ifwitool')
2437 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002438
Simon Glass80025522022-01-29 14:14:04 -07002439 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002440 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002441
2442 def testPackX86RomIfwi(self):
2443 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2444 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002445 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002446 self._CheckIfwi(data)
2447
2448 def testPackX86RomIfwiNoDesc(self):
2449 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2450 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002451 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002452 self._CheckIfwi(data)
2453
2454 def testPackX86RomIfwiNoData(self):
2455 """Test that an x86 ROM with IFWI handles missing data"""
2456 self._SetupIfwi('ifwi.bin')
2457 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002458 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002459 self.assertIn('Could not complete processing of contents',
2460 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002461
Simon Glass66152ce2022-01-09 20:14:09 -07002462 def testIfwiMissing(self):
2463 """Test that binman still produces an image if ifwitool is missing"""
2464 self._SetupIfwi('fitimage.bin')
2465 with test_util.capture_sys_output() as (_, stderr):
2466 self._DoTestFile('111_x86_rom_ifwi.dts',
2467 force_missing_bintools='ifwitool')
2468 err = stderr.getvalue()
2469 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002470 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002471
Simon Glassc2f1aed2019-07-08 13:18:56 -06002472 def testCbfsOffset(self):
2473 """Test a CBFS with files at particular offsets
2474
2475 Like all CFBS tests, this is just checking the logic that calls
2476 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2477 """
2478 data = self._DoReadFile('114_cbfs_offset.dts')
2479 size = 0x200
2480
2481 cbfs = cbfs_util.CbfsReader(data)
2482 self.assertEqual(size, cbfs.rom_size)
2483
2484 self.assertIn('u-boot', cbfs.files)
2485 cfile = cbfs.files['u-boot']
2486 self.assertEqual(U_BOOT_DATA, cfile.data)
2487 self.assertEqual(0x40, cfile.cbfs_offset)
2488
2489 self.assertIn('u-boot-dtb', cbfs.files)
2490 cfile2 = cbfs.files['u-boot-dtb']
2491 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2492 self.assertEqual(0x140, cfile2.cbfs_offset)
2493
Simon Glass0f621332019-07-08 14:25:27 -06002494 def testFdtmap(self):
2495 """Test an FDT map can be inserted in the image"""
2496 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2497 fdtmap_data = data[len(U_BOOT_DATA):]
2498 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002499 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002500 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002501
2502 fdt_data = fdtmap_data[16:]
2503 dtb = fdt.Fdt.FromData(fdt_data)
2504 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002505 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002506 self.assertEqual({
2507 'image-pos': 0,
2508 'offset': 0,
2509 'u-boot:offset': 0,
2510 'u-boot:size': len(U_BOOT_DATA),
2511 'u-boot:image-pos': 0,
2512 'fdtmap:image-pos': 4,
2513 'fdtmap:offset': 4,
2514 'fdtmap:size': len(fdtmap_data),
2515 'size': len(data),
2516 }, props)
2517
2518 def testFdtmapNoMatch(self):
2519 """Check handling of an FDT map when the section cannot be found"""
2520 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2521
2522 # Mangle the section name, which should cause a mismatch between the
2523 # correct FDT path and the one expected by the section
2524 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002525 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002526 entries = image.GetEntries()
2527 fdtmap = entries['fdtmap']
2528 with self.assertRaises(ValueError) as e:
2529 fdtmap._GetFdtmap()
2530 self.assertIn("Cannot locate node for path '/binman-suffix'",
2531 str(e.exception))
2532
Simon Glasscec34ba2019-07-08 14:25:28 -06002533 def testFdtmapHeader(self):
2534 """Test an FDT map and image header can be inserted in the image"""
2535 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2536 fdtmap_pos = len(U_BOOT_DATA)
2537 fdtmap_data = data[fdtmap_pos:]
2538 fdt_data = fdtmap_data[16:]
2539 dtb = fdt.Fdt.FromData(fdt_data)
2540 fdt_size = dtb.GetFdtObj().totalsize()
2541 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002542 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002543 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2544 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2545
2546 def testFdtmapHeaderStart(self):
2547 """Test an image header can be inserted at the image start"""
2548 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2549 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2550 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002551 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002552 offset = struct.unpack('<I', hdr_data[4:])[0]
2553 self.assertEqual(fdtmap_pos, offset)
2554
2555 def testFdtmapHeaderPos(self):
2556 """Test an image header can be inserted at a chosen position"""
2557 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2558 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2559 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002560 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002561 offset = struct.unpack('<I', hdr_data[4:])[0]
2562 self.assertEqual(fdtmap_pos, offset)
2563
2564 def testHeaderMissingFdtmap(self):
2565 """Test an image header requires an fdtmap"""
2566 with self.assertRaises(ValueError) as e:
2567 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2568 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2569 str(e.exception))
2570
2571 def testHeaderNoLocation(self):
2572 """Test an image header with a no specified location is detected"""
2573 with self.assertRaises(ValueError) as e:
2574 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2575 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2576 str(e.exception))
2577
Simon Glasse61b6f62019-07-08 14:25:37 -06002578 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002579 """Test extending an entry after it is packed"""
2580 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002581 self.assertEqual(b'aaa', data[:3])
2582 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2583 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002584
Simon Glassdd156a42022-03-05 20:18:59 -07002585 def testEntryExtendBad(self):
2586 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002587 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002588 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002589 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002590 str(e.exception))
2591
Simon Glassdd156a42022-03-05 20:18:59 -07002592 def testEntryExtendSection(self):
2593 """Test extending an entry within a section after it is packed"""
2594 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002595 self.assertEqual(b'aaa', data[:3])
2596 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2597 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002598
Simon Glass90d29682019-07-08 14:25:38 -06002599 def testCompressDtb(self):
2600 """Test that compress of device-tree files is supported"""
2601 self._CheckLz4()
2602 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2603 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2604 comp_data = data[len(U_BOOT_DATA):]
2605 orig = self._decompress(comp_data)
2606 dtb = fdt.Fdt.FromData(orig)
2607 dtb.Scan()
2608 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2609 expected = {
2610 'u-boot:size': len(U_BOOT_DATA),
2611 'u-boot-dtb:uncomp-size': len(orig),
2612 'u-boot-dtb:size': len(comp_data),
2613 'size': len(data),
2614 }
2615 self.assertEqual(expected, props)
2616
Simon Glass151bbbf2019-07-08 14:25:41 -06002617 def testCbfsUpdateFdt(self):
2618 """Test that we can update the device tree with CBFS offset/size info"""
2619 self._CheckLz4()
2620 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2621 update_dtb=True)
2622 dtb = fdt.Fdt(out_dtb_fname)
2623 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002624 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002625 del props['cbfs/u-boot:size']
2626 self.assertEqual({
2627 'offset': 0,
2628 'size': len(data),
2629 'image-pos': 0,
2630 'cbfs:offset': 0,
2631 'cbfs:size': len(data),
2632 'cbfs:image-pos': 0,
2633 'cbfs/u-boot:offset': 0x38,
2634 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2635 'cbfs/u-boot:image-pos': 0x38,
2636 'cbfs/u-boot-dtb:offset': 0xb8,
2637 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2638 'cbfs/u-boot-dtb:image-pos': 0xb8,
2639 }, props)
2640
Simon Glass3c9b4f22019-07-08 14:25:42 -06002641 def testCbfsBadType(self):
2642 """Test an image header with a no specified location is detected"""
2643 with self.assertRaises(ValueError) as e:
2644 self._DoReadFile('126_cbfs_bad_type.dts')
2645 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2646
Simon Glass6b156f82019-07-08 14:25:43 -06002647 def testList(self):
2648 """Test listing the files in an image"""
2649 self._CheckLz4()
2650 data = self._DoReadFile('127_list.dts')
2651 image = control.images['image']
2652 entries = image.BuildEntryList()
2653 self.assertEqual(7, len(entries))
2654
2655 ent = entries[0]
2656 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002657 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002658 self.assertEqual('section', ent.etype)
2659 self.assertEqual(len(data), ent.size)
2660 self.assertEqual(0, ent.image_pos)
2661 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002662 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002663
2664 ent = entries[1]
2665 self.assertEqual(1, ent.indent)
2666 self.assertEqual('u-boot', ent.name)
2667 self.assertEqual('u-boot', ent.etype)
2668 self.assertEqual(len(U_BOOT_DATA), ent.size)
2669 self.assertEqual(0, ent.image_pos)
2670 self.assertEqual(None, ent.uncomp_size)
2671 self.assertEqual(0, ent.offset)
2672
2673 ent = entries[2]
2674 self.assertEqual(1, ent.indent)
2675 self.assertEqual('section', ent.name)
2676 self.assertEqual('section', ent.etype)
2677 section_size = ent.size
2678 self.assertEqual(0x100, ent.image_pos)
2679 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002680 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002681
2682 ent = entries[3]
2683 self.assertEqual(2, ent.indent)
2684 self.assertEqual('cbfs', ent.name)
2685 self.assertEqual('cbfs', ent.etype)
2686 self.assertEqual(0x400, ent.size)
2687 self.assertEqual(0x100, ent.image_pos)
2688 self.assertEqual(None, ent.uncomp_size)
2689 self.assertEqual(0, ent.offset)
2690
2691 ent = entries[4]
2692 self.assertEqual(3, ent.indent)
2693 self.assertEqual('u-boot', ent.name)
2694 self.assertEqual('u-boot', ent.etype)
2695 self.assertEqual(len(U_BOOT_DATA), ent.size)
2696 self.assertEqual(0x138, ent.image_pos)
2697 self.assertEqual(None, ent.uncomp_size)
2698 self.assertEqual(0x38, ent.offset)
2699
2700 ent = entries[5]
2701 self.assertEqual(3, ent.indent)
2702 self.assertEqual('u-boot-dtb', ent.name)
2703 self.assertEqual('text', ent.etype)
2704 self.assertGreater(len(COMPRESS_DATA), ent.size)
2705 self.assertEqual(0x178, ent.image_pos)
2706 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2707 self.assertEqual(0x78, ent.offset)
2708
2709 ent = entries[6]
2710 self.assertEqual(2, ent.indent)
2711 self.assertEqual('u-boot-dtb', ent.name)
2712 self.assertEqual('u-boot-dtb', ent.etype)
2713 self.assertEqual(0x500, ent.image_pos)
2714 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2715 dtb_size = ent.size
2716 # Compressing this data expands it since headers are added
2717 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2718 self.assertEqual(0x400, ent.offset)
2719
2720 self.assertEqual(len(data), 0x100 + section_size)
2721 self.assertEqual(section_size, 0x400 + dtb_size)
2722
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002723 def testFindFdtmap(self):
2724 """Test locating an FDT map in an image"""
2725 self._CheckLz4()
2726 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2727 image = control.images['image']
2728 entries = image.GetEntries()
2729 entry = entries['fdtmap']
2730 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2731
2732 def testFindFdtmapMissing(self):
2733 """Test failing to locate an FDP map"""
2734 data = self._DoReadFile('005_simple.dts')
2735 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2736
Simon Glassed39a3c2019-07-08 14:25:45 -06002737 def testFindImageHeader(self):
2738 """Test locating a image header"""
2739 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002740 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002741 image = control.images['image']
2742 entries = image.GetEntries()
2743 entry = entries['fdtmap']
2744 # The header should point to the FDT map
2745 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2746
2747 def testFindImageHeaderStart(self):
2748 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002749 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002750 image = control.images['image']
2751 entries = image.GetEntries()
2752 entry = entries['fdtmap']
2753 # The header should point to the FDT map
2754 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2755
2756 def testFindImageHeaderMissing(self):
2757 """Test failing to locate an image header"""
2758 data = self._DoReadFile('005_simple.dts')
2759 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2760
Simon Glassb8424fa2019-07-08 14:25:46 -06002761 def testReadImage(self):
2762 """Test reading an image and accessing its FDT map"""
2763 self._CheckLz4()
2764 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002765 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002766 orig_image = control.images['image']
2767 image = Image.FromFile(image_fname)
2768 self.assertEqual(orig_image.GetEntries().keys(),
2769 image.GetEntries().keys())
2770
2771 orig_entry = orig_image.GetEntries()['fdtmap']
2772 entry = image.GetEntries()['fdtmap']
2773 self.assertEquals(orig_entry.offset, entry.offset)
2774 self.assertEquals(orig_entry.size, entry.size)
2775 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2776
2777 def testReadImageNoHeader(self):
2778 """Test accessing an image's FDT map without an image header"""
2779 self._CheckLz4()
2780 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002781 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002782 image = Image.FromFile(image_fname)
2783 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002784 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002785
2786 def testReadImageFail(self):
2787 """Test failing to read an image image's FDT map"""
2788 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002789 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002790 with self.assertRaises(ValueError) as e:
2791 image = Image.FromFile(image_fname)
2792 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002793
Simon Glassb2fd11d2019-07-08 14:25:48 -06002794 def testListCmd(self):
2795 """Test listing the files in an image using an Fdtmap"""
2796 self._CheckLz4()
2797 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2798
2799 # lz4 compression size differs depending on the version
2800 image = control.images['image']
2801 entries = image.GetEntries()
2802 section_size = entries['section'].size
2803 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2804 fdtmap_offset = entries['fdtmap'].offset
2805
Simon Glassb3d6fc72019-07-20 12:24:10 -06002806 try:
2807 tmpdir, updated_fname = self._SetupImageInTmpdir()
2808 with test_util.capture_sys_output() as (stdout, stderr):
2809 self._DoBinman('ls', '-i', updated_fname)
2810 finally:
2811 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002812 lines = stdout.getvalue().splitlines()
2813 expected = [
2814'Name Image-pos Size Entry-type Offset Uncomp-size',
2815'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002816'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002817' u-boot 0 4 u-boot 0',
2818' section 100 %x section 100' % section_size,
2819' cbfs 100 400 cbfs 0',
2820' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002821' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002822' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002823' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002824 (fdtmap_offset, fdtmap_offset),
2825' image-header bf8 8 image-header bf8',
2826 ]
2827 self.assertEqual(expected, lines)
2828
2829 def testListCmdFail(self):
2830 """Test failing to list an image"""
2831 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002832 try:
2833 tmpdir, updated_fname = self._SetupImageInTmpdir()
2834 with self.assertRaises(ValueError) as e:
2835 self._DoBinman('ls', '-i', updated_fname)
2836 finally:
2837 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002838 self.assertIn("Cannot find FDT map in image", str(e.exception))
2839
2840 def _RunListCmd(self, paths, expected):
2841 """List out entries and check the result
2842
2843 Args:
2844 paths: List of paths to pass to the list command
2845 expected: Expected list of filenames to be returned, in order
2846 """
2847 self._CheckLz4()
2848 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002849 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002850 image = Image.FromFile(image_fname)
2851 lines = image.GetListEntries(paths)[1]
2852 files = [line[0].strip() for line in lines[1:]]
2853 self.assertEqual(expected, files)
2854
2855 def testListCmdSection(self):
2856 """Test listing the files in a section"""
2857 self._RunListCmd(['section'],
2858 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2859
2860 def testListCmdFile(self):
2861 """Test listing a particular file"""
2862 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2863
2864 def testListCmdWildcard(self):
2865 """Test listing a wildcarded file"""
2866 self._RunListCmd(['*boot*'],
2867 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2868
2869 def testListCmdWildcardMulti(self):
2870 """Test listing a wildcarded file"""
2871 self._RunListCmd(['*cb*', '*head*'],
2872 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2873
2874 def testListCmdEmpty(self):
2875 """Test listing a wildcarded file"""
2876 self._RunListCmd(['nothing'], [])
2877
2878 def testListCmdPath(self):
2879 """Test listing the files in a sub-entry of a section"""
2880 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2881
Simon Glass4c613bf2019-07-08 14:25:50 -06002882 def _RunExtractCmd(self, entry_name, decomp=True):
2883 """Extract an entry from an image
2884
2885 Args:
2886 entry_name: Entry name to extract
2887 decomp: True to decompress the data if compressed, False to leave
2888 it in its raw uncompressed format
2889
2890 Returns:
2891 data from entry
2892 """
2893 self._CheckLz4()
2894 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002895 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002896 return control.ReadEntry(image_fname, entry_name, decomp)
2897
2898 def testExtractSimple(self):
2899 """Test extracting a single file"""
2900 data = self._RunExtractCmd('u-boot')
2901 self.assertEqual(U_BOOT_DATA, data)
2902
Simon Glass980a2842019-07-08 14:25:52 -06002903 def testExtractSection(self):
2904 """Test extracting the files in a section"""
2905 data = self._RunExtractCmd('section')
2906 cbfs_data = data[:0x400]
2907 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002908 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002909 dtb_data = data[0x400:]
2910 dtb = self._decompress(dtb_data)
2911 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2912
2913 def testExtractCompressed(self):
2914 """Test extracting compressed data"""
2915 data = self._RunExtractCmd('section/u-boot-dtb')
2916 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2917
2918 def testExtractRaw(self):
2919 """Test extracting compressed data without decompressing it"""
2920 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2921 dtb = self._decompress(data)
2922 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2923
2924 def testExtractCbfs(self):
2925 """Test extracting CBFS data"""
2926 data = self._RunExtractCmd('section/cbfs/u-boot')
2927 self.assertEqual(U_BOOT_DATA, data)
2928
2929 def testExtractCbfsCompressed(self):
2930 """Test extracting CBFS compressed data"""
2931 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2932 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2933
2934 def testExtractCbfsRaw(self):
2935 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002936 bintool = self.comp_bintools['lzma_alone']
2937 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06002938 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002939 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06002940 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2941
Simon Glass4c613bf2019-07-08 14:25:50 -06002942 def testExtractBadEntry(self):
2943 """Test extracting a bad section path"""
2944 with self.assertRaises(ValueError) as e:
2945 self._RunExtractCmd('section/does-not-exist')
2946 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2947 str(e.exception))
2948
2949 def testExtractMissingFile(self):
2950 """Test extracting file that does not exist"""
2951 with self.assertRaises(IOError) as e:
2952 control.ReadEntry('missing-file', 'name')
2953
2954 def testExtractBadFile(self):
2955 """Test extracting an invalid file"""
2956 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002957 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002958 with self.assertRaises(ValueError) as e:
2959 control.ReadEntry(fname, 'name')
2960
Simon Glass980a2842019-07-08 14:25:52 -06002961 def testExtractCmd(self):
2962 """Test extracting a file fron an image on the command line"""
2963 self._CheckLz4()
2964 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002965 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002966 try:
2967 tmpdir, updated_fname = self._SetupImageInTmpdir()
2968 with test_util.capture_sys_output() as (stdout, stderr):
2969 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2970 '-f', fname)
2971 finally:
2972 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07002973 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002974 self.assertEqual(U_BOOT_DATA, data)
2975
2976 def testExtractOneEntry(self):
2977 """Test extracting a single entry fron an image """
2978 self._CheckLz4()
2979 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002980 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002981 fname = os.path.join(self._indir, 'output.extact')
2982 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07002983 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002984 self.assertEqual(U_BOOT_DATA, data)
2985
2986 def _CheckExtractOutput(self, decomp):
2987 """Helper to test file output with and without decompression
2988
2989 Args:
2990 decomp: True to decompress entry data, False to output it raw
2991 """
2992 def _CheckPresent(entry_path, expect_data, expect_size=None):
2993 """Check and remove expected file
2994
2995 This checks the data/size of a file and removes the file both from
2996 the outfiles set and from the output directory. Once all files are
2997 processed, both the set and directory should be empty.
2998
2999 Args:
3000 entry_path: Entry path
3001 expect_data: Data to expect in file, or None to skip check
3002 expect_size: Size of data to expect in file, or None to skip
3003 """
3004 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07003005 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06003006 os.remove(path)
3007 if expect_data:
3008 self.assertEqual(expect_data, data)
3009 elif expect_size:
3010 self.assertEqual(expect_size, len(data))
3011 outfiles.remove(path)
3012
3013 def _CheckDirPresent(name):
3014 """Remove expected directory
3015
3016 This gives an error if the directory does not exist as expected
3017
3018 Args:
3019 name: Name of directory to remove
3020 """
3021 path = os.path.join(outdir, name)
3022 os.rmdir(path)
3023
3024 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003025 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003026 outdir = os.path.join(self._indir, 'extract')
3027 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3028
3029 # Create a set of all file that were output (should be 9)
3030 outfiles = set()
3031 for root, dirs, files in os.walk(outdir):
3032 outfiles |= set([os.path.join(root, fname) for fname in files])
3033 self.assertEqual(9, len(outfiles))
3034 self.assertEqual(9, len(einfos))
3035
3036 image = control.images['image']
3037 entries = image.GetEntries()
3038
3039 # Check the 9 files in various ways
3040 section = entries['section']
3041 section_entries = section.GetEntries()
3042 cbfs_entries = section_entries['cbfs'].GetEntries()
3043 _CheckPresent('u-boot', U_BOOT_DATA)
3044 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3045 dtb_len = EXTRACT_DTB_SIZE
3046 if not decomp:
3047 dtb_len = cbfs_entries['u-boot-dtb'].size
3048 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3049 if not decomp:
3050 dtb_len = section_entries['u-boot-dtb'].size
3051 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3052
3053 fdtmap = entries['fdtmap']
3054 _CheckPresent('fdtmap', fdtmap.data)
3055 hdr = entries['image-header']
3056 _CheckPresent('image-header', hdr.data)
3057
3058 _CheckPresent('section/root', section.data)
3059 cbfs = section_entries['cbfs']
3060 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003061 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003062 _CheckPresent('root', data)
3063
3064 # There should be no files left. Remove all the directories to check.
3065 # If there are any files/dirs remaining, one of these checks will fail.
3066 self.assertEqual(0, len(outfiles))
3067 _CheckDirPresent('section/cbfs')
3068 _CheckDirPresent('section')
3069 _CheckDirPresent('')
3070 self.assertFalse(os.path.exists(outdir))
3071
3072 def testExtractAllEntries(self):
3073 """Test extracting all entries"""
3074 self._CheckLz4()
3075 self._CheckExtractOutput(decomp=True)
3076
3077 def testExtractAllEntriesRaw(self):
3078 """Test extracting all entries without decompressing them"""
3079 self._CheckLz4()
3080 self._CheckExtractOutput(decomp=False)
3081
3082 def testExtractSelectedEntries(self):
3083 """Test extracting some entries"""
3084 self._CheckLz4()
3085 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003086 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003087 outdir = os.path.join(self._indir, 'extract')
3088 einfos = control.ExtractEntries(image_fname, None, outdir,
3089 ['*cb*', '*head*'])
3090
3091 # File output is tested by testExtractAllEntries(), so just check that
3092 # the expected entries are selected
3093 names = [einfo.name for einfo in einfos]
3094 self.assertEqual(names,
3095 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3096
3097 def testExtractNoEntryPaths(self):
3098 """Test extracting some entries"""
3099 self._CheckLz4()
3100 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003101 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003102 with self.assertRaises(ValueError) as e:
3103 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003104 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003105 str(e.exception))
3106
3107 def testExtractTooManyEntryPaths(self):
3108 """Test extracting some entries"""
3109 self._CheckLz4()
3110 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003111 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003112 with self.assertRaises(ValueError) as e:
3113 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003114 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003115 str(e.exception))
3116
Simon Glass52d06212019-07-08 14:25:53 -06003117 def testPackAlignSection(self):
3118 """Test that sections can have alignment"""
3119 self._DoReadFile('131_pack_align_section.dts')
3120
3121 self.assertIn('image', control.images)
3122 image = control.images['image']
3123 entries = image.GetEntries()
3124 self.assertEqual(3, len(entries))
3125
3126 # First u-boot
3127 self.assertIn('u-boot', entries)
3128 entry = entries['u-boot']
3129 self.assertEqual(0, entry.offset)
3130 self.assertEqual(0, entry.image_pos)
3131 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3132 self.assertEqual(len(U_BOOT_DATA), entry.size)
3133
3134 # Section0
3135 self.assertIn('section0', entries)
3136 section0 = entries['section0']
3137 self.assertEqual(0x10, section0.offset)
3138 self.assertEqual(0x10, section0.image_pos)
3139 self.assertEqual(len(U_BOOT_DATA), section0.size)
3140
3141 # Second u-boot
3142 section_entries = section0.GetEntries()
3143 self.assertIn('u-boot', section_entries)
3144 entry = section_entries['u-boot']
3145 self.assertEqual(0, entry.offset)
3146 self.assertEqual(0x10, entry.image_pos)
3147 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3148 self.assertEqual(len(U_BOOT_DATA), entry.size)
3149
3150 # Section1
3151 self.assertIn('section1', entries)
3152 section1 = entries['section1']
3153 self.assertEqual(0x14, section1.offset)
3154 self.assertEqual(0x14, section1.image_pos)
3155 self.assertEqual(0x20, section1.size)
3156
3157 # Second u-boot
3158 section_entries = section1.GetEntries()
3159 self.assertIn('u-boot', section_entries)
3160 entry = section_entries['u-boot']
3161 self.assertEqual(0, entry.offset)
3162 self.assertEqual(0x14, entry.image_pos)
3163 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3164 self.assertEqual(len(U_BOOT_DATA), entry.size)
3165
3166 # Section2
3167 self.assertIn('section2', section_entries)
3168 section2 = section_entries['section2']
3169 self.assertEqual(0x4, section2.offset)
3170 self.assertEqual(0x18, section2.image_pos)
3171 self.assertEqual(4, section2.size)
3172
3173 # Third u-boot
3174 section_entries = section2.GetEntries()
3175 self.assertIn('u-boot', section_entries)
3176 entry = section_entries['u-boot']
3177 self.assertEqual(0, entry.offset)
3178 self.assertEqual(0x18, entry.image_pos)
3179 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3180 self.assertEqual(len(U_BOOT_DATA), entry.size)
3181
Simon Glassf8a54bc2019-07-20 12:23:56 -06003182 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3183 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003184 """Replace an entry in an image
3185
3186 This writes the entry data to update it, then opens the updated file and
3187 returns the value that it now finds there.
3188
3189 Args:
3190 entry_name: Entry name to replace
3191 data: Data to replace it with
3192 decomp: True to compress the data if needed, False if data is
3193 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003194 allow_resize: True to allow entries to change size, False to raise
3195 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003196
3197 Returns:
3198 Tuple:
3199 data from entry
3200 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003201 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003202 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003203 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003204 update_dtb=True)[1]
3205
3206 self.assertIn('image', control.images)
3207 image = control.images['image']
3208 entries = image.GetEntries()
3209 orig_dtb_data = entries['u-boot-dtb'].data
3210 orig_fdtmap_data = entries['fdtmap'].data
3211
Simon Glass80025522022-01-29 14:14:04 -07003212 image_fname = tools.get_output_filename('image.bin')
3213 updated_fname = tools.get_output_filename('image-updated.bin')
3214 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003215 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3216 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003217 data = control.ReadEntry(updated_fname, entry_name, decomp)
3218
Simon Glassf8a54bc2019-07-20 12:23:56 -06003219 # The DT data should not change unless resized:
3220 if not allow_resize:
3221 new_dtb_data = entries['u-boot-dtb'].data
3222 self.assertEqual(new_dtb_data, orig_dtb_data)
3223 new_fdtmap_data = entries['fdtmap'].data
3224 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003225
Simon Glassf8a54bc2019-07-20 12:23:56 -06003226 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003227
3228 def testReplaceSimple(self):
3229 """Test replacing a single file"""
3230 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003231 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3232 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003233 self.assertEqual(expected, data)
3234
3235 # Test that the state looks right. There should be an FDT for the fdtmap
3236 # that we jsut read back in, and it should match what we find in the
3237 # 'control' tables. Checking for an FDT that does not exist should
3238 # return None.
3239 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003240 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003241 self.assertEqual(expected_fdtmap, fdtmap)
3242
3243 dtb = state.GetFdtForEtype('fdtmap')
3244 self.assertEqual(dtb.GetContents(), fdtmap)
3245
3246 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3247 self.assertIsNone(missing_path)
3248 self.assertIsNone(missing_fdtmap)
3249
3250 missing_dtb = state.GetFdtForEtype('missing')
3251 self.assertIsNone(missing_dtb)
3252
3253 self.assertEqual('/binman', state.fdt_path_prefix)
3254
3255 def testReplaceResizeFail(self):
3256 """Test replacing a file by something larger"""
3257 expected = U_BOOT_DATA + b'x'
3258 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003259 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3260 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003261 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3262 str(e.exception))
3263
3264 def testReplaceMulti(self):
3265 """Test replacing entry data where multiple images are generated"""
3266 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3267 update_dtb=True)[0]
3268 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003269 updated_fname = tools.get_output_filename('image-updated.bin')
3270 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003271 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003272 control.WriteEntry(updated_fname, entry_name, expected,
3273 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003274 data = control.ReadEntry(updated_fname, entry_name)
3275 self.assertEqual(expected, data)
3276
3277 # Check the state looks right.
3278 self.assertEqual('/binman/image', state.fdt_path_prefix)
3279
3280 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003281 image_fname = tools.get_output_filename('first-image.bin')
3282 updated_fname = tools.get_output_filename('first-updated.bin')
3283 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003284 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003285 control.WriteEntry(updated_fname, entry_name, expected,
3286 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003287 data = control.ReadEntry(updated_fname, entry_name)
3288 self.assertEqual(expected, data)
3289
3290 # Check the state looks right.
3291 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003292
Simon Glassfb30e292019-07-20 12:23:51 -06003293 def testUpdateFdtAllRepack(self):
3294 """Test that all device trees are updated with offset/size info"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003295 self._SetupSplElf()
3296 self._SetupTplElf()
Simon Glassfb30e292019-07-20 12:23:51 -06003297 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3298 SECTION_SIZE = 0x300
3299 DTB_SIZE = 602
3300 FDTMAP_SIZE = 608
3301 base_expected = {
3302 'offset': 0,
3303 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3304 'image-pos': 0,
3305 'section:offset': 0,
3306 'section:size': SECTION_SIZE,
3307 'section:image-pos': 0,
3308 'section/u-boot-dtb:offset': 4,
3309 'section/u-boot-dtb:size': 636,
3310 'section/u-boot-dtb:image-pos': 4,
3311 'u-boot-spl-dtb:offset': SECTION_SIZE,
3312 'u-boot-spl-dtb:size': DTB_SIZE,
3313 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3314 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3315 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3316 'u-boot-tpl-dtb:size': DTB_SIZE,
3317 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3318 'fdtmap:size': FDTMAP_SIZE,
3319 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3320 }
3321 main_expected = {
3322 'section:orig-size': SECTION_SIZE,
3323 'section/u-boot-dtb:orig-offset': 4,
3324 }
3325
3326 # We expect three device-tree files in the output, with the first one
3327 # within a fixed-size section.
3328 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3329 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3330 # main U-Boot tree. All three should have the same positions and offset
3331 # except that the main tree should include the main_expected properties
3332 start = 4
3333 for item in ['', 'spl', 'tpl', None]:
3334 if item is None:
3335 start += 16 # Move past fdtmap header
3336 dtb = fdt.Fdt.FromData(data[start:])
3337 dtb.Scan()
3338 props = self._GetPropTree(dtb,
3339 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3340 prefix='/' if item is None else '/binman/')
3341 expected = dict(base_expected)
3342 if item:
3343 expected[item] = 0
3344 else:
3345 # Main DTB and fdtdec should include the 'orig-' properties
3346 expected.update(main_expected)
3347 # Helpful for debugging:
3348 #for prop in sorted(props):
3349 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3350 self.assertEqual(expected, props)
3351 if item == '':
3352 start = SECTION_SIZE
3353 else:
3354 start += dtb._fdt_obj.totalsize()
3355
Simon Glass11453762019-07-20 12:23:55 -06003356 def testFdtmapHeaderMiddle(self):
3357 """Test an FDT map in the middle of an image when it should be at end"""
3358 with self.assertRaises(ValueError) as e:
3359 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3360 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3361 str(e.exception))
3362
3363 def testFdtmapHeaderStartBad(self):
3364 """Test an FDT map in middle of an image when it should be at start"""
3365 with self.assertRaises(ValueError) as e:
3366 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3367 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3368 str(e.exception))
3369
3370 def testFdtmapHeaderEndBad(self):
3371 """Test an FDT map at the start of an image when it should be at end"""
3372 with self.assertRaises(ValueError) as e:
3373 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3374 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3375 str(e.exception))
3376
3377 def testFdtmapHeaderNoSize(self):
3378 """Test an image header at the end of an image with undefined size"""
3379 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3380
Simon Glassf8a54bc2019-07-20 12:23:56 -06003381 def testReplaceResize(self):
3382 """Test replacing a single file in an entry with a larger file"""
3383 expected = U_BOOT_DATA + b'x'
3384 data, _, image = self._RunReplaceCmd('u-boot', expected,
3385 dts='139_replace_repack.dts')
3386 self.assertEqual(expected, data)
3387
3388 entries = image.GetEntries()
3389 dtb_data = entries['u-boot-dtb'].data
3390 dtb = fdt.Fdt.FromData(dtb_data)
3391 dtb.Scan()
3392
3393 # The u-boot section should now be larger in the dtb
3394 node = dtb.GetNode('/binman/u-boot')
3395 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3396
3397 # Same for the fdtmap
3398 fdata = entries['fdtmap'].data
3399 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3400 fdtb.Scan()
3401 fnode = fdtb.GetNode('/u-boot')
3402 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3403
3404 def testReplaceResizeNoRepack(self):
3405 """Test replacing an entry with a larger file when not allowed"""
3406 expected = U_BOOT_DATA + b'x'
3407 with self.assertRaises(ValueError) as e:
3408 self._RunReplaceCmd('u-boot', expected)
3409 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3410 str(e.exception))
3411
Simon Glass9d8ee322019-07-20 12:23:58 -06003412 def testEntryShrink(self):
3413 """Test contracting an entry after it is packed"""
3414 try:
3415 state.SetAllowEntryContraction(True)
3416 data = self._DoReadFileDtb('140_entry_shrink.dts',
3417 update_dtb=True)[0]
3418 finally:
3419 state.SetAllowEntryContraction(False)
3420 self.assertEqual(b'a', data[:1])
3421 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3422 self.assertEqual(b'a', data[-1:])
3423
3424 def testEntryShrinkFail(self):
3425 """Test not being allowed to contract an entry after it is packed"""
3426 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3427
3428 # In this case there is a spare byte at the end of the data. The size of
3429 # the contents is only 1 byte but we still have the size before it
3430 # shrunk.
3431 self.assertEqual(b'a\0', data[:2])
3432 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3433 self.assertEqual(b'a\0', data[-2:])
3434
Simon Glass70e32982019-07-20 12:24:01 -06003435 def testDescriptorOffset(self):
3436 """Test that the Intel descriptor is always placed at at the start"""
3437 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3438 image = control.images['image']
3439 entries = image.GetEntries()
3440 desc = entries['intel-descriptor']
3441 self.assertEqual(0xff800000, desc.offset);
3442 self.assertEqual(0xff800000, desc.image_pos);
3443
Simon Glass37fdd142019-07-20 12:24:06 -06003444 def testReplaceCbfs(self):
3445 """Test replacing a single file in CBFS without changing the size"""
3446 self._CheckLz4()
3447 expected = b'x' * len(U_BOOT_DATA)
3448 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003449 updated_fname = tools.get_output_filename('image-updated.bin')
3450 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003451 entry_name = 'section/cbfs/u-boot'
3452 control.WriteEntry(updated_fname, entry_name, expected,
3453 allow_resize=True)
3454 data = control.ReadEntry(updated_fname, entry_name)
3455 self.assertEqual(expected, data)
3456
3457 def testReplaceResizeCbfs(self):
3458 """Test replacing a single file in CBFS with one of a different size"""
3459 self._CheckLz4()
3460 expected = U_BOOT_DATA + b'x'
3461 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003462 updated_fname = tools.get_output_filename('image-updated.bin')
3463 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003464 entry_name = 'section/cbfs/u-boot'
3465 control.WriteEntry(updated_fname, entry_name, expected,
3466 allow_resize=True)
3467 data = control.ReadEntry(updated_fname, entry_name)
3468 self.assertEqual(expected, data)
3469
Simon Glass30033c22019-07-20 12:24:15 -06003470 def _SetupForReplace(self):
3471 """Set up some files to use to replace entries
3472
3473 This generates an image, copies it to a new file, extracts all the files
3474 in it and updates some of them
3475
3476 Returns:
3477 List
3478 Image filename
3479 Output directory
3480 Expected values for updated entries, each a string
3481 """
3482 data = self._DoReadFileRealDtb('143_replace_all.dts')
3483
Simon Glass80025522022-01-29 14:14:04 -07003484 updated_fname = tools.get_output_filename('image-updated.bin')
3485 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003486
3487 outdir = os.path.join(self._indir, 'extract')
3488 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3489
3490 expected1 = b'x' + U_BOOT_DATA + b'y'
3491 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003492 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003493
3494 expected2 = b'a' + U_BOOT_DATA + b'b'
3495 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003496 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003497
3498 expected_text = b'not the same text'
3499 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003500 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003501
3502 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3503 dtb = fdt.FdtScan(dtb_fname)
3504 node = dtb.GetNode('/binman/text')
3505 node.AddString('my-property', 'the value')
3506 dtb.Sync(auto_resize=True)
3507 dtb.Flush()
3508
3509 return updated_fname, outdir, expected1, expected2, expected_text
3510
3511 def _CheckReplaceMultiple(self, entry_paths):
3512 """Handle replacing the contents of multiple entries
3513
3514 Args:
3515 entry_paths: List of entry paths to replace
3516
3517 Returns:
3518 List
3519 Dict of entries in the image:
3520 key: Entry name
3521 Value: Entry object
3522 Expected values for updated entries, each a string
3523 """
3524 updated_fname, outdir, expected1, expected2, expected_text = (
3525 self._SetupForReplace())
3526 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3527
3528 image = Image.FromFile(updated_fname)
3529 image.LoadData()
3530 return image.GetEntries(), expected1, expected2, expected_text
3531
3532 def testReplaceAll(self):
3533 """Test replacing the contents of all entries"""
3534 entries, expected1, expected2, expected_text = (
3535 self._CheckReplaceMultiple([]))
3536 data = entries['u-boot'].data
3537 self.assertEqual(expected1, data)
3538
3539 data = entries['u-boot2'].data
3540 self.assertEqual(expected2, data)
3541
3542 data = entries['text'].data
3543 self.assertEqual(expected_text, data)
3544
3545 # Check that the device tree is updated
3546 data = entries['u-boot-dtb'].data
3547 dtb = fdt.Fdt.FromData(data)
3548 dtb.Scan()
3549 node = dtb.GetNode('/binman/text')
3550 self.assertEqual('the value', node.props['my-property'].value)
3551
3552 def testReplaceSome(self):
3553 """Test replacing the contents of a few entries"""
3554 entries, expected1, expected2, expected_text = (
3555 self._CheckReplaceMultiple(['u-boot2', 'text']))
3556
3557 # This one should not change
3558 data = entries['u-boot'].data
3559 self.assertEqual(U_BOOT_DATA, data)
3560
3561 data = entries['u-boot2'].data
3562 self.assertEqual(expected2, data)
3563
3564 data = entries['text'].data
3565 self.assertEqual(expected_text, data)
3566
3567 def testReplaceCmd(self):
3568 """Test replacing a file fron an image on the command line"""
3569 self._DoReadFileRealDtb('143_replace_all.dts')
3570
3571 try:
3572 tmpdir, updated_fname = self._SetupImageInTmpdir()
3573
3574 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3575 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003576 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003577
3578 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003579 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003580 self.assertEqual(expected, data[:len(expected)])
3581 map_fname = os.path.join(tmpdir, 'image-updated.map')
3582 self.assertFalse(os.path.exists(map_fname))
3583 finally:
3584 shutil.rmtree(tmpdir)
3585
3586 def testReplaceCmdSome(self):
3587 """Test replacing some files fron an image on the command line"""
3588 updated_fname, outdir, expected1, expected2, expected_text = (
3589 self._SetupForReplace())
3590
3591 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3592 'u-boot2', 'text')
3593
Simon Glass80025522022-01-29 14:14:04 -07003594 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003595 image = Image.FromFile(updated_fname)
3596 image.LoadData()
3597 entries = image.GetEntries()
3598
3599 # This one should not change
3600 data = entries['u-boot'].data
3601 self.assertEqual(U_BOOT_DATA, data)
3602
3603 data = entries['u-boot2'].data
3604 self.assertEqual(expected2, data)
3605
3606 data = entries['text'].data
3607 self.assertEqual(expected_text, data)
3608
3609 def testReplaceMissing(self):
3610 """Test replacing entries where the file is missing"""
3611 updated_fname, outdir, expected1, expected2, expected_text = (
3612 self._SetupForReplace())
3613
3614 # Remove one of the files, to generate a warning
3615 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3616 os.remove(u_boot_fname1)
3617
3618 with test_util.capture_sys_output() as (stdout, stderr):
3619 control.ReplaceEntries(updated_fname, None, outdir, [])
3620 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003621 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003622
3623 def testReplaceCmdMap(self):
3624 """Test replacing a file fron an image on the command line"""
3625 self._DoReadFileRealDtb('143_replace_all.dts')
3626
3627 try:
3628 tmpdir, updated_fname = self._SetupImageInTmpdir()
3629
3630 fname = os.path.join(self._indir, 'update-u-boot.bin')
3631 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003632 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003633
3634 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3635 '-f', fname, '-m')
3636 map_fname = os.path.join(tmpdir, 'image-updated.map')
3637 self.assertTrue(os.path.exists(map_fname))
3638 finally:
3639 shutil.rmtree(tmpdir)
3640
3641 def testReplaceNoEntryPaths(self):
3642 """Test replacing an entry without an entry path"""
3643 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003644 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003645 with self.assertRaises(ValueError) as e:
3646 control.ReplaceEntries(image_fname, 'fname', None, [])
3647 self.assertIn('Must specify an entry path to read with -f',
3648 str(e.exception))
3649
3650 def testReplaceTooManyEntryPaths(self):
3651 """Test extracting some entries"""
3652 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003653 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003654 with self.assertRaises(ValueError) as e:
3655 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3656 self.assertIn('Must specify exactly one entry path to write with -f',
3657 str(e.exception))
3658
Simon Glass0b074d62019-08-24 07:22:48 -06003659 def testPackReset16(self):
3660 """Test that an image with an x86 reset16 region can be created"""
3661 data = self._DoReadFile('144_x86_reset16.dts')
3662 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3663
3664 def testPackReset16Spl(self):
3665 """Test that an image with an x86 reset16-spl region can be created"""
3666 data = self._DoReadFile('145_x86_reset16_spl.dts')
3667 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3668
3669 def testPackReset16Tpl(self):
3670 """Test that an image with an x86 reset16-tpl region can be created"""
3671 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3672 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3673
Simon Glass232f90c2019-08-24 07:22:50 -06003674 def testPackIntelFit(self):
3675 """Test that an image with an Intel FIT and pointer can be created"""
3676 data = self._DoReadFile('147_intel_fit.dts')
3677 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3678 fit = data[16:32];
3679 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3680 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3681
3682 image = control.images['image']
3683 entries = image.GetEntries()
3684 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3685 self.assertEqual(expected_ptr, ptr)
3686
3687 def testPackIntelFitMissing(self):
3688 """Test detection of a FIT pointer with not FIT region"""
3689 with self.assertRaises(ValueError) as e:
3690 self._DoReadFile('148_intel_fit_missing.dts')
3691 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3692 str(e.exception))
3693
Simon Glass72555fa2019-11-06 17:22:44 -07003694 def _CheckSymbolsTplSection(self, dts, expected_vals):
3695 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003696 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003697 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003698 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003699 self.assertEqual(expected1, data[:upto1])
3700
3701 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003702 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003703 self.assertEqual(expected2, data[upto1:upto2])
3704
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003705 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003706 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003707 self.assertEqual(expected3, data[upto2:upto3])
3708
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003709 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003710 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3711
3712 def testSymbolsTplSection(self):
3713 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3714 self._SetupSplElf('u_boot_binman_syms')
3715 self._SetupTplElf('u_boot_binman_syms')
3716 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003717 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003718
3719 def testSymbolsTplSectionX86(self):
3720 """Test binman can assign symbols in a section with end-at-4gb"""
3721 self._SetupSplElf('u_boot_binman_syms_x86')
3722 self._SetupTplElf('u_boot_binman_syms_x86')
3723 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003724 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003725 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003726
Simon Glass98c59572019-08-24 07:23:03 -06003727 def testPackX86RomIfwiSectiom(self):
3728 """Test that a section can be placed in an IFWI region"""
3729 self._SetupIfwi('fitimage.bin')
3730 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3731 self._CheckIfwi(data)
3732
Simon Glassba7985d2019-08-24 07:23:07 -06003733 def testPackFspM(self):
3734 """Test that an image with a FSP memory-init binary can be created"""
3735 data = self._DoReadFile('152_intel_fsp_m.dts')
3736 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3737
Simon Glass4d9086d2019-10-20 21:31:35 -06003738 def testPackFspS(self):
3739 """Test that an image with a FSP silicon-init binary can be created"""
3740 data = self._DoReadFile('153_intel_fsp_s.dts')
3741 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003742
Simon Glass9ea87b22019-10-20 21:31:36 -06003743 def testPackFspT(self):
3744 """Test that an image with a FSP temp-ram-init binary can be created"""
3745 data = self._DoReadFile('154_intel_fsp_t.dts')
3746 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3747
Simon Glass48f3aad2020-07-09 18:39:31 -06003748 def testMkimage(self):
3749 """Test using mkimage to build an image"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003750 self._SetupSplElf()
Simon Glass48f3aad2020-07-09 18:39:31 -06003751 data = self._DoReadFile('156_mkimage.dts')
3752
3753 # Just check that the data appears in the file somewhere
3754 self.assertIn(U_BOOT_SPL_DATA, data)
3755
Simon Glass66152ce2022-01-09 20:14:09 -07003756 def testMkimageMissing(self):
3757 """Test that binman still produces an image if mkimage is missing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003758 self._SetupSplElf()
Simon Glass66152ce2022-01-09 20:14:09 -07003759 with test_util.capture_sys_output() as (_, stderr):
3760 self._DoTestFile('156_mkimage.dts',
3761 force_missing_bintools='mkimage')
3762 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003763 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003764
Simon Glass5e560182020-07-09 18:39:36 -06003765 def testExtblob(self):
3766 """Test an image with an external blob"""
3767 data = self._DoReadFile('157_blob_ext.dts')
3768 self.assertEqual(REFCODE_DATA, data)
3769
3770 def testExtblobMissing(self):
3771 """Test an image with a missing external blob"""
3772 with self.assertRaises(ValueError) as e:
3773 self._DoReadFile('158_blob_ext_missing.dts')
3774 self.assertIn("Filename 'missing-file' not found in input path",
3775 str(e.exception))
3776
Simon Glass5d94cc62020-07-09 18:39:38 -06003777 def testExtblobMissingOk(self):
3778 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003779 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003780 ret = self._DoTestFile('158_blob_ext_missing.dts',
3781 allow_missing=True)
3782 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003783 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003784 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003785 self.assertIn('Some images are invalid', err)
3786
3787 def testExtblobMissingOkFlag(self):
3788 """Test an image with an missing external blob allowed with -W"""
3789 with test_util.capture_sys_output() as (stdout, stderr):
3790 ret = self._DoTestFile('158_blob_ext_missing.dts',
3791 allow_missing=True, ignore_missing=True)
3792 self.assertEqual(0, ret)
3793 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003794 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003795 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003796
3797 def testExtblobMissingOkSect(self):
3798 """Test an image with an missing external blob that is allowed"""
3799 with test_util.capture_sys_output() as (stdout, stderr):
3800 self._DoTestFile('159_blob_ext_missing_sect.dts',
3801 allow_missing=True)
3802 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003803 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003804
Simon Glasse88cef92020-07-09 18:39:41 -06003805 def testPackX86RomMeMissingDesc(self):
3806 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003807 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003808 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003809 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003810 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003811
3812 def testPackX86RomMissingIfwi(self):
3813 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3814 self._SetupIfwi('fitimage.bin')
3815 pathname = os.path.join(self._indir, 'fitimage.bin')
3816 os.remove(pathname)
3817 with test_util.capture_sys_output() as (stdout, stderr):
3818 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3819 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003820 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003821
Simon Glass2a0fa982022-02-11 13:23:21 -07003822 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003823 """Test that zero-size overlapping regions are ignored"""
3824 self._DoTestFile('160_pack_overlap_zero.dts')
3825
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003826 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003827 # The data should be inside the FIT
3828 dtb = fdt.Fdt.FromData(fit_data)
3829 dtb.Scan()
3830 fnode = dtb.GetNode('/images/kernel')
3831 self.assertIn('data', fnode.props)
3832
3833 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003834 tools.write_file(fname, fit_data)
3835 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003836
3837 # Check a few features to make sure the plumbing works. We don't need
3838 # to test the operation of mkimage or dumpimage here. First convert the
3839 # output into a dict where the keys are the fields printed by dumpimage
3840 # and the values are a list of values for each field
3841 lines = out.splitlines()
3842
3843 # Converts "Compression: gzip compressed" into two groups:
3844 # 'Compression' and 'gzip compressed'
3845 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3846 vals = collections.defaultdict(list)
3847 for line in lines:
3848 mat = re_line.match(line)
3849 vals[mat.group(1)].append(mat.group(2))
3850
3851 self.assertEquals('FIT description: test-desc', lines[0])
3852 self.assertIn('Created:', lines[1])
3853 self.assertIn('Image 0 (kernel)', vals)
3854 self.assertIn('Hash value', vals)
3855 data_sizes = vals.get('Data Size')
3856 self.assertIsNotNone(data_sizes)
3857 self.assertEqual(2, len(data_sizes))
3858 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003859 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3860 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3861
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003862 # Check if entry listing correctly omits /images/
3863 image = control.images['image']
3864 fit_entry = image.GetEntries()['fit']
3865 subentries = list(fit_entry.GetEntries().keys())
3866 expected = ['kernel', 'fdt-1']
3867 self.assertEqual(expected, subentries)
3868
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003869 def testSimpleFit(self):
3870 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06003871 self._SetupSplElf()
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003872 data = self._DoReadFile('161_fit.dts')
3873 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3874 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3875 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3876
3877 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3878
3879 def testSimpleFitExpandsSubentries(self):
3880 """Test that FIT images expand their subentries"""
3881 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3882 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3883 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3884 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3885
3886 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003887
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003888 def testSimpleFitImagePos(self):
3889 """Test that we have correct image-pos for FIT subentries"""
3890 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3891 update_dtb=True)
3892 dtb = fdt.Fdt(out_dtb_fname)
3893 dtb.Scan()
3894 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3895
Simon Glassb7bad182022-03-05 20:19:01 -07003896 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003897 self.assertEqual({
3898 'image-pos': 0,
3899 'offset': 0,
3900 'size': 1890,
3901
3902 'u-boot:image-pos': 0,
3903 'u-boot:offset': 0,
3904 'u-boot:size': 4,
3905
3906 'fit:image-pos': 4,
3907 'fit:offset': 4,
3908 'fit:size': 1840,
3909
Simon Glassb7bad182022-03-05 20:19:01 -07003910 'fit/images/kernel:image-pos': 304,
3911 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003912 'fit/images/kernel:size': 4,
3913
Simon Glassb7bad182022-03-05 20:19:01 -07003914 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003915 'fit/images/kernel/u-boot:offset': 0,
3916 'fit/images/kernel/u-boot:size': 4,
3917
Simon Glassb7bad182022-03-05 20:19:01 -07003918 'fit/images/fdt-1:image-pos': 552,
3919 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003920 'fit/images/fdt-1:size': 6,
3921
Simon Glassb7bad182022-03-05 20:19:01 -07003922 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003923 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3924 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3925
3926 'u-boot-nodtb:image-pos': 1844,
3927 'u-boot-nodtb:offset': 1844,
3928 'u-boot-nodtb:size': 46,
3929 }, props)
3930
3931 # Actually check the data is where we think it is
3932 for node, expected in [
3933 ("u-boot", U_BOOT_DATA),
3934 ("fit/images/kernel", U_BOOT_DATA),
3935 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3936 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3937 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3938 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3939 ]:
3940 image_pos = props[f"{node}:image-pos"]
3941 size = props[f"{node}:size"]
3942 self.assertEqual(len(expected), size)
3943 self.assertEqual(expected, data[image_pos:image_pos+size])
3944
Simon Glass45d556d2020-07-09 18:39:45 -06003945 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003946 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003947 data = self._DoReadFile('162_fit_external.dts')
3948 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3949
Simon Glass7932c882022-01-09 20:13:39 -07003950 # Size of the external-data region as set up by mkimage
3951 external_data_size = len(U_BOOT_DATA) + 2
3952 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003953 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003954 len(U_BOOT_NODTB_DATA))
3955
Simon Glass45d556d2020-07-09 18:39:45 -06003956 # The data should be outside the FIT
3957 dtb = fdt.Fdt.FromData(fit_data)
3958 dtb.Scan()
3959 fnode = dtb.GetNode('/images/kernel')
3960 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003961 self.assertEqual(len(U_BOOT_DATA),
3962 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3963 fit_pos = 0x400;
3964 self.assertEqual(
3965 fit_pos,
3966 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3967
3968 self.assertEquals(expected_size, len(data))
3969 actual_pos = len(U_BOOT_DATA) + fit_pos
3970 self.assertEqual(U_BOOT_DATA + b'aa',
3971 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003972
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003973 def testFitExternalImagePos(self):
3974 """Test that we have correct image-pos for external FIT subentries"""
3975 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3976 update_dtb=True)
3977 dtb = fdt.Fdt(out_dtb_fname)
3978 dtb.Scan()
3979 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3980
3981 self.assertEqual({
3982 'image-pos': 0,
3983 'offset': 0,
3984 'size': 1082,
3985
3986 'u-boot:image-pos': 0,
3987 'u-boot:offset': 0,
3988 'u-boot:size': 4,
3989
3990 'fit:size': 1032,
3991 'fit:offset': 4,
3992 'fit:image-pos': 4,
3993
3994 'fit/images/kernel:size': 4,
3995 'fit/images/kernel:offset': 1024,
3996 'fit/images/kernel:image-pos': 1028,
3997
3998 'fit/images/kernel/u-boot:size': 4,
3999 'fit/images/kernel/u-boot:offset': 0,
4000 'fit/images/kernel/u-boot:image-pos': 1028,
4001
4002 'fit/images/fdt-1:size': 2,
4003 'fit/images/fdt-1:offset': 1028,
4004 'fit/images/fdt-1:image-pos': 1032,
4005
4006 'fit/images/fdt-1/_testing:size': 2,
4007 'fit/images/fdt-1/_testing:offset': 0,
4008 'fit/images/fdt-1/_testing:image-pos': 1032,
4009
4010 'u-boot-nodtb:image-pos': 1036,
4011 'u-boot-nodtb:offset': 1036,
4012 'u-boot-nodtb:size': 46,
4013 }, props)
4014
4015 # Actually check the data is where we think it is
4016 for node, expected in [
4017 ("u-boot", U_BOOT_DATA),
4018 ("fit/images/kernel", U_BOOT_DATA),
4019 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4020 ("fit/images/fdt-1", b'aa'),
4021 ("fit/images/fdt-1/_testing", b'aa'),
4022 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4023 ]:
4024 image_pos = props[f"{node}:image-pos"]
4025 size = props[f"{node}:size"]
4026 self.assertEqual(len(expected), size)
4027 self.assertEqual(expected, data[image_pos:image_pos+size])
4028
Simon Glass66152ce2022-01-09 20:14:09 -07004029 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004030 """Test that binman complains if mkimage is missing"""
4031 with self.assertRaises(ValueError) as e:
4032 self._DoTestFile('162_fit_external.dts',
4033 force_missing_bintools='mkimage')
4034 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4035 str(e.exception))
4036
4037 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004038 """Test that binman still produces a FIT image if mkimage is missing"""
4039 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004040 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004041 force_missing_bintools='mkimage')
4042 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004043 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004044
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004045 def testSectionIgnoreHashSignature(self):
4046 """Test that sections ignore hash, signature nodes for its data"""
4047 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4048 expected = (U_BOOT_DATA + U_BOOT_DATA)
4049 self.assertEqual(expected, data)
4050
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004051 def testPadInSections(self):
4052 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004053 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4054 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004055 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4056 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004057 U_BOOT_DATA)
4058 self.assertEqual(expected, data)
4059
Simon Glassd12599d2020-10-26 17:40:09 -06004060 dtb = fdt.Fdt(out_dtb_fname)
4061 dtb.Scan()
4062 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4063 expected = {
4064 'image-pos': 0,
4065 'offset': 0,
4066 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4067
4068 'section:image-pos': 0,
4069 'section:offset': 0,
4070 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4071
4072 'section/before:image-pos': 0,
4073 'section/before:offset': 0,
4074 'section/before:size': len(U_BOOT_DATA),
4075
4076 'section/u-boot:image-pos': 4,
4077 'section/u-boot:offset': 4,
4078 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4079
4080 'section/after:image-pos': 26,
4081 'section/after:offset': 26,
4082 'section/after:size': len(U_BOOT_DATA),
4083 }
4084 self.assertEqual(expected, props)
4085
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004086 def testFitImageSubentryAlignment(self):
4087 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004088 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004089 entry_args = {
4090 'test-id': TEXT_DATA,
4091 }
4092 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4093 entry_args=entry_args)
4094 dtb = fdt.Fdt.FromData(data)
4095 dtb.Scan()
4096
4097 node = dtb.GetNode('/images/kernel')
4098 data = dtb.GetProps(node)["data"].bytes
4099 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004100 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4101 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004102 self.assertEqual(expected, data)
4103
4104 node = dtb.GetNode('/images/fdt-1')
4105 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004106 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4107 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004108 U_BOOT_DTB_DATA)
4109 self.assertEqual(expected, data)
4110
4111 def testFitExtblobMissingOk(self):
4112 """Test a FIT with a missing external blob that is allowed"""
4113 with test_util.capture_sys_output() as (stdout, stderr):
4114 self._DoTestFile('168_fit_missing_blob.dts',
4115 allow_missing=True)
4116 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004117 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004118
Simon Glass21db0ff2020-09-01 05:13:54 -06004119 def testBlobNamedByArgMissing(self):
4120 """Test handling of a missing entry arg"""
4121 with self.assertRaises(ValueError) as e:
4122 self._DoReadFile('068_blob_named_by_arg.dts')
4123 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4124 str(e.exception))
4125
Simon Glass559c4de2020-09-01 05:13:58 -06004126 def testPackBl31(self):
4127 """Test that an image with an ATF BL31 binary can be created"""
4128 data = self._DoReadFile('169_atf_bl31.dts')
4129 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4130
Samuel Holland9d8cc632020-10-21 21:12:15 -05004131 def testPackScp(self):
4132 """Test that an image with an SCP binary can be created"""
4133 data = self._DoReadFile('172_scp.dts')
4134 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4135
Simon Glassa435cd12020-09-01 05:13:59 -06004136 def testFitFdt(self):
4137 """Test an image with an FIT with multiple FDT images"""
4138 def _CheckFdt(seq, expected_data):
4139 """Check the FDT nodes
4140
4141 Args:
4142 seq: Sequence number to check (0 or 1)
4143 expected_data: Expected contents of 'data' property
4144 """
4145 name = 'fdt-%d' % seq
4146 fnode = dtb.GetNode('/images/%s' % name)
4147 self.assertIsNotNone(fnode)
4148 self.assertEqual({'description','type', 'compression', 'data'},
4149 set(fnode.props.keys()))
4150 self.assertEqual(expected_data, fnode.props['data'].bytes)
4151 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4152 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004153 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004154
4155 def _CheckConfig(seq, expected_data):
4156 """Check the configuration nodes
4157
4158 Args:
4159 seq: Sequence number to check (0 or 1)
4160 expected_data: Expected contents of 'data' property
4161 """
4162 cnode = dtb.GetNode('/configurations')
4163 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004164 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004165
4166 name = 'config-%d' % seq
4167 fnode = dtb.GetNode('/configurations/%s' % name)
4168 self.assertIsNotNone(fnode)
4169 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4170 set(fnode.props.keys()))
4171 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4172 fnode.props['description'].value)
4173 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4174
4175 entry_args = {
4176 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004177 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004178 }
4179 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004180 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004181 entry_args=entry_args,
4182 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4183 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4184 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4185
4186 dtb = fdt.Fdt.FromData(fit_data)
4187 dtb.Scan()
4188 fnode = dtb.GetNode('/images/kernel')
4189 self.assertIn('data', fnode.props)
4190
4191 # Check all the properties in fdt-1 and fdt-2
4192 _CheckFdt(1, TEST_FDT1_DATA)
4193 _CheckFdt(2, TEST_FDT2_DATA)
4194
4195 # Check configurations
4196 _CheckConfig(1, TEST_FDT1_DATA)
4197 _CheckConfig(2, TEST_FDT2_DATA)
4198
4199 def testFitFdtMissingList(self):
4200 """Test handling of a missing 'of-list' entry arg"""
4201 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004202 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004203 self.assertIn("Generator node requires 'of-list' entry argument",
4204 str(e.exception))
4205
4206 def testFitFdtEmptyList(self):
4207 """Test handling of an empty 'of-list' entry arg"""
4208 entry_args = {
4209 'of-list': '',
4210 }
4211 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4212
4213 def testFitFdtMissingProp(self):
4214 """Test handling of a missing 'fit,fdt-list' property"""
4215 with self.assertRaises(ValueError) as e:
4216 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4217 self.assertIn("Generator node requires 'fit,fdt-list' property",
4218 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004219
Simon Glass1032acc2020-09-06 10:39:08 -06004220 def testFitFdtMissing(self):
4221 """Test handling of a missing 'default-dt' entry arg"""
4222 entry_args = {
4223 'of-list': 'test-fdt1 test-fdt2',
4224 }
4225 with self.assertRaises(ValueError) as e:
4226 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004227 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004228 entry_args=entry_args,
4229 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4230 self.assertIn("Generated 'default' node requires default-dt entry argument",
4231 str(e.exception))
4232
4233 def testFitFdtNotInList(self):
4234 """Test handling of a default-dt that is not in the of-list"""
4235 entry_args = {
4236 'of-list': 'test-fdt1 test-fdt2',
4237 'default-dt': 'test-fdt3',
4238 }
4239 with self.assertRaises(ValueError) as e:
4240 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004241 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004242 entry_args=entry_args,
4243 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4244 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4245 str(e.exception))
4246
Simon Glassa820af72020-09-06 10:39:09 -06004247 def testFitExtblobMissingHelp(self):
4248 """Test display of help messages when an external blob is missing"""
4249 control.missing_blob_help = control._ReadMissingBlobHelp()
4250 control.missing_blob_help['wibble'] = 'Wibble test'
4251 control.missing_blob_help['another'] = 'Another test'
4252 with test_util.capture_sys_output() as (stdout, stderr):
4253 self._DoTestFile('168_fit_missing_blob.dts',
4254 allow_missing=True)
4255 err = stderr.getvalue()
4256
4257 # We can get the tag from the name, the type or the missing-msg
4258 # property. Check all three.
4259 self.assertIn('You may need to build ARM Trusted', err)
4260 self.assertIn('Wibble test', err)
4261 self.assertIn('Another test', err)
4262
Simon Glass6f1f4d42020-09-06 10:35:32 -06004263 def testMissingBlob(self):
4264 """Test handling of a blob containing a missing file"""
4265 with self.assertRaises(ValueError) as e:
4266 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4267 self.assertIn("Filename 'missing' not found in input path",
4268 str(e.exception))
4269
Simon Glassa0729502020-09-06 10:35:33 -06004270 def testEnvironment(self):
4271 """Test adding a U-Boot environment"""
4272 data = self._DoReadFile('174_env.dts')
4273 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4274 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4275 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4276 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4277 env)
4278
4279 def testEnvironmentNoSize(self):
4280 """Test that a missing 'size' property is detected"""
4281 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004282 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004283 self.assertIn("'u-boot-env' entry must have a size property",
4284 str(e.exception))
4285
4286 def testEnvironmentTooSmall(self):
4287 """Test handling of an environment that does not fit"""
4288 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004289 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004290
4291 # checksum, start byte, environment with \0 terminator, final \0
4292 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4293 short = need - 0x8
4294 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4295 str(e.exception))
4296
Simon Glassd1fdf752020-10-26 17:40:01 -06004297 def testSkipAtStart(self):
4298 """Test handling of skip-at-start section"""
4299 data = self._DoReadFile('177_skip_at_start.dts')
4300 self.assertEqual(U_BOOT_DATA, data)
4301
4302 image = control.images['image']
4303 entries = image.GetEntries()
4304 section = entries['section']
4305 self.assertEqual(0, section.offset)
4306 self.assertEqual(len(U_BOOT_DATA), section.size)
4307 self.assertEqual(U_BOOT_DATA, section.GetData())
4308
4309 entry = section.GetEntries()['u-boot']
4310 self.assertEqual(16, entry.offset)
4311 self.assertEqual(len(U_BOOT_DATA), entry.size)
4312 self.assertEqual(U_BOOT_DATA, entry.data)
4313
4314 def testSkipAtStartPad(self):
4315 """Test handling of skip-at-start section with padded entry"""
4316 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004317 before = tools.get_bytes(0, 8)
4318 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004319 all = before + U_BOOT_DATA + after
4320 self.assertEqual(all, data)
4321
4322 image = control.images['image']
4323 entries = image.GetEntries()
4324 section = entries['section']
4325 self.assertEqual(0, section.offset)
4326 self.assertEqual(len(all), section.size)
4327 self.assertEqual(all, section.GetData())
4328
4329 entry = section.GetEntries()['u-boot']
4330 self.assertEqual(16, entry.offset)
4331 self.assertEqual(len(all), entry.size)
4332 self.assertEqual(U_BOOT_DATA, entry.data)
4333
4334 def testSkipAtStartSectionPad(self):
4335 """Test handling of skip-at-start section with padding"""
4336 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004337 before = tools.get_bytes(0, 8)
4338 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004339 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004340 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004341
4342 image = control.images['image']
4343 entries = image.GetEntries()
4344 section = entries['section']
4345 self.assertEqual(0, section.offset)
4346 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004347 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004348 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004349
4350 entry = section.GetEntries()['u-boot']
4351 self.assertEqual(16, entry.offset)
4352 self.assertEqual(len(U_BOOT_DATA), entry.size)
4353 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004354
Simon Glassbb395742020-10-26 17:40:14 -06004355 def testSectionPad(self):
4356 """Testing padding with sections"""
4357 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004358 expected = (tools.get_bytes(ord('&'), 3) +
4359 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004360 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004361 tools.get_bytes(ord('!'), 1) +
4362 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004363 self.assertEqual(expected, data)
4364
4365 def testSectionAlign(self):
4366 """Testing alignment with sections"""
4367 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4368 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004369 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004370 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004371 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004372 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004373 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4374 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004375 self.assertEqual(expected, data)
4376
Simon Glassd92c8362020-10-26 17:40:25 -06004377 def testCompressImage(self):
4378 """Test compression of the entire image"""
4379 self._CheckLz4()
4380 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4381 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4382 dtb = fdt.Fdt(out_dtb_fname)
4383 dtb.Scan()
4384 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4385 'uncomp-size'])
4386 orig = self._decompress(data)
4387 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4388
4389 # Do a sanity check on various fields
4390 image = control.images['image']
4391 entries = image.GetEntries()
4392 self.assertEqual(2, len(entries))
4393
4394 entry = entries['blob']
4395 self.assertEqual(COMPRESS_DATA, entry.data)
4396 self.assertEqual(len(COMPRESS_DATA), entry.size)
4397
4398 entry = entries['u-boot']
4399 self.assertEqual(U_BOOT_DATA, entry.data)
4400 self.assertEqual(len(U_BOOT_DATA), entry.size)
4401
4402 self.assertEqual(len(data), image.size)
4403 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4404 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4405 orig = self._decompress(image.data)
4406 self.assertEqual(orig, image.uncomp_data)
4407
4408 expected = {
4409 'blob:offset': 0,
4410 'blob:size': len(COMPRESS_DATA),
4411 'u-boot:offset': len(COMPRESS_DATA),
4412 'u-boot:size': len(U_BOOT_DATA),
4413 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4414 'offset': 0,
4415 'image-pos': 0,
4416 'size': len(data),
4417 }
4418 self.assertEqual(expected, props)
4419
4420 def testCompressImageLess(self):
4421 """Test compression where compression reduces the image size"""
4422 self._CheckLz4()
4423 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4424 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4425 dtb = fdt.Fdt(out_dtb_fname)
4426 dtb.Scan()
4427 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4428 'uncomp-size'])
4429 orig = self._decompress(data)
4430
4431 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4432
4433 # Do a sanity check on various fields
4434 image = control.images['image']
4435 entries = image.GetEntries()
4436 self.assertEqual(2, len(entries))
4437
4438 entry = entries['blob']
4439 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4440 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4441
4442 entry = entries['u-boot']
4443 self.assertEqual(U_BOOT_DATA, entry.data)
4444 self.assertEqual(len(U_BOOT_DATA), entry.size)
4445
4446 self.assertEqual(len(data), image.size)
4447 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4448 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4449 image.uncomp_size)
4450 orig = self._decompress(image.data)
4451 self.assertEqual(orig, image.uncomp_data)
4452
4453 expected = {
4454 'blob:offset': 0,
4455 'blob:size': len(COMPRESS_DATA_BIG),
4456 'u-boot:offset': len(COMPRESS_DATA_BIG),
4457 'u-boot:size': len(U_BOOT_DATA),
4458 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4459 'offset': 0,
4460 'image-pos': 0,
4461 'size': len(data),
4462 }
4463 self.assertEqual(expected, props)
4464
4465 def testCompressSectionSize(self):
4466 """Test compression of a section with a fixed size"""
4467 self._CheckLz4()
4468 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4469 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4470 dtb = fdt.Fdt(out_dtb_fname)
4471 dtb.Scan()
4472 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4473 'uncomp-size'])
4474 orig = self._decompress(data)
4475 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4476 expected = {
4477 'section/blob:offset': 0,
4478 'section/blob:size': len(COMPRESS_DATA),
4479 'section/u-boot:offset': len(COMPRESS_DATA),
4480 'section/u-boot:size': len(U_BOOT_DATA),
4481 'section:offset': 0,
4482 'section:image-pos': 0,
4483 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4484 'section:size': 0x30,
4485 'offset': 0,
4486 'image-pos': 0,
4487 'size': 0x30,
4488 }
4489 self.assertEqual(expected, props)
4490
4491 def testCompressSection(self):
4492 """Test compression of a section with no fixed size"""
4493 self._CheckLz4()
4494 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4495 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4496 dtb = fdt.Fdt(out_dtb_fname)
4497 dtb.Scan()
4498 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4499 'uncomp-size'])
4500 orig = self._decompress(data)
4501 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4502 expected = {
4503 'section/blob:offset': 0,
4504 'section/blob:size': len(COMPRESS_DATA),
4505 'section/u-boot:offset': len(COMPRESS_DATA),
4506 'section/u-boot:size': len(U_BOOT_DATA),
4507 'section:offset': 0,
4508 'section:image-pos': 0,
4509 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4510 'section:size': len(data),
4511 'offset': 0,
4512 'image-pos': 0,
4513 'size': len(data),
4514 }
4515 self.assertEqual(expected, props)
4516
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004517 def testLz4Missing(self):
4518 """Test that binman still produces an image if lz4 is missing"""
4519 with test_util.capture_sys_output() as (_, stderr):
4520 self._DoTestFile('185_compress_section.dts',
4521 force_missing_bintools='lz4')
4522 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004523 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004524
Simon Glassd92c8362020-10-26 17:40:25 -06004525 def testCompressExtra(self):
4526 """Test compression of a section with no fixed size"""
4527 self._CheckLz4()
4528 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4529 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4530 dtb = fdt.Fdt(out_dtb_fname)
4531 dtb.Scan()
4532 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4533 'uncomp-size'])
4534
4535 base = data[len(U_BOOT_DATA):]
4536 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4537 rest = base[len(U_BOOT_DATA):]
4538
4539 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004540 bintool = self.comp_bintools['lz4']
4541 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004542 data1 = rest[:len(expect1)]
4543 section1 = self._decompress(data1)
4544 self.assertEquals(expect1, data1)
Simon Glassd92c8362020-10-26 17:40:25 -06004545 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4546 rest1 = rest[len(expect1):]
4547
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004548 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004549 data2 = rest1[:len(expect2)]
4550 section2 = self._decompress(data2)
4551 self.assertEquals(expect2, data2)
Simon Glassd92c8362020-10-26 17:40:25 -06004552 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4553 rest2 = rest1[len(expect2):]
4554
4555 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4556 len(expect2) + len(U_BOOT_DATA))
4557 #self.assertEquals(expect_size, len(data))
4558
4559 #self.assertEquals(U_BOOT_DATA, rest2)
4560
4561 self.maxDiff = None
4562 expected = {
4563 'u-boot:offset': 0,
4564 'u-boot:image-pos': 0,
4565 'u-boot:size': len(U_BOOT_DATA),
4566
4567 'base:offset': len(U_BOOT_DATA),
4568 'base:image-pos': len(U_BOOT_DATA),
4569 'base:size': len(data) - len(U_BOOT_DATA),
4570 'base/u-boot:offset': 0,
4571 'base/u-boot:image-pos': len(U_BOOT_DATA),
4572 'base/u-boot:size': len(U_BOOT_DATA),
4573 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4574 len(expect2),
4575 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4576 len(expect2),
4577 'base/u-boot2:size': len(U_BOOT_DATA),
4578
4579 'base/section:offset': len(U_BOOT_DATA),
4580 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4581 'base/section:size': len(expect1),
4582 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4583 'base/section/blob:offset': 0,
4584 'base/section/blob:size': len(COMPRESS_DATA),
4585 'base/section/u-boot:offset': len(COMPRESS_DATA),
4586 'base/section/u-boot:size': len(U_BOOT_DATA),
4587
4588 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4589 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4590 'base/section2:size': len(expect2),
4591 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4592 'base/section2/blob:offset': 0,
4593 'base/section2/blob:size': len(COMPRESS_DATA),
4594 'base/section2/blob2:offset': len(COMPRESS_DATA),
4595 'base/section2/blob2:size': len(COMPRESS_DATA),
4596
4597 'offset': 0,
4598 'image-pos': 0,
4599 'size': len(data),
4600 }
4601 self.assertEqual(expected, props)
4602
Simon Glassecbe4732021-01-06 21:35:15 -07004603 def testSymbolsSubsection(self):
4604 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004605 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004606
Simon Glass3fb25402021-01-06 21:35:16 -07004607 def testReadImageEntryArg(self):
4608 """Test reading an image that would need an entry arg to generate"""
4609 entry_args = {
4610 'cros-ec-rw-path': 'ecrw.bin',
4611 }
4612 data = self.data = self._DoReadFileDtb(
4613 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4614 entry_args=entry_args)
4615
Simon Glass80025522022-01-29 14:14:04 -07004616 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004617 orig_image = control.images['image']
4618
4619 # This should not generate an error about the missing 'cros-ec-rw-path'
4620 # since we are reading the image from a file. Compare with
4621 # testEntryArgsRequired()
4622 image = Image.FromFile(image_fname)
4623 self.assertEqual(orig_image.GetEntries().keys(),
4624 image.GetEntries().keys())
4625
Simon Glassa2af7302021-01-06 21:35:18 -07004626 def testFilesAlign(self):
4627 """Test alignment with files"""
4628 data = self._DoReadFile('190_files_align.dts')
4629
4630 # The first string is 15 bytes so will align to 16
4631 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4632 self.assertEqual(expect, data)
4633
Simon Glassdb84b562021-01-06 21:35:19 -07004634 def testReadImageSkip(self):
4635 """Test reading an image and accessing its FDT map"""
4636 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004637 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004638 orig_image = control.images['image']
4639 image = Image.FromFile(image_fname)
4640 self.assertEqual(orig_image.GetEntries().keys(),
4641 image.GetEntries().keys())
4642
4643 orig_entry = orig_image.GetEntries()['fdtmap']
4644 entry = image.GetEntries()['fdtmap']
4645 self.assertEqual(orig_entry.offset, entry.offset)
4646 self.assertEqual(orig_entry.size, entry.size)
4647 self.assertEqual(16, entry.image_pos)
4648
4649 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4650
4651 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4652
Simon Glassc98de972021-03-18 20:24:57 +13004653 def testTplNoDtb(self):
4654 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004655 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004656 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4657 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4658 data[:len(U_BOOT_TPL_NODTB_DATA)])
4659
Simon Glass63f41d42021-03-18 20:24:58 +13004660 def testTplBssPad(self):
4661 """Test that we can pad TPL's BSS with zeros"""
4662 # ELF file with a '__bss_size' symbol
4663 self._SetupTplElf()
4664 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004665 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004666 data)
4667
4668 def testTplBssPadMissing(self):
4669 """Test that a missing symbol is detected"""
4670 self._SetupTplElf('u_boot_ucode_ptr')
4671 with self.assertRaises(ValueError) as e:
4672 self._DoReadFile('193_tpl_bss_pad.dts')
4673 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4674 str(e.exception))
4675
Simon Glass718b5292021-03-18 20:25:07 +13004676 def checkDtbSizes(self, data, pad_len, start):
4677 """Check the size arguments in a dtb embedded in an image
4678
4679 Args:
4680 data: The image data
4681 pad_len: Length of the pad section in the image, in bytes
4682 start: Start offset of the devicetree to examine, within the image
4683
4684 Returns:
4685 Size of the devicetree in bytes
4686 """
4687 dtb_data = data[start:]
4688 dtb = fdt.Fdt.FromData(dtb_data)
4689 fdt_size = dtb.GetFdtObj().totalsize()
4690 dtb.Scan()
4691 props = self._GetPropTree(dtb, 'size')
4692 self.assertEqual({
4693 'size': len(data),
4694 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4695 'u-boot-spl/u-boot-spl-dtb:size': 801,
4696 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4697 'u-boot-spl:size': 860,
4698 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4699 'u-boot/u-boot-dtb:size': 781,
4700 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4701 'u-boot:size': 827,
4702 }, props)
4703 return fdt_size
4704
4705 def testExpanded(self):
4706 """Test that an expanded entry type is selected when needed"""
4707 self._SetupSplElf()
4708 self._SetupTplElf()
4709
4710 # SPL has a devicetree, TPL does not
4711 entry_args = {
4712 'spl-dtb': '1',
4713 'spl-bss-pad': 'y',
4714 'tpl-dtb': '',
4715 }
4716 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4717 entry_args=entry_args)
4718 image = control.images['image']
4719 entries = image.GetEntries()
4720 self.assertEqual(3, len(entries))
4721
4722 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4723 self.assertIn('u-boot', entries)
4724 entry = entries['u-boot']
4725 self.assertEqual('u-boot-expanded', entry.etype)
4726 subent = entry.GetEntries()
4727 self.assertEqual(2, len(subent))
4728 self.assertIn('u-boot-nodtb', subent)
4729 self.assertIn('u-boot-dtb', subent)
4730
4731 # Second, u-boot-spl, which should be expanded into three parts
4732 self.assertIn('u-boot-spl', entries)
4733 entry = entries['u-boot-spl']
4734 self.assertEqual('u-boot-spl-expanded', entry.etype)
4735 subent = entry.GetEntries()
4736 self.assertEqual(3, len(subent))
4737 self.assertIn('u-boot-spl-nodtb', subent)
4738 self.assertIn('u-boot-spl-bss-pad', subent)
4739 self.assertIn('u-boot-spl-dtb', subent)
4740
4741 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4742 # devicetree
4743 self.assertIn('u-boot-tpl', entries)
4744 entry = entries['u-boot-tpl']
4745 self.assertEqual('u-boot-tpl', entry.etype)
4746 self.assertEqual(None, entry.GetEntries())
4747
4748 def testExpandedTpl(self):
4749 """Test that an expanded entry type is selected for TPL when needed"""
4750 self._SetupTplElf()
4751
4752 entry_args = {
4753 'tpl-bss-pad': 'y',
4754 'tpl-dtb': 'y',
4755 }
4756 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4757 entry_args=entry_args)
4758 image = control.images['image']
4759 entries = image.GetEntries()
4760 self.assertEqual(1, len(entries))
4761
4762 # We only have u-boot-tpl, which be expanded
4763 self.assertIn('u-boot-tpl', entries)
4764 entry = entries['u-boot-tpl']
4765 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4766 subent = entry.GetEntries()
4767 self.assertEqual(3, len(subent))
4768 self.assertIn('u-boot-tpl-nodtb', subent)
4769 self.assertIn('u-boot-tpl-bss-pad', subent)
4770 self.assertIn('u-boot-tpl-dtb', subent)
4771
4772 def testExpandedNoPad(self):
4773 """Test an expanded entry without BSS pad enabled"""
4774 self._SetupSplElf()
4775 self._SetupTplElf()
4776
4777 # SPL has a devicetree, TPL does not
4778 entry_args = {
4779 'spl-dtb': 'something',
4780 'spl-bss-pad': 'n',
4781 'tpl-dtb': '',
4782 }
4783 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4784 entry_args=entry_args)
4785 image = control.images['image']
4786 entries = image.GetEntries()
4787
4788 # Just check u-boot-spl, which should be expanded into two parts
4789 self.assertIn('u-boot-spl', entries)
4790 entry = entries['u-boot-spl']
4791 self.assertEqual('u-boot-spl-expanded', entry.etype)
4792 subent = entry.GetEntries()
4793 self.assertEqual(2, len(subent))
4794 self.assertIn('u-boot-spl-nodtb', subent)
4795 self.assertIn('u-boot-spl-dtb', subent)
4796
4797 def testExpandedTplNoPad(self):
4798 """Test that an expanded entry type with padding disabled in TPL"""
4799 self._SetupTplElf()
4800
4801 entry_args = {
4802 'tpl-bss-pad': '',
4803 'tpl-dtb': 'y',
4804 }
4805 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4806 entry_args=entry_args)
4807 image = control.images['image']
4808 entries = image.GetEntries()
4809 self.assertEqual(1, len(entries))
4810
4811 # We only have u-boot-tpl, which be expanded
4812 self.assertIn('u-boot-tpl', entries)
4813 entry = entries['u-boot-tpl']
4814 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4815 subent = entry.GetEntries()
4816 self.assertEqual(2, len(subent))
4817 self.assertIn('u-boot-tpl-nodtb', subent)
4818 self.assertIn('u-boot-tpl-dtb', subent)
4819
4820 def testFdtInclude(self):
4821 """Test that an Fdt is update within all binaries"""
4822 self._SetupSplElf()
4823 self._SetupTplElf()
4824
4825 # SPL has a devicetree, TPL does not
4826 self.maxDiff = None
4827 entry_args = {
4828 'spl-dtb': '1',
4829 'spl-bss-pad': 'y',
4830 'tpl-dtb': '',
4831 }
4832 # Build the image. It includes two separate devicetree binaries, each
4833 # with their own contents, but all contain the binman definition.
4834 data = self._DoReadFileDtb(
4835 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4836 update_dtb=True, entry_args=entry_args)[0]
4837 pad_len = 10
4838
4839 # Check the U-Boot dtb
4840 start = len(U_BOOT_NODTB_DATA)
4841 fdt_size = self.checkDtbSizes(data, pad_len, start)
4842
4843 # Now check SPL
4844 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4845 fdt_size = self.checkDtbSizes(data, pad_len, start)
4846
4847 # TPL has no devicetree
4848 start += fdt_size + len(U_BOOT_TPL_DATA)
4849 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004850
Simon Glass7098b7f2021-03-21 18:24:30 +13004851 def testSymbolsExpanded(self):
4852 """Test binman can assign symbols in expanded entries"""
4853 entry_args = {
4854 'spl-dtb': '1',
4855 }
4856 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4857 U_BOOT_SPL_DTB_DATA, 0x38,
4858 entry_args=entry_args, use_expanded=True)
4859
Simon Glasse1915782021-03-21 18:24:31 +13004860 def testCollection(self):
4861 """Test a collection"""
4862 data = self._DoReadFile('198_collection.dts')
4863 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004864 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4865 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004866 data)
4867
Simon Glass27a7f772021-03-21 18:24:32 +13004868 def testCollectionSection(self):
4869 """Test a collection where a section must be built first"""
4870 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004871 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004872 # building the contents, producing an error is anything is still
4873 # missing.
4874 data = self._DoReadFile('199_collection_section.dts')
4875 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004876 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4877 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004878 data)
4879
Simon Glassf427c5f2021-03-21 18:24:33 +13004880 def testAlignDefault(self):
4881 """Test that default alignment works on sections"""
4882 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004883 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004884 U_BOOT_DATA)
4885 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004886 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004887 # No alignment within the nested section
4888 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4889 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004890 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004891 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004892
Bin Mengc0b15742021-05-10 20:23:33 +08004893 def testPackOpenSBI(self):
4894 """Test that an image with an OpenSBI binary can be created"""
4895 data = self._DoReadFile('201_opensbi.dts')
4896 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4897
Simon Glass76f496d2021-07-06 10:36:37 -06004898 def testSectionsSingleThread(self):
4899 """Test sections without multithreading"""
4900 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004901 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4902 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4903 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004904 self.assertEqual(expected, data)
4905
4906 def testThreadTimeout(self):
4907 """Test handling a thread that takes too long"""
4908 with self.assertRaises(ValueError) as e:
4909 self._DoTestFile('202_section_timeout.dts',
4910 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004911 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004912
Simon Glass748a1d42021-07-06 10:36:41 -06004913 def testTiming(self):
4914 """Test output of timing information"""
4915 data = self._DoReadFile('055_sections.dts')
4916 with test_util.capture_sys_output() as (stdout, stderr):
4917 state.TimingShow()
4918 self.assertIn('read:', stdout.getvalue())
4919 self.assertIn('compress:', stdout.getvalue())
4920
Simon Glassadfb8492021-11-03 21:09:18 -06004921 def testUpdateFdtInElf(self):
4922 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004923 if not elf.ELF_TOOLS:
4924 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004925 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4926 outfile = os.path.join(self._indir, 'u-boot.out')
4927 begin_sym = 'dtb_embed_begin'
4928 end_sym = 'dtb_embed_end'
4929 retcode = self._DoTestFile(
4930 '060_fdt_update.dts', update_dtb=True,
4931 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4932 self.assertEqual(0, retcode)
4933
4934 # Check that the output file does in fact contact a dtb with the binman
4935 # definition in the correct place
4936 syms = elf.GetSymbolFileOffset(infile,
4937 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004938 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004939 dtb_data = data[syms['dtb_embed_begin'].offset:
4940 syms['dtb_embed_end'].offset]
4941
4942 dtb = fdt.Fdt.FromData(dtb_data)
4943 dtb.Scan()
4944 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4945 self.assertEqual({
4946 'image-pos': 0,
4947 'offset': 0,
4948 '_testing:offset': 32,
4949 '_testing:size': 2,
4950 '_testing:image-pos': 32,
4951 'section@0/u-boot:offset': 0,
4952 'section@0/u-boot:size': len(U_BOOT_DATA),
4953 'section@0/u-boot:image-pos': 0,
4954 'section@0:offset': 0,
4955 'section@0:size': 16,
4956 'section@0:image-pos': 0,
4957
4958 'section@1/u-boot:offset': 0,
4959 'section@1/u-boot:size': len(U_BOOT_DATA),
4960 'section@1/u-boot:image-pos': 16,
4961 'section@1:offset': 16,
4962 'section@1:size': 16,
4963 'section@1:image-pos': 16,
4964 'size': 40
4965 }, props)
4966
4967 def testUpdateFdtInElfInvalid(self):
4968 """Test that invalid args are detected with --update-fdt-in-elf"""
4969 with self.assertRaises(ValueError) as e:
4970 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4971 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4972 str(e.exception))
4973
4974 def testUpdateFdtInElfNoSyms(self):
4975 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004976 if not elf.ELF_TOOLS:
4977 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004978 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4979 outfile = ''
4980 begin_sym = 'wrong_begin'
4981 end_sym = 'wrong_end'
4982 with self.assertRaises(ValueError) as e:
4983 self._DoTestFile(
4984 '060_fdt_update.dts',
4985 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4986 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4987 str(e.exception))
4988
4989 def testUpdateFdtInElfTooSmall(self):
4990 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004991 if not elf.ELF_TOOLS:
4992 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004993 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4994 outfile = os.path.join(self._indir, 'u-boot.out')
4995 begin_sym = 'dtb_embed_begin'
4996 end_sym = 'dtb_embed_end'
4997 with self.assertRaises(ValueError) as e:
4998 self._DoTestFile(
4999 '060_fdt_update.dts', update_dtb=True,
5000 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
5001 self.assertRegex(
5002 str(e.exception),
5003 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
5004
Simon Glass88e04da2021-11-23 11:03:42 -07005005 def testVersion(self):
5006 """Test we can get the binman version"""
5007 version = '(unreleased)'
5008 self.assertEqual(version, state.GetVersion(self._indir))
5009
5010 with self.assertRaises(SystemExit):
5011 with test_util.capture_sys_output() as (_, stderr):
5012 self._DoBinman('-V')
5013 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5014
5015 # Try running the tool too, just to be safe
5016 result = self._RunBinman('-V')
5017 self.assertEqual('Binman %s\n' % version, result.stderr)
5018
5019 # Set up a version file to make sure that works
5020 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005021 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005022 binary=False)
5023 self.assertEqual(version, state.GetVersion(self._indir))
5024
Simon Glass637958f2021-11-23 21:09:50 -07005025 def testAltFormat(self):
5026 """Test that alternative formats can be used to extract"""
5027 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5028
5029 try:
5030 tmpdir, updated_fname = self._SetupImageInTmpdir()
5031 with test_util.capture_sys_output() as (stdout, _):
5032 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5033 self.assertEqual(
5034 '''Flag (-F) Entry type Description
5035fdt fdtmap Extract the devicetree blob from the fdtmap
5036''',
5037 stdout.getvalue())
5038
5039 dtb = os.path.join(tmpdir, 'fdt.dtb')
5040 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5041 dtb, 'fdtmap')
5042
5043 # Check that we can read it and it can be scanning, meaning it does
5044 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005045 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005046 dtb = fdt.Fdt.FromData(data)
5047 dtb.Scan()
5048
5049 # Now check u-boot which has no alt_format
5050 fname = os.path.join(tmpdir, 'fdt.dtb')
5051 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5052 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005053 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005054 self.assertEqual(U_BOOT_DATA, data)
5055
5056 finally:
5057 shutil.rmtree(tmpdir)
5058
Simon Glass0b00ae62021-11-23 21:09:52 -07005059 def testExtblobList(self):
5060 """Test an image with an external blob list"""
5061 data = self._DoReadFile('215_blob_ext_list.dts')
5062 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5063
5064 def testExtblobListMissing(self):
5065 """Test an image with a missing external blob"""
5066 with self.assertRaises(ValueError) as e:
5067 self._DoReadFile('216_blob_ext_list_missing.dts')
5068 self.assertIn("Filename 'missing-file' not found in input path",
5069 str(e.exception))
5070
5071 def testExtblobListMissingOk(self):
5072 """Test an image with an missing external blob that is allowed"""
5073 with test_util.capture_sys_output() as (stdout, stderr):
5074 self._DoTestFile('216_blob_ext_list_missing.dts',
5075 allow_missing=True)
5076 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005077 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005078
Simon Glass3efb2972021-11-23 21:08:59 -07005079 def testFip(self):
5080 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5081 data = self._DoReadFile('203_fip.dts')
5082 hdr, fents = fip_util.decode_fip(data)
5083 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5084 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5085 self.assertEqual(0x123, hdr.flags)
5086
5087 self.assertEqual(2, len(fents))
5088
5089 fent = fents[0]
5090 self.assertEqual(
5091 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5092 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5093 self.assertEqual('soc-fw', fent.fip_type)
5094 self.assertEqual(0x88, fent.offset)
5095 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5096 self.assertEqual(0x123456789abcdef, fent.flags)
5097 self.assertEqual(ATF_BL31_DATA, fent.data)
5098 self.assertEqual(True, fent.valid)
5099
5100 fent = fents[1]
5101 self.assertEqual(
5102 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5103 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5104 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5105 self.assertEqual(0x8c, fent.offset)
5106 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5107 self.assertEqual(0, fent.flags)
5108 self.assertEqual(ATF_BL2U_DATA, fent.data)
5109 self.assertEqual(True, fent.valid)
5110
5111 def testFipOther(self):
5112 """Basic FIP with something that isn't a external blob"""
5113 data = self._DoReadFile('204_fip_other.dts')
5114 hdr, fents = fip_util.decode_fip(data)
5115
5116 self.assertEqual(2, len(fents))
5117 fent = fents[1]
5118 self.assertEqual('rot-cert', fent.fip_type)
5119 self.assertEqual(b'aa', fent.data)
5120
Simon Glass3efb2972021-11-23 21:08:59 -07005121 def testFipNoType(self):
5122 """FIP with an entry of an unknown type"""
5123 with self.assertRaises(ValueError) as e:
5124 self._DoReadFile('205_fip_no_type.dts')
5125 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5126 str(e.exception))
5127
5128 def testFipUuid(self):
5129 """Basic FIP with a manual uuid"""
5130 data = self._DoReadFile('206_fip_uuid.dts')
5131 hdr, fents = fip_util.decode_fip(data)
5132
5133 self.assertEqual(2, len(fents))
5134 fent = fents[1]
5135 self.assertEqual(None, fent.fip_type)
5136 self.assertEqual(
5137 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5138 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5139 fent.uuid)
5140 self.assertEqual(U_BOOT_DATA, fent.data)
5141
5142 def testFipLs(self):
5143 """Test listing a FIP"""
5144 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5145 hdr, fents = fip_util.decode_fip(data)
5146
5147 try:
5148 tmpdir, updated_fname = self._SetupImageInTmpdir()
5149 with test_util.capture_sys_output() as (stdout, stderr):
5150 self._DoBinman('ls', '-i', updated_fname)
5151 finally:
5152 shutil.rmtree(tmpdir)
5153 lines = stdout.getvalue().splitlines()
5154 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005155'Name Image-pos Size Entry-type Offset Uncomp-size',
5156'--------------------------------------------------------------',
5157'image 0 2d3 section 0',
5158' atf-fip 0 90 atf-fip 0',
5159' soc-fw 88 4 blob-ext 88',
5160' u-boot 8c 4 u-boot 8c',
5161' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005162]
5163 self.assertEqual(expected, lines)
5164
5165 image = control.images['image']
5166 entries = image.GetEntries()
5167 fdtmap = entries['fdtmap']
5168
5169 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5170 magic = fdtmap_data[:8]
5171 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005172 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005173
5174 fdt_data = fdtmap_data[16:]
5175 dtb = fdt.Fdt.FromData(fdt_data)
5176 dtb.Scan()
5177 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5178 self.assertEqual({
5179 'atf-fip/soc-fw:image-pos': 136,
5180 'atf-fip/soc-fw:offset': 136,
5181 'atf-fip/soc-fw:size': 4,
5182 'atf-fip/u-boot:image-pos': 140,
5183 'atf-fip/u-boot:offset': 140,
5184 'atf-fip/u-boot:size': 4,
5185 'atf-fip:image-pos': 0,
5186 'atf-fip:offset': 0,
5187 'atf-fip:size': 144,
5188 'image-pos': 0,
5189 'offset': 0,
5190 'fdtmap:image-pos': fdtmap.image_pos,
5191 'fdtmap:offset': fdtmap.offset,
5192 'fdtmap:size': len(fdtmap_data),
5193 'size': len(data),
5194 }, props)
5195
5196 def testFipExtractOneEntry(self):
5197 """Test extracting a single entry fron an FIP"""
5198 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005199 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005200 fname = os.path.join(self._indir, 'output.extact')
5201 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005202 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005203 self.assertEqual(U_BOOT_DATA, data)
5204
5205 def testFipReplace(self):
5206 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005207 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005208 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005209 updated_fname = tools.get_output_filename('image-updated.bin')
5210 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005211 entry_name = 'atf-fip/u-boot'
5212 control.WriteEntry(updated_fname, entry_name, expected,
5213 allow_resize=True)
5214 actual = control.ReadEntry(updated_fname, entry_name)
5215 self.assertEqual(expected, actual)
5216
Simon Glass80025522022-01-29 14:14:04 -07005217 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005218 hdr, fents = fip_util.decode_fip(new_data)
5219
5220 self.assertEqual(2, len(fents))
5221
5222 # Check that the FIP entry is updated
5223 fent = fents[1]
5224 self.assertEqual(0x8c, fent.offset)
5225 self.assertEqual(len(expected), fent.size)
5226 self.assertEqual(0, fent.flags)
5227 self.assertEqual(expected, fent.data)
5228 self.assertEqual(True, fent.valid)
5229
5230 def testFipMissing(self):
5231 with test_util.capture_sys_output() as (stdout, stderr):
5232 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5233 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005234 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005235
5236 def testFipSize(self):
5237 """Test a FIP with a size property"""
5238 data = self._DoReadFile('210_fip_size.dts')
5239 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5240 hdr, fents = fip_util.decode_fip(data)
5241 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5242 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5243
5244 self.assertEqual(1, len(fents))
5245
5246 fent = fents[0]
5247 self.assertEqual('soc-fw', fent.fip_type)
5248 self.assertEqual(0x60, fent.offset)
5249 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5250 self.assertEqual(ATF_BL31_DATA, fent.data)
5251 self.assertEqual(True, fent.valid)
5252
5253 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005254 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005255
5256 def testFipBadAlign(self):
5257 """Test that an invalid alignment value in a FIP is detected"""
5258 with self.assertRaises(ValueError) as e:
5259 self._DoTestFile('211_fip_bad_align.dts')
5260 self.assertIn(
5261 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5262 str(e.exception))
5263
5264 def testFipCollection(self):
5265 """Test using a FIP in a collection"""
5266 data = self._DoReadFile('212_fip_collection.dts')
5267 entry1 = control.images['image'].GetEntries()['collection']
5268 data1 = data[:entry1.size]
5269 hdr1, fents2 = fip_util.decode_fip(data1)
5270
5271 entry2 = control.images['image'].GetEntries()['atf-fip']
5272 data2 = data[entry2.offset:entry2.offset + entry2.size]
5273 hdr1, fents2 = fip_util.decode_fip(data2)
5274
5275 # The 'collection' entry should have U-Boot included at the end
5276 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5277 self.assertEqual(data1, data2 + U_BOOT_DATA)
5278 self.assertEqual(U_BOOT_DATA, data1[-4:])
5279
5280 # There should be a U-Boot after the final FIP
5281 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005282
Simon Glassccae6862022-01-12 13:10:35 -07005283 def testFakeBlob(self):
5284 """Test handling of faking an external blob"""
5285 with test_util.capture_sys_output() as (stdout, stderr):
5286 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5287 allow_fake_blobs=True)
5288 err = stderr.getvalue()
5289 self.assertRegex(
5290 err,
5291 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005292
Simon Glassceb5f912022-01-09 20:13:46 -07005293 def testExtblobListFaked(self):
5294 """Test an extblob with missing external blob that are faked"""
5295 with test_util.capture_sys_output() as (stdout, stderr):
5296 self._DoTestFile('216_blob_ext_list_missing.dts',
5297 allow_fake_blobs=True)
5298 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005299 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005300
Simon Glass162017b2022-01-09 20:13:57 -07005301 def testListBintools(self):
5302 args = ['tool', '--list']
5303 with test_util.capture_sys_output() as (stdout, _):
5304 self._DoBinman(*args)
5305 out = stdout.getvalue().splitlines()
5306 self.assertTrue(len(out) >= 2)
5307
5308 def testFetchBintools(self):
5309 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005310 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005311 raise urllib.error.URLError('my error')
5312
5313 args = ['tool']
5314 with self.assertRaises(ValueError) as e:
5315 self._DoBinman(*args)
5316 self.assertIn("Invalid arguments to 'tool' subcommand",
5317 str(e.exception))
5318
5319 args = ['tool', '--fetch']
5320 with self.assertRaises(ValueError) as e:
5321 self._DoBinman(*args)
5322 self.assertIn('Please specify bintools to fetch', str(e.exception))
5323
5324 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005325 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005326 side_effect=fail_download):
5327 with test_util.capture_sys_output() as (stdout, _):
5328 self._DoBinman(*args)
5329 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5330
Simon Glass620c4462022-01-09 20:14:11 -07005331 def testBintoolDocs(self):
5332 """Test for creation of bintool documentation"""
5333 with test_util.capture_sys_output() as (stdout, stderr):
5334 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5335 self.assertTrue(len(stdout.getvalue()) > 0)
5336
5337 def testBintoolDocsMissing(self):
5338 """Test handling of missing bintool documentation"""
5339 with self.assertRaises(ValueError) as e:
5340 with test_util.capture_sys_output() as (stdout, stderr):
5341 control.write_bintool_docs(
5342 control.bintool.Bintool.get_tool_list(), 'mkimage')
5343 self.assertIn('Documentation is missing for modules: mkimage',
5344 str(e.exception))
5345
Jan Kiszka58c407f2022-01-28 20:37:53 +01005346 def testListWithGenNode(self):
5347 """Check handling of an FDT map when the section cannot be found"""
5348 entry_args = {
5349 'of-list': 'test-fdt1 test-fdt2',
5350 }
5351 data = self._DoReadFileDtb(
5352 '219_fit_gennode.dts',
5353 entry_args=entry_args,
5354 use_real_dtb=True,
5355 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5356
5357 try:
5358 tmpdir, updated_fname = self._SetupImageInTmpdir()
5359 with test_util.capture_sys_output() as (stdout, stderr):
5360 self._RunBinman('ls', '-i', updated_fname)
5361 finally:
5362 shutil.rmtree(tmpdir)
5363
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005364 def testFitSubentryUsesBintool(self):
5365 """Test that binman FIT subentries can use bintools"""
5366 command.test_result = self._HandleGbbCommand
5367 entry_args = {
5368 'keydir': 'devkeys',
5369 'bmpblk': 'bmpblk.bin',
5370 }
5371 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5372 entry_args=entry_args)
5373
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005374 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5375 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005376 self.assertIn(expected, data)
5377
5378 def testFitSubentryMissingBintool(self):
5379 """Test that binman reports missing bintools for FIT subentries"""
5380 entry_args = {
5381 'keydir': 'devkeys',
5382 }
5383 with test_util.capture_sys_output() as (_, stderr):
5384 self._DoTestFile('220_fit_subentry_bintool.dts',
5385 force_missing_bintools='futility', entry_args=entry_args)
5386 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005387 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005388
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005389 def testFitSubentryHashSubnode(self):
5390 """Test an image with a FIT inside"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005391 self._SetupSplElf()
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005392 data, _, _, out_dtb_name = self._DoReadFileDtb(
5393 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5394
5395 mkimage_dtb = fdt.Fdt.FromData(data)
5396 mkimage_dtb.Scan()
5397 binman_dtb = fdt.Fdt(out_dtb_name)
5398 binman_dtb.Scan()
5399
5400 # Check that binman didn't add hash values
5401 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5402 self.assertNotIn('value', fnode.props)
5403
5404 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5405 self.assertNotIn('value', fnode.props)
5406
5407 # Check that mkimage added hash values
5408 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5409 self.assertIn('value', fnode.props)
5410
5411 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5412 self.assertIn('value', fnode.props)
5413
Roger Quadros5cdcea02022-02-19 20:50:04 +02005414 def testPackTeeOs(self):
5415 """Test that an image with an TEE binary can be created"""
5416 data = self._DoReadFile('222_tee_os.dts')
5417 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5418
Simon Glass912339f2022-02-08 11:50:03 -07005419 def testFitFdtOper(self):
5420 """Check handling of a specified FIT operation"""
5421 entry_args = {
5422 'of-list': 'test-fdt1 test-fdt2',
5423 'default-dt': 'test-fdt2',
5424 }
5425 self._DoReadFileDtb(
5426 '223_fit_fdt_oper.dts',
5427 entry_args=entry_args,
5428 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5429
5430 def testFitFdtBadOper(self):
5431 """Check handling of an FDT map when the section cannot be found"""
5432 with self.assertRaises(ValueError) as exc:
5433 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005434 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005435 str(exc.exception))
5436
Simon Glassdd156a42022-03-05 20:18:59 -07005437 def test_uses_expand_size(self):
5438 """Test that the 'expand-size' property cannot be used anymore"""
5439 with self.assertRaises(ValueError) as e:
5440 data = self._DoReadFile('225_expand_size_bad.dts')
5441 self.assertIn(
5442 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5443 str(e.exception))
5444
Simon Glass5f423422022-03-05 20:19:12 -07005445 def testFitSplitElf(self):
5446 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005447 if not elf.ELF_TOOLS:
5448 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005449 entry_args = {
5450 'of-list': 'test-fdt1 test-fdt2',
5451 'default-dt': 'test-fdt2',
5452 'atf-bl31-path': 'bl31.elf',
5453 'tee-os-path': 'tee.elf',
5454 }
5455 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5456 data = self._DoReadFileDtb(
5457 '226_fit_split_elf.dts',
5458 entry_args=entry_args,
5459 extra_indirs=[test_subdir])[0]
5460
5461 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5462 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5463
5464 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5465 'data', 'load'}
5466 dtb = fdt.Fdt.FromData(fit_data)
5467 dtb.Scan()
5468
5469 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5470 segments, entry = elf.read_loadable_segments(elf_data)
5471
5472 # We assume there are two segments
5473 self.assertEquals(2, len(segments))
5474
5475 atf1 = dtb.GetNode('/images/atf-1')
5476 _, start, data = segments[0]
5477 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5478 self.assertEqual(entry,
5479 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5480 self.assertEqual(start,
5481 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5482 self.assertEqual(data, atf1.props['data'].bytes)
5483
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005484 hash_node = atf1.FindNode('hash')
5485 self.assertIsNotNone(hash_node)
5486 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5487
Simon Glass5f423422022-03-05 20:19:12 -07005488 atf2 = dtb.GetNode('/images/atf-2')
5489 self.assertEqual(base_keys, atf2.props.keys())
5490 _, start, data = segments[1]
5491 self.assertEqual(start,
5492 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5493 self.assertEqual(data, atf2.props['data'].bytes)
5494
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005495 hash_node = atf2.FindNode('hash')
5496 self.assertIsNotNone(hash_node)
5497 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5498
5499 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5500 self.assertIsNotNone(hash_node)
5501 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5502
Simon Glass5f423422022-03-05 20:19:12 -07005503 conf = dtb.GetNode('/configurations')
5504 self.assertEqual({'default'}, conf.props.keys())
5505
5506 for subnode in conf.subnodes:
5507 self.assertEqual({'description', 'fdt', 'loadables'},
5508 subnode.props.keys())
5509 self.assertEqual(
5510 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5511 fdt_util.GetStringList(subnode, 'loadables'))
5512
5513 def _check_bad_fit(self, dts):
5514 """Check a bad FIT
5515
5516 This runs with the given dts and returns the assertion raised
5517
5518 Args:
5519 dts (str): dts filename to use
5520
5521 Returns:
5522 str: Assertion string raised
5523 """
5524 entry_args = {
5525 'of-list': 'test-fdt1 test-fdt2',
5526 'default-dt': 'test-fdt2',
5527 'atf-bl31-path': 'bl31.elf',
5528 'tee-os-path': 'tee.elf',
5529 }
5530 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5531 with self.assertRaises(ValueError) as exc:
5532 self._DoReadFileDtb(dts, entry_args=entry_args,
5533 extra_indirs=[test_subdir])[0]
5534 return str(exc.exception)
5535
5536 def testFitSplitElfBadElf(self):
5537 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005538 if not elf.ELF_TOOLS:
5539 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005540 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5541 entry_args = {
5542 'of-list': 'test-fdt1 test-fdt2',
5543 'default-dt': 'test-fdt2',
5544 'atf-bl31-path': 'bad.elf',
5545 'tee-os-path': 'tee.elf',
5546 }
5547 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5548 with self.assertRaises(ValueError) as exc:
5549 self._DoReadFileDtb(
5550 '226_fit_split_elf.dts',
5551 entry_args=entry_args,
5552 extra_indirs=[test_subdir])[0]
5553 self.assertIn(
5554 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5555 str(exc.exception))
5556
Simon Glass5f423422022-03-05 20:19:12 -07005557 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005558 """Test an split-elf FIT with a missing ELF file
5559
5560 Args:
5561 kwargs (dict of str): Arguments to pass to _DoTestFile()
5562
5563 Returns:
5564 tuple:
5565 str: stdout result
5566 str: stderr result
5567 """
Simon Glass5f423422022-03-05 20:19:12 -07005568 entry_args = {
5569 'of-list': 'test-fdt1 test-fdt2',
5570 'default-dt': 'test-fdt2',
5571 'atf-bl31-path': 'bl31.elf',
5572 'tee-os-path': 'missing.elf',
5573 }
5574 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5575 with test_util.capture_sys_output() as (stdout, stderr):
5576 self._DoTestFile(
5577 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005578 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5579 out = stdout.getvalue()
5580 err = stderr.getvalue()
5581 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005582
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005583 def testFitSplitElfBadDirective(self):
5584 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5585 if not elf.ELF_TOOLS:
5586 self.skipTest('Python elftools not available')
5587 err = self._check_bad_fit('227_fit_bad_dir.dts')
5588 self.assertIn(
5589 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5590 err)
5591
5592 def testFitSplitElfBadDirectiveConfig(self):
5593 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5594 if not elf.ELF_TOOLS:
5595 self.skipTest('Python elftools not available')
5596 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5597 self.assertEqual(
5598 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5599 err)
5600
5601
Simon Glass5f423422022-03-05 20:19:12 -07005602 def testFitSplitElfMissing(self):
5603 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005604 if not elf.ELF_TOOLS:
5605 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005606 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005607 self.assertRegex(
5608 err,
5609 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005610 self.assertNotRegex(out, '.*Faked blob.*')
5611 fname = tools.get_output_filename('binman-fake/missing.elf')
5612 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005613
5614 def testFitSplitElfFaked(self):
5615 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005616 if not elf.ELF_TOOLS:
5617 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005618 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005619 self.assertRegex(
5620 err,
5621 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005622 self.assertRegex(
5623 out,
5624 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5625 fname = tools.get_output_filename('binman-fake/missing.elf')
5626 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005627
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005628 def testMkimageMissingBlob(self):
5629 """Test using mkimage to build an image"""
5630 with test_util.capture_sys_output() as (stdout, stderr):
5631 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5632 allow_fake_blobs=True)
5633 err = stderr.getvalue()
5634 self.assertRegex(
5635 err,
5636 "Image '.*' has faked external blobs and is non-functional: .*")
5637
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005638 def testPreLoad(self):
5639 """Test an image with a pre-load header"""
5640 entry_args = {
5641 'pre-load-key-path': '.',
5642 }
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005643 data, _, _, _ = self._DoReadFileDtb('230_pre_load.dts',
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005644 entry_args=entry_args)
5645 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5646 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5647 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005648 data = self._DoReadFile('230_pre_load.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005649 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5650 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5651 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5652
5653 def testPreLoadPkcs(self):
5654 """Test an image with a pre-load header with padding pkcs"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005655 data = self._DoReadFile('231_pre_load_pkcs.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005656 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5657 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5658 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5659
5660 def testPreLoadPss(self):
5661 """Test an image with a pre-load header with padding pss"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005662 data = self._DoReadFile('232_pre_load_pss.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005663 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5664 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5665 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5666
5667 def testPreLoadInvalidPadding(self):
5668 """Test an image with a pre-load header with an invalid padding"""
5669 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005670 data = self._DoReadFile('233_pre_load_invalid_padding.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005671
5672 def testPreLoadInvalidSha(self):
5673 """Test an image with a pre-load header with an invalid hash"""
5674 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005675 data = self._DoReadFile('234_pre_load_invalid_sha.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005676
5677 def testPreLoadInvalidAlgo(self):
5678 """Test an image with a pre-load header with an invalid algo"""
5679 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005680 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005681
5682 def testPreLoadInvalidKey(self):
5683 """Test an image with a pre-load header with an invalid key"""
5684 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005685 data = self._DoReadFile('236_pre_load_invalid_key.dts')
Roger Quadros5cdcea02022-02-19 20:50:04 +02005686
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005687 def _CheckSafeUniqueNames(self, *images):
5688 """Check all entries of given images for unsafe unique names"""
5689 for image in images:
5690 entries = {}
5691 image._CollectEntries(entries, {}, image)
5692 for entry in entries.values():
5693 uniq = entry.GetUniqueName()
5694
5695 # Used as part of a filename, so must not be absolute paths.
5696 self.assertFalse(os.path.isabs(uniq))
5697
5698 def testSafeUniqueNames(self):
5699 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005700 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005701
5702 orig_image = control.images['image']
5703 image_fname = tools.get_output_filename('image.bin')
5704 image = Image.FromFile(image_fname)
5705
5706 self._CheckSafeUniqueNames(orig_image, image)
5707
5708 def testSafeUniqueNamesMulti(self):
5709 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005710 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005711
5712 orig_image = control.images['image']
5713 image_fname = tools.get_output_filename('image.bin')
5714 image = Image.FromFile(image_fname)
5715
5716 self._CheckSafeUniqueNames(orig_image, image)
5717
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005718 def testReplaceCmdWithBintool(self):
5719 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005720 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005721 expected = U_BOOT_DATA + b'aa'
5722 self.assertEqual(expected, data[:len(expected)])
5723
5724 try:
5725 tmpdir, updated_fname = self._SetupImageInTmpdir()
5726 fname = os.path.join(tmpdir, 'update-testing.bin')
5727 tools.write_file(fname, b'zz')
5728 self._DoBinman('replace', '-i', updated_fname,
5729 '_testing', '-f', fname)
5730
5731 data = tools.read_file(updated_fname)
5732 expected = U_BOOT_DATA + b'zz'
5733 self.assertEqual(expected, data[:len(expected)])
5734 finally:
5735 shutil.rmtree(tmpdir)
5736
5737 def testReplaceCmdOtherWithBintool(self):
5738 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005739 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005740 expected = U_BOOT_DATA + b'aa'
5741 self.assertEqual(expected, data[:len(expected)])
5742
5743 try:
5744 tmpdir, updated_fname = self._SetupImageInTmpdir()
5745 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5746 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5747 self._DoBinman('replace', '-i', updated_fname,
5748 'u-boot', '-f', fname)
5749
5750 data = tools.read_file(updated_fname)
5751 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5752 self.assertEqual(expected, data[:len(expected)])
5753 finally:
5754 shutil.rmtree(tmpdir)
5755
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005756 def testReplaceResizeNoRepackSameSize(self):
5757 """Test replacing entries with same-size data without repacking"""
5758 expected = b'x' * len(U_BOOT_DATA)
5759 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5760 self.assertEqual(expected, data)
5761
5762 path, fdtmap = state.GetFdtContents('fdtmap')
5763 self.assertIsNotNone(path)
5764 self.assertEqual(expected_fdtmap, fdtmap)
5765
5766 def testReplaceResizeNoRepackSmallerSize(self):
5767 """Test replacing entries with smaller-size data without repacking"""
5768 new_data = b'x'
5769 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5770 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5771 self.assertEqual(expected, data)
5772
5773 path, fdtmap = state.GetFdtContents('fdtmap')
5774 self.assertIsNotNone(path)
5775 self.assertEqual(expected_fdtmap, fdtmap)
5776
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005777 def testExtractFit(self):
5778 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005779 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005780 image_fname = tools.get_output_filename('image.bin')
5781
5782 fit_data = control.ReadEntry(image_fname, 'fit')
5783 fit = fdt.Fdt.FromData(fit_data)
5784 fit.Scan()
5785
5786 # Check subentry data inside the extracted fit
5787 for node_path, expected in [
5788 ('/images/kernel', U_BOOT_DATA),
5789 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5790 ('/images/scr-1', COMPRESS_DATA),
5791 ]:
5792 node = fit.GetNode(node_path)
5793 data = fit.GetProps(node)['data'].bytes
5794 self.assertEqual(expected, data)
5795
5796 def testExtractFitSubentries(self):
5797 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005798 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005799 image_fname = tools.get_output_filename('image.bin')
5800
5801 for entry_path, expected in [
5802 ('fit/kernel', U_BOOT_DATA),
5803 ('fit/kernel/u-boot', U_BOOT_DATA),
5804 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5805 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5806 ('fit/scr-1', COMPRESS_DATA),
5807 ('fit/scr-1/blob', COMPRESS_DATA),
5808 ]:
5809 data = control.ReadEntry(image_fname, entry_path)
5810 self.assertEqual(expected, data)
5811
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005812 def testReplaceFitSubentryLeafSameSize(self):
5813 """Test replacing a FIT leaf subentry with same-size data"""
5814 new_data = b'x' * len(U_BOOT_DATA)
5815 data, expected_fdtmap, _ = self._RunReplaceCmd(
5816 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005817 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005818 self.assertEqual(new_data, data)
5819
5820 path, fdtmap = state.GetFdtContents('fdtmap')
5821 self.assertIsNotNone(path)
5822 self.assertEqual(expected_fdtmap, fdtmap)
5823
5824 def testReplaceFitSubentryLeafBiggerSize(self):
5825 """Test replacing a FIT leaf subentry with bigger-size data"""
5826 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5827 data, expected_fdtmap, _ = self._RunReplaceCmd(
5828 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005829 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005830 self.assertEqual(new_data, data)
5831
5832 # Will be repacked, so fdtmap must change
5833 path, fdtmap = state.GetFdtContents('fdtmap')
5834 self.assertIsNotNone(path)
5835 self.assertNotEqual(expected_fdtmap, fdtmap)
5836
5837 def testReplaceFitSubentryLeafSmallerSize(self):
5838 """Test replacing a FIT leaf subentry with smaller-size data"""
5839 new_data = b'x'
5840 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5841 data, expected_fdtmap, _ = self._RunReplaceCmd(
5842 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005843 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005844 self.assertEqual(expected, data)
5845
5846 path, fdtmap = state.GetFdtContents('fdtmap')
5847 self.assertIsNotNone(path)
5848 self.assertEqual(expected_fdtmap, fdtmap)
5849
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005850 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005851 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005852 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005853 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5854 new_data, dts='241_replace_section_simple.dts')
5855 self.assertEqual(new_data, data)
5856
5857 entries = image.GetEntries()
5858 self.assertIn('section', entries)
5859 entry = entries['section']
5860 self.assertEqual(len(new_data), entry.size)
5861
5862 def testReplaceSectionLarger(self):
5863 """Test replacing a simple section with larger data"""
5864 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5865 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5866 new_data, dts='241_replace_section_simple.dts')
5867 self.assertEqual(new_data, data)
5868
5869 entries = image.GetEntries()
5870 self.assertIn('section', entries)
5871 entry = entries['section']
5872 self.assertEqual(len(new_data), entry.size)
5873 fentry = entries['fdtmap']
5874 self.assertEqual(entry.offset + entry.size, fentry.offset)
5875
5876 def testReplaceSectionSmaller(self):
5877 """Test replacing a simple section with smaller data"""
5878 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
5879 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5880 new_data, dts='241_replace_section_simple.dts')
5881 self.assertEqual(new_data, data)
5882
5883 # The new size is the same as the old, just with a pad byte at the end
5884 entries = image.GetEntries()
5885 self.assertIn('section', entries)
5886 entry = entries['section']
5887 self.assertEqual(len(new_data), entry.size)
5888
5889 def testReplaceSectionSmallerAllow(self):
5890 """Test failing to replace a simple section with smaller data"""
5891 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5892 try:
5893 state.SetAllowEntryContraction(True)
5894 with self.assertRaises(ValueError) as exc:
5895 self._RunReplaceCmd('section', new_data,
5896 dts='241_replace_section_simple.dts')
5897 finally:
5898 state.SetAllowEntryContraction(False)
5899
5900 # Since we have no information about the position of things within the
5901 # section, we cannot adjust the position of /section-u-boot so it ends
5902 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06005903 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07005904 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5905 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06005906 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005907
Simon Glass8fbca772022-08-13 11:40:48 -06005908 def testMkimageImagename(self):
5909 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005910 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005911 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005912
5913 # Check that the data appears in the file somewhere
5914 self.assertIn(U_BOOT_SPL_DATA, data)
5915
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005916 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005917 name = data[0x20:0x40]
5918
5919 # Build the filename that we expect to be placed in there, by virtue of
5920 # the -n paraameter
5921 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5922
5923 # Check that the image name is set to the temporary filename used
5924 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5925
Simon Glassb1669752022-08-13 11:40:49 -06005926 def testMkimageImage(self):
5927 """Test using mkimage with -n holding the data too"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005928 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005929 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005930
5931 # Check that the data appears in the file somewhere
5932 self.assertIn(U_BOOT_SPL_DATA, data)
5933
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005934 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06005935 name = data[0x20:0x40]
5936
5937 # Build the filename that we expect to be placed in there, by virtue of
5938 # the -n paraameter
5939 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5940
5941 # Check that the image name is set to the temporary filename used
5942 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5943
5944 # Check the corect data is in the imagename file
5945 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5946
5947 def testMkimageImageNoContent(self):
5948 """Test using mkimage with -n and no data"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005949 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06005950 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005951 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005952 self.assertIn('Could not complete processing of contents',
5953 str(exc.exception))
5954
5955 def testMkimageImageBad(self):
5956 """Test using mkimage with imagename node and data-to-imagename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005957 self._SetupSplElf()
Simon Glassb1669752022-08-13 11:40:49 -06005958 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005959 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005960 self.assertIn('Cannot use both imagename node and data-to-imagename',
5961 str(exc.exception))
5962
Simon Glassbd5cd882022-08-13 11:40:50 -06005963 def testCollectionOther(self):
5964 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005965 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005966 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5967 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5968 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5969 data)
5970
5971 def testMkimageCollection(self):
5972 """Test using a collection referring to an entry in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06005973 self._SetupSplElf()
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005974 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005975 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5976 self.assertEqual(expect, data[:len(expect)])
5977
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005978 def testCompressDtbPrependInvalid(self):
5979 """Test that invalid header is detected"""
5980 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005981 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005982 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5983 "'u-boot-dtb': 'invalid'", str(e.exception))
5984
5985 def testCompressDtbPrependLength(self):
5986 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005987 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005988 image = control.images['image']
5989 entries = image.GetEntries()
5990 self.assertIn('u-boot-dtb', entries)
5991 u_boot_dtb = entries['u-boot-dtb']
5992 self.assertIn('fdtmap', entries)
5993 fdtmap = entries['fdtmap']
5994
5995 image_fname = tools.get_output_filename('image.bin')
5996 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
5997 dtb = fdt.Fdt.FromData(orig)
5998 dtb.Scan()
5999 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
6000 expected = {
6001 'u-boot:size': len(U_BOOT_DATA),
6002 'u-boot-dtb:uncomp-size': len(orig),
6003 'u-boot-dtb:size': u_boot_dtb.size,
6004 'fdtmap:size': fdtmap.size,
6005 'size': len(data),
6006 }
6007 self.assertEqual(expected, props)
6008
6009 # Check implementation
6010 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6011 rest = data[len(U_BOOT_DATA):]
6012 comp_data_len = struct.unpack('<I', rest[:4])[0]
6013 comp_data = rest[4:4 + comp_data_len]
6014 orig2 = self._decompress(comp_data)
6015 self.assertEqual(orig, orig2)
6016
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006017 def testInvalidCompress(self):
6018 """Test that invalid compress algorithm is detected"""
6019 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006020 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006021 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6022
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006023 def testCompUtilCompressions(self):
6024 """Test compression algorithms"""
6025 for bintool in self.comp_bintools.values():
6026 self._CheckBintool(bintool)
6027 data = bintool.compress(COMPRESS_DATA)
6028 self.assertNotEqual(COMPRESS_DATA, data)
6029 orig = bintool.decompress(data)
6030 self.assertEquals(COMPRESS_DATA, orig)
6031
6032 def testCompUtilVersions(self):
6033 """Test tool version of compression algorithms"""
6034 for bintool in self.comp_bintools.values():
6035 self._CheckBintool(bintool)
6036 version = bintool.version()
6037 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6038
6039 def testCompUtilPadding(self):
6040 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006041 # Skip zstd because it doesn't support padding
6042 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006043 self._CheckBintool(bintool)
6044 data = bintool.compress(COMPRESS_DATA)
6045 self.assertNotEqual(COMPRESS_DATA, data)
6046 data += tools.get_bytes(0, 64)
6047 orig = bintool.decompress(data)
6048 self.assertEquals(COMPRESS_DATA, orig)
6049
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006050 def testCompressDtbZstd(self):
6051 """Test that zstd compress of device-tree files failed"""
6052 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006053 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006054 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6055 "requires a length header", str(e.exception))
6056
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006057 def testMkimageMultipleDataFiles(self):
6058 """Test passing multiple files to mkimage in a mkimage entry"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006059 self._SetupSplElf()
6060 self._SetupTplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006061 data = self._DoReadFile('252_mkimage_mult_data.dts')
6062 # Size of files are packed in their 4B big-endian format
6063 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6064 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6065 # Size info is always followed by a 4B zero value.
6066 expect += tools.get_bytes(0, 4)
6067 expect += U_BOOT_TPL_DATA
6068 # All but last files are 4B-aligned
6069 align_pad = len(U_BOOT_TPL_DATA) % 4
6070 if align_pad:
6071 expect += tools.get_bytes(0, align_pad)
6072 expect += U_BOOT_SPL_DATA
6073 self.assertEqual(expect, data[-len(expect):])
6074
Marek Vasutf7413f02023-07-18 07:23:58 -06006075 def testMkimageMultipleExpanded(self):
6076 """Test passing multiple files to mkimage in a mkimage entry"""
6077 self._SetupSplElf()
6078 self._SetupTplElf()
6079 entry_args = {
6080 'spl-bss-pad': 'y',
6081 'spl-dtb': 'y',
6082 }
6083 data = self._DoReadFileDtb('252_mkimage_mult_data.dts',
6084 use_expanded=True, entry_args=entry_args)[0]
6085 pad_len = 10
6086 tpl_expect = U_BOOT_TPL_DATA
6087 spl_expect = U_BOOT_SPL_NODTB_DATA + tools.get_bytes(0, pad_len)
6088 spl_expect += U_BOOT_SPL_DTB_DATA
6089
6090 content = data[0x40:]
6091 lens = struct.unpack('>III', content[:12])
6092
6093 # Size of files are packed in their 4B big-endian format
6094 # Size info is always followed by a 4B zero value.
6095 self.assertEqual(len(tpl_expect), lens[0])
6096 self.assertEqual(len(spl_expect), lens[1])
6097 self.assertEqual(0, lens[2])
6098
6099 rest = content[12:]
6100 self.assertEqual(tpl_expect, rest[:len(tpl_expect)])
6101
6102 rest = rest[len(tpl_expect):]
6103 align_pad = len(tpl_expect) % 4
6104 self.assertEqual(tools.get_bytes(0, align_pad), rest[:align_pad])
6105 rest = rest[align_pad:]
6106 self.assertEqual(spl_expect, rest)
6107
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006108 def testMkimageMultipleNoContent(self):
6109 """Test passing multiple data files to mkimage with one data file having no content"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006110 self._SetupSplElf()
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006111 with self.assertRaises(ValueError) as exc:
6112 self._DoReadFile('253_mkimage_mult_no_content.dts')
6113 self.assertIn('Could not complete processing of contents',
6114 str(exc.exception))
6115
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006116 def testMkimageFilename(self):
6117 """Test using mkimage to build a binary with a filename"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006118 self._SetupSplElf()
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006119 retcode = self._DoTestFile('254_mkimage_filename.dts')
6120 self.assertEqual(0, retcode)
6121 fname = tools.get_output_filename('mkimage-test.bin')
6122 self.assertTrue(os.path.exists(fname))
6123
Simon Glass56d05412022-02-28 07:16:54 -07006124 def testVpl(self):
6125 """Test that an image with VPL and its device tree can be created"""
6126 # ELF file with a '__bss_size' symbol
6127 self._SetupVplElf()
6128 data = self._DoReadFile('255_u_boot_vpl.dts')
6129 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6130
6131 def testVplNoDtb(self):
6132 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6133 self._SetupVplElf()
6134 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6135 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6136 data[:len(U_BOOT_VPL_NODTB_DATA)])
6137
6138 def testExpandedVpl(self):
6139 """Test that an expanded entry type is selected for TPL when needed"""
6140 self._SetupVplElf()
6141
6142 entry_args = {
6143 'vpl-bss-pad': 'y',
6144 'vpl-dtb': 'y',
6145 }
6146 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6147 entry_args=entry_args)
6148 image = control.images['image']
6149 entries = image.GetEntries()
6150 self.assertEqual(1, len(entries))
6151
6152 # We only have u-boot-vpl, which be expanded
6153 self.assertIn('u-boot-vpl', entries)
6154 entry = entries['u-boot-vpl']
6155 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6156 subent = entry.GetEntries()
6157 self.assertEqual(3, len(subent))
6158 self.assertIn('u-boot-vpl-nodtb', subent)
6159 self.assertIn('u-boot-vpl-bss-pad', subent)
6160 self.assertIn('u-boot-vpl-dtb', subent)
6161
6162 def testVplBssPadMissing(self):
6163 """Test that a missing symbol is detected"""
6164 self._SetupVplElf('u_boot_ucode_ptr')
6165 with self.assertRaises(ValueError) as e:
6166 self._DoReadFile('258_vpl_bss_pad.dts')
6167 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6168 str(e.exception))
6169
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306170 def testSymlink(self):
6171 """Test that image files can be named"""
6172 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6173 self.assertEqual(0, retcode)
6174 image = control.images['test_image']
6175 fname = tools.get_output_filename('test_image.bin')
6176 sname = tools.get_output_filename('symlink_to_test.bin')
6177 self.assertTrue(os.path.islink(sname))
6178 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006179
Simon Glass37f85de2022-10-20 18:22:47 -06006180 def testSymbolsElf(self):
6181 """Test binman can assign symbols embedded in an ELF file"""
6182 if not elf.ELF_TOOLS:
6183 self.skipTest('Python elftools not available')
6184 self._SetupTplElf('u_boot_binman_syms')
6185 self._SetupVplElf('u_boot_binman_syms')
6186 self._SetupSplElf('u_boot_binman_syms')
6187 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6188 image_fname = tools.get_output_filename('image.bin')
6189
6190 image = control.images['image']
6191 entries = image.GetEntries()
6192
6193 for entry in entries.values():
6194 # No symbols in u-boot and it has faked contents anyway
6195 if entry.name == 'u-boot':
6196 continue
6197 edata = data[entry.image_pos:entry.image_pos + entry.size]
6198 efname = tools.get_output_filename(f'edata-{entry.name}')
6199 tools.write_file(efname, edata)
6200
6201 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6202 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6203 for name, sym in syms.items():
6204 msg = 'test'
6205 val = elf.GetSymbolValue(sym, edata, msg)
6206 entry_m = re_name.match(name)
6207 if entry_m:
6208 ename, prop = entry_m.group(1), entry_m.group(3)
6209 entry, entry_name, prop_name = image.LookupEntry(entries,
6210 name, msg)
6211 if prop_name == 'offset':
6212 expect_val = entry.offset
6213 elif prop_name == 'image_pos':
6214 expect_val = entry.image_pos
6215 elif prop_name == 'size':
6216 expect_val = entry.size
6217 self.assertEqual(expect_val, val)
6218
6219 def testSymbolsElfBad(self):
6220 """Check error when trying to write symbols without the elftools lib"""
6221 if not elf.ELF_TOOLS:
6222 self.skipTest('Python elftools not available')
6223 self._SetupTplElf('u_boot_binman_syms')
6224 self._SetupVplElf('u_boot_binman_syms')
6225 self._SetupSplElf('u_boot_binman_syms')
6226 try:
6227 elf.ELF_TOOLS = False
6228 with self.assertRaises(ValueError) as exc:
6229 self._DoReadFileDtb('260_symbols_elf.dts')
6230 finally:
6231 elf.ELF_TOOLS = True
6232 self.assertIn(
6233 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6234 'Cannot write symbols to an ELF file without Python elftools',
6235 str(exc.exception))
6236
Simon Glassde244162023-01-07 14:07:08 -07006237 def testSectionFilename(self):
6238 """Check writing of section contents to a file"""
6239 data = self._DoReadFile('261_section_fname.dts')
6240 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6241 tools.get_bytes(ord('!'), 7) +
6242 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6243 self.assertEqual(expected, data)
6244
6245 sect_fname = tools.get_output_filename('outfile.bin')
6246 self.assertTrue(os.path.exists(sect_fname))
6247 sect_data = tools.read_file(sect_fname)
6248 self.assertEqual(U_BOOT_DATA, sect_data)
6249
Simon Glass1e9e61c2023-01-07 14:07:12 -07006250 def testAbsent(self):
6251 """Check handling of absent entries"""
6252 data = self._DoReadFile('262_absent.dts')
6253 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6254
Simon Glassad5cfe12023-01-07 14:07:14 -07006255 def testPackTeeOsOptional(self):
6256 """Test that an image with an optional TEE binary can be created"""
6257 entry_args = {
6258 'tee-os-path': 'tee.elf',
6259 }
6260 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6261 entry_args=entry_args)[0]
6262 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6263
6264 def checkFitTee(self, dts, tee_fname):
6265 """Check that a tee-os entry works and returns data
6266
6267 Args:
6268 dts (str): Device tree filename to use
6269 tee_fname (str): filename containing tee-os
6270
6271 Returns:
6272 bytes: Image contents
6273 """
6274 if not elf.ELF_TOOLS:
6275 self.skipTest('Python elftools not available')
6276 entry_args = {
6277 'of-list': 'test-fdt1 test-fdt2',
6278 'default-dt': 'test-fdt2',
6279 'tee-os-path': tee_fname,
6280 }
6281 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6282 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6283 extra_indirs=[test_subdir])[0]
6284 return data
6285
6286 def testFitTeeOsOptionalFit(self):
6287 """Test an image with a FIT with an optional OP-TEE binary"""
6288 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6289
6290 # There should be only one node, holding the data set up in SetUpClass()
6291 # for tee.bin
6292 dtb = fdt.Fdt.FromData(data)
6293 dtb.Scan()
6294 node = dtb.GetNode('/images/tee-1')
6295 self.assertEqual(TEE_ADDR,
6296 fdt_util.fdt32_to_cpu(node.props['load'].value))
6297 self.assertEqual(TEE_ADDR,
6298 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6299 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6300
6301 def testFitTeeOsOptionalFitBad(self):
6302 """Test an image with a FIT with an optional OP-TEE binary"""
6303 with self.assertRaises(ValueError) as exc:
6304 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6305 self.assertIn(
6306 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6307 str(exc.exception))
6308
6309 def testFitTeeOsBad(self):
6310 """Test an OP-TEE binary with wrong formats"""
6311 self.make_tee_bin('tee.bad1', 123)
6312 with self.assertRaises(ValueError) as exc:
6313 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6314 self.assertIn(
6315 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6316 str(exc.exception))
6317
6318 self.make_tee_bin('tee.bad2', 0, b'extra data')
6319 with self.assertRaises(ValueError) as exc:
6320 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6321 self.assertIn(
6322 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6323 str(exc.exception))
6324
Simon Glass63328f12023-01-07 14:07:15 -07006325 def testExtblobOptional(self):
6326 """Test an image with an external blob that is optional"""
6327 with test_util.capture_sys_output() as (stdout, stderr):
6328 data = self._DoReadFile('266_blob_ext_opt.dts')
6329 self.assertEqual(REFCODE_DATA, data)
6330 err = stderr.getvalue()
6331 self.assertRegex(
6332 err,
6333 "Image '.*' is missing external blobs but is still functional: missing")
6334
Simon Glass7447a9d2023-01-11 16:10:12 -07006335 def testSectionInner(self):
6336 """Test an inner section with a size"""
6337 data = self._DoReadFile('267_section_inner.dts')
6338 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6339 self.assertEqual(expected, data)
6340
Simon Glassa4948b22023-01-11 16:10:14 -07006341 def testNull(self):
6342 """Test an image with a null entry"""
6343 data = self._DoReadFile('268_null.dts')
6344 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6345
Simon Glassf1ee03b2023-01-11 16:10:16 -07006346 def testOverlap(self):
6347 """Test an image with a overlapping entry"""
6348 data = self._DoReadFile('269_overlap.dts')
6349 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6350
6351 image = control.images['image']
6352 entries = image.GetEntries()
6353
6354 self.assertIn('inset', entries)
6355 inset = entries['inset']
6356 self.assertEqual(1, inset.offset);
6357 self.assertEqual(1, inset.image_pos);
6358 self.assertEqual(2, inset.size);
6359
6360 def testOverlapNull(self):
6361 """Test an image with a null overlap"""
6362 data = self._DoReadFile('270_overlap_null.dts')
6363 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6364
6365 # Check the FMAP
6366 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6367 self.assertEqual(4, fhdr.nareas)
6368 fiter = iter(fentries)
6369
6370 fentry = next(fiter)
6371 self.assertEqual(b'SECTION', fentry.name)
6372 self.assertEqual(0, fentry.offset)
6373 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6374 self.assertEqual(0, fentry.flags)
6375
6376 fentry = next(fiter)
6377 self.assertEqual(b'U_BOOT', 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 # Make sure that the NULL entry appears in the FMAP
6383 fentry = next(fiter)
6384 self.assertEqual(b'NULL', fentry.name)
6385 self.assertEqual(1, fentry.offset)
6386 self.assertEqual(2, fentry.size)
6387 self.assertEqual(0, fentry.flags)
6388
6389 fentry = next(fiter)
6390 self.assertEqual(b'FMAP', fentry.name)
6391 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6392
6393 def testOverlapBad(self):
6394 """Test an image with a bad overlapping entry"""
6395 with self.assertRaises(ValueError) as exc:
6396 self._DoReadFile('271_overlap_bad.dts')
6397 self.assertIn(
6398 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6399 str(exc.exception))
6400
6401 def testOverlapNoOffset(self):
6402 """Test an image with a bad overlapping entry"""
6403 with self.assertRaises(ValueError) as exc:
6404 self._DoReadFile('272_overlap_no_size.dts')
6405 self.assertIn(
6406 "Node '/binman/inset': 'fill' entry is missing properties: size",
6407 str(exc.exception))
6408
Simon Glasse0035c92023-01-11 16:10:17 -07006409 def testBlobSymbol(self):
6410 """Test a blob with symbols read from an ELF file"""
6411 elf_fname = self.ElfTestFile('blob_syms')
6412 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6413 TestFunctional._MakeInputFile('blob_syms.bin',
6414 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6415
6416 data = self._DoReadFile('273_blob_symbol.dts')
6417
6418 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6419 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6420 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6421 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6422 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6423
6424 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6425 expected = sym_values
6426 self.assertEqual(expected, data[:len(expected)])
6427
Simon Glass49e9c002023-01-11 16:10:19 -07006428 def testOffsetFromElf(self):
6429 """Test a blob with symbols read from an ELF file"""
6430 elf_fname = self.ElfTestFile('blob_syms')
6431 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6432 TestFunctional._MakeInputFile('blob_syms.bin',
6433 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6434
6435 data = self._DoReadFile('274_offset_from_elf.dts')
6436
6437 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6438 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6439
6440 image = control.images['image']
6441 entries = image.GetEntries()
6442
6443 self.assertIn('inset', entries)
6444 inset = entries['inset']
6445
6446 self.assertEqual(base + 4, inset.offset);
6447 self.assertEqual(base + 4, inset.image_pos);
6448 self.assertEqual(4, inset.size);
6449
6450 self.assertIn('inset2', entries)
6451 inset = entries['inset2']
6452 self.assertEqual(base + 8, inset.offset);
6453 self.assertEqual(base + 8, inset.image_pos);
6454 self.assertEqual(4, inset.size);
6455
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006456 def testFitAlign(self):
6457 """Test an image with an FIT with aligned external data"""
6458 data = self._DoReadFile('275_fit_align.dts')
6459 self.assertEqual(4096, len(data))
6460
6461 dtb = fdt.Fdt.FromData(data)
6462 dtb.Scan()
6463
6464 props = self._GetPropTree(dtb, ['data-position'])
6465 expected = {
6466 'u-boot:data-position': 1024,
6467 'fdt-1:data-position': 2048,
6468 'fdt-2:data-position': 3072,
6469 }
6470 self.assertEqual(expected, props)
6471
Jonas Karlman490f73c2023-01-21 19:02:12 +00006472 def testFitFirmwareLoadables(self):
6473 """Test an image with an FIT that use fit,firmware"""
6474 if not elf.ELF_TOOLS:
6475 self.skipTest('Python elftools not available')
6476 entry_args = {
6477 'of-list': 'test-fdt1',
6478 'default-dt': 'test-fdt1',
6479 'atf-bl31-path': 'bl31.elf',
6480 'tee-os-path': 'missing.bin',
6481 }
6482 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006483 with test_util.capture_sys_output() as (stdout, stderr):
6484 data = self._DoReadFileDtb(
6485 '276_fit_firmware_loadables.dts',
6486 entry_args=entry_args,
6487 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006488
6489 dtb = fdt.Fdt.FromData(data)
6490 dtb.Scan()
6491
6492 node = dtb.GetNode('/configurations/conf-uboot-1')
6493 self.assertEqual('u-boot', node.props['firmware'].value)
6494 self.assertEqual(['atf-1', 'atf-2'],
6495 fdt_util.GetStringList(node, 'loadables'))
6496
6497 node = dtb.GetNode('/configurations/conf-atf-1')
6498 self.assertEqual('atf-1', node.props['firmware'].value)
6499 self.assertEqual(['u-boot', 'atf-2'],
6500 fdt_util.GetStringList(node, 'loadables'))
6501
6502 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6503 self.assertEqual('u-boot', node.props['firmware'].value)
6504 self.assertEqual(['atf-1', 'atf-2'],
6505 fdt_util.GetStringList(node, 'loadables'))
6506
6507 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6508 self.assertEqual('atf-1', node.props['firmware'].value)
6509 self.assertEqual(['u-boot', 'atf-2'],
6510 fdt_util.GetStringList(node, 'loadables'))
6511
6512 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6513 self.assertEqual('atf-1', node.props['firmware'].value)
6514 self.assertEqual(['u-boot', 'atf-2'],
6515 fdt_util.GetStringList(node, 'loadables'))
6516
Simon Glass9a1c7262023-02-22 12:14:49 -07006517 def testTooldir(self):
6518 """Test that we can specify the tooldir"""
6519 with test_util.capture_sys_output() as (stdout, stderr):
6520 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6521 'tool', '-l'))
6522 self.assertEqual('fred', bintool.Bintool.tooldir)
6523
6524 # Check that the toolpath is updated correctly
6525 self.assertEqual(['fred'], tools.tool_search_paths)
6526
6527 # Try with a few toolpaths; the tooldir should be at the end
6528 with test_util.capture_sys_output() as (stdout, stderr):
6529 self.assertEqual(0, self._DoBinman(
6530 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6531 'tool', '-l'))
6532 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6533
Simon Glass49b77e82023-03-02 17:02:44 -07006534 def testReplaceSectionEntry(self):
6535 """Test replacing an entry in a section"""
6536 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6537 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6538 expect_data, dts='241_replace_section_simple.dts')
6539 self.assertEqual(expect_data, entry_data)
6540
6541 entries = image.GetEntries()
6542 self.assertIn('section', entries)
6543 section = entries['section']
6544
6545 sect_entries = section.GetEntries()
6546 self.assertIn('blob', sect_entries)
6547 entry = sect_entries['blob']
6548 self.assertEqual(len(expect_data), entry.size)
6549
6550 fname = tools.get_output_filename('image-updated.bin')
6551 data = tools.read_file(fname)
6552
6553 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6554 self.assertEqual(expect_data, new_blob_data)
6555
6556 self.assertEqual(U_BOOT_DATA,
6557 data[entry.image_pos + len(expect_data):]
6558 [:len(U_BOOT_DATA)])
6559
6560 def testReplaceSectionDeep(self):
6561 """Test replacing an entry in two levels of sections"""
6562 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6563 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6564 'section/section/blob', expect_data,
6565 dts='278_replace_section_deep.dts')
6566 self.assertEqual(expect_data, entry_data)
6567
6568 entries = image.GetEntries()
6569 self.assertIn('section', entries)
6570 section = entries['section']
6571
6572 subentries = section.GetEntries()
6573 self.assertIn('section', subentries)
6574 section = subentries['section']
6575
6576 sect_entries = section.GetEntries()
6577 self.assertIn('blob', sect_entries)
6578 entry = sect_entries['blob']
6579 self.assertEqual(len(expect_data), entry.size)
6580
6581 fname = tools.get_output_filename('image-updated.bin')
6582 data = tools.read_file(fname)
6583
6584 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6585 self.assertEqual(expect_data, new_blob_data)
6586
6587 self.assertEqual(U_BOOT_DATA,
6588 data[entry.image_pos + len(expect_data):]
6589 [:len(U_BOOT_DATA)])
6590
6591 def testReplaceFitSibling(self):
6592 """Test an image with a FIT inside where we replace its sibling"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006593 self._SetupSplElf()
Simon Glass49b77e82023-03-02 17:02:44 -07006594 fname = TestFunctional._MakeInputFile('once', b'available once')
6595 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6596 os.remove(fname)
6597
6598 try:
6599 tmpdir, updated_fname = self._SetupImageInTmpdir()
6600
6601 fname = os.path.join(tmpdir, 'update-blob')
6602 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6603 tools.write_file(fname, expected)
6604
6605 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6606 data = tools.read_file(updated_fname)
6607 start = len(U_BOOT_DTB_DATA)
6608 self.assertEqual(expected, data[start:start + len(expected)])
6609 map_fname = os.path.join(tmpdir, 'image-updated.map')
6610 self.assertFalse(os.path.exists(map_fname))
6611 finally:
6612 shutil.rmtree(tmpdir)
6613
Simon Glassc3fe97f2023-03-02 17:02:45 -07006614 def testX509Cert(self):
6615 """Test creating an X509 certificate"""
6616 keyfile = self.TestFile('key.key')
6617 entry_args = {
6618 'keyfile': keyfile,
6619 }
6620 data = self._DoReadFileDtb('279_x509_cert.dts',
6621 entry_args=entry_args)[0]
6622 cert = data[:-4]
6623 self.assertEqual(U_BOOT_DATA, data[-4:])
6624
6625 # TODO: verify the signature
6626
6627 def testX509CertMissing(self):
6628 """Test that binman still produces an image if openssl is missing"""
6629 keyfile = self.TestFile('key.key')
6630 entry_args = {
6631 'keyfile': 'keyfile',
6632 }
6633 with test_util.capture_sys_output() as (_, stderr):
6634 self._DoTestFile('279_x509_cert.dts',
6635 force_missing_bintools='openssl',
6636 entry_args=entry_args)
6637 err = stderr.getvalue()
6638 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6639
Jonas Karlman35305492023-02-25 19:01:33 +00006640 def testPackRockchipTpl(self):
6641 """Test that an image with a Rockchip TPL binary can be created"""
6642 data = self._DoReadFile('277_rockchip_tpl.dts')
6643 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6644
Jonas Karlman1016ec72023-02-25 19:01:35 +00006645 def testMkimageMissingBlobMultiple(self):
6646 """Test missing blob with mkimage entry and multiple-data-files"""
6647 with test_util.capture_sys_output() as (stdout, stderr):
6648 self._DoTestFile('278_mkimage_missing_multiple.dts', allow_missing=True)
6649 err = stderr.getvalue()
6650 self.assertIn("is missing external blobs and is non-functional", err)
6651
6652 with self.assertRaises(ValueError) as e:
6653 self._DoTestFile('278_mkimage_missing_multiple.dts', allow_missing=False)
6654 self.assertIn("not found in input path", str(e.exception))
6655
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006656 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6657 """Prepare sign environment
6658
6659 Create private and public keys, add pubkey into dtb.
6660
6661 Returns:
6662 Tuple:
6663 FIT container
6664 Image name
6665 Private key
6666 DTB
6667 """
Marek Vasutf7413f02023-07-18 07:23:58 -06006668 self._SetupSplElf()
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006669 data = self._DoReadFileRealDtb(dts)
6670 updated_fname = tools.get_output_filename('image-updated.bin')
6671 tools.write_file(updated_fname, data)
6672 dtb = tools.get_output_filename('source.dtb')
6673 private_key = tools.get_output_filename('test_key.key')
6674 public_key = tools.get_output_filename('test_key.crt')
6675 fit = tools.get_output_filename('fit.fit')
6676 key_dir = tools.get_output_dir()
6677
6678 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6679 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6680 private_key, '-out', public_key)
6681 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6682 '-n', 'test_key', '-r', 'conf', dtb)
6683
6684 return fit, updated_fname, private_key, dtb
6685
6686 def testSignSimple(self):
6687 """Test that a FIT container can be signed in image"""
6688 is_signed = False
6689 fit, fname, private_key, dtb = self._PrepareSignEnv()
6690
6691 # do sign with private key
6692 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6693 ['fit'])
6694 is_signed = self._CheckSign(fit, dtb)
6695
6696 self.assertEqual(is_signed, True)
6697
6698 def testSignExactFIT(self):
6699 """Test that a FIT container can be signed and replaced in image"""
6700 is_signed = False
6701 fit, fname, private_key, dtb = self._PrepareSignEnv()
6702
6703 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6704 args = []
6705 if self.toolpath:
6706 for path in self.toolpath:
6707 args += ['--toolpath', path]
6708
6709 # do sign with private key
6710 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6711 'sha256,rsa4096', '-f', fit, 'fit')
6712 is_signed = self._CheckSign(fit, dtb)
6713
6714 self.assertEqual(is_signed, True)
6715
6716 def testSignNonFit(self):
6717 """Test a non-FIT entry cannot be signed"""
6718 is_signed = False
6719 fit, fname, private_key, _ = self._PrepareSignEnv(
6720 '281_sign_non_fit.dts')
6721
6722 # do sign with private key
6723 with self.assertRaises(ValueError) as e:
6724 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6725 'sha256,rsa4096', '-f', fit, 'u-boot')
6726 self.assertIn(
6727 "Node '/u-boot': Updating signatures is not supported with this entry type",
6728 str(e.exception))
6729
6730 def testSignMissingMkimage(self):
6731 """Test that FIT signing handles a missing mkimage tool"""
6732 fit, fname, private_key, _ = self._PrepareSignEnv()
6733
6734 # try to sign with a missing mkimage tool
6735 bintool.Bintool.set_missing_list(['mkimage'])
6736 with self.assertRaises(ValueError) as e:
6737 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6738 ['fit'])
6739 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6740
Simon Glass4abf7842023-07-18 07:23:54 -06006741 def testSymbolNoWrite(self):
6742 """Test disabling of symbol writing"""
Marek Vasutf7413f02023-07-18 07:23:58 -06006743 self._SetupSplElf()
Simon Glass4abf7842023-07-18 07:23:54 -06006744 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6745 no_write_symbols=True)
6746
6747 def testSymbolNoWriteExpanded(self):
6748 """Test disabling of symbol writing in expanded entries"""
6749 entry_args = {
6750 'spl-dtb': '1',
6751 }
6752 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6753 U_BOOT_SPL_DTB_DATA, 0x38,
6754 entry_args=entry_args, use_expanded=True,
6755 no_write_symbols=True)
6756
Marek Vasutf7413f02023-07-18 07:23:58 -06006757 def testMkimageSpecial(self):
6758 """Test mkimage ignores special hash-1 node"""
6759 data = self._DoReadFile('283_mkimage_special.dts')
6760
6761 # Just check that the data appears in the file somewhere
6762 self.assertIn(U_BOOT_DATA, data)
6763
Simon Glass2d94c422023-07-18 07:23:59 -06006764 def testFitFdtList(self):
6765 """Test an image with an FIT with the fit,fdt-list-val option"""
6766 entry_args = {
6767 'default-dt': 'test-fdt2',
6768 }
6769 data = self._DoReadFileDtb(
6770 '284_fit_fdt_list.dts',
6771 entry_args=entry_args,
6772 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
6773 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
6774 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
6775
Simon Glass83b8bfe2023-07-18 07:24:01 -06006776 def testSplEmptyBss(self):
6777 """Test an expanded SPL with a zero-size BSS"""
6778 # ELF file with a '__bss_size' symbol
6779 self._SetupSplElf(src_fname='bss_data_zero')
6780
6781 entry_args = {
6782 'spl-bss-pad': 'y',
6783 'spl-dtb': 'y',
6784 }
6785 data = self._DoReadFileDtb('285_spl_expand.dts',
6786 use_expanded=True, entry_args=entry_args)[0]
6787
Simon Glassfc792842023-07-18 07:24:04 -06006788 def testTemplate(self):
6789 """Test using a template"""
6790 TestFunctional._MakeInputFile('vga2.bin', b'#' + VGA_DATA)
6791 data = self._DoReadFile('286_template.dts')
6792 first = U_BOOT_DATA + VGA_DATA + U_BOOT_DTB_DATA
6793 second = U_BOOT_DATA + b'#' + VGA_DATA + U_BOOT_DTB_DATA
6794 self.assertEqual(U_BOOT_IMG_DATA + first + second, data)
6795
Simon Glassde244162023-01-07 14:07:08 -07006796
Simon Glassac599912017-11-12 21:52:22 -07006797if __name__ == "__main__":
6798 unittest.main()