blob: dabb3f689fdb70cf1571796cf3f806136050e253 [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"""
Simon Glass57454f42016-11-25 20:15:52 -07001106 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001107 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001108 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001109 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1110 str(e.exception))
1111
1112 def testPackUbootDtb(self):
1113 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001114 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001115 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001116
1117 def testPackX86RomNoSize(self):
1118 """Test that the end-at-4gb property requires a size property"""
1119 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001120 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001121 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001122 "using end-at-4gb", str(e.exception))
1123
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301124 def test4gbAndSkipAtStartTogether(self):
1125 """Test that the end-at-4gb and skip-at-size property can't be used
1126 together"""
1127 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001128 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001129 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301130 "'skip-at-start'", str(e.exception))
1131
Simon Glass72232452016-11-25 20:15:53 -07001132 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001133 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -07001134 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001135 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001136 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1137 "is outside the section '/binman' starting at "
1138 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001139 str(e.exception))
1140
1141 def testPackX86Rom(self):
1142 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001143 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001144 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001145 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1146 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001147
1148 def testPackX86RomMeNoDesc(self):
1149 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001150 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001151 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001152 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001153 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001154 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1155 str(e.exception))
1156 finally:
1157 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001158
1159 def testPackX86RomBadDesc(self):
1160 """Test that the Intel requires a descriptor entry"""
1161 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001162 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001163 self.assertIn("Node '/binman/intel-me': No offset set with "
1164 "offset-unset: should another entry provide this correct "
1165 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001166
1167 def testPackX86RomMe(self):
1168 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001169 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001170 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001171 if data[:0x1000] != expected_desc:
1172 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001173 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1174
1175 def testPackVga(self):
1176 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001177 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001178 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1179
1180 def testPackStart16(self):
1181 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001182 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001183 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1184
Jagdish Gediya311d4842018-09-03 21:35:08 +05301185 def testPackPowerpcMpc85xxBootpgResetvec(self):
1186 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1187 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001188 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301189 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1190
Simon Glass6ba679c2018-07-06 10:27:17 -06001191 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001192 """Handle running a test for insertion of microcode
1193
1194 Args:
1195 dts_fname: Name of test .dts file
1196 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001197 ucode_second: True if the microsecond entry is second instead of
1198 third
Simon Glass820af1d2018-07-06 10:27:16 -06001199
1200 Returns:
1201 Tuple:
1202 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001203 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001204 in the above (two 4-byte words)
1205 """
Simon Glass3d274232017-11-12 21:52:27 -07001206 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001207
1208 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001209 if ucode_second:
1210 ucode_content = data[len(nodtb_data):]
1211 ucode_pos = len(nodtb_data)
1212 dtb_with_ucode = ucode_content[16:]
1213 fdt_len = self.GetFdtLen(dtb_with_ucode)
1214 else:
1215 dtb_with_ucode = data[len(nodtb_data):]
1216 fdt_len = self.GetFdtLen(dtb_with_ucode)
1217 ucode_content = dtb_with_ucode[fdt_len:]
1218 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001219 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001220 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001221 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001222 dtb = fdt.FdtScan(fname)
1223 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001224 self.assertTrue(ucode)
1225 for node in ucode.subnodes:
1226 self.assertFalse(node.props.get('data'))
1227
Simon Glass72232452016-11-25 20:15:53 -07001228 # Check that the microcode appears immediately after the Fdt
1229 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001230 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001231 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1232 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001233 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001234
1235 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001236 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001237 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1238 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001239 u_boot = data[:len(nodtb_data)]
1240 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001241
1242 def testPackUbootMicrocode(self):
1243 """Test that x86 microcode can be handled correctly
1244
1245 We expect to see the following in the image, in order:
1246 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1247 place
1248 u-boot.dtb with the microcode removed
1249 the microcode
1250 """
Simon Glass511f6582018-10-01 12:22:30 -06001251 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001252 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001253 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1254 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001255
Simon Glassbac25c82017-05-27 07:38:26 -06001256 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001257 """Test that x86 microcode can be handled correctly
1258
1259 We expect to see the following in the image, in order:
1260 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1261 place
1262 u-boot.dtb with the microcode
1263 an empty microcode region
1264 """
1265 # We need the libfdt library to run this test since only that allows
1266 # finding the offset of a property. This is required by
1267 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001268 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001269
1270 second = data[len(U_BOOT_NODTB_DATA):]
1271
1272 fdt_len = self.GetFdtLen(second)
1273 third = second[fdt_len:]
1274 second = second[:fdt_len]
1275
Simon Glassbac25c82017-05-27 07:38:26 -06001276 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1277 self.assertIn(ucode_data, second)
1278 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001279
Simon Glassbac25c82017-05-27 07:38:26 -06001280 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001281 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001282 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1283 len(ucode_data))
1284 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001285 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1286 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001287
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001288 def testPackUbootSingleMicrocode(self):
1289 """Test that x86 microcode can be handled correctly with fdt_normal.
1290 """
Simon Glassbac25c82017-05-27 07:38:26 -06001291 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001292
Simon Glass996021e2016-11-25 20:15:54 -07001293 def testUBootImg(self):
1294 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001295 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001296 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001297
1298 def testNoMicrocode(self):
1299 """Test that a missing microcode region is detected"""
1300 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001301 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001302 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1303 "node found in ", str(e.exception))
1304
1305 def testMicrocodeWithoutNode(self):
1306 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1307 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001308 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001309 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1310 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1311
1312 def testMicrocodeWithoutNode2(self):
1313 """Test that a missing u-boot-ucode node is detected"""
1314 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001315 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001316 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1317 "microcode region u-boot-ucode", str(e.exception))
1318
1319 def testMicrocodeWithoutPtrInElf(self):
1320 """Test that a U-Boot binary without the microcode symbol is detected"""
1321 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001322 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001323 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001324 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001325
1326 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001327 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001328 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1329 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1330
1331 finally:
1332 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001333 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001334 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001335
1336 def testMicrocodeNotInImage(self):
1337 """Test that microcode must be placed within the image"""
1338 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001339 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001340 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1341 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001342 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001343
1344 def testWithoutMicrocode(self):
1345 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001346 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001347 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001348 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001349
1350 # Now check the device tree has no microcode
1351 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1352 second = data[len(U_BOOT_NODTB_DATA):]
1353
1354 fdt_len = self.GetFdtLen(second)
1355 self.assertEqual(dtb, second[:fdt_len])
1356
1357 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1358 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001359 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001360
1361 def testUnknownPosSize(self):
1362 """Test that microcode must be placed within the image"""
1363 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001364 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001365 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001366 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001367
1368 def testPackFsp(self):
1369 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001370 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001371 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1372
1373 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001374 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001375 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001376 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001377
1378 def testPackVbt(self):
1379 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001380 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001381 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001382
Simon Glass7f94e832017-11-12 21:52:25 -07001383 def testSplBssPad(self):
1384 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001385 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001386 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001387 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001388 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001389 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001390
Simon Glass04cda032018-10-01 21:12:42 -06001391 def testSplBssPadMissing(self):
1392 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001393 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001394 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001395 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001396 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1397 str(e.exception))
1398
Simon Glasse83679d2017-11-12 21:52:26 -07001399 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001400 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001401 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001402 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1403
Simon Glass6ba679c2018-07-06 10:27:17 -06001404 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1405 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001406
1407 We expect to see the following in the image, in order:
1408 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1409 correct place
1410 u-boot.dtb with the microcode removed
1411 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001412
1413 Args:
1414 dts: Device tree file to use for test
1415 ucode_second: True if the microsecond entry is second instead of
1416 third
Simon Glass3d274232017-11-12 21:52:27 -07001417 """
Simon Glass7057d022018-10-01 21:12:47 -06001418 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001419 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1420 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001421 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1422 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001423
Simon Glass6ba679c2018-07-06 10:27:17 -06001424 def testPackUbootSplMicrocode(self):
1425 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001426 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001427
1428 def testPackUbootSplMicrocodeReorder(self):
1429 """Test that order doesn't matter for microcode entries
1430
1431 This is the same as testPackUbootSplMicrocode but when we process the
1432 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1433 entry, so we reply on binman to try later.
1434 """
Simon Glass511f6582018-10-01 12:22:30 -06001435 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001436 ucode_second=True)
1437
Simon Glassa409c932017-11-12 21:52:28 -07001438 def testPackMrc(self):
1439 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001440 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001441 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1442
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001443 def testSplDtb(self):
1444 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001445 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001446 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1447
Simon Glass0a6da312017-11-13 18:54:56 -07001448 def testSplNoDtb(self):
1449 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001450 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001451 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001452 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1453
Simon Glass7098b7f2021-03-21 18:24:30 +13001454 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
Simon Glass4abf7842023-07-18 07:23:54 -06001455 use_expanded=False, no_write_symbols=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001456 """Check the image contains the expected symbol values
1457
1458 Args:
1459 dts: Device tree file to use for test
1460 base_data: Data before and after 'u-boot' section
1461 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001462 entry_args: Dict of entry args to supply to binman
1463 key: arg name
1464 value: value of that arg
1465 use_expanded: True to use expanded entries where available, e.g.
1466 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001467 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001468 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001469 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1470 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001471 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001472 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001473 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001474
Simon Glass7057d022018-10-01 21:12:47 -06001475 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001476 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1477 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001478 # The image should contain the symbols from u_boot_binman_syms.c
1479 # Note that image_pos is adjusted by the base address of the image,
1480 # which is 0x10 in our test image
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001481 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1482 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glass31e04cb2021-03-18 20:24:56 +13001483 0x10 + u_boot_offset, 0x04)
Simon Glass4abf7842023-07-18 07:23:54 -06001484 if no_write_symbols:
1485 expected = (base_data +
1486 tools.get_bytes(0xff, 0x38 - len(base_data)) +
1487 U_BOOT_DATA + base_data)
1488 else:
1489 expected = (sym_values + base_data[24:] +
1490 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
1491 base_data[24:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001492 self.assertEqual(expected, data)
1493
Simon Glass31e04cb2021-03-18 20:24:56 +13001494 def testSymbols(self):
1495 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001496 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001497
1498 def testSymbolsNoDtb(self):
1499 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001500 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001501 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1502 0x38)
1503
Simon Glasse76a3e62018-06-01 09:38:11 -06001504 def testPackUnitAddress(self):
1505 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001506 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001507 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1508
Simon Glassa91e1152018-06-01 09:38:16 -06001509 def testSections(self):
1510 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001511 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001512 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1513 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1514 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001515 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001516
Simon Glass30732662018-06-01 09:38:20 -06001517 def testMap(self):
1518 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001519 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001520 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700152100000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600152200000000 00000000 00000010 section@0
152300000000 00000000 00000004 u-boot
152400000010 00000010 00000010 section@1
152500000010 00000000 00000004 u-boot
152600000020 00000020 00000004 section@2
152700000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001528''', map_data)
1529
Simon Glass3b78d532018-06-01 09:38:21 -06001530 def testNamePrefix(self):
1531 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001532 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001533 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700153400000000 00000000 00000028 image
Simon Glass7eca7922018-07-17 13:25:49 -0600153500000000 00000000 00000010 section@0
153600000000 00000000 00000004 ro-u-boot
153700000010 00000010 00000010 section@1
153800000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001539''', map_data)
1540
Simon Glass6ba679c2018-07-06 10:27:17 -06001541 def testUnknownContents(self):
1542 """Test that obtaining the contents works as expected"""
1543 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001544 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001545 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001546 "processing of contents: remaining ["
1547 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001548
Simon Glass2e1169f2018-07-06 10:27:19 -06001549 def testBadChangeSize(self):
1550 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001551 try:
1552 state.SetAllowEntryExpansion(False)
1553 with self.assertRaises(ValueError) as e:
1554 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001555 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001556 str(e.exception))
1557 finally:
1558 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001559
Simon Glassa87014e2018-07-06 10:27:42 -06001560 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001561 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001562 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001563 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001564 dtb = fdt.Fdt(out_dtb_fname)
1565 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001566 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001567 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001568 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001569 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001570 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001571 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001572 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001573 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001574 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001575 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001576 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001577 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001578 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001579
Simon Glasse8561af2018-08-01 15:22:37 -06001580 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001581 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001582 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001583 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001584 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001585 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001586 'size': 40
1587 }, props)
1588
1589 def testUpdateFdtBad(self):
1590 """Test that we detect when ProcessFdt never completes"""
1591 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001592 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001593 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001594 '[<binman.etype._testing.Entry__testing',
1595 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001596
Simon Glass91710b32018-07-17 13:25:32 -06001597 def testEntryArgs(self):
1598 """Test passing arguments to entries from the command line"""
1599 entry_args = {
1600 'test-str-arg': 'test1',
1601 'test-int-arg': '456',
1602 }
Simon Glass511f6582018-10-01 12:22:30 -06001603 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001604 self.assertIn('image', control.images)
1605 entry = control.images['image'].GetEntries()['_testing']
1606 self.assertEqual('test0', entry.test_str_fdt)
1607 self.assertEqual('test1', entry.test_str_arg)
1608 self.assertEqual(123, entry.test_int_fdt)
1609 self.assertEqual(456, entry.test_int_arg)
1610
1611 def testEntryArgsMissing(self):
1612 """Test missing arguments and properties"""
1613 entry_args = {
1614 'test-int-arg': '456',
1615 }
Simon Glass511f6582018-10-01 12:22:30 -06001616 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001617 entry = control.images['image'].GetEntries()['_testing']
1618 self.assertEqual('test0', entry.test_str_fdt)
1619 self.assertEqual(None, entry.test_str_arg)
1620 self.assertEqual(None, entry.test_int_fdt)
1621 self.assertEqual(456, entry.test_int_arg)
1622
1623 def testEntryArgsRequired(self):
1624 """Test missing arguments and properties"""
1625 entry_args = {
1626 'test-int-arg': '456',
1627 }
1628 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001629 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001630 self.assertIn("Node '/binman/_testing': "
1631 'Missing required properties/entry args: test-str-arg, '
1632 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001633 str(e.exception))
1634
1635 def testEntryArgsInvalidFormat(self):
1636 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001637 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1638 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001639 with self.assertRaises(ValueError) as e:
1640 self._DoBinman(*args)
1641 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1642
1643 def testEntryArgsInvalidInteger(self):
1644 """Test that an invalid entry-argument integer is detected"""
1645 entry_args = {
1646 'test-int-arg': 'abc',
1647 }
1648 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001649 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001650 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1651 "'test-int-arg' (value 'abc') to integer",
1652 str(e.exception))
1653
1654 def testEntryArgsInvalidDatatype(self):
1655 """Test that an invalid entry-argument datatype is detected
1656
1657 This test could be written in entry_test.py except that it needs
1658 access to control.entry_args, which seems more than that module should
1659 be able to see.
1660 """
1661 entry_args = {
1662 'test-bad-datatype-arg': '12',
1663 }
1664 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001665 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001666 entry_args=entry_args)
1667 self.assertIn('GetArg() internal error: Unknown data type ',
1668 str(e.exception))
1669
Simon Glass2ca52032018-07-17 13:25:33 -06001670 def testText(self):
1671 """Test for a text entry type"""
1672 entry_args = {
1673 'test-id': TEXT_DATA,
1674 'test-id2': TEXT_DATA2,
1675 'test-id3': TEXT_DATA3,
1676 }
Simon Glass511f6582018-10-01 12:22:30 -06001677 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001678 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001679 expected = (tools.to_bytes(TEXT_DATA) +
1680 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1681 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001682 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001683 self.assertEqual(expected, data)
1684
Simon Glass969616c2018-07-17 13:25:36 -06001685 def testEntryDocs(self):
1686 """Test for creation of entry documentation"""
1687 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001688 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001689 self.assertTrue(len(stdout.getvalue()) > 0)
1690
1691 def testEntryDocsMissing(self):
1692 """Test handling of missing entry documentation"""
1693 with self.assertRaises(ValueError) as e:
1694 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001695 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001696 self.assertIn('Documentation is missing for modules: u_boot',
1697 str(e.exception))
1698
Simon Glass704784b2018-07-17 13:25:38 -06001699 def testFmap(self):
1700 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001701 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001702 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001703 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1704 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001705 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001706 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001707 self.assertEqual(1, fhdr.ver_major)
1708 self.assertEqual(0, fhdr.ver_minor)
1709 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001710 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001711 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001712 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001713 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001714 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001715
Simon Glass82059c22021-04-03 11:05:09 +13001716 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001717 self.assertEqual(b'SECTION0', fentry.name)
1718 self.assertEqual(0, fentry.offset)
1719 self.assertEqual(16, fentry.size)
Simon Glasscda991e2023-02-12 17:11:15 -07001720 self.assertEqual(fmap_util.FMAP_AREA_PRESERVE, fentry.flags)
Simon Glassb1d414c2021-04-03 11:05:10 +13001721
1722 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001723 self.assertEqual(b'RO_U_BOOT', fentry.name)
1724 self.assertEqual(0, fentry.offset)
1725 self.assertEqual(4, fentry.size)
1726 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001727
Simon Glass82059c22021-04-03 11:05:09 +13001728 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001729 self.assertEqual(b'SECTION1', fentry.name)
1730 self.assertEqual(16, fentry.offset)
1731 self.assertEqual(16, fentry.size)
1732 self.assertEqual(0, fentry.flags)
1733
1734 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001735 self.assertEqual(b'RW_U_BOOT', fentry.name)
1736 self.assertEqual(16, fentry.offset)
1737 self.assertEqual(4, fentry.size)
1738 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001739
Simon Glass82059c22021-04-03 11:05:09 +13001740 fentry = next(fiter)
1741 self.assertEqual(b'FMAP', fentry.name)
1742 self.assertEqual(32, fentry.offset)
1743 self.assertEqual(expect_size, fentry.size)
1744 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001745
Simon Glassdb168d42018-07-17 13:25:39 -06001746 def testBlobNamedByArg(self):
1747 """Test we can add a blob with the filename coming from an entry arg"""
1748 entry_args = {
1749 'cros-ec-rw-path': 'ecrw.bin',
1750 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001751 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001752
Simon Glass53f53992018-07-17 13:25:40 -06001753 def testFill(self):
1754 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001755 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001756 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001757 self.assertEqual(expected, data)
1758
1759 def testFillNoSize(self):
1760 """Test for an fill entry type with no size"""
1761 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001762 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001763 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001764 str(e.exception))
1765
Simon Glassc1ae83c2018-07-17 13:25:44 -06001766 def _HandleGbbCommand(self, pipe_list):
1767 """Fake calls to the futility utility"""
Simon Glass9a1c7262023-02-22 12:14:49 -07001768 if 'futility' in pipe_list[0][0]:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001769 fname = pipe_list[0][-1]
1770 # Append our GBB data to the file, which will happen every time the
1771 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001772 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001773 fd.write(GBB_DATA)
1774 return command.CommandResult()
1775
1776 def testGbb(self):
1777 """Test for the Chromium OS Google Binary Block"""
1778 command.test_result = self._HandleGbbCommand
1779 entry_args = {
1780 'keydir': 'devkeys',
1781 'bmpblk': 'bmpblk.bin',
1782 }
Simon Glass511f6582018-10-01 12:22:30 -06001783 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001784
1785 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001786 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1787 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001788 self.assertEqual(expected, data)
1789
1790 def testGbbTooSmall(self):
1791 """Test for the Chromium OS Google Binary Block being large enough"""
1792 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001793 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001794 self.assertIn("Node '/binman/gbb': GBB is too small",
1795 str(e.exception))
1796
1797 def testGbbNoSize(self):
1798 """Test for the Chromium OS Google Binary Block having a size"""
1799 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001800 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001801 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1802 str(e.exception))
1803
Simon Glass66152ce2022-01-09 20:14:09 -07001804 def testGbbMissing(self):
1805 """Test that binman still produces an image if futility is missing"""
1806 entry_args = {
1807 'keydir': 'devkeys',
1808 }
1809 with test_util.capture_sys_output() as (_, stderr):
1810 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1811 entry_args=entry_args)
1812 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001813 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001814
Simon Glass5c350162018-07-17 13:25:47 -06001815 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001816 """Fake calls to the futility utility
1817
1818 The expected pipe is:
1819
1820 [('futility', 'vbutil_firmware', '--vblock',
1821 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1822 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1823 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1824 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1825
1826 This writes to the output file (here, 'vblock.vblock'). If
1827 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1828 of the input data (here, 'input.vblock').
1829 """
Simon Glass9a1c7262023-02-22 12:14:49 -07001830 if 'futility' in pipe_list[0][0]:
Simon Glass5c350162018-07-17 13:25:47 -06001831 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001832 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001833 if self._hash_data:
1834 infile = pipe_list[0][11]
1835 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001836 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001837 m.update(data)
1838 fd.write(m.digest())
1839 else:
1840 fd.write(VBLOCK_DATA)
1841
Simon Glass5c350162018-07-17 13:25:47 -06001842 return command.CommandResult()
1843
1844 def testVblock(self):
1845 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001846 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001847 command.test_result = self._HandleVblockCommand
1848 entry_args = {
1849 'keydir': 'devkeys',
1850 }
Simon Glass511f6582018-10-01 12:22:30 -06001851 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001852 entry_args=entry_args)
1853 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1854 self.assertEqual(expected, data)
1855
1856 def testVblockNoContent(self):
1857 """Test we detect a vblock which has no content to sign"""
1858 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001859 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001860 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001861 'property', str(e.exception))
1862
1863 def testVblockBadPhandle(self):
1864 """Test that we detect a vblock with an invalid phandle in contents"""
1865 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001866 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001867 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1868 '1000', str(e.exception))
1869
1870 def testVblockBadEntry(self):
1871 """Test that we detect an entry that points to a non-entry"""
1872 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001873 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001874 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1875 "'other'", str(e.exception))
1876
Simon Glass220c6222021-01-06 21:35:17 -07001877 def testVblockContent(self):
1878 """Test that the vblock signs the right data"""
1879 self._hash_data = True
1880 command.test_result = self._HandleVblockCommand
1881 entry_args = {
1882 'keydir': 'devkeys',
1883 }
1884 data = self._DoReadFileDtb(
1885 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1886 entry_args=entry_args)[0]
1887 hashlen = 32 # SHA256 hash is 32 bytes
1888 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1889 hashval = data[-hashlen:]
1890 dtb = data[len(U_BOOT_DATA):-hashlen]
1891
1892 expected_data = U_BOOT_DATA + dtb
1893
1894 # The hashval should be a hash of the dtb
1895 m = hashlib.sha256()
1896 m.update(expected_data)
1897 expected_hashval = m.digest()
1898 self.assertEqual(expected_hashval, hashval)
1899
Simon Glass66152ce2022-01-09 20:14:09 -07001900 def testVblockMissing(self):
1901 """Test that binman still produces an image if futility is missing"""
1902 entry_args = {
1903 'keydir': 'devkeys',
1904 }
1905 with test_util.capture_sys_output() as (_, stderr):
1906 self._DoTestFile('074_vblock.dts',
1907 force_missing_bintools='futility',
1908 entry_args=entry_args)
1909 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07001910 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glass66152ce2022-01-09 20:14:09 -07001911
Simon Glass8425a1f2018-07-17 13:25:48 -06001912 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001913 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001914 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001915 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001916 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001917 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1918
Simon Glass24b97442018-07-17 13:25:51 -06001919 def testUsesPos(self):
1920 """Test that the 'pos' property cannot be used anymore"""
1921 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001922 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001923 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1924 "'pos'", str(e.exception))
1925
Simon Glass274bf092018-09-14 04:57:08 -06001926 def testFillZero(self):
1927 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001928 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001929 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001930
Simon Glass267de432018-09-14 04:57:09 -06001931 def testTextMissing(self):
1932 """Test for a text entry type where there is no text"""
1933 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001934 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001935 self.assertIn("Node '/binman/text': No value provided for text label "
1936 "'test-id'", str(e.exception))
1937
Simon Glassed40e962018-09-14 04:57:10 -06001938 def testPackStart16Tpl(self):
1939 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001940 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001941 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1942
Simon Glass3b376c32018-09-14 04:57:12 -06001943 def testSelectImage(self):
1944 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001945 expected = 'Skipping images: image1'
1946
1947 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001948 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001949 with test_util.capture_sys_output() as (stdout, stderr):
1950 retcode = self._DoTestFile('006_dual_image.dts',
1951 verbosity=verbosity,
1952 images=['image2'])
1953 self.assertEqual(0, retcode)
1954 if verbosity:
1955 self.assertIn(expected, stdout.getvalue())
1956 else:
1957 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001958
Simon Glass80025522022-01-29 14:14:04 -07001959 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1960 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001961 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001962
Simon Glasse219aa42018-09-14 04:57:24 -06001963 def testUpdateFdtAll(self):
1964 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001965 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001966
1967 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06001968 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001969 'image-pos': 0,
1970 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06001971 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001972 'section:image-pos': 0,
1973 'section:size': 565,
1974 'section/u-boot-dtb:offset': 0,
1975 'section/u-boot-dtb:image-pos': 0,
1976 'section/u-boot-dtb:size': 565,
1977 'u-boot-spl-dtb:offset': 565,
1978 'u-boot-spl-dtb:image-pos': 565,
1979 'u-boot-spl-dtb:size': 585,
1980 'u-boot-tpl-dtb:offset': 1150,
1981 'u-boot-tpl-dtb:image-pos': 1150,
1982 'u-boot-tpl-dtb:size': 585,
1983 'u-boot-vpl-dtb:image-pos': 1735,
1984 'u-boot-vpl-dtb:offset': 1735,
1985 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06001986 }
1987
1988 # We expect three device-tree files in the output, one after the other.
1989 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1990 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1991 # main U-Boot tree. All three should have the same postions and offset.
1992 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07001993 self.maxDiff = None
1994 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06001995 dtb = fdt.Fdt.FromData(data[start:])
1996 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001997 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07001998 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001999 expected = dict(base_expected)
2000 if item:
2001 expected[item] = 0
2002 self.assertEqual(expected, props)
2003 start += dtb._fdt_obj.totalsize()
2004
2005 def testUpdateFdtOutput(self):
2006 """Test that output DTB files are updated"""
2007 try:
Simon Glass511f6582018-10-01 12:22:30 -06002008 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06002009 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
2010
2011 # Unfortunately, compiling a source file always results in a file
2012 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06002013 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06002014 # binman as a file called u-boot.dtb. To fix this, copy the file
2015 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06002016 start = 0
2017 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07002018 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06002019 dtb = fdt.Fdt.FromData(data[start:])
2020 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07002021 pathname = tools.get_output_filename(os.path.split(fname)[1])
2022 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06002023 name = os.path.split(fname)[0]
2024
2025 if name:
Simon Glass56d05412022-02-28 07:16:54 -07002026 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06002027 else:
2028 orig_indata = dtb_data
2029 self.assertNotEqual(outdata, orig_indata,
2030 "Expected output file '%s' be updated" % pathname)
2031 self.assertEqual(outdata, data[start:start + size],
2032 "Expected output file '%s' to match output image" %
2033 pathname)
2034 start += size
2035 finally:
2036 self._ResetDtbs()
2037
Simon Glass7ba33592018-09-14 04:57:26 -06002038 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002039 bintool = self.comp_bintools['lz4']
2040 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002041
2042 def testCompress(self):
2043 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002044 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002045 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002046 use_real_dtb=True, update_dtb=True)
2047 dtb = fdt.Fdt(out_dtb_fname)
2048 dtb.Scan()
2049 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2050 orig = self._decompress(data)
2051 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002052
2053 # Do a sanity check on various fields
2054 image = control.images['image']
2055 entries = image.GetEntries()
2056 self.assertEqual(1, len(entries))
2057
2058 entry = entries['blob']
2059 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2060 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2061 orig = self._decompress(entry.data)
2062 self.assertEqual(orig, entry.uncomp_data)
2063
Simon Glass72eeff12020-10-26 17:40:16 -06002064 self.assertEqual(image.data, entry.data)
2065
Simon Glass7ba33592018-09-14 04:57:26 -06002066 expected = {
2067 'blob:uncomp-size': len(COMPRESS_DATA),
2068 'blob:size': len(data),
2069 'size': len(data),
2070 }
2071 self.assertEqual(expected, props)
2072
Simon Glassac6328c2018-09-14 04:57:28 -06002073 def testFiles(self):
2074 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002075 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002076 self.assertEqual(FILES_DATA, data)
2077
2078 def testFilesCompress(self):
2079 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002080 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002081 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002082
2083 image = control.images['image']
2084 entries = image.GetEntries()
2085 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002086 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002087
Simon Glass303f62f2019-05-17 22:00:46 -06002088 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002089 for i in range(1, 3):
2090 key = '%d.dat' % i
2091 start = entries[key].image_pos
2092 len = entries[key].size
2093 chunk = data[start:start + len]
2094 orig += self._decompress(chunk)
2095
2096 self.assertEqual(FILES_DATA, orig)
2097
2098 def testFilesMissing(self):
2099 """Test missing files"""
2100 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002101 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002102 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2103 'no files', str(e.exception))
2104
2105 def testFilesNoPattern(self):
2106 """Test missing files"""
2107 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002108 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002109 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2110 str(e.exception))
2111
Simon Glassdd156a42022-03-05 20:18:59 -07002112 def testExtendSize(self):
2113 """Test an extending entry"""
2114 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002115 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002116 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2117 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2118 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2119 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002120 self.assertEqual(expect, data)
2121 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700212200000000 00000000 00000028 image
Simon Glassfa79a812018-09-14 04:57:29 -0600212300000000 00000000 00000008 fill
212400000008 00000008 00000004 u-boot
21250000000c 0000000c 00000004 section
21260000000c 00000000 00000003 intel-mrc
212700000010 00000010 00000004 u-boot2
212800000014 00000014 0000000c section2
212900000014 00000000 00000008 fill
21300000001c 00000008 00000004 u-boot
213100000020 00000020 00000008 fill2
2132''', map_data)
2133
Simon Glassdd156a42022-03-05 20:18:59 -07002134 def testExtendSizeBad(self):
2135 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002136 with test_util.capture_sys_output() as (stdout, stderr):
2137 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002138 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002139 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2140 'expanding entry', str(e.exception))
2141
Simon Glassae7cf032018-09-14 04:57:31 -06002142 def testHash(self):
2143 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002144 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002145 use_real_dtb=True, update_dtb=True)
2146 dtb = fdt.Fdt(out_dtb_fname)
2147 dtb.Scan()
2148 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2149 m = hashlib.sha256()
2150 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002151 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002152
2153 def testHashNoAlgo(self):
2154 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002155 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002156 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2157 'hash node', str(e.exception))
2158
2159 def testHashBadAlgo(self):
2160 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002161 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002162 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002163 str(e.exception))
2164
2165 def testHashSection(self):
2166 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002167 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002168 use_real_dtb=True, update_dtb=True)
2169 dtb = fdt.Fdt(out_dtb_fname)
2170 dtb.Scan()
2171 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2172 m = hashlib.sha256()
2173 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002174 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002175 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002176
Simon Glass3fb4f422018-09-14 04:57:32 -06002177 def testPackUBootTplMicrocode(self):
2178 """Test that x86 microcode can be handled correctly in TPL
2179
2180 We expect to see the following in the image, in order:
2181 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2182 place
2183 u-boot-tpl.dtb with the microcode removed
2184 the microcode
2185 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002186 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002187 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002188 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002189 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2190 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002191
Simon Glassc64aea52018-09-14 04:57:34 -06002192 def testFmapX86(self):
2193 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002194 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002195 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002196 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002197 self.assertEqual(expected, data[:32])
2198 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2199
2200 self.assertEqual(0x100, fhdr.image_size)
2201
2202 self.assertEqual(0, fentries[0].offset)
2203 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002204 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002205
2206 self.assertEqual(4, fentries[1].offset)
2207 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002208 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002209
2210 self.assertEqual(32, fentries[2].offset)
2211 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2212 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002213 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002214
2215 def testFmapX86Section(self):
2216 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002217 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002218 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002219 self.assertEqual(expected, data[:32])
2220 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2221
Simon Glassb1d414c2021-04-03 11:05:10 +13002222 self.assertEqual(0x180, fhdr.image_size)
2223 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002224 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002225
Simon Glass82059c22021-04-03 11:05:09 +13002226 fentry = next(fiter)
2227 self.assertEqual(b'U_BOOT', fentry.name)
2228 self.assertEqual(0, fentry.offset)
2229 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002230
Simon Glass82059c22021-04-03 11:05:09 +13002231 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002232 self.assertEqual(b'SECTION', fentry.name)
2233 self.assertEqual(4, fentry.offset)
2234 self.assertEqual(0x20 + expect_size, fentry.size)
2235
2236 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002237 self.assertEqual(b'INTEL_MRC', fentry.name)
2238 self.assertEqual(4, fentry.offset)
2239 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002240
Simon Glass82059c22021-04-03 11:05:09 +13002241 fentry = next(fiter)
2242 self.assertEqual(b'FMAP', fentry.name)
2243 self.assertEqual(36, fentry.offset)
2244 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002245
Simon Glassb1714232018-09-14 04:57:35 -06002246 def testElf(self):
2247 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002248 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002249 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002250 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002251 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002252 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002253
Simon Glass0d673792019-07-08 13:18:25 -06002254 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002255 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002256 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002257 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002258 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002259 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002260
Simon Glasscd817d52018-09-14 04:57:36 -06002261 def testPackOverlapMap(self):
2262 """Test that overlapping regions are detected"""
2263 with test_util.capture_sys_output() as (stdout, stderr):
2264 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002265 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002266 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002267 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2268 stdout.getvalue())
2269
2270 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002271 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002272 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002273 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002274 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -07002275<none> 00000000 00000008 image
Simon Glasscd817d52018-09-14 04:57:36 -06002276<none> 00000000 00000004 u-boot
2277<none> 00000003 00000004 u-boot-align
2278''', map_data)
2279
Simon Glass0d673792019-07-08 13:18:25 -06002280 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002281 """Test that an image with an Intel Reference code binary works"""
2282 data = self._DoReadFile('100_intel_refcode.dts')
2283 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2284
Simon Glasseb023b32019-04-25 21:58:39 -06002285 def testSectionOffset(self):
2286 """Tests use of a section with an offset"""
2287 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2288 map=True)
2289 self.assertEqual('''ImagePos Offset Size Name
Simon Glass49cd2b32023-02-07 14:34:18 -0700229000000000 00000000 00000038 image
Simon Glasseb023b32019-04-25 21:58:39 -0600229100000004 00000004 00000010 section@0
229200000004 00000000 00000004 u-boot
229300000018 00000018 00000010 section@1
229400000018 00000000 00000004 u-boot
22950000002c 0000002c 00000004 section@2
22960000002c 00000000 00000004 u-boot
2297''', map_data)
2298 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002299 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2300 tools.get_bytes(0x21, 12) +
2301 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2302 tools.get_bytes(0x61, 12) +
2303 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2304 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002305
Simon Glass1de34482019-07-08 13:18:53 -06002306 def testCbfsRaw(self):
2307 """Test base handling of a Coreboot Filesystem (CBFS)
2308
2309 The exact contents of the CBFS is verified by similar tests in
2310 cbfs_util_test.py. The tests here merely check that the files added to
2311 the CBFS can be found in the final image.
2312 """
2313 data = self._DoReadFile('102_cbfs_raw.dts')
2314 size = 0xb0
2315
2316 cbfs = cbfs_util.CbfsReader(data)
2317 self.assertEqual(size, cbfs.rom_size)
2318
2319 self.assertIn('u-boot-dtb', cbfs.files)
2320 cfile = cbfs.files['u-boot-dtb']
2321 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2322
2323 def testCbfsArch(self):
2324 """Test on non-x86 architecture"""
2325 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2326 size = 0x100
2327
2328 cbfs = cbfs_util.CbfsReader(data)
2329 self.assertEqual(size, cbfs.rom_size)
2330
2331 self.assertIn('u-boot-dtb', cbfs.files)
2332 cfile = cbfs.files['u-boot-dtb']
2333 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2334
2335 def testCbfsStage(self):
2336 """Tests handling of a Coreboot Filesystem (CBFS)"""
2337 if not elf.ELF_TOOLS:
2338 self.skipTest('Python elftools not available')
2339 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2340 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2341 size = 0xb0
2342
2343 data = self._DoReadFile('104_cbfs_stage.dts')
2344 cbfs = cbfs_util.CbfsReader(data)
2345 self.assertEqual(size, cbfs.rom_size)
2346
2347 self.assertIn('u-boot', cbfs.files)
2348 cfile = cbfs.files['u-boot']
2349 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2350
2351 def testCbfsRawCompress(self):
2352 """Test handling of compressing raw files"""
2353 self._CheckLz4()
2354 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2355 size = 0x140
2356
2357 cbfs = cbfs_util.CbfsReader(data)
2358 self.assertIn('u-boot', cbfs.files)
2359 cfile = cbfs.files['u-boot']
2360 self.assertEqual(COMPRESS_DATA, cfile.data)
2361
2362 def testCbfsBadArch(self):
2363 """Test handling of a bad architecture"""
2364 with self.assertRaises(ValueError) as e:
2365 self._DoReadFile('106_cbfs_bad_arch.dts')
2366 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2367
2368 def testCbfsNoSize(self):
2369 """Test handling of a missing size property"""
2370 with self.assertRaises(ValueError) as e:
2371 self._DoReadFile('107_cbfs_no_size.dts')
2372 self.assertIn('entry must have a size property', str(e.exception))
2373
Simon Glass3e28f4f2021-11-23 11:03:54 -07002374 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002375 """Test handling of a CBFS entry which does not provide contentsy"""
2376 with self.assertRaises(ValueError) as e:
2377 self._DoReadFile('108_cbfs_no_contents.dts')
2378 self.assertIn('Could not complete processing of contents',
2379 str(e.exception))
2380
2381 def testCbfsBadCompress(self):
2382 """Test handling of a bad architecture"""
2383 with self.assertRaises(ValueError) as e:
2384 self._DoReadFile('109_cbfs_bad_compress.dts')
2385 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2386 str(e.exception))
2387
2388 def testCbfsNamedEntries(self):
2389 """Test handling of named entries"""
2390 data = self._DoReadFile('110_cbfs_name.dts')
2391
2392 cbfs = cbfs_util.CbfsReader(data)
2393 self.assertIn('FRED', cbfs.files)
2394 cfile1 = cbfs.files['FRED']
2395 self.assertEqual(U_BOOT_DATA, cfile1.data)
2396
2397 self.assertIn('hello', cbfs.files)
2398 cfile2 = cbfs.files['hello']
2399 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2400
Simon Glass759af872019-07-08 13:18:54 -06002401 def _SetupIfwi(self, fname):
2402 """Set up to run an IFWI test
2403
2404 Args:
2405 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2406 """
2407 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002408 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002409
2410 # Intel Integrated Firmware Image (IFWI) file
2411 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2412 data = fd.read()
2413 TestFunctional._MakeInputFile(fname,data)
2414
2415 def _CheckIfwi(self, data):
2416 """Check that an image with an IFWI contains the correct output
2417
2418 Args:
2419 data: Conents of output file
2420 """
Simon Glass80025522022-01-29 14:14:04 -07002421 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002422 if data[:0x1000] != expected_desc:
2423 self.fail('Expected descriptor binary at start of image')
2424
2425 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002426 image_fname = tools.get_output_filename('image.bin')
2427 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002428 ifwitool = bintool.Bintool.create('ifwitool')
2429 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002430
Simon Glass80025522022-01-29 14:14:04 -07002431 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002432 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002433
2434 def testPackX86RomIfwi(self):
2435 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2436 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002437 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002438 self._CheckIfwi(data)
2439
2440 def testPackX86RomIfwiNoDesc(self):
2441 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2442 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002443 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002444 self._CheckIfwi(data)
2445
2446 def testPackX86RomIfwiNoData(self):
2447 """Test that an x86 ROM with IFWI handles missing data"""
2448 self._SetupIfwi('ifwi.bin')
2449 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002450 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002451 self.assertIn('Could not complete processing of contents',
2452 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002453
Simon Glass66152ce2022-01-09 20:14:09 -07002454 def testIfwiMissing(self):
2455 """Test that binman still produces an image if ifwitool is missing"""
2456 self._SetupIfwi('fitimage.bin')
2457 with test_util.capture_sys_output() as (_, stderr):
2458 self._DoTestFile('111_x86_rom_ifwi.dts',
2459 force_missing_bintools='ifwitool')
2460 err = stderr.getvalue()
2461 self.assertRegex(err,
Simon Glass49cd2b32023-02-07 14:34:18 -07002462 "Image 'image'.*missing bintools.*: ifwitool")
Simon Glass66152ce2022-01-09 20:14:09 -07002463
Simon Glassc2f1aed2019-07-08 13:18:56 -06002464 def testCbfsOffset(self):
2465 """Test a CBFS with files at particular offsets
2466
2467 Like all CFBS tests, this is just checking the logic that calls
2468 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2469 """
2470 data = self._DoReadFile('114_cbfs_offset.dts')
2471 size = 0x200
2472
2473 cbfs = cbfs_util.CbfsReader(data)
2474 self.assertEqual(size, cbfs.rom_size)
2475
2476 self.assertIn('u-boot', cbfs.files)
2477 cfile = cbfs.files['u-boot']
2478 self.assertEqual(U_BOOT_DATA, cfile.data)
2479 self.assertEqual(0x40, cfile.cbfs_offset)
2480
2481 self.assertIn('u-boot-dtb', cbfs.files)
2482 cfile2 = cbfs.files['u-boot-dtb']
2483 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2484 self.assertEqual(0x140, cfile2.cbfs_offset)
2485
Simon Glass0f621332019-07-08 14:25:27 -06002486 def testFdtmap(self):
2487 """Test an FDT map can be inserted in the image"""
2488 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2489 fdtmap_data = data[len(U_BOOT_DATA):]
2490 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002491 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002492 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002493
2494 fdt_data = fdtmap_data[16:]
2495 dtb = fdt.Fdt.FromData(fdt_data)
2496 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002497 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002498 self.assertEqual({
2499 'image-pos': 0,
2500 'offset': 0,
2501 'u-boot:offset': 0,
2502 'u-boot:size': len(U_BOOT_DATA),
2503 'u-boot:image-pos': 0,
2504 'fdtmap:image-pos': 4,
2505 'fdtmap:offset': 4,
2506 'fdtmap:size': len(fdtmap_data),
2507 'size': len(data),
2508 }, props)
2509
2510 def testFdtmapNoMatch(self):
2511 """Check handling of an FDT map when the section cannot be found"""
2512 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2513
2514 # Mangle the section name, which should cause a mismatch between the
2515 # correct FDT path and the one expected by the section
2516 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002517 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002518 entries = image.GetEntries()
2519 fdtmap = entries['fdtmap']
2520 with self.assertRaises(ValueError) as e:
2521 fdtmap._GetFdtmap()
2522 self.assertIn("Cannot locate node for path '/binman-suffix'",
2523 str(e.exception))
2524
Simon Glasscec34ba2019-07-08 14:25:28 -06002525 def testFdtmapHeader(self):
2526 """Test an FDT map and image header can be inserted in the image"""
2527 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2528 fdtmap_pos = len(U_BOOT_DATA)
2529 fdtmap_data = data[fdtmap_pos:]
2530 fdt_data = fdtmap_data[16:]
2531 dtb = fdt.Fdt.FromData(fdt_data)
2532 fdt_size = dtb.GetFdtObj().totalsize()
2533 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002534 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002535 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2536 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2537
2538 def testFdtmapHeaderStart(self):
2539 """Test an image header can be inserted at the image start"""
2540 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2541 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2542 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002543 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002544 offset = struct.unpack('<I', hdr_data[4:])[0]
2545 self.assertEqual(fdtmap_pos, offset)
2546
2547 def testFdtmapHeaderPos(self):
2548 """Test an image header can be inserted at a chosen position"""
2549 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2550 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2551 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002552 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002553 offset = struct.unpack('<I', hdr_data[4:])[0]
2554 self.assertEqual(fdtmap_pos, offset)
2555
2556 def testHeaderMissingFdtmap(self):
2557 """Test an image header requires an fdtmap"""
2558 with self.assertRaises(ValueError) as e:
2559 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2560 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2561 str(e.exception))
2562
2563 def testHeaderNoLocation(self):
2564 """Test an image header with a no specified location is detected"""
2565 with self.assertRaises(ValueError) as e:
2566 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2567 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2568 str(e.exception))
2569
Simon Glasse61b6f62019-07-08 14:25:37 -06002570 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002571 """Test extending an entry after it is packed"""
2572 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002573 self.assertEqual(b'aaa', data[:3])
2574 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2575 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002576
Simon Glassdd156a42022-03-05 20:18:59 -07002577 def testEntryExtendBad(self):
2578 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002579 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002580 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002581 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002582 str(e.exception))
2583
Simon Glassdd156a42022-03-05 20:18:59 -07002584 def testEntryExtendSection(self):
2585 """Test extending an entry within a section after it is packed"""
2586 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002587 self.assertEqual(b'aaa', data[:3])
2588 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2589 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002590
Simon Glass90d29682019-07-08 14:25:38 -06002591 def testCompressDtb(self):
2592 """Test that compress of device-tree files is supported"""
2593 self._CheckLz4()
2594 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2595 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2596 comp_data = data[len(U_BOOT_DATA):]
2597 orig = self._decompress(comp_data)
2598 dtb = fdt.Fdt.FromData(orig)
2599 dtb.Scan()
2600 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2601 expected = {
2602 'u-boot:size': len(U_BOOT_DATA),
2603 'u-boot-dtb:uncomp-size': len(orig),
2604 'u-boot-dtb:size': len(comp_data),
2605 'size': len(data),
2606 }
2607 self.assertEqual(expected, props)
2608
Simon Glass151bbbf2019-07-08 14:25:41 -06002609 def testCbfsUpdateFdt(self):
2610 """Test that we can update the device tree with CBFS offset/size info"""
2611 self._CheckLz4()
2612 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2613 update_dtb=True)
2614 dtb = fdt.Fdt(out_dtb_fname)
2615 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002616 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002617 del props['cbfs/u-boot:size']
2618 self.assertEqual({
2619 'offset': 0,
2620 'size': len(data),
2621 'image-pos': 0,
2622 'cbfs:offset': 0,
2623 'cbfs:size': len(data),
2624 'cbfs:image-pos': 0,
2625 'cbfs/u-boot:offset': 0x38,
2626 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2627 'cbfs/u-boot:image-pos': 0x38,
2628 'cbfs/u-boot-dtb:offset': 0xb8,
2629 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2630 'cbfs/u-boot-dtb:image-pos': 0xb8,
2631 }, props)
2632
Simon Glass3c9b4f22019-07-08 14:25:42 -06002633 def testCbfsBadType(self):
2634 """Test an image header with a no specified location is detected"""
2635 with self.assertRaises(ValueError) as e:
2636 self._DoReadFile('126_cbfs_bad_type.dts')
2637 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2638
Simon Glass6b156f82019-07-08 14:25:43 -06002639 def testList(self):
2640 """Test listing the files in an image"""
2641 self._CheckLz4()
2642 data = self._DoReadFile('127_list.dts')
2643 image = control.images['image']
2644 entries = image.BuildEntryList()
2645 self.assertEqual(7, len(entries))
2646
2647 ent = entries[0]
2648 self.assertEqual(0, ent.indent)
Simon Glass49cd2b32023-02-07 14:34:18 -07002649 self.assertEqual('image', ent.name)
Simon Glass6b156f82019-07-08 14:25:43 -06002650 self.assertEqual('section', ent.etype)
2651 self.assertEqual(len(data), ent.size)
2652 self.assertEqual(0, ent.image_pos)
2653 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002654 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002655
2656 ent = entries[1]
2657 self.assertEqual(1, ent.indent)
2658 self.assertEqual('u-boot', ent.name)
2659 self.assertEqual('u-boot', ent.etype)
2660 self.assertEqual(len(U_BOOT_DATA), ent.size)
2661 self.assertEqual(0, ent.image_pos)
2662 self.assertEqual(None, ent.uncomp_size)
2663 self.assertEqual(0, ent.offset)
2664
2665 ent = entries[2]
2666 self.assertEqual(1, ent.indent)
2667 self.assertEqual('section', ent.name)
2668 self.assertEqual('section', ent.etype)
2669 section_size = ent.size
2670 self.assertEqual(0x100, ent.image_pos)
2671 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002672 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002673
2674 ent = entries[3]
2675 self.assertEqual(2, ent.indent)
2676 self.assertEqual('cbfs', ent.name)
2677 self.assertEqual('cbfs', ent.etype)
2678 self.assertEqual(0x400, ent.size)
2679 self.assertEqual(0x100, ent.image_pos)
2680 self.assertEqual(None, ent.uncomp_size)
2681 self.assertEqual(0, ent.offset)
2682
2683 ent = entries[4]
2684 self.assertEqual(3, ent.indent)
2685 self.assertEqual('u-boot', ent.name)
2686 self.assertEqual('u-boot', ent.etype)
2687 self.assertEqual(len(U_BOOT_DATA), ent.size)
2688 self.assertEqual(0x138, ent.image_pos)
2689 self.assertEqual(None, ent.uncomp_size)
2690 self.assertEqual(0x38, ent.offset)
2691
2692 ent = entries[5]
2693 self.assertEqual(3, ent.indent)
2694 self.assertEqual('u-boot-dtb', ent.name)
2695 self.assertEqual('text', ent.etype)
2696 self.assertGreater(len(COMPRESS_DATA), ent.size)
2697 self.assertEqual(0x178, ent.image_pos)
2698 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2699 self.assertEqual(0x78, ent.offset)
2700
2701 ent = entries[6]
2702 self.assertEqual(2, ent.indent)
2703 self.assertEqual('u-boot-dtb', ent.name)
2704 self.assertEqual('u-boot-dtb', ent.etype)
2705 self.assertEqual(0x500, ent.image_pos)
2706 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2707 dtb_size = ent.size
2708 # Compressing this data expands it since headers are added
2709 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2710 self.assertEqual(0x400, ent.offset)
2711
2712 self.assertEqual(len(data), 0x100 + section_size)
2713 self.assertEqual(section_size, 0x400 + dtb_size)
2714
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002715 def testFindFdtmap(self):
2716 """Test locating an FDT map in an image"""
2717 self._CheckLz4()
2718 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2719 image = control.images['image']
2720 entries = image.GetEntries()
2721 entry = entries['fdtmap']
2722 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2723
2724 def testFindFdtmapMissing(self):
2725 """Test failing to locate an FDP map"""
2726 data = self._DoReadFile('005_simple.dts')
2727 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2728
Simon Glassed39a3c2019-07-08 14:25:45 -06002729 def testFindImageHeader(self):
2730 """Test locating a image header"""
2731 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002732 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002733 image = control.images['image']
2734 entries = image.GetEntries()
2735 entry = entries['fdtmap']
2736 # The header should point to the FDT map
2737 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2738
2739 def testFindImageHeaderStart(self):
2740 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002741 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002742 image = control.images['image']
2743 entries = image.GetEntries()
2744 entry = entries['fdtmap']
2745 # The header should point to the FDT map
2746 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2747
2748 def testFindImageHeaderMissing(self):
2749 """Test failing to locate an image header"""
2750 data = self._DoReadFile('005_simple.dts')
2751 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2752
Simon Glassb8424fa2019-07-08 14:25:46 -06002753 def testReadImage(self):
2754 """Test reading an image and accessing its FDT map"""
2755 self._CheckLz4()
2756 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002757 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002758 orig_image = control.images['image']
2759 image = Image.FromFile(image_fname)
2760 self.assertEqual(orig_image.GetEntries().keys(),
2761 image.GetEntries().keys())
2762
2763 orig_entry = orig_image.GetEntries()['fdtmap']
2764 entry = image.GetEntries()['fdtmap']
2765 self.assertEquals(orig_entry.offset, entry.offset)
2766 self.assertEquals(orig_entry.size, entry.size)
2767 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2768
2769 def testReadImageNoHeader(self):
2770 """Test accessing an image's FDT map without an image header"""
2771 self._CheckLz4()
2772 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002773 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002774 image = Image.FromFile(image_fname)
2775 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002776 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002777
2778 def testReadImageFail(self):
2779 """Test failing to read an image image's FDT map"""
2780 self._DoReadFile('005_simple.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 with self.assertRaises(ValueError) as e:
2783 image = Image.FromFile(image_fname)
2784 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002785
Simon Glassb2fd11d2019-07-08 14:25:48 -06002786 def testListCmd(self):
2787 """Test listing the files in an image using an Fdtmap"""
2788 self._CheckLz4()
2789 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2790
2791 # lz4 compression size differs depending on the version
2792 image = control.images['image']
2793 entries = image.GetEntries()
2794 section_size = entries['section'].size
2795 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2796 fdtmap_offset = entries['fdtmap'].offset
2797
Simon Glassb3d6fc72019-07-20 12:24:10 -06002798 try:
2799 tmpdir, updated_fname = self._SetupImageInTmpdir()
2800 with test_util.capture_sys_output() as (stdout, stderr):
2801 self._DoBinman('ls', '-i', updated_fname)
2802 finally:
2803 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002804 lines = stdout.getvalue().splitlines()
2805 expected = [
2806'Name Image-pos Size Entry-type Offset Uncomp-size',
2807'----------------------------------------------------------------------',
Simon Glass49cd2b32023-02-07 14:34:18 -07002808'image 0 c00 section 0',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002809' u-boot 0 4 u-boot 0',
2810' section 100 %x section 100' % section_size,
2811' cbfs 100 400 cbfs 0',
2812' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002813' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002814' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002815' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002816 (fdtmap_offset, fdtmap_offset),
2817' image-header bf8 8 image-header bf8',
2818 ]
2819 self.assertEqual(expected, lines)
2820
2821 def testListCmdFail(self):
2822 """Test failing to list an image"""
2823 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002824 try:
2825 tmpdir, updated_fname = self._SetupImageInTmpdir()
2826 with self.assertRaises(ValueError) as e:
2827 self._DoBinman('ls', '-i', updated_fname)
2828 finally:
2829 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002830 self.assertIn("Cannot find FDT map in image", str(e.exception))
2831
2832 def _RunListCmd(self, paths, expected):
2833 """List out entries and check the result
2834
2835 Args:
2836 paths: List of paths to pass to the list command
2837 expected: Expected list of filenames to be returned, in order
2838 """
2839 self._CheckLz4()
2840 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002841 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002842 image = Image.FromFile(image_fname)
2843 lines = image.GetListEntries(paths)[1]
2844 files = [line[0].strip() for line in lines[1:]]
2845 self.assertEqual(expected, files)
2846
2847 def testListCmdSection(self):
2848 """Test listing the files in a section"""
2849 self._RunListCmd(['section'],
2850 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2851
2852 def testListCmdFile(self):
2853 """Test listing a particular file"""
2854 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2855
2856 def testListCmdWildcard(self):
2857 """Test listing a wildcarded file"""
2858 self._RunListCmd(['*boot*'],
2859 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2860
2861 def testListCmdWildcardMulti(self):
2862 """Test listing a wildcarded file"""
2863 self._RunListCmd(['*cb*', '*head*'],
2864 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2865
2866 def testListCmdEmpty(self):
2867 """Test listing a wildcarded file"""
2868 self._RunListCmd(['nothing'], [])
2869
2870 def testListCmdPath(self):
2871 """Test listing the files in a sub-entry of a section"""
2872 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2873
Simon Glass4c613bf2019-07-08 14:25:50 -06002874 def _RunExtractCmd(self, entry_name, decomp=True):
2875 """Extract an entry from an image
2876
2877 Args:
2878 entry_name: Entry name to extract
2879 decomp: True to decompress the data if compressed, False to leave
2880 it in its raw uncompressed format
2881
2882 Returns:
2883 data from entry
2884 """
2885 self._CheckLz4()
2886 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002887 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002888 return control.ReadEntry(image_fname, entry_name, decomp)
2889
2890 def testExtractSimple(self):
2891 """Test extracting a single file"""
2892 data = self._RunExtractCmd('u-boot')
2893 self.assertEqual(U_BOOT_DATA, data)
2894
Simon Glass980a2842019-07-08 14:25:52 -06002895 def testExtractSection(self):
2896 """Test extracting the files in a section"""
2897 data = self._RunExtractCmd('section')
2898 cbfs_data = data[:0x400]
2899 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002900 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002901 dtb_data = data[0x400:]
2902 dtb = self._decompress(dtb_data)
2903 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2904
2905 def testExtractCompressed(self):
2906 """Test extracting compressed data"""
2907 data = self._RunExtractCmd('section/u-boot-dtb')
2908 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2909
2910 def testExtractRaw(self):
2911 """Test extracting compressed data without decompressing it"""
2912 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2913 dtb = self._decompress(data)
2914 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2915
2916 def testExtractCbfs(self):
2917 """Test extracting CBFS data"""
2918 data = self._RunExtractCmd('section/cbfs/u-boot')
2919 self.assertEqual(U_BOOT_DATA, data)
2920
2921 def testExtractCbfsCompressed(self):
2922 """Test extracting CBFS compressed data"""
2923 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2924 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2925
2926 def testExtractCbfsRaw(self):
2927 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002928 bintool = self.comp_bintools['lzma_alone']
2929 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06002930 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002931 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06002932 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2933
Simon Glass4c613bf2019-07-08 14:25:50 -06002934 def testExtractBadEntry(self):
2935 """Test extracting a bad section path"""
2936 with self.assertRaises(ValueError) as e:
2937 self._RunExtractCmd('section/does-not-exist')
2938 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2939 str(e.exception))
2940
2941 def testExtractMissingFile(self):
2942 """Test extracting file that does not exist"""
2943 with self.assertRaises(IOError) as e:
2944 control.ReadEntry('missing-file', 'name')
2945
2946 def testExtractBadFile(self):
2947 """Test extracting an invalid file"""
2948 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002949 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002950 with self.assertRaises(ValueError) as e:
2951 control.ReadEntry(fname, 'name')
2952
Simon Glass980a2842019-07-08 14:25:52 -06002953 def testExtractCmd(self):
2954 """Test extracting a file fron an image on the command line"""
2955 self._CheckLz4()
2956 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002957 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002958 try:
2959 tmpdir, updated_fname = self._SetupImageInTmpdir()
2960 with test_util.capture_sys_output() as (stdout, stderr):
2961 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2962 '-f', fname)
2963 finally:
2964 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07002965 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002966 self.assertEqual(U_BOOT_DATA, data)
2967
2968 def testExtractOneEntry(self):
2969 """Test extracting a single entry fron an image """
2970 self._CheckLz4()
2971 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002972 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002973 fname = os.path.join(self._indir, 'output.extact')
2974 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07002975 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002976 self.assertEqual(U_BOOT_DATA, data)
2977
2978 def _CheckExtractOutput(self, decomp):
2979 """Helper to test file output with and without decompression
2980
2981 Args:
2982 decomp: True to decompress entry data, False to output it raw
2983 """
2984 def _CheckPresent(entry_path, expect_data, expect_size=None):
2985 """Check and remove expected file
2986
2987 This checks the data/size of a file and removes the file both from
2988 the outfiles set and from the output directory. Once all files are
2989 processed, both the set and directory should be empty.
2990
2991 Args:
2992 entry_path: Entry path
2993 expect_data: Data to expect in file, or None to skip check
2994 expect_size: Size of data to expect in file, or None to skip
2995 """
2996 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07002997 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06002998 os.remove(path)
2999 if expect_data:
3000 self.assertEqual(expect_data, data)
3001 elif expect_size:
3002 self.assertEqual(expect_size, len(data))
3003 outfiles.remove(path)
3004
3005 def _CheckDirPresent(name):
3006 """Remove expected directory
3007
3008 This gives an error if the directory does not exist as expected
3009
3010 Args:
3011 name: Name of directory to remove
3012 """
3013 path = os.path.join(outdir, name)
3014 os.rmdir(path)
3015
3016 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003017 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003018 outdir = os.path.join(self._indir, 'extract')
3019 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
3020
3021 # Create a set of all file that were output (should be 9)
3022 outfiles = set()
3023 for root, dirs, files in os.walk(outdir):
3024 outfiles |= set([os.path.join(root, fname) for fname in files])
3025 self.assertEqual(9, len(outfiles))
3026 self.assertEqual(9, len(einfos))
3027
3028 image = control.images['image']
3029 entries = image.GetEntries()
3030
3031 # Check the 9 files in various ways
3032 section = entries['section']
3033 section_entries = section.GetEntries()
3034 cbfs_entries = section_entries['cbfs'].GetEntries()
3035 _CheckPresent('u-boot', U_BOOT_DATA)
3036 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
3037 dtb_len = EXTRACT_DTB_SIZE
3038 if not decomp:
3039 dtb_len = cbfs_entries['u-boot-dtb'].size
3040 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3041 if not decomp:
3042 dtb_len = section_entries['u-boot-dtb'].size
3043 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3044
3045 fdtmap = entries['fdtmap']
3046 _CheckPresent('fdtmap', fdtmap.data)
3047 hdr = entries['image-header']
3048 _CheckPresent('image-header', hdr.data)
3049
3050 _CheckPresent('section/root', section.data)
3051 cbfs = section_entries['cbfs']
3052 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003053 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003054 _CheckPresent('root', data)
3055
3056 # There should be no files left. Remove all the directories to check.
3057 # If there are any files/dirs remaining, one of these checks will fail.
3058 self.assertEqual(0, len(outfiles))
3059 _CheckDirPresent('section/cbfs')
3060 _CheckDirPresent('section')
3061 _CheckDirPresent('')
3062 self.assertFalse(os.path.exists(outdir))
3063
3064 def testExtractAllEntries(self):
3065 """Test extracting all entries"""
3066 self._CheckLz4()
3067 self._CheckExtractOutput(decomp=True)
3068
3069 def testExtractAllEntriesRaw(self):
3070 """Test extracting all entries without decompressing them"""
3071 self._CheckLz4()
3072 self._CheckExtractOutput(decomp=False)
3073
3074 def testExtractSelectedEntries(self):
3075 """Test extracting some entries"""
3076 self._CheckLz4()
3077 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003078 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003079 outdir = os.path.join(self._indir, 'extract')
3080 einfos = control.ExtractEntries(image_fname, None, outdir,
3081 ['*cb*', '*head*'])
3082
3083 # File output is tested by testExtractAllEntries(), so just check that
3084 # the expected entries are selected
3085 names = [einfo.name for einfo in einfos]
3086 self.assertEqual(names,
3087 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3088
3089 def testExtractNoEntryPaths(self):
3090 """Test extracting some entries"""
3091 self._CheckLz4()
3092 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003093 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003094 with self.assertRaises(ValueError) as e:
3095 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003096 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003097 str(e.exception))
3098
3099 def testExtractTooManyEntryPaths(self):
3100 """Test extracting some entries"""
3101 self._CheckLz4()
3102 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003103 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003104 with self.assertRaises(ValueError) as e:
3105 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003106 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003107 str(e.exception))
3108
Simon Glass52d06212019-07-08 14:25:53 -06003109 def testPackAlignSection(self):
3110 """Test that sections can have alignment"""
3111 self._DoReadFile('131_pack_align_section.dts')
3112
3113 self.assertIn('image', control.images)
3114 image = control.images['image']
3115 entries = image.GetEntries()
3116 self.assertEqual(3, len(entries))
3117
3118 # First u-boot
3119 self.assertIn('u-boot', entries)
3120 entry = entries['u-boot']
3121 self.assertEqual(0, entry.offset)
3122 self.assertEqual(0, entry.image_pos)
3123 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3124 self.assertEqual(len(U_BOOT_DATA), entry.size)
3125
3126 # Section0
3127 self.assertIn('section0', entries)
3128 section0 = entries['section0']
3129 self.assertEqual(0x10, section0.offset)
3130 self.assertEqual(0x10, section0.image_pos)
3131 self.assertEqual(len(U_BOOT_DATA), section0.size)
3132
3133 # Second u-boot
3134 section_entries = section0.GetEntries()
3135 self.assertIn('u-boot', section_entries)
3136 entry = section_entries['u-boot']
3137 self.assertEqual(0, entry.offset)
3138 self.assertEqual(0x10, entry.image_pos)
3139 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3140 self.assertEqual(len(U_BOOT_DATA), entry.size)
3141
3142 # Section1
3143 self.assertIn('section1', entries)
3144 section1 = entries['section1']
3145 self.assertEqual(0x14, section1.offset)
3146 self.assertEqual(0x14, section1.image_pos)
3147 self.assertEqual(0x20, section1.size)
3148
3149 # Second u-boot
3150 section_entries = section1.GetEntries()
3151 self.assertIn('u-boot', section_entries)
3152 entry = section_entries['u-boot']
3153 self.assertEqual(0, entry.offset)
3154 self.assertEqual(0x14, entry.image_pos)
3155 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3156 self.assertEqual(len(U_BOOT_DATA), entry.size)
3157
3158 # Section2
3159 self.assertIn('section2', section_entries)
3160 section2 = section_entries['section2']
3161 self.assertEqual(0x4, section2.offset)
3162 self.assertEqual(0x18, section2.image_pos)
3163 self.assertEqual(4, section2.size)
3164
3165 # Third u-boot
3166 section_entries = section2.GetEntries()
3167 self.assertIn('u-boot', section_entries)
3168 entry = section_entries['u-boot']
3169 self.assertEqual(0, entry.offset)
3170 self.assertEqual(0x18, entry.image_pos)
3171 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3172 self.assertEqual(len(U_BOOT_DATA), entry.size)
3173
Simon Glassf8a54bc2019-07-20 12:23:56 -06003174 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3175 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003176 """Replace an entry in an image
3177
3178 This writes the entry data to update it, then opens the updated file and
3179 returns the value that it now finds there.
3180
3181 Args:
3182 entry_name: Entry name to replace
3183 data: Data to replace it with
3184 decomp: True to compress the data if needed, False if data is
3185 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003186 allow_resize: True to allow entries to change size, False to raise
3187 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003188
3189 Returns:
3190 Tuple:
3191 data from entry
3192 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003193 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003194 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003195 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003196 update_dtb=True)[1]
3197
3198 self.assertIn('image', control.images)
3199 image = control.images['image']
3200 entries = image.GetEntries()
3201 orig_dtb_data = entries['u-boot-dtb'].data
3202 orig_fdtmap_data = entries['fdtmap'].data
3203
Simon Glass80025522022-01-29 14:14:04 -07003204 image_fname = tools.get_output_filename('image.bin')
3205 updated_fname = tools.get_output_filename('image-updated.bin')
3206 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003207 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3208 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003209 data = control.ReadEntry(updated_fname, entry_name, decomp)
3210
Simon Glassf8a54bc2019-07-20 12:23:56 -06003211 # The DT data should not change unless resized:
3212 if not allow_resize:
3213 new_dtb_data = entries['u-boot-dtb'].data
3214 self.assertEqual(new_dtb_data, orig_dtb_data)
3215 new_fdtmap_data = entries['fdtmap'].data
3216 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003217
Simon Glassf8a54bc2019-07-20 12:23:56 -06003218 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003219
3220 def testReplaceSimple(self):
3221 """Test replacing a single file"""
3222 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003223 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3224 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003225 self.assertEqual(expected, data)
3226
3227 # Test that the state looks right. There should be an FDT for the fdtmap
3228 # that we jsut read back in, and it should match what we find in the
3229 # 'control' tables. Checking for an FDT that does not exist should
3230 # return None.
3231 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003232 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003233 self.assertEqual(expected_fdtmap, fdtmap)
3234
3235 dtb = state.GetFdtForEtype('fdtmap')
3236 self.assertEqual(dtb.GetContents(), fdtmap)
3237
3238 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3239 self.assertIsNone(missing_path)
3240 self.assertIsNone(missing_fdtmap)
3241
3242 missing_dtb = state.GetFdtForEtype('missing')
3243 self.assertIsNone(missing_dtb)
3244
3245 self.assertEqual('/binman', state.fdt_path_prefix)
3246
3247 def testReplaceResizeFail(self):
3248 """Test replacing a file by something larger"""
3249 expected = U_BOOT_DATA + b'x'
3250 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003251 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3252 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003253 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3254 str(e.exception))
3255
3256 def testReplaceMulti(self):
3257 """Test replacing entry data where multiple images are generated"""
3258 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3259 update_dtb=True)[0]
3260 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003261 updated_fname = tools.get_output_filename('image-updated.bin')
3262 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003263 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003264 control.WriteEntry(updated_fname, entry_name, expected,
3265 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003266 data = control.ReadEntry(updated_fname, entry_name)
3267 self.assertEqual(expected, data)
3268
3269 # Check the state looks right.
3270 self.assertEqual('/binman/image', state.fdt_path_prefix)
3271
3272 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003273 image_fname = tools.get_output_filename('first-image.bin')
3274 updated_fname = tools.get_output_filename('first-updated.bin')
3275 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003276 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003277 control.WriteEntry(updated_fname, entry_name, expected,
3278 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003279 data = control.ReadEntry(updated_fname, entry_name)
3280 self.assertEqual(expected, data)
3281
3282 # Check the state looks right.
3283 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003284
Simon Glassfb30e292019-07-20 12:23:51 -06003285 def testUpdateFdtAllRepack(self):
3286 """Test that all device trees are updated with offset/size info"""
3287 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3288 SECTION_SIZE = 0x300
3289 DTB_SIZE = 602
3290 FDTMAP_SIZE = 608
3291 base_expected = {
3292 'offset': 0,
3293 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3294 'image-pos': 0,
3295 'section:offset': 0,
3296 'section:size': SECTION_SIZE,
3297 'section:image-pos': 0,
3298 'section/u-boot-dtb:offset': 4,
3299 'section/u-boot-dtb:size': 636,
3300 'section/u-boot-dtb:image-pos': 4,
3301 'u-boot-spl-dtb:offset': SECTION_SIZE,
3302 'u-boot-spl-dtb:size': DTB_SIZE,
3303 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3304 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3305 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3306 'u-boot-tpl-dtb:size': DTB_SIZE,
3307 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3308 'fdtmap:size': FDTMAP_SIZE,
3309 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3310 }
3311 main_expected = {
3312 'section:orig-size': SECTION_SIZE,
3313 'section/u-boot-dtb:orig-offset': 4,
3314 }
3315
3316 # We expect three device-tree files in the output, with the first one
3317 # within a fixed-size section.
3318 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3319 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3320 # main U-Boot tree. All three should have the same positions and offset
3321 # except that the main tree should include the main_expected properties
3322 start = 4
3323 for item in ['', 'spl', 'tpl', None]:
3324 if item is None:
3325 start += 16 # Move past fdtmap header
3326 dtb = fdt.Fdt.FromData(data[start:])
3327 dtb.Scan()
3328 props = self._GetPropTree(dtb,
3329 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3330 prefix='/' if item is None else '/binman/')
3331 expected = dict(base_expected)
3332 if item:
3333 expected[item] = 0
3334 else:
3335 # Main DTB and fdtdec should include the 'orig-' properties
3336 expected.update(main_expected)
3337 # Helpful for debugging:
3338 #for prop in sorted(props):
3339 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3340 self.assertEqual(expected, props)
3341 if item == '':
3342 start = SECTION_SIZE
3343 else:
3344 start += dtb._fdt_obj.totalsize()
3345
Simon Glass11453762019-07-20 12:23:55 -06003346 def testFdtmapHeaderMiddle(self):
3347 """Test an FDT map in the middle of an image when it should be at end"""
3348 with self.assertRaises(ValueError) as e:
3349 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3350 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3351 str(e.exception))
3352
3353 def testFdtmapHeaderStartBad(self):
3354 """Test an FDT map in middle of an image when it should be at start"""
3355 with self.assertRaises(ValueError) as e:
3356 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3357 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3358 str(e.exception))
3359
3360 def testFdtmapHeaderEndBad(self):
3361 """Test an FDT map at the start of an image when it should be at end"""
3362 with self.assertRaises(ValueError) as e:
3363 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3364 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3365 str(e.exception))
3366
3367 def testFdtmapHeaderNoSize(self):
3368 """Test an image header at the end of an image with undefined size"""
3369 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3370
Simon Glassf8a54bc2019-07-20 12:23:56 -06003371 def testReplaceResize(self):
3372 """Test replacing a single file in an entry with a larger file"""
3373 expected = U_BOOT_DATA + b'x'
3374 data, _, image = self._RunReplaceCmd('u-boot', expected,
3375 dts='139_replace_repack.dts')
3376 self.assertEqual(expected, data)
3377
3378 entries = image.GetEntries()
3379 dtb_data = entries['u-boot-dtb'].data
3380 dtb = fdt.Fdt.FromData(dtb_data)
3381 dtb.Scan()
3382
3383 # The u-boot section should now be larger in the dtb
3384 node = dtb.GetNode('/binman/u-boot')
3385 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3386
3387 # Same for the fdtmap
3388 fdata = entries['fdtmap'].data
3389 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3390 fdtb.Scan()
3391 fnode = fdtb.GetNode('/u-boot')
3392 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3393
3394 def testReplaceResizeNoRepack(self):
3395 """Test replacing an entry with a larger file when not allowed"""
3396 expected = U_BOOT_DATA + b'x'
3397 with self.assertRaises(ValueError) as e:
3398 self._RunReplaceCmd('u-boot', expected)
3399 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3400 str(e.exception))
3401
Simon Glass9d8ee322019-07-20 12:23:58 -06003402 def testEntryShrink(self):
3403 """Test contracting an entry after it is packed"""
3404 try:
3405 state.SetAllowEntryContraction(True)
3406 data = self._DoReadFileDtb('140_entry_shrink.dts',
3407 update_dtb=True)[0]
3408 finally:
3409 state.SetAllowEntryContraction(False)
3410 self.assertEqual(b'a', data[:1])
3411 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3412 self.assertEqual(b'a', data[-1:])
3413
3414 def testEntryShrinkFail(self):
3415 """Test not being allowed to contract an entry after it is packed"""
3416 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3417
3418 # In this case there is a spare byte at the end of the data. The size of
3419 # the contents is only 1 byte but we still have the size before it
3420 # shrunk.
3421 self.assertEqual(b'a\0', data[:2])
3422 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3423 self.assertEqual(b'a\0', data[-2:])
3424
Simon Glass70e32982019-07-20 12:24:01 -06003425 def testDescriptorOffset(self):
3426 """Test that the Intel descriptor is always placed at at the start"""
3427 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3428 image = control.images['image']
3429 entries = image.GetEntries()
3430 desc = entries['intel-descriptor']
3431 self.assertEqual(0xff800000, desc.offset);
3432 self.assertEqual(0xff800000, desc.image_pos);
3433
Simon Glass37fdd142019-07-20 12:24:06 -06003434 def testReplaceCbfs(self):
3435 """Test replacing a single file in CBFS without changing the size"""
3436 self._CheckLz4()
3437 expected = b'x' * len(U_BOOT_DATA)
3438 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003439 updated_fname = tools.get_output_filename('image-updated.bin')
3440 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003441 entry_name = 'section/cbfs/u-boot'
3442 control.WriteEntry(updated_fname, entry_name, expected,
3443 allow_resize=True)
3444 data = control.ReadEntry(updated_fname, entry_name)
3445 self.assertEqual(expected, data)
3446
3447 def testReplaceResizeCbfs(self):
3448 """Test replacing a single file in CBFS with one of a different size"""
3449 self._CheckLz4()
3450 expected = U_BOOT_DATA + b'x'
3451 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003452 updated_fname = tools.get_output_filename('image-updated.bin')
3453 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003454 entry_name = 'section/cbfs/u-boot'
3455 control.WriteEntry(updated_fname, entry_name, expected,
3456 allow_resize=True)
3457 data = control.ReadEntry(updated_fname, entry_name)
3458 self.assertEqual(expected, data)
3459
Simon Glass30033c22019-07-20 12:24:15 -06003460 def _SetupForReplace(self):
3461 """Set up some files to use to replace entries
3462
3463 This generates an image, copies it to a new file, extracts all the files
3464 in it and updates some of them
3465
3466 Returns:
3467 List
3468 Image filename
3469 Output directory
3470 Expected values for updated entries, each a string
3471 """
3472 data = self._DoReadFileRealDtb('143_replace_all.dts')
3473
Simon Glass80025522022-01-29 14:14:04 -07003474 updated_fname = tools.get_output_filename('image-updated.bin')
3475 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003476
3477 outdir = os.path.join(self._indir, 'extract')
3478 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3479
3480 expected1 = b'x' + U_BOOT_DATA + b'y'
3481 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003482 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003483
3484 expected2 = b'a' + U_BOOT_DATA + b'b'
3485 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003486 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003487
3488 expected_text = b'not the same text'
3489 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003490 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003491
3492 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3493 dtb = fdt.FdtScan(dtb_fname)
3494 node = dtb.GetNode('/binman/text')
3495 node.AddString('my-property', 'the value')
3496 dtb.Sync(auto_resize=True)
3497 dtb.Flush()
3498
3499 return updated_fname, outdir, expected1, expected2, expected_text
3500
3501 def _CheckReplaceMultiple(self, entry_paths):
3502 """Handle replacing the contents of multiple entries
3503
3504 Args:
3505 entry_paths: List of entry paths to replace
3506
3507 Returns:
3508 List
3509 Dict of entries in the image:
3510 key: Entry name
3511 Value: Entry object
3512 Expected values for updated entries, each a string
3513 """
3514 updated_fname, outdir, expected1, expected2, expected_text = (
3515 self._SetupForReplace())
3516 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3517
3518 image = Image.FromFile(updated_fname)
3519 image.LoadData()
3520 return image.GetEntries(), expected1, expected2, expected_text
3521
3522 def testReplaceAll(self):
3523 """Test replacing the contents of all entries"""
3524 entries, expected1, expected2, expected_text = (
3525 self._CheckReplaceMultiple([]))
3526 data = entries['u-boot'].data
3527 self.assertEqual(expected1, data)
3528
3529 data = entries['u-boot2'].data
3530 self.assertEqual(expected2, data)
3531
3532 data = entries['text'].data
3533 self.assertEqual(expected_text, data)
3534
3535 # Check that the device tree is updated
3536 data = entries['u-boot-dtb'].data
3537 dtb = fdt.Fdt.FromData(data)
3538 dtb.Scan()
3539 node = dtb.GetNode('/binman/text')
3540 self.assertEqual('the value', node.props['my-property'].value)
3541
3542 def testReplaceSome(self):
3543 """Test replacing the contents of a few entries"""
3544 entries, expected1, expected2, expected_text = (
3545 self._CheckReplaceMultiple(['u-boot2', 'text']))
3546
3547 # This one should not change
3548 data = entries['u-boot'].data
3549 self.assertEqual(U_BOOT_DATA, data)
3550
3551 data = entries['u-boot2'].data
3552 self.assertEqual(expected2, data)
3553
3554 data = entries['text'].data
3555 self.assertEqual(expected_text, data)
3556
3557 def testReplaceCmd(self):
3558 """Test replacing a file fron an image on the command line"""
3559 self._DoReadFileRealDtb('143_replace_all.dts')
3560
3561 try:
3562 tmpdir, updated_fname = self._SetupImageInTmpdir()
3563
3564 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3565 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003566 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003567
3568 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003569 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003570 self.assertEqual(expected, data[:len(expected)])
3571 map_fname = os.path.join(tmpdir, 'image-updated.map')
3572 self.assertFalse(os.path.exists(map_fname))
3573 finally:
3574 shutil.rmtree(tmpdir)
3575
3576 def testReplaceCmdSome(self):
3577 """Test replacing some files fron an image on the command line"""
3578 updated_fname, outdir, expected1, expected2, expected_text = (
3579 self._SetupForReplace())
3580
3581 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3582 'u-boot2', 'text')
3583
Simon Glass80025522022-01-29 14:14:04 -07003584 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003585 image = Image.FromFile(updated_fname)
3586 image.LoadData()
3587 entries = image.GetEntries()
3588
3589 # This one should not change
3590 data = entries['u-boot'].data
3591 self.assertEqual(U_BOOT_DATA, data)
3592
3593 data = entries['u-boot2'].data
3594 self.assertEqual(expected2, data)
3595
3596 data = entries['text'].data
3597 self.assertEqual(expected_text, data)
3598
3599 def testReplaceMissing(self):
3600 """Test replacing entries where the file is missing"""
3601 updated_fname, outdir, expected1, expected2, expected_text = (
3602 self._SetupForReplace())
3603
3604 # Remove one of the files, to generate a warning
3605 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3606 os.remove(u_boot_fname1)
3607
3608 with test_util.capture_sys_output() as (stdout, stderr):
3609 control.ReplaceEntries(updated_fname, None, outdir, [])
3610 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003611 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003612
3613 def testReplaceCmdMap(self):
3614 """Test replacing a file fron an image on the command line"""
3615 self._DoReadFileRealDtb('143_replace_all.dts')
3616
3617 try:
3618 tmpdir, updated_fname = self._SetupImageInTmpdir()
3619
3620 fname = os.path.join(self._indir, 'update-u-boot.bin')
3621 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003622 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003623
3624 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3625 '-f', fname, '-m')
3626 map_fname = os.path.join(tmpdir, 'image-updated.map')
3627 self.assertTrue(os.path.exists(map_fname))
3628 finally:
3629 shutil.rmtree(tmpdir)
3630
3631 def testReplaceNoEntryPaths(self):
3632 """Test replacing an entry without an entry path"""
3633 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003634 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003635 with self.assertRaises(ValueError) as e:
3636 control.ReplaceEntries(image_fname, 'fname', None, [])
3637 self.assertIn('Must specify an entry path to read with -f',
3638 str(e.exception))
3639
3640 def testReplaceTooManyEntryPaths(self):
3641 """Test extracting some entries"""
3642 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003643 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003644 with self.assertRaises(ValueError) as e:
3645 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3646 self.assertIn('Must specify exactly one entry path to write with -f',
3647 str(e.exception))
3648
Simon Glass0b074d62019-08-24 07:22:48 -06003649 def testPackReset16(self):
3650 """Test that an image with an x86 reset16 region can be created"""
3651 data = self._DoReadFile('144_x86_reset16.dts')
3652 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3653
3654 def testPackReset16Spl(self):
3655 """Test that an image with an x86 reset16-spl region can be created"""
3656 data = self._DoReadFile('145_x86_reset16_spl.dts')
3657 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3658
3659 def testPackReset16Tpl(self):
3660 """Test that an image with an x86 reset16-tpl region can be created"""
3661 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3662 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3663
Simon Glass232f90c2019-08-24 07:22:50 -06003664 def testPackIntelFit(self):
3665 """Test that an image with an Intel FIT and pointer can be created"""
3666 data = self._DoReadFile('147_intel_fit.dts')
3667 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3668 fit = data[16:32];
3669 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3670 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3671
3672 image = control.images['image']
3673 entries = image.GetEntries()
3674 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3675 self.assertEqual(expected_ptr, ptr)
3676
3677 def testPackIntelFitMissing(self):
3678 """Test detection of a FIT pointer with not FIT region"""
3679 with self.assertRaises(ValueError) as e:
3680 self._DoReadFile('148_intel_fit_missing.dts')
3681 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3682 str(e.exception))
3683
Simon Glass72555fa2019-11-06 17:22:44 -07003684 def _CheckSymbolsTplSection(self, dts, expected_vals):
3685 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003686 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003687 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003688 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003689 self.assertEqual(expected1, data[:upto1])
3690
3691 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003692 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003693 self.assertEqual(expected2, data[upto1:upto2])
3694
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003695 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003696 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003697 self.assertEqual(expected3, data[upto2:upto3])
3698
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003699 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003700 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3701
3702 def testSymbolsTplSection(self):
3703 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3704 self._SetupSplElf('u_boot_binman_syms')
3705 self._SetupTplElf('u_boot_binman_syms')
3706 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003707 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003708
3709 def testSymbolsTplSectionX86(self):
3710 """Test binman can assign symbols in a section with end-at-4gb"""
3711 self._SetupSplElf('u_boot_binman_syms_x86')
3712 self._SetupTplElf('u_boot_binman_syms_x86')
3713 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003714 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003715 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003716
Simon Glass98c59572019-08-24 07:23:03 -06003717 def testPackX86RomIfwiSectiom(self):
3718 """Test that a section can be placed in an IFWI region"""
3719 self._SetupIfwi('fitimage.bin')
3720 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3721 self._CheckIfwi(data)
3722
Simon Glassba7985d2019-08-24 07:23:07 -06003723 def testPackFspM(self):
3724 """Test that an image with a FSP memory-init binary can be created"""
3725 data = self._DoReadFile('152_intel_fsp_m.dts')
3726 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3727
Simon Glass4d9086d2019-10-20 21:31:35 -06003728 def testPackFspS(self):
3729 """Test that an image with a FSP silicon-init binary can be created"""
3730 data = self._DoReadFile('153_intel_fsp_s.dts')
3731 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003732
Simon Glass9ea87b22019-10-20 21:31:36 -06003733 def testPackFspT(self):
3734 """Test that an image with a FSP temp-ram-init binary can be created"""
3735 data = self._DoReadFile('154_intel_fsp_t.dts')
3736 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3737
Simon Glass48f3aad2020-07-09 18:39:31 -06003738 def testMkimage(self):
3739 """Test using mkimage to build an image"""
3740 data = self._DoReadFile('156_mkimage.dts')
3741
3742 # Just check that the data appears in the file somewhere
3743 self.assertIn(U_BOOT_SPL_DATA, data)
3744
Simon Glass66152ce2022-01-09 20:14:09 -07003745 def testMkimageMissing(self):
3746 """Test that binman still produces an image if mkimage is missing"""
3747 with test_util.capture_sys_output() as (_, stderr):
3748 self._DoTestFile('156_mkimage.dts',
3749 force_missing_bintools='mkimage')
3750 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003751 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07003752
Simon Glass5e560182020-07-09 18:39:36 -06003753 def testExtblob(self):
3754 """Test an image with an external blob"""
3755 data = self._DoReadFile('157_blob_ext.dts')
3756 self.assertEqual(REFCODE_DATA, data)
3757
3758 def testExtblobMissing(self):
3759 """Test an image with a missing external blob"""
3760 with self.assertRaises(ValueError) as e:
3761 self._DoReadFile('158_blob_ext_missing.dts')
3762 self.assertIn("Filename 'missing-file' not found in input path",
3763 str(e.exception))
3764
Simon Glass5d94cc62020-07-09 18:39:38 -06003765 def testExtblobMissingOk(self):
3766 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003767 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003768 ret = self._DoTestFile('158_blob_ext_missing.dts',
3769 allow_missing=True)
3770 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003771 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003772 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003773 self.assertIn('Some images are invalid', err)
3774
3775 def testExtblobMissingOkFlag(self):
3776 """Test an image with an missing external blob allowed with -W"""
3777 with test_util.capture_sys_output() as (stdout, stderr):
3778 ret = self._DoTestFile('158_blob_ext_missing.dts',
3779 allow_missing=True, ignore_missing=True)
3780 self.assertEqual(0, ret)
3781 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003782 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003783 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003784
3785 def testExtblobMissingOkSect(self):
3786 """Test an image with an missing external blob that is allowed"""
3787 with test_util.capture_sys_output() as (stdout, stderr):
3788 self._DoTestFile('159_blob_ext_missing_sect.dts',
3789 allow_missing=True)
3790 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003791 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003792
Simon Glasse88cef92020-07-09 18:39:41 -06003793 def testPackX86RomMeMissingDesc(self):
3794 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003795 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003796 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003797 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003798 self.assertRegex(err, "Image 'image'.*missing.*: intel-descriptor")
Simon Glasse88cef92020-07-09 18:39:41 -06003799
3800 def testPackX86RomMissingIfwi(self):
3801 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3802 self._SetupIfwi('fitimage.bin')
3803 pathname = os.path.join(self._indir, 'fitimage.bin')
3804 os.remove(pathname)
3805 with test_util.capture_sys_output() as (stdout, stderr):
3806 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3807 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07003808 self.assertRegex(err, "Image 'image'.*missing.*: intel-ifwi")
Simon Glasse88cef92020-07-09 18:39:41 -06003809
Simon Glass2a0fa982022-02-11 13:23:21 -07003810 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003811 """Test that zero-size overlapping regions are ignored"""
3812 self._DoTestFile('160_pack_overlap_zero.dts')
3813
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003814 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003815 # The data should be inside the FIT
3816 dtb = fdt.Fdt.FromData(fit_data)
3817 dtb.Scan()
3818 fnode = dtb.GetNode('/images/kernel')
3819 self.assertIn('data', fnode.props)
3820
3821 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003822 tools.write_file(fname, fit_data)
3823 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003824
3825 # Check a few features to make sure the plumbing works. We don't need
3826 # to test the operation of mkimage or dumpimage here. First convert the
3827 # output into a dict where the keys are the fields printed by dumpimage
3828 # and the values are a list of values for each field
3829 lines = out.splitlines()
3830
3831 # Converts "Compression: gzip compressed" into two groups:
3832 # 'Compression' and 'gzip compressed'
3833 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3834 vals = collections.defaultdict(list)
3835 for line in lines:
3836 mat = re_line.match(line)
3837 vals[mat.group(1)].append(mat.group(2))
3838
3839 self.assertEquals('FIT description: test-desc', lines[0])
3840 self.assertIn('Created:', lines[1])
3841 self.assertIn('Image 0 (kernel)', vals)
3842 self.assertIn('Hash value', vals)
3843 data_sizes = vals.get('Data Size')
3844 self.assertIsNotNone(data_sizes)
3845 self.assertEqual(2, len(data_sizes))
3846 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003847 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3848 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3849
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003850 # Check if entry listing correctly omits /images/
3851 image = control.images['image']
3852 fit_entry = image.GetEntries()['fit']
3853 subentries = list(fit_entry.GetEntries().keys())
3854 expected = ['kernel', 'fdt-1']
3855 self.assertEqual(expected, subentries)
3856
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003857 def testSimpleFit(self):
3858 """Test an image with a FIT inside"""
3859 data = self._DoReadFile('161_fit.dts')
3860 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3861 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3862 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3863
3864 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3865
3866 def testSimpleFitExpandsSubentries(self):
3867 """Test that FIT images expand their subentries"""
3868 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3869 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3870 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3871 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3872
3873 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003874
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003875 def testSimpleFitImagePos(self):
3876 """Test that we have correct image-pos for FIT subentries"""
3877 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3878 update_dtb=True)
3879 dtb = fdt.Fdt(out_dtb_fname)
3880 dtb.Scan()
3881 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3882
Simon Glassb7bad182022-03-05 20:19:01 -07003883 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003884 self.assertEqual({
3885 'image-pos': 0,
3886 'offset': 0,
3887 'size': 1890,
3888
3889 'u-boot:image-pos': 0,
3890 'u-boot:offset': 0,
3891 'u-boot:size': 4,
3892
3893 'fit:image-pos': 4,
3894 'fit:offset': 4,
3895 'fit:size': 1840,
3896
Simon Glassb7bad182022-03-05 20:19:01 -07003897 'fit/images/kernel:image-pos': 304,
3898 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003899 'fit/images/kernel:size': 4,
3900
Simon Glassb7bad182022-03-05 20:19:01 -07003901 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003902 'fit/images/kernel/u-boot:offset': 0,
3903 'fit/images/kernel/u-boot:size': 4,
3904
Simon Glassb7bad182022-03-05 20:19:01 -07003905 'fit/images/fdt-1:image-pos': 552,
3906 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003907 'fit/images/fdt-1:size': 6,
3908
Simon Glassb7bad182022-03-05 20:19:01 -07003909 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003910 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3911 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3912
3913 'u-boot-nodtb:image-pos': 1844,
3914 'u-boot-nodtb:offset': 1844,
3915 'u-boot-nodtb:size': 46,
3916 }, props)
3917
3918 # Actually check the data is where we think it is
3919 for node, expected in [
3920 ("u-boot", U_BOOT_DATA),
3921 ("fit/images/kernel", U_BOOT_DATA),
3922 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3923 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3924 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3925 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3926 ]:
3927 image_pos = props[f"{node}:image-pos"]
3928 size = props[f"{node}:size"]
3929 self.assertEqual(len(expected), size)
3930 self.assertEqual(expected, data[image_pos:image_pos+size])
3931
Simon Glass45d556d2020-07-09 18:39:45 -06003932 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003933 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003934 data = self._DoReadFile('162_fit_external.dts')
3935 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3936
Simon Glass7932c882022-01-09 20:13:39 -07003937 # Size of the external-data region as set up by mkimage
3938 external_data_size = len(U_BOOT_DATA) + 2
3939 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003940 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003941 len(U_BOOT_NODTB_DATA))
3942
Simon Glass45d556d2020-07-09 18:39:45 -06003943 # The data should be outside the FIT
3944 dtb = fdt.Fdt.FromData(fit_data)
3945 dtb.Scan()
3946 fnode = dtb.GetNode('/images/kernel')
3947 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003948 self.assertEqual(len(U_BOOT_DATA),
3949 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3950 fit_pos = 0x400;
3951 self.assertEqual(
3952 fit_pos,
3953 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3954
3955 self.assertEquals(expected_size, len(data))
3956 actual_pos = len(U_BOOT_DATA) + fit_pos
3957 self.assertEqual(U_BOOT_DATA + b'aa',
3958 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003959
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003960 def testFitExternalImagePos(self):
3961 """Test that we have correct image-pos for external FIT subentries"""
3962 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3963 update_dtb=True)
3964 dtb = fdt.Fdt(out_dtb_fname)
3965 dtb.Scan()
3966 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3967
3968 self.assertEqual({
3969 'image-pos': 0,
3970 'offset': 0,
3971 'size': 1082,
3972
3973 'u-boot:image-pos': 0,
3974 'u-boot:offset': 0,
3975 'u-boot:size': 4,
3976
3977 'fit:size': 1032,
3978 'fit:offset': 4,
3979 'fit:image-pos': 4,
3980
3981 'fit/images/kernel:size': 4,
3982 'fit/images/kernel:offset': 1024,
3983 'fit/images/kernel:image-pos': 1028,
3984
3985 'fit/images/kernel/u-boot:size': 4,
3986 'fit/images/kernel/u-boot:offset': 0,
3987 'fit/images/kernel/u-boot:image-pos': 1028,
3988
3989 'fit/images/fdt-1:size': 2,
3990 'fit/images/fdt-1:offset': 1028,
3991 'fit/images/fdt-1:image-pos': 1032,
3992
3993 'fit/images/fdt-1/_testing:size': 2,
3994 'fit/images/fdt-1/_testing:offset': 0,
3995 'fit/images/fdt-1/_testing:image-pos': 1032,
3996
3997 'u-boot-nodtb:image-pos': 1036,
3998 'u-boot-nodtb:offset': 1036,
3999 'u-boot-nodtb:size': 46,
4000 }, props)
4001
4002 # Actually check the data is where we think it is
4003 for node, expected in [
4004 ("u-boot", U_BOOT_DATA),
4005 ("fit/images/kernel", U_BOOT_DATA),
4006 ("fit/images/kernel/u-boot", U_BOOT_DATA),
4007 ("fit/images/fdt-1", b'aa'),
4008 ("fit/images/fdt-1/_testing", b'aa'),
4009 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
4010 ]:
4011 image_pos = props[f"{node}:image-pos"]
4012 size = props[f"{node}:size"]
4013 self.assertEqual(len(expected), size)
4014 self.assertEqual(expected, data[image_pos:image_pos+size])
4015
Simon Glass66152ce2022-01-09 20:14:09 -07004016 def testFitMissing(self):
Simon Glass039d65f2023-03-02 17:02:43 -07004017 """Test that binman complains if mkimage is missing"""
4018 with self.assertRaises(ValueError) as e:
4019 self._DoTestFile('162_fit_external.dts',
4020 force_missing_bintools='mkimage')
4021 self.assertIn("Node '/binman/fit': Missing tool: 'mkimage'",
4022 str(e.exception))
4023
4024 def testFitMissingOK(self):
Simon Glass66152ce2022-01-09 20:14:09 -07004025 """Test that binman still produces a FIT image if mkimage is missing"""
4026 with test_util.capture_sys_output() as (_, stderr):
Simon Glass039d65f2023-03-02 17:02:43 -07004027 self._DoTestFile('162_fit_external.dts', allow_missing=True,
Simon Glass66152ce2022-01-09 20:14:09 -07004028 force_missing_bintools='mkimage')
4029 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004030 self.assertRegex(err, "Image 'image'.*missing bintools.*: mkimage")
Simon Glass66152ce2022-01-09 20:14:09 -07004031
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03004032 def testSectionIgnoreHashSignature(self):
4033 """Test that sections ignore hash, signature nodes for its data"""
4034 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
4035 expected = (U_BOOT_DATA + U_BOOT_DATA)
4036 self.assertEqual(expected, data)
4037
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004038 def testPadInSections(self):
4039 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06004040 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4041 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07004042 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4043 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004044 U_BOOT_DATA)
4045 self.assertEqual(expected, data)
4046
Simon Glassd12599d2020-10-26 17:40:09 -06004047 dtb = fdt.Fdt(out_dtb_fname)
4048 dtb.Scan()
4049 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4050 expected = {
4051 'image-pos': 0,
4052 'offset': 0,
4053 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4054
4055 'section:image-pos': 0,
4056 'section:offset': 0,
4057 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4058
4059 'section/before:image-pos': 0,
4060 'section/before:offset': 0,
4061 'section/before:size': len(U_BOOT_DATA),
4062
4063 'section/u-boot:image-pos': 4,
4064 'section/u-boot:offset': 4,
4065 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4066
4067 'section/after:image-pos': 26,
4068 'section/after:offset': 26,
4069 'section/after:size': len(U_BOOT_DATA),
4070 }
4071 self.assertEqual(expected, props)
4072
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004073 def testFitImageSubentryAlignment(self):
4074 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004075 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004076 entry_args = {
4077 'test-id': TEXT_DATA,
4078 }
4079 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4080 entry_args=entry_args)
4081 dtb = fdt.Fdt.FromData(data)
4082 dtb.Scan()
4083
4084 node = dtb.GetNode('/images/kernel')
4085 data = dtb.GetProps(node)["data"].bytes
4086 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004087 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4088 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004089 self.assertEqual(expected, data)
4090
4091 node = dtb.GetNode('/images/fdt-1')
4092 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004093 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4094 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004095 U_BOOT_DTB_DATA)
4096 self.assertEqual(expected, data)
4097
4098 def testFitExtblobMissingOk(self):
4099 """Test a FIT with a missing external blob that is allowed"""
4100 with test_util.capture_sys_output() as (stdout, stderr):
4101 self._DoTestFile('168_fit_missing_blob.dts',
4102 allow_missing=True)
4103 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004104 self.assertRegex(err, "Image 'image'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004105
Simon Glass21db0ff2020-09-01 05:13:54 -06004106 def testBlobNamedByArgMissing(self):
4107 """Test handling of a missing entry arg"""
4108 with self.assertRaises(ValueError) as e:
4109 self._DoReadFile('068_blob_named_by_arg.dts')
4110 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4111 str(e.exception))
4112
Simon Glass559c4de2020-09-01 05:13:58 -06004113 def testPackBl31(self):
4114 """Test that an image with an ATF BL31 binary can be created"""
4115 data = self._DoReadFile('169_atf_bl31.dts')
4116 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4117
Samuel Holland9d8cc632020-10-21 21:12:15 -05004118 def testPackScp(self):
4119 """Test that an image with an SCP binary can be created"""
4120 data = self._DoReadFile('172_scp.dts')
4121 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4122
Simon Glassa435cd12020-09-01 05:13:59 -06004123 def testFitFdt(self):
4124 """Test an image with an FIT with multiple FDT images"""
4125 def _CheckFdt(seq, expected_data):
4126 """Check the FDT nodes
4127
4128 Args:
4129 seq: Sequence number to check (0 or 1)
4130 expected_data: Expected contents of 'data' property
4131 """
4132 name = 'fdt-%d' % seq
4133 fnode = dtb.GetNode('/images/%s' % name)
4134 self.assertIsNotNone(fnode)
4135 self.assertEqual({'description','type', 'compression', 'data'},
4136 set(fnode.props.keys()))
4137 self.assertEqual(expected_data, fnode.props['data'].bytes)
4138 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4139 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004140 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004141
4142 def _CheckConfig(seq, expected_data):
4143 """Check the configuration nodes
4144
4145 Args:
4146 seq: Sequence number to check (0 or 1)
4147 expected_data: Expected contents of 'data' property
4148 """
4149 cnode = dtb.GetNode('/configurations')
4150 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004151 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004152
4153 name = 'config-%d' % seq
4154 fnode = dtb.GetNode('/configurations/%s' % name)
4155 self.assertIsNotNone(fnode)
4156 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4157 set(fnode.props.keys()))
4158 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4159 fnode.props['description'].value)
4160 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4161
4162 entry_args = {
4163 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004164 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004165 }
4166 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004167 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004168 entry_args=entry_args,
4169 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4170 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4171 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4172
4173 dtb = fdt.Fdt.FromData(fit_data)
4174 dtb.Scan()
4175 fnode = dtb.GetNode('/images/kernel')
4176 self.assertIn('data', fnode.props)
4177
4178 # Check all the properties in fdt-1 and fdt-2
4179 _CheckFdt(1, TEST_FDT1_DATA)
4180 _CheckFdt(2, TEST_FDT2_DATA)
4181
4182 # Check configurations
4183 _CheckConfig(1, TEST_FDT1_DATA)
4184 _CheckConfig(2, TEST_FDT2_DATA)
4185
4186 def testFitFdtMissingList(self):
4187 """Test handling of a missing 'of-list' entry arg"""
4188 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004189 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004190 self.assertIn("Generator node requires 'of-list' entry argument",
4191 str(e.exception))
4192
4193 def testFitFdtEmptyList(self):
4194 """Test handling of an empty 'of-list' entry arg"""
4195 entry_args = {
4196 'of-list': '',
4197 }
4198 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4199
4200 def testFitFdtMissingProp(self):
4201 """Test handling of a missing 'fit,fdt-list' property"""
4202 with self.assertRaises(ValueError) as e:
4203 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4204 self.assertIn("Generator node requires 'fit,fdt-list' property",
4205 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004206
Simon Glass1032acc2020-09-06 10:39:08 -06004207 def testFitFdtMissing(self):
4208 """Test handling of a missing 'default-dt' entry arg"""
4209 entry_args = {
4210 'of-list': 'test-fdt1 test-fdt2',
4211 }
4212 with self.assertRaises(ValueError) as e:
4213 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004214 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004215 entry_args=entry_args,
4216 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4217 self.assertIn("Generated 'default' node requires default-dt entry argument",
4218 str(e.exception))
4219
4220 def testFitFdtNotInList(self):
4221 """Test handling of a default-dt that is not in the of-list"""
4222 entry_args = {
4223 'of-list': 'test-fdt1 test-fdt2',
4224 'default-dt': 'test-fdt3',
4225 }
4226 with self.assertRaises(ValueError) as e:
4227 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004228 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004229 entry_args=entry_args,
4230 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4231 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4232 str(e.exception))
4233
Simon Glassa820af72020-09-06 10:39:09 -06004234 def testFitExtblobMissingHelp(self):
4235 """Test display of help messages when an external blob is missing"""
4236 control.missing_blob_help = control._ReadMissingBlobHelp()
4237 control.missing_blob_help['wibble'] = 'Wibble test'
4238 control.missing_blob_help['another'] = 'Another test'
4239 with test_util.capture_sys_output() as (stdout, stderr):
4240 self._DoTestFile('168_fit_missing_blob.dts',
4241 allow_missing=True)
4242 err = stderr.getvalue()
4243
4244 # We can get the tag from the name, the type or the missing-msg
4245 # property. Check all three.
4246 self.assertIn('You may need to build ARM Trusted', err)
4247 self.assertIn('Wibble test', err)
4248 self.assertIn('Another test', err)
4249
Simon Glass6f1f4d42020-09-06 10:35:32 -06004250 def testMissingBlob(self):
4251 """Test handling of a blob containing a missing file"""
4252 with self.assertRaises(ValueError) as e:
4253 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4254 self.assertIn("Filename 'missing' not found in input path",
4255 str(e.exception))
4256
Simon Glassa0729502020-09-06 10:35:33 -06004257 def testEnvironment(self):
4258 """Test adding a U-Boot environment"""
4259 data = self._DoReadFile('174_env.dts')
4260 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4261 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4262 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4263 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4264 env)
4265
4266 def testEnvironmentNoSize(self):
4267 """Test that a missing 'size' property is detected"""
4268 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004269 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004270 self.assertIn("'u-boot-env' entry must have a size property",
4271 str(e.exception))
4272
4273 def testEnvironmentTooSmall(self):
4274 """Test handling of an environment that does not fit"""
4275 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004276 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004277
4278 # checksum, start byte, environment with \0 terminator, final \0
4279 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4280 short = need - 0x8
4281 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4282 str(e.exception))
4283
Simon Glassd1fdf752020-10-26 17:40:01 -06004284 def testSkipAtStart(self):
4285 """Test handling of skip-at-start section"""
4286 data = self._DoReadFile('177_skip_at_start.dts')
4287 self.assertEqual(U_BOOT_DATA, data)
4288
4289 image = control.images['image']
4290 entries = image.GetEntries()
4291 section = entries['section']
4292 self.assertEqual(0, section.offset)
4293 self.assertEqual(len(U_BOOT_DATA), section.size)
4294 self.assertEqual(U_BOOT_DATA, section.GetData())
4295
4296 entry = section.GetEntries()['u-boot']
4297 self.assertEqual(16, entry.offset)
4298 self.assertEqual(len(U_BOOT_DATA), entry.size)
4299 self.assertEqual(U_BOOT_DATA, entry.data)
4300
4301 def testSkipAtStartPad(self):
4302 """Test handling of skip-at-start section with padded entry"""
4303 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004304 before = tools.get_bytes(0, 8)
4305 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004306 all = before + U_BOOT_DATA + after
4307 self.assertEqual(all, data)
4308
4309 image = control.images['image']
4310 entries = image.GetEntries()
4311 section = entries['section']
4312 self.assertEqual(0, section.offset)
4313 self.assertEqual(len(all), section.size)
4314 self.assertEqual(all, section.GetData())
4315
4316 entry = section.GetEntries()['u-boot']
4317 self.assertEqual(16, entry.offset)
4318 self.assertEqual(len(all), entry.size)
4319 self.assertEqual(U_BOOT_DATA, entry.data)
4320
4321 def testSkipAtStartSectionPad(self):
4322 """Test handling of skip-at-start section with padding"""
4323 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004324 before = tools.get_bytes(0, 8)
4325 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004326 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004327 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004328
4329 image = control.images['image']
4330 entries = image.GetEntries()
4331 section = entries['section']
4332 self.assertEqual(0, section.offset)
4333 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004334 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004335 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004336
4337 entry = section.GetEntries()['u-boot']
4338 self.assertEqual(16, entry.offset)
4339 self.assertEqual(len(U_BOOT_DATA), entry.size)
4340 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004341
Simon Glassbb395742020-10-26 17:40:14 -06004342 def testSectionPad(self):
4343 """Testing padding with sections"""
4344 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004345 expected = (tools.get_bytes(ord('&'), 3) +
4346 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004347 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004348 tools.get_bytes(ord('!'), 1) +
4349 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004350 self.assertEqual(expected, data)
4351
4352 def testSectionAlign(self):
4353 """Testing alignment with sections"""
4354 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4355 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004356 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004357 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004358 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004359 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004360 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4361 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004362 self.assertEqual(expected, data)
4363
Simon Glassd92c8362020-10-26 17:40:25 -06004364 def testCompressImage(self):
4365 """Test compression of the entire image"""
4366 self._CheckLz4()
4367 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4368 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4369 dtb = fdt.Fdt(out_dtb_fname)
4370 dtb.Scan()
4371 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4372 'uncomp-size'])
4373 orig = self._decompress(data)
4374 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4375
4376 # Do a sanity check on various fields
4377 image = control.images['image']
4378 entries = image.GetEntries()
4379 self.assertEqual(2, len(entries))
4380
4381 entry = entries['blob']
4382 self.assertEqual(COMPRESS_DATA, entry.data)
4383 self.assertEqual(len(COMPRESS_DATA), entry.size)
4384
4385 entry = entries['u-boot']
4386 self.assertEqual(U_BOOT_DATA, entry.data)
4387 self.assertEqual(len(U_BOOT_DATA), entry.size)
4388
4389 self.assertEqual(len(data), image.size)
4390 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4391 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4392 orig = self._decompress(image.data)
4393 self.assertEqual(orig, image.uncomp_data)
4394
4395 expected = {
4396 'blob:offset': 0,
4397 'blob:size': len(COMPRESS_DATA),
4398 'u-boot:offset': len(COMPRESS_DATA),
4399 'u-boot:size': len(U_BOOT_DATA),
4400 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4401 'offset': 0,
4402 'image-pos': 0,
4403 'size': len(data),
4404 }
4405 self.assertEqual(expected, props)
4406
4407 def testCompressImageLess(self):
4408 """Test compression where compression reduces the image size"""
4409 self._CheckLz4()
4410 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4411 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4412 dtb = fdt.Fdt(out_dtb_fname)
4413 dtb.Scan()
4414 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4415 'uncomp-size'])
4416 orig = self._decompress(data)
4417
4418 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4419
4420 # Do a sanity check on various fields
4421 image = control.images['image']
4422 entries = image.GetEntries()
4423 self.assertEqual(2, len(entries))
4424
4425 entry = entries['blob']
4426 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4427 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4428
4429 entry = entries['u-boot']
4430 self.assertEqual(U_BOOT_DATA, entry.data)
4431 self.assertEqual(len(U_BOOT_DATA), entry.size)
4432
4433 self.assertEqual(len(data), image.size)
4434 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4435 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4436 image.uncomp_size)
4437 orig = self._decompress(image.data)
4438 self.assertEqual(orig, image.uncomp_data)
4439
4440 expected = {
4441 'blob:offset': 0,
4442 'blob:size': len(COMPRESS_DATA_BIG),
4443 'u-boot:offset': len(COMPRESS_DATA_BIG),
4444 'u-boot:size': len(U_BOOT_DATA),
4445 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4446 'offset': 0,
4447 'image-pos': 0,
4448 'size': len(data),
4449 }
4450 self.assertEqual(expected, props)
4451
4452 def testCompressSectionSize(self):
4453 """Test compression of a section with a fixed size"""
4454 self._CheckLz4()
4455 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4456 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4457 dtb = fdt.Fdt(out_dtb_fname)
4458 dtb.Scan()
4459 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4460 'uncomp-size'])
4461 orig = self._decompress(data)
4462 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4463 expected = {
4464 'section/blob:offset': 0,
4465 'section/blob:size': len(COMPRESS_DATA),
4466 'section/u-boot:offset': len(COMPRESS_DATA),
4467 'section/u-boot:size': len(U_BOOT_DATA),
4468 'section:offset': 0,
4469 'section:image-pos': 0,
4470 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4471 'section:size': 0x30,
4472 'offset': 0,
4473 'image-pos': 0,
4474 'size': 0x30,
4475 }
4476 self.assertEqual(expected, props)
4477
4478 def testCompressSection(self):
4479 """Test compression of a section with no fixed size"""
4480 self._CheckLz4()
4481 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4482 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4483 dtb = fdt.Fdt(out_dtb_fname)
4484 dtb.Scan()
4485 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4486 'uncomp-size'])
4487 orig = self._decompress(data)
4488 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4489 expected = {
4490 'section/blob:offset': 0,
4491 'section/blob:size': len(COMPRESS_DATA),
4492 'section/u-boot:offset': len(COMPRESS_DATA),
4493 'section/u-boot:size': len(U_BOOT_DATA),
4494 'section:offset': 0,
4495 'section:image-pos': 0,
4496 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4497 'section:size': len(data),
4498 'offset': 0,
4499 'image-pos': 0,
4500 'size': len(data),
4501 }
4502 self.assertEqual(expected, props)
4503
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004504 def testLz4Missing(self):
4505 """Test that binman still produces an image if lz4 is missing"""
4506 with test_util.capture_sys_output() as (_, stderr):
4507 self._DoTestFile('185_compress_section.dts',
4508 force_missing_bintools='lz4')
4509 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07004510 self.assertRegex(err, "Image 'image'.*missing bintools.*: lz4")
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004511
Simon Glassd92c8362020-10-26 17:40:25 -06004512 def testCompressExtra(self):
4513 """Test compression of a section with no fixed size"""
4514 self._CheckLz4()
4515 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4516 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4517 dtb = fdt.Fdt(out_dtb_fname)
4518 dtb.Scan()
4519 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4520 'uncomp-size'])
4521
4522 base = data[len(U_BOOT_DATA):]
4523 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4524 rest = base[len(U_BOOT_DATA):]
4525
4526 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004527 bintool = self.comp_bintools['lz4']
4528 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004529 data1 = rest[:len(expect1)]
4530 section1 = self._decompress(data1)
4531 self.assertEquals(expect1, data1)
Simon Glassd92c8362020-10-26 17:40:25 -06004532 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4533 rest1 = rest[len(expect1):]
4534
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004535 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004536 data2 = rest1[:len(expect2)]
4537 section2 = self._decompress(data2)
4538 self.assertEquals(expect2, data2)
Simon Glassd92c8362020-10-26 17:40:25 -06004539 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4540 rest2 = rest1[len(expect2):]
4541
4542 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4543 len(expect2) + len(U_BOOT_DATA))
4544 #self.assertEquals(expect_size, len(data))
4545
4546 #self.assertEquals(U_BOOT_DATA, rest2)
4547
4548 self.maxDiff = None
4549 expected = {
4550 'u-boot:offset': 0,
4551 'u-boot:image-pos': 0,
4552 'u-boot:size': len(U_BOOT_DATA),
4553
4554 'base:offset': len(U_BOOT_DATA),
4555 'base:image-pos': len(U_BOOT_DATA),
4556 'base:size': len(data) - len(U_BOOT_DATA),
4557 'base/u-boot:offset': 0,
4558 'base/u-boot:image-pos': len(U_BOOT_DATA),
4559 'base/u-boot:size': len(U_BOOT_DATA),
4560 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4561 len(expect2),
4562 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4563 len(expect2),
4564 'base/u-boot2:size': len(U_BOOT_DATA),
4565
4566 'base/section:offset': len(U_BOOT_DATA),
4567 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4568 'base/section:size': len(expect1),
4569 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4570 'base/section/blob:offset': 0,
4571 'base/section/blob:size': len(COMPRESS_DATA),
4572 'base/section/u-boot:offset': len(COMPRESS_DATA),
4573 'base/section/u-boot:size': len(U_BOOT_DATA),
4574
4575 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4576 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4577 'base/section2:size': len(expect2),
4578 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4579 'base/section2/blob:offset': 0,
4580 'base/section2/blob:size': len(COMPRESS_DATA),
4581 'base/section2/blob2:offset': len(COMPRESS_DATA),
4582 'base/section2/blob2:size': len(COMPRESS_DATA),
4583
4584 'offset': 0,
4585 'image-pos': 0,
4586 'size': len(data),
4587 }
4588 self.assertEqual(expected, props)
4589
Simon Glassecbe4732021-01-06 21:35:15 -07004590 def testSymbolsSubsection(self):
4591 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004592 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004593
Simon Glass3fb25402021-01-06 21:35:16 -07004594 def testReadImageEntryArg(self):
4595 """Test reading an image that would need an entry arg to generate"""
4596 entry_args = {
4597 'cros-ec-rw-path': 'ecrw.bin',
4598 }
4599 data = self.data = self._DoReadFileDtb(
4600 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4601 entry_args=entry_args)
4602
Simon Glass80025522022-01-29 14:14:04 -07004603 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004604 orig_image = control.images['image']
4605
4606 # This should not generate an error about the missing 'cros-ec-rw-path'
4607 # since we are reading the image from a file. Compare with
4608 # testEntryArgsRequired()
4609 image = Image.FromFile(image_fname)
4610 self.assertEqual(orig_image.GetEntries().keys(),
4611 image.GetEntries().keys())
4612
Simon Glassa2af7302021-01-06 21:35:18 -07004613 def testFilesAlign(self):
4614 """Test alignment with files"""
4615 data = self._DoReadFile('190_files_align.dts')
4616
4617 # The first string is 15 bytes so will align to 16
4618 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4619 self.assertEqual(expect, data)
4620
Simon Glassdb84b562021-01-06 21:35:19 -07004621 def testReadImageSkip(self):
4622 """Test reading an image and accessing its FDT map"""
4623 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004624 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004625 orig_image = control.images['image']
4626 image = Image.FromFile(image_fname)
4627 self.assertEqual(orig_image.GetEntries().keys(),
4628 image.GetEntries().keys())
4629
4630 orig_entry = orig_image.GetEntries()['fdtmap']
4631 entry = image.GetEntries()['fdtmap']
4632 self.assertEqual(orig_entry.offset, entry.offset)
4633 self.assertEqual(orig_entry.size, entry.size)
4634 self.assertEqual(16, entry.image_pos)
4635
4636 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4637
4638 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4639
Simon Glassc98de972021-03-18 20:24:57 +13004640 def testTplNoDtb(self):
4641 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004642 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004643 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4644 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4645 data[:len(U_BOOT_TPL_NODTB_DATA)])
4646
Simon Glass63f41d42021-03-18 20:24:58 +13004647 def testTplBssPad(self):
4648 """Test that we can pad TPL's BSS with zeros"""
4649 # ELF file with a '__bss_size' symbol
4650 self._SetupTplElf()
4651 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004652 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004653 data)
4654
4655 def testTplBssPadMissing(self):
4656 """Test that a missing symbol is detected"""
4657 self._SetupTplElf('u_boot_ucode_ptr')
4658 with self.assertRaises(ValueError) as e:
4659 self._DoReadFile('193_tpl_bss_pad.dts')
4660 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4661 str(e.exception))
4662
Simon Glass718b5292021-03-18 20:25:07 +13004663 def checkDtbSizes(self, data, pad_len, start):
4664 """Check the size arguments in a dtb embedded in an image
4665
4666 Args:
4667 data: The image data
4668 pad_len: Length of the pad section in the image, in bytes
4669 start: Start offset of the devicetree to examine, within the image
4670
4671 Returns:
4672 Size of the devicetree in bytes
4673 """
4674 dtb_data = data[start:]
4675 dtb = fdt.Fdt.FromData(dtb_data)
4676 fdt_size = dtb.GetFdtObj().totalsize()
4677 dtb.Scan()
4678 props = self._GetPropTree(dtb, 'size')
4679 self.assertEqual({
4680 'size': len(data),
4681 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4682 'u-boot-spl/u-boot-spl-dtb:size': 801,
4683 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4684 'u-boot-spl:size': 860,
4685 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4686 'u-boot/u-boot-dtb:size': 781,
4687 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4688 'u-boot:size': 827,
4689 }, props)
4690 return fdt_size
4691
4692 def testExpanded(self):
4693 """Test that an expanded entry type is selected when needed"""
4694 self._SetupSplElf()
4695 self._SetupTplElf()
4696
4697 # SPL has a devicetree, TPL does not
4698 entry_args = {
4699 'spl-dtb': '1',
4700 'spl-bss-pad': 'y',
4701 'tpl-dtb': '',
4702 }
4703 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4704 entry_args=entry_args)
4705 image = control.images['image']
4706 entries = image.GetEntries()
4707 self.assertEqual(3, len(entries))
4708
4709 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4710 self.assertIn('u-boot', entries)
4711 entry = entries['u-boot']
4712 self.assertEqual('u-boot-expanded', entry.etype)
4713 subent = entry.GetEntries()
4714 self.assertEqual(2, len(subent))
4715 self.assertIn('u-boot-nodtb', subent)
4716 self.assertIn('u-boot-dtb', subent)
4717
4718 # Second, u-boot-spl, which should be expanded into three parts
4719 self.assertIn('u-boot-spl', entries)
4720 entry = entries['u-boot-spl']
4721 self.assertEqual('u-boot-spl-expanded', entry.etype)
4722 subent = entry.GetEntries()
4723 self.assertEqual(3, len(subent))
4724 self.assertIn('u-boot-spl-nodtb', subent)
4725 self.assertIn('u-boot-spl-bss-pad', subent)
4726 self.assertIn('u-boot-spl-dtb', subent)
4727
4728 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4729 # devicetree
4730 self.assertIn('u-boot-tpl', entries)
4731 entry = entries['u-boot-tpl']
4732 self.assertEqual('u-boot-tpl', entry.etype)
4733 self.assertEqual(None, entry.GetEntries())
4734
4735 def testExpandedTpl(self):
4736 """Test that an expanded entry type is selected for TPL when needed"""
4737 self._SetupTplElf()
4738
4739 entry_args = {
4740 'tpl-bss-pad': 'y',
4741 'tpl-dtb': 'y',
4742 }
4743 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4744 entry_args=entry_args)
4745 image = control.images['image']
4746 entries = image.GetEntries()
4747 self.assertEqual(1, len(entries))
4748
4749 # We only have u-boot-tpl, which be expanded
4750 self.assertIn('u-boot-tpl', entries)
4751 entry = entries['u-boot-tpl']
4752 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4753 subent = entry.GetEntries()
4754 self.assertEqual(3, len(subent))
4755 self.assertIn('u-boot-tpl-nodtb', subent)
4756 self.assertIn('u-boot-tpl-bss-pad', subent)
4757 self.assertIn('u-boot-tpl-dtb', subent)
4758
4759 def testExpandedNoPad(self):
4760 """Test an expanded entry without BSS pad enabled"""
4761 self._SetupSplElf()
4762 self._SetupTplElf()
4763
4764 # SPL has a devicetree, TPL does not
4765 entry_args = {
4766 'spl-dtb': 'something',
4767 'spl-bss-pad': 'n',
4768 'tpl-dtb': '',
4769 }
4770 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4771 entry_args=entry_args)
4772 image = control.images['image']
4773 entries = image.GetEntries()
4774
4775 # Just check u-boot-spl, which should be expanded into two parts
4776 self.assertIn('u-boot-spl', entries)
4777 entry = entries['u-boot-spl']
4778 self.assertEqual('u-boot-spl-expanded', entry.etype)
4779 subent = entry.GetEntries()
4780 self.assertEqual(2, len(subent))
4781 self.assertIn('u-boot-spl-nodtb', subent)
4782 self.assertIn('u-boot-spl-dtb', subent)
4783
4784 def testExpandedTplNoPad(self):
4785 """Test that an expanded entry type with padding disabled in TPL"""
4786 self._SetupTplElf()
4787
4788 entry_args = {
4789 'tpl-bss-pad': '',
4790 'tpl-dtb': 'y',
4791 }
4792 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4793 entry_args=entry_args)
4794 image = control.images['image']
4795 entries = image.GetEntries()
4796 self.assertEqual(1, len(entries))
4797
4798 # We only have u-boot-tpl, which be expanded
4799 self.assertIn('u-boot-tpl', entries)
4800 entry = entries['u-boot-tpl']
4801 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4802 subent = entry.GetEntries()
4803 self.assertEqual(2, len(subent))
4804 self.assertIn('u-boot-tpl-nodtb', subent)
4805 self.assertIn('u-boot-tpl-dtb', subent)
4806
4807 def testFdtInclude(self):
4808 """Test that an Fdt is update within all binaries"""
4809 self._SetupSplElf()
4810 self._SetupTplElf()
4811
4812 # SPL has a devicetree, TPL does not
4813 self.maxDiff = None
4814 entry_args = {
4815 'spl-dtb': '1',
4816 'spl-bss-pad': 'y',
4817 'tpl-dtb': '',
4818 }
4819 # Build the image. It includes two separate devicetree binaries, each
4820 # with their own contents, but all contain the binman definition.
4821 data = self._DoReadFileDtb(
4822 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4823 update_dtb=True, entry_args=entry_args)[0]
4824 pad_len = 10
4825
4826 # Check the U-Boot dtb
4827 start = len(U_BOOT_NODTB_DATA)
4828 fdt_size = self.checkDtbSizes(data, pad_len, start)
4829
4830 # Now check SPL
4831 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4832 fdt_size = self.checkDtbSizes(data, pad_len, start)
4833
4834 # TPL has no devicetree
4835 start += fdt_size + len(U_BOOT_TPL_DATA)
4836 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004837
Simon Glass7098b7f2021-03-21 18:24:30 +13004838 def testSymbolsExpanded(self):
4839 """Test binman can assign symbols in expanded entries"""
4840 entry_args = {
4841 'spl-dtb': '1',
4842 }
4843 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4844 U_BOOT_SPL_DTB_DATA, 0x38,
4845 entry_args=entry_args, use_expanded=True)
4846
Simon Glasse1915782021-03-21 18:24:31 +13004847 def testCollection(self):
4848 """Test a collection"""
4849 data = self._DoReadFile('198_collection.dts')
4850 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004851 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4852 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004853 data)
4854
Simon Glass27a7f772021-03-21 18:24:32 +13004855 def testCollectionSection(self):
4856 """Test a collection where a section must be built first"""
4857 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004858 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004859 # building the contents, producing an error is anything is still
4860 # missing.
4861 data = self._DoReadFile('199_collection_section.dts')
4862 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004863 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4864 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004865 data)
4866
Simon Glassf427c5f2021-03-21 18:24:33 +13004867 def testAlignDefault(self):
4868 """Test that default alignment works on sections"""
4869 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004870 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004871 U_BOOT_DATA)
4872 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004873 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004874 # No alignment within the nested section
4875 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4876 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004877 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004878 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004879
Bin Mengc0b15742021-05-10 20:23:33 +08004880 def testPackOpenSBI(self):
4881 """Test that an image with an OpenSBI binary can be created"""
4882 data = self._DoReadFile('201_opensbi.dts')
4883 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4884
Simon Glass76f496d2021-07-06 10:36:37 -06004885 def testSectionsSingleThread(self):
4886 """Test sections without multithreading"""
4887 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004888 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4889 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4890 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004891 self.assertEqual(expected, data)
4892
4893 def testThreadTimeout(self):
4894 """Test handling a thread that takes too long"""
4895 with self.assertRaises(ValueError) as e:
4896 self._DoTestFile('202_section_timeout.dts',
4897 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004898 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004899
Simon Glass748a1d42021-07-06 10:36:41 -06004900 def testTiming(self):
4901 """Test output of timing information"""
4902 data = self._DoReadFile('055_sections.dts')
4903 with test_util.capture_sys_output() as (stdout, stderr):
4904 state.TimingShow()
4905 self.assertIn('read:', stdout.getvalue())
4906 self.assertIn('compress:', stdout.getvalue())
4907
Simon Glassadfb8492021-11-03 21:09:18 -06004908 def testUpdateFdtInElf(self):
4909 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004910 if not elf.ELF_TOOLS:
4911 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004912 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4913 outfile = os.path.join(self._indir, 'u-boot.out')
4914 begin_sym = 'dtb_embed_begin'
4915 end_sym = 'dtb_embed_end'
4916 retcode = self._DoTestFile(
4917 '060_fdt_update.dts', update_dtb=True,
4918 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4919 self.assertEqual(0, retcode)
4920
4921 # Check that the output file does in fact contact a dtb with the binman
4922 # definition in the correct place
4923 syms = elf.GetSymbolFileOffset(infile,
4924 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004925 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004926 dtb_data = data[syms['dtb_embed_begin'].offset:
4927 syms['dtb_embed_end'].offset]
4928
4929 dtb = fdt.Fdt.FromData(dtb_data)
4930 dtb.Scan()
4931 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4932 self.assertEqual({
4933 'image-pos': 0,
4934 'offset': 0,
4935 '_testing:offset': 32,
4936 '_testing:size': 2,
4937 '_testing:image-pos': 32,
4938 'section@0/u-boot:offset': 0,
4939 'section@0/u-boot:size': len(U_BOOT_DATA),
4940 'section@0/u-boot:image-pos': 0,
4941 'section@0:offset': 0,
4942 'section@0:size': 16,
4943 'section@0:image-pos': 0,
4944
4945 'section@1/u-boot:offset': 0,
4946 'section@1/u-boot:size': len(U_BOOT_DATA),
4947 'section@1/u-boot:image-pos': 16,
4948 'section@1:offset': 16,
4949 'section@1:size': 16,
4950 'section@1:image-pos': 16,
4951 'size': 40
4952 }, props)
4953
4954 def testUpdateFdtInElfInvalid(self):
4955 """Test that invalid args are detected with --update-fdt-in-elf"""
4956 with self.assertRaises(ValueError) as e:
4957 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4958 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4959 str(e.exception))
4960
4961 def testUpdateFdtInElfNoSyms(self):
4962 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004963 if not elf.ELF_TOOLS:
4964 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004965 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4966 outfile = ''
4967 begin_sym = 'wrong_begin'
4968 end_sym = 'wrong_end'
4969 with self.assertRaises(ValueError) as e:
4970 self._DoTestFile(
4971 '060_fdt_update.dts',
4972 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4973 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4974 str(e.exception))
4975
4976 def testUpdateFdtInElfTooSmall(self):
4977 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004978 if not elf.ELF_TOOLS:
4979 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004980 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4981 outfile = os.path.join(self._indir, 'u-boot.out')
4982 begin_sym = 'dtb_embed_begin'
4983 end_sym = 'dtb_embed_end'
4984 with self.assertRaises(ValueError) as e:
4985 self._DoTestFile(
4986 '060_fdt_update.dts', update_dtb=True,
4987 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4988 self.assertRegex(
4989 str(e.exception),
4990 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4991
Simon Glass88e04da2021-11-23 11:03:42 -07004992 def testVersion(self):
4993 """Test we can get the binman version"""
4994 version = '(unreleased)'
4995 self.assertEqual(version, state.GetVersion(self._indir))
4996
4997 with self.assertRaises(SystemExit):
4998 with test_util.capture_sys_output() as (_, stderr):
4999 self._DoBinman('-V')
5000 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
5001
5002 # Try running the tool too, just to be safe
5003 result = self._RunBinman('-V')
5004 self.assertEqual('Binman %s\n' % version, result.stderr)
5005
5006 # Set up a version file to make sure that works
5007 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07005008 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07005009 binary=False)
5010 self.assertEqual(version, state.GetVersion(self._indir))
5011
Simon Glass637958f2021-11-23 21:09:50 -07005012 def testAltFormat(self):
5013 """Test that alternative formats can be used to extract"""
5014 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
5015
5016 try:
5017 tmpdir, updated_fname = self._SetupImageInTmpdir()
5018 with test_util.capture_sys_output() as (stdout, _):
5019 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
5020 self.assertEqual(
5021 '''Flag (-F) Entry type Description
5022fdt fdtmap Extract the devicetree blob from the fdtmap
5023''',
5024 stdout.getvalue())
5025
5026 dtb = os.path.join(tmpdir, 'fdt.dtb')
5027 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
5028 dtb, 'fdtmap')
5029
5030 # Check that we can read it and it can be scanning, meaning it does
5031 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07005032 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07005033 dtb = fdt.Fdt.FromData(data)
5034 dtb.Scan()
5035
5036 # Now check u-boot which has no alt_format
5037 fname = os.path.join(tmpdir, 'fdt.dtb')
5038 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
5039 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07005040 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07005041 self.assertEqual(U_BOOT_DATA, data)
5042
5043 finally:
5044 shutil.rmtree(tmpdir)
5045
Simon Glass0b00ae62021-11-23 21:09:52 -07005046 def testExtblobList(self):
5047 """Test an image with an external blob list"""
5048 data = self._DoReadFile('215_blob_ext_list.dts')
5049 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5050
5051 def testExtblobListMissing(self):
5052 """Test an image with a missing external blob"""
5053 with self.assertRaises(ValueError) as e:
5054 self._DoReadFile('216_blob_ext_list_missing.dts')
5055 self.assertIn("Filename 'missing-file' not found in input path",
5056 str(e.exception))
5057
5058 def testExtblobListMissingOk(self):
5059 """Test an image with an missing external blob that is allowed"""
5060 with test_util.capture_sys_output() as (stdout, stderr):
5061 self._DoTestFile('216_blob_ext_list_missing.dts',
5062 allow_missing=True)
5063 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005064 self.assertRegex(err, "Image 'image'.*missing.*: blob-ext")
Simon Glass0b00ae62021-11-23 21:09:52 -07005065
Simon Glass3efb2972021-11-23 21:08:59 -07005066 def testFip(self):
5067 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5068 data = self._DoReadFile('203_fip.dts')
5069 hdr, fents = fip_util.decode_fip(data)
5070 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5071 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5072 self.assertEqual(0x123, hdr.flags)
5073
5074 self.assertEqual(2, len(fents))
5075
5076 fent = fents[0]
5077 self.assertEqual(
5078 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5079 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5080 self.assertEqual('soc-fw', fent.fip_type)
5081 self.assertEqual(0x88, fent.offset)
5082 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5083 self.assertEqual(0x123456789abcdef, fent.flags)
5084 self.assertEqual(ATF_BL31_DATA, fent.data)
5085 self.assertEqual(True, fent.valid)
5086
5087 fent = fents[1]
5088 self.assertEqual(
5089 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5090 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5091 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5092 self.assertEqual(0x8c, fent.offset)
5093 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5094 self.assertEqual(0, fent.flags)
5095 self.assertEqual(ATF_BL2U_DATA, fent.data)
5096 self.assertEqual(True, fent.valid)
5097
5098 def testFipOther(self):
5099 """Basic FIP with something that isn't a external blob"""
5100 data = self._DoReadFile('204_fip_other.dts')
5101 hdr, fents = fip_util.decode_fip(data)
5102
5103 self.assertEqual(2, len(fents))
5104 fent = fents[1]
5105 self.assertEqual('rot-cert', fent.fip_type)
5106 self.assertEqual(b'aa', fent.data)
5107
Simon Glass3efb2972021-11-23 21:08:59 -07005108 def testFipNoType(self):
5109 """FIP with an entry of an unknown type"""
5110 with self.assertRaises(ValueError) as e:
5111 self._DoReadFile('205_fip_no_type.dts')
5112 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5113 str(e.exception))
5114
5115 def testFipUuid(self):
5116 """Basic FIP with a manual uuid"""
5117 data = self._DoReadFile('206_fip_uuid.dts')
5118 hdr, fents = fip_util.decode_fip(data)
5119
5120 self.assertEqual(2, len(fents))
5121 fent = fents[1]
5122 self.assertEqual(None, fent.fip_type)
5123 self.assertEqual(
5124 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5125 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5126 fent.uuid)
5127 self.assertEqual(U_BOOT_DATA, fent.data)
5128
5129 def testFipLs(self):
5130 """Test listing a FIP"""
5131 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5132 hdr, fents = fip_util.decode_fip(data)
5133
5134 try:
5135 tmpdir, updated_fname = self._SetupImageInTmpdir()
5136 with test_util.capture_sys_output() as (stdout, stderr):
5137 self._DoBinman('ls', '-i', updated_fname)
5138 finally:
5139 shutil.rmtree(tmpdir)
5140 lines = stdout.getvalue().splitlines()
5141 expected = [
Simon Glass49cd2b32023-02-07 14:34:18 -07005142'Name Image-pos Size Entry-type Offset Uncomp-size',
5143'--------------------------------------------------------------',
5144'image 0 2d3 section 0',
5145' atf-fip 0 90 atf-fip 0',
5146' soc-fw 88 4 blob-ext 88',
5147' u-boot 8c 4 u-boot 8c',
5148' fdtmap 90 243 fdtmap 90',
Simon Glass3efb2972021-11-23 21:08:59 -07005149]
5150 self.assertEqual(expected, lines)
5151
5152 image = control.images['image']
5153 entries = image.GetEntries()
5154 fdtmap = entries['fdtmap']
5155
5156 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5157 magic = fdtmap_data[:8]
5158 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005159 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005160
5161 fdt_data = fdtmap_data[16:]
5162 dtb = fdt.Fdt.FromData(fdt_data)
5163 dtb.Scan()
5164 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5165 self.assertEqual({
5166 'atf-fip/soc-fw:image-pos': 136,
5167 'atf-fip/soc-fw:offset': 136,
5168 'atf-fip/soc-fw:size': 4,
5169 'atf-fip/u-boot:image-pos': 140,
5170 'atf-fip/u-boot:offset': 140,
5171 'atf-fip/u-boot:size': 4,
5172 'atf-fip:image-pos': 0,
5173 'atf-fip:offset': 0,
5174 'atf-fip:size': 144,
5175 'image-pos': 0,
5176 'offset': 0,
5177 'fdtmap:image-pos': fdtmap.image_pos,
5178 'fdtmap:offset': fdtmap.offset,
5179 'fdtmap:size': len(fdtmap_data),
5180 'size': len(data),
5181 }, props)
5182
5183 def testFipExtractOneEntry(self):
5184 """Test extracting a single entry fron an FIP"""
5185 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005186 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005187 fname = os.path.join(self._indir, 'output.extact')
5188 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005189 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005190 self.assertEqual(U_BOOT_DATA, data)
5191
5192 def testFipReplace(self):
5193 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005194 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005195 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005196 updated_fname = tools.get_output_filename('image-updated.bin')
5197 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005198 entry_name = 'atf-fip/u-boot'
5199 control.WriteEntry(updated_fname, entry_name, expected,
5200 allow_resize=True)
5201 actual = control.ReadEntry(updated_fname, entry_name)
5202 self.assertEqual(expected, actual)
5203
Simon Glass80025522022-01-29 14:14:04 -07005204 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005205 hdr, fents = fip_util.decode_fip(new_data)
5206
5207 self.assertEqual(2, len(fents))
5208
5209 # Check that the FIP entry is updated
5210 fent = fents[1]
5211 self.assertEqual(0x8c, fent.offset)
5212 self.assertEqual(len(expected), fent.size)
5213 self.assertEqual(0, fent.flags)
5214 self.assertEqual(expected, fent.data)
5215 self.assertEqual(True, fent.valid)
5216
5217 def testFipMissing(self):
5218 with test_util.capture_sys_output() as (stdout, stderr):
5219 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5220 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005221 self.assertRegex(err, "Image 'image'.*missing.*: rmm-fw")
Simon Glass3efb2972021-11-23 21:08:59 -07005222
5223 def testFipSize(self):
5224 """Test a FIP with a size property"""
5225 data = self._DoReadFile('210_fip_size.dts')
5226 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5227 hdr, fents = fip_util.decode_fip(data)
5228 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5229 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5230
5231 self.assertEqual(1, len(fents))
5232
5233 fent = fents[0]
5234 self.assertEqual('soc-fw', fent.fip_type)
5235 self.assertEqual(0x60, fent.offset)
5236 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5237 self.assertEqual(ATF_BL31_DATA, fent.data)
5238 self.assertEqual(True, fent.valid)
5239
5240 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005241 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005242
5243 def testFipBadAlign(self):
5244 """Test that an invalid alignment value in a FIP is detected"""
5245 with self.assertRaises(ValueError) as e:
5246 self._DoTestFile('211_fip_bad_align.dts')
5247 self.assertIn(
5248 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5249 str(e.exception))
5250
5251 def testFipCollection(self):
5252 """Test using a FIP in a collection"""
5253 data = self._DoReadFile('212_fip_collection.dts')
5254 entry1 = control.images['image'].GetEntries()['collection']
5255 data1 = data[:entry1.size]
5256 hdr1, fents2 = fip_util.decode_fip(data1)
5257
5258 entry2 = control.images['image'].GetEntries()['atf-fip']
5259 data2 = data[entry2.offset:entry2.offset + entry2.size]
5260 hdr1, fents2 = fip_util.decode_fip(data2)
5261
5262 # The 'collection' entry should have U-Boot included at the end
5263 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5264 self.assertEqual(data1, data2 + U_BOOT_DATA)
5265 self.assertEqual(U_BOOT_DATA, data1[-4:])
5266
5267 # There should be a U-Boot after the final FIP
5268 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005269
Simon Glassccae6862022-01-12 13:10:35 -07005270 def testFakeBlob(self):
5271 """Test handling of faking an external blob"""
5272 with test_util.capture_sys_output() as (stdout, stderr):
5273 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5274 allow_fake_blobs=True)
5275 err = stderr.getvalue()
5276 self.assertRegex(
5277 err,
5278 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005279
Simon Glassceb5f912022-01-09 20:13:46 -07005280 def testExtblobListFaked(self):
5281 """Test an extblob with missing external blob that are faked"""
5282 with test_util.capture_sys_output() as (stdout, stderr):
5283 self._DoTestFile('216_blob_ext_list_missing.dts',
5284 allow_fake_blobs=True)
5285 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005286 self.assertRegex(err, "Image 'image'.*faked.*: blob-ext-list")
Simon Glassceb5f912022-01-09 20:13:46 -07005287
Simon Glass162017b2022-01-09 20:13:57 -07005288 def testListBintools(self):
5289 args = ['tool', '--list']
5290 with test_util.capture_sys_output() as (stdout, _):
5291 self._DoBinman(*args)
5292 out = stdout.getvalue().splitlines()
5293 self.assertTrue(len(out) >= 2)
5294
5295 def testFetchBintools(self):
5296 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005297 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005298 raise urllib.error.URLError('my error')
5299
5300 args = ['tool']
5301 with self.assertRaises(ValueError) as e:
5302 self._DoBinman(*args)
5303 self.assertIn("Invalid arguments to 'tool' subcommand",
5304 str(e.exception))
5305
5306 args = ['tool', '--fetch']
5307 with self.assertRaises(ValueError) as e:
5308 self._DoBinman(*args)
5309 self.assertIn('Please specify bintools to fetch', str(e.exception))
5310
5311 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005312 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005313 side_effect=fail_download):
5314 with test_util.capture_sys_output() as (stdout, _):
5315 self._DoBinman(*args)
5316 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5317
Simon Glass620c4462022-01-09 20:14:11 -07005318 def testBintoolDocs(self):
5319 """Test for creation of bintool documentation"""
5320 with test_util.capture_sys_output() as (stdout, stderr):
5321 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5322 self.assertTrue(len(stdout.getvalue()) > 0)
5323
5324 def testBintoolDocsMissing(self):
5325 """Test handling of missing bintool documentation"""
5326 with self.assertRaises(ValueError) as e:
5327 with test_util.capture_sys_output() as (stdout, stderr):
5328 control.write_bintool_docs(
5329 control.bintool.Bintool.get_tool_list(), 'mkimage')
5330 self.assertIn('Documentation is missing for modules: mkimage',
5331 str(e.exception))
5332
Jan Kiszka58c407f2022-01-28 20:37:53 +01005333 def testListWithGenNode(self):
5334 """Check handling of an FDT map when the section cannot be found"""
5335 entry_args = {
5336 'of-list': 'test-fdt1 test-fdt2',
5337 }
5338 data = self._DoReadFileDtb(
5339 '219_fit_gennode.dts',
5340 entry_args=entry_args,
5341 use_real_dtb=True,
5342 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5343
5344 try:
5345 tmpdir, updated_fname = self._SetupImageInTmpdir()
5346 with test_util.capture_sys_output() as (stdout, stderr):
5347 self._RunBinman('ls', '-i', updated_fname)
5348 finally:
5349 shutil.rmtree(tmpdir)
5350
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005351 def testFitSubentryUsesBintool(self):
5352 """Test that binman FIT subentries can use bintools"""
5353 command.test_result = self._HandleGbbCommand
5354 entry_args = {
5355 'keydir': 'devkeys',
5356 'bmpblk': 'bmpblk.bin',
5357 }
5358 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5359 entry_args=entry_args)
5360
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005361 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5362 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005363 self.assertIn(expected, data)
5364
5365 def testFitSubentryMissingBintool(self):
5366 """Test that binman reports missing bintools for FIT subentries"""
5367 entry_args = {
5368 'keydir': 'devkeys',
5369 }
5370 with test_util.capture_sys_output() as (_, stderr):
5371 self._DoTestFile('220_fit_subentry_bintool.dts',
5372 force_missing_bintools='futility', entry_args=entry_args)
5373 err = stderr.getvalue()
Simon Glass49cd2b32023-02-07 14:34:18 -07005374 self.assertRegex(err, "Image 'image'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005375
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005376 def testFitSubentryHashSubnode(self):
5377 """Test an image with a FIT inside"""
5378 data, _, _, out_dtb_name = self._DoReadFileDtb(
5379 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5380
5381 mkimage_dtb = fdt.Fdt.FromData(data)
5382 mkimage_dtb.Scan()
5383 binman_dtb = fdt.Fdt(out_dtb_name)
5384 binman_dtb.Scan()
5385
5386 # Check that binman didn't add hash values
5387 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5388 self.assertNotIn('value', fnode.props)
5389
5390 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5391 self.assertNotIn('value', fnode.props)
5392
5393 # Check that mkimage added hash values
5394 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5395 self.assertIn('value', fnode.props)
5396
5397 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5398 self.assertIn('value', fnode.props)
5399
Roger Quadros5cdcea02022-02-19 20:50:04 +02005400 def testPackTeeOs(self):
5401 """Test that an image with an TEE binary can be created"""
5402 data = self._DoReadFile('222_tee_os.dts')
5403 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5404
Simon Glass912339f2022-02-08 11:50:03 -07005405 def testFitFdtOper(self):
5406 """Check handling of a specified FIT operation"""
5407 entry_args = {
5408 'of-list': 'test-fdt1 test-fdt2',
5409 'default-dt': 'test-fdt2',
5410 }
5411 self._DoReadFileDtb(
5412 '223_fit_fdt_oper.dts',
5413 entry_args=entry_args,
5414 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5415
5416 def testFitFdtBadOper(self):
5417 """Check handling of an FDT map when the section cannot be found"""
5418 with self.assertRaises(ValueError) as exc:
5419 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005420 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005421 str(exc.exception))
5422
Simon Glassdd156a42022-03-05 20:18:59 -07005423 def test_uses_expand_size(self):
5424 """Test that the 'expand-size' property cannot be used anymore"""
5425 with self.assertRaises(ValueError) as e:
5426 data = self._DoReadFile('225_expand_size_bad.dts')
5427 self.assertIn(
5428 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5429 str(e.exception))
5430
Simon Glass5f423422022-03-05 20:19:12 -07005431 def testFitSplitElf(self):
5432 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005433 if not elf.ELF_TOOLS:
5434 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005435 entry_args = {
5436 'of-list': 'test-fdt1 test-fdt2',
5437 'default-dt': 'test-fdt2',
5438 'atf-bl31-path': 'bl31.elf',
5439 'tee-os-path': 'tee.elf',
5440 }
5441 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5442 data = self._DoReadFileDtb(
5443 '226_fit_split_elf.dts',
5444 entry_args=entry_args,
5445 extra_indirs=[test_subdir])[0]
5446
5447 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5448 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5449
5450 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5451 'data', 'load'}
5452 dtb = fdt.Fdt.FromData(fit_data)
5453 dtb.Scan()
5454
5455 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5456 segments, entry = elf.read_loadable_segments(elf_data)
5457
5458 # We assume there are two segments
5459 self.assertEquals(2, len(segments))
5460
5461 atf1 = dtb.GetNode('/images/atf-1')
5462 _, start, data = segments[0]
5463 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5464 self.assertEqual(entry,
5465 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5466 self.assertEqual(start,
5467 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5468 self.assertEqual(data, atf1.props['data'].bytes)
5469
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005470 hash_node = atf1.FindNode('hash')
5471 self.assertIsNotNone(hash_node)
5472 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5473
Simon Glass5f423422022-03-05 20:19:12 -07005474 atf2 = dtb.GetNode('/images/atf-2')
5475 self.assertEqual(base_keys, atf2.props.keys())
5476 _, start, data = segments[1]
5477 self.assertEqual(start,
5478 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5479 self.assertEqual(data, atf2.props['data'].bytes)
5480
Jonas Karlmand2c7d902023-01-21 19:01:48 +00005481 hash_node = atf2.FindNode('hash')
5482 self.assertIsNotNone(hash_node)
5483 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5484
5485 hash_node = dtb.GetNode('/images/tee-1/hash-1')
5486 self.assertIsNotNone(hash_node)
5487 self.assertEqual({'algo', 'value'}, hash_node.props.keys())
5488
Simon Glass5f423422022-03-05 20:19:12 -07005489 conf = dtb.GetNode('/configurations')
5490 self.assertEqual({'default'}, conf.props.keys())
5491
5492 for subnode in conf.subnodes:
5493 self.assertEqual({'description', 'fdt', 'loadables'},
5494 subnode.props.keys())
5495 self.assertEqual(
5496 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5497 fdt_util.GetStringList(subnode, 'loadables'))
5498
5499 def _check_bad_fit(self, dts):
5500 """Check a bad FIT
5501
5502 This runs with the given dts and returns the assertion raised
5503
5504 Args:
5505 dts (str): dts filename to use
5506
5507 Returns:
5508 str: Assertion string raised
5509 """
5510 entry_args = {
5511 'of-list': 'test-fdt1 test-fdt2',
5512 'default-dt': 'test-fdt2',
5513 'atf-bl31-path': 'bl31.elf',
5514 'tee-os-path': 'tee.elf',
5515 }
5516 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5517 with self.assertRaises(ValueError) as exc:
5518 self._DoReadFileDtb(dts, entry_args=entry_args,
5519 extra_indirs=[test_subdir])[0]
5520 return str(exc.exception)
5521
5522 def testFitSplitElfBadElf(self):
5523 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005524 if not elf.ELF_TOOLS:
5525 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005526 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5527 entry_args = {
5528 'of-list': 'test-fdt1 test-fdt2',
5529 'default-dt': 'test-fdt2',
5530 'atf-bl31-path': 'bad.elf',
5531 'tee-os-path': 'tee.elf',
5532 }
5533 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5534 with self.assertRaises(ValueError) as exc:
5535 self._DoReadFileDtb(
5536 '226_fit_split_elf.dts',
5537 entry_args=entry_args,
5538 extra_indirs=[test_subdir])[0]
5539 self.assertIn(
5540 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5541 str(exc.exception))
5542
Simon Glass5f423422022-03-05 20:19:12 -07005543 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005544 """Test an split-elf FIT with a missing ELF file
5545
5546 Args:
5547 kwargs (dict of str): Arguments to pass to _DoTestFile()
5548
5549 Returns:
5550 tuple:
5551 str: stdout result
5552 str: stderr result
5553 """
Simon Glass5f423422022-03-05 20:19:12 -07005554 entry_args = {
5555 'of-list': 'test-fdt1 test-fdt2',
5556 'default-dt': 'test-fdt2',
5557 'atf-bl31-path': 'bl31.elf',
5558 'tee-os-path': 'missing.elf',
5559 }
5560 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5561 with test_util.capture_sys_output() as (stdout, stderr):
5562 self._DoTestFile(
5563 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005564 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5565 out = stdout.getvalue()
5566 err = stderr.getvalue()
5567 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005568
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005569 def testFitSplitElfBadDirective(self):
5570 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5571 if not elf.ELF_TOOLS:
5572 self.skipTest('Python elftools not available')
5573 err = self._check_bad_fit('227_fit_bad_dir.dts')
5574 self.assertIn(
5575 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5576 err)
5577
5578 def testFitSplitElfBadDirectiveConfig(self):
5579 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5580 if not elf.ELF_TOOLS:
5581 self.skipTest('Python elftools not available')
5582 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5583 self.assertEqual(
5584 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5585 err)
5586
5587
Simon Glass5f423422022-03-05 20:19:12 -07005588 def testFitSplitElfMissing(self):
5589 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005590 if not elf.ELF_TOOLS:
5591 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005592 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005593 self.assertRegex(
5594 err,
5595 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005596 self.assertNotRegex(out, '.*Faked blob.*')
5597 fname = tools.get_output_filename('binman-fake/missing.elf')
5598 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005599
5600 def testFitSplitElfFaked(self):
5601 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005602 if not elf.ELF_TOOLS:
5603 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005604 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005605 self.assertRegex(
5606 err,
5607 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005608 self.assertRegex(
5609 out,
5610 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5611 fname = tools.get_output_filename('binman-fake/missing.elf')
5612 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005613
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005614 def testMkimageMissingBlob(self):
5615 """Test using mkimage to build an image"""
5616 with test_util.capture_sys_output() as (stdout, stderr):
5617 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5618 allow_fake_blobs=True)
5619 err = stderr.getvalue()
5620 self.assertRegex(
5621 err,
5622 "Image '.*' has faked external blobs and is non-functional: .*")
5623
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005624 def testPreLoad(self):
5625 """Test an image with a pre-load header"""
5626 entry_args = {
5627 'pre-load-key-path': '.',
5628 }
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005629 data, _, _, _ = self._DoReadFileDtb('230_pre_load.dts',
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005630 entry_args=entry_args)
5631 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5632 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5633 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005634 data = self._DoReadFile('230_pre_load.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005635 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5636 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5637 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5638
5639 def testPreLoadPkcs(self):
5640 """Test an image with a pre-load header with padding pkcs"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005641 data = self._DoReadFile('231_pre_load_pkcs.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005642 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5643 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5644 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5645
5646 def testPreLoadPss(self):
5647 """Test an image with a pre-load header with padding pss"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005648 data = self._DoReadFile('232_pre_load_pss.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 testPreLoadInvalidPadding(self):
5654 """Test an image with a pre-load header with an invalid padding"""
5655 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005656 data = self._DoReadFile('233_pre_load_invalid_padding.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005657
5658 def testPreLoadInvalidSha(self):
5659 """Test an image with a pre-load header with an invalid hash"""
5660 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005661 data = self._DoReadFile('234_pre_load_invalid_sha.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005662
5663 def testPreLoadInvalidAlgo(self):
5664 """Test an image with a pre-load header with an invalid algo"""
5665 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005666 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005667
5668 def testPreLoadInvalidKey(self):
5669 """Test an image with a pre-load header with an invalid key"""
5670 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005671 data = self._DoReadFile('236_pre_load_invalid_key.dts')
Roger Quadros5cdcea02022-02-19 20:50:04 +02005672
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005673 def _CheckSafeUniqueNames(self, *images):
5674 """Check all entries of given images for unsafe unique names"""
5675 for image in images:
5676 entries = {}
5677 image._CollectEntries(entries, {}, image)
5678 for entry in entries.values():
5679 uniq = entry.GetUniqueName()
5680
5681 # Used as part of a filename, so must not be absolute paths.
5682 self.assertFalse(os.path.isabs(uniq))
5683
5684 def testSafeUniqueNames(self):
5685 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005686 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005687
5688 orig_image = control.images['image']
5689 image_fname = tools.get_output_filename('image.bin')
5690 image = Image.FromFile(image_fname)
5691
5692 self._CheckSafeUniqueNames(orig_image, image)
5693
5694 def testSafeUniqueNamesMulti(self):
5695 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005696 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005697
5698 orig_image = control.images['image']
5699 image_fname = tools.get_output_filename('image.bin')
5700 image = Image.FromFile(image_fname)
5701
5702 self._CheckSafeUniqueNames(orig_image, image)
5703
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005704 def testReplaceCmdWithBintool(self):
5705 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005706 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005707 expected = U_BOOT_DATA + b'aa'
5708 self.assertEqual(expected, data[:len(expected)])
5709
5710 try:
5711 tmpdir, updated_fname = self._SetupImageInTmpdir()
5712 fname = os.path.join(tmpdir, 'update-testing.bin')
5713 tools.write_file(fname, b'zz')
5714 self._DoBinman('replace', '-i', updated_fname,
5715 '_testing', '-f', fname)
5716
5717 data = tools.read_file(updated_fname)
5718 expected = U_BOOT_DATA + b'zz'
5719 self.assertEqual(expected, data[:len(expected)])
5720 finally:
5721 shutil.rmtree(tmpdir)
5722
5723 def testReplaceCmdOtherWithBintool(self):
5724 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005725 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005726 expected = U_BOOT_DATA + b'aa'
5727 self.assertEqual(expected, data[:len(expected)])
5728
5729 try:
5730 tmpdir, updated_fname = self._SetupImageInTmpdir()
5731 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5732 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5733 self._DoBinman('replace', '-i', updated_fname,
5734 'u-boot', '-f', fname)
5735
5736 data = tools.read_file(updated_fname)
5737 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5738 self.assertEqual(expected, data[:len(expected)])
5739 finally:
5740 shutil.rmtree(tmpdir)
5741
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005742 def testReplaceResizeNoRepackSameSize(self):
5743 """Test replacing entries with same-size data without repacking"""
5744 expected = b'x' * len(U_BOOT_DATA)
5745 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5746 self.assertEqual(expected, data)
5747
5748 path, fdtmap = state.GetFdtContents('fdtmap')
5749 self.assertIsNotNone(path)
5750 self.assertEqual(expected_fdtmap, fdtmap)
5751
5752 def testReplaceResizeNoRepackSmallerSize(self):
5753 """Test replacing entries with smaller-size data without repacking"""
5754 new_data = b'x'
5755 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5756 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5757 self.assertEqual(expected, data)
5758
5759 path, fdtmap = state.GetFdtContents('fdtmap')
5760 self.assertIsNotNone(path)
5761 self.assertEqual(expected_fdtmap, fdtmap)
5762
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005763 def testExtractFit(self):
5764 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005765 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005766 image_fname = tools.get_output_filename('image.bin')
5767
5768 fit_data = control.ReadEntry(image_fname, 'fit')
5769 fit = fdt.Fdt.FromData(fit_data)
5770 fit.Scan()
5771
5772 # Check subentry data inside the extracted fit
5773 for node_path, expected in [
5774 ('/images/kernel', U_BOOT_DATA),
5775 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5776 ('/images/scr-1', COMPRESS_DATA),
5777 ]:
5778 node = fit.GetNode(node_path)
5779 data = fit.GetProps(node)['data'].bytes
5780 self.assertEqual(expected, data)
5781
5782 def testExtractFitSubentries(self):
5783 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005784 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005785 image_fname = tools.get_output_filename('image.bin')
5786
5787 for entry_path, expected in [
5788 ('fit/kernel', U_BOOT_DATA),
5789 ('fit/kernel/u-boot', U_BOOT_DATA),
5790 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5791 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5792 ('fit/scr-1', COMPRESS_DATA),
5793 ('fit/scr-1/blob', COMPRESS_DATA),
5794 ]:
5795 data = control.ReadEntry(image_fname, entry_path)
5796 self.assertEqual(expected, data)
5797
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005798 def testReplaceFitSubentryLeafSameSize(self):
5799 """Test replacing a FIT leaf subentry with same-size data"""
5800 new_data = b'x' * len(U_BOOT_DATA)
5801 data, expected_fdtmap, _ = self._RunReplaceCmd(
5802 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005803 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005804 self.assertEqual(new_data, data)
5805
5806 path, fdtmap = state.GetFdtContents('fdtmap')
5807 self.assertIsNotNone(path)
5808 self.assertEqual(expected_fdtmap, fdtmap)
5809
5810 def testReplaceFitSubentryLeafBiggerSize(self):
5811 """Test replacing a FIT leaf subentry with bigger-size data"""
5812 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5813 data, expected_fdtmap, _ = self._RunReplaceCmd(
5814 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005815 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005816 self.assertEqual(new_data, data)
5817
5818 # Will be repacked, so fdtmap must change
5819 path, fdtmap = state.GetFdtContents('fdtmap')
5820 self.assertIsNotNone(path)
5821 self.assertNotEqual(expected_fdtmap, fdtmap)
5822
5823 def testReplaceFitSubentryLeafSmallerSize(self):
5824 """Test replacing a FIT leaf subentry with smaller-size data"""
5825 new_data = b'x'
5826 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
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(expected, data)
5831
5832 path, fdtmap = state.GetFdtContents('fdtmap')
5833 self.assertIsNotNone(path)
5834 self.assertEqual(expected_fdtmap, fdtmap)
5835
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005836 def testReplaceSectionSimple(self):
Simon Glass49b77e82023-03-02 17:02:44 -07005837 """Test replacing a simple section with same-sized data"""
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005838 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glass49b77e82023-03-02 17:02:44 -07005839 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5840 new_data, dts='241_replace_section_simple.dts')
5841 self.assertEqual(new_data, data)
5842
5843 entries = image.GetEntries()
5844 self.assertIn('section', entries)
5845 entry = entries['section']
5846 self.assertEqual(len(new_data), entry.size)
5847
5848 def testReplaceSectionLarger(self):
5849 """Test replacing a simple section with larger data"""
5850 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
5851 data, expected_fdtmap, image = self._RunReplaceCmd('section',
5852 new_data, dts='241_replace_section_simple.dts')
5853 self.assertEqual(new_data, data)
5854
5855 entries = image.GetEntries()
5856 self.assertIn('section', entries)
5857 entry = entries['section']
5858 self.assertEqual(len(new_data), entry.size)
5859 fentry = entries['fdtmap']
5860 self.assertEqual(entry.offset + entry.size, fentry.offset)
5861
5862 def testReplaceSectionSmaller(self):
5863 """Test replacing a simple section with smaller data"""
5864 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1) + b'\0'
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 # The new size is the same as the old, just with a pad byte at the end
5870 entries = image.GetEntries()
5871 self.assertIn('section', entries)
5872 entry = entries['section']
5873 self.assertEqual(len(new_data), entry.size)
5874
5875 def testReplaceSectionSmallerAllow(self):
5876 """Test failing to replace a simple section with smaller data"""
5877 new_data = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) - 1)
5878 try:
5879 state.SetAllowEntryContraction(True)
5880 with self.assertRaises(ValueError) as exc:
5881 self._RunReplaceCmd('section', new_data,
5882 dts='241_replace_section_simple.dts')
5883 finally:
5884 state.SetAllowEntryContraction(False)
5885
5886 # Since we have no information about the position of things within the
5887 # section, we cannot adjust the position of /section-u-boot so it ends
5888 # up outside the section
Simon Glassc6b283f2022-08-13 11:40:46 -06005889 self.assertIn(
Simon Glass49b77e82023-03-02 17:02:44 -07005890 "Node '/section/u-boot': Offset 0x24 (36) size 0x4 (4) is outside "
5891 "the section '/section' starting at 0x0 (0) of size 0x27 (39)",
Simon Glassc6b283f2022-08-13 11:40:46 -06005892 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005893
Simon Glass8fbca772022-08-13 11:40:48 -06005894 def testMkimageImagename(self):
5895 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005896 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005897
5898 # Check that the data appears in the file somewhere
5899 self.assertIn(U_BOOT_SPL_DATA, data)
5900
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005901 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005902 name = data[0x20:0x40]
5903
5904 # Build the filename that we expect to be placed in there, by virtue of
5905 # the -n paraameter
5906 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5907
5908 # Check that the image name is set to the temporary filename used
5909 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5910
Simon Glassb1669752022-08-13 11:40:49 -06005911 def testMkimageImage(self):
5912 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005913 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005914
5915 # Check that the data appears in the file somewhere
5916 self.assertIn(U_BOOT_SPL_DATA, data)
5917
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005918 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06005919 name = data[0x20:0x40]
5920
5921 # Build the filename that we expect to be placed in there, by virtue of
5922 # the -n paraameter
5923 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5924
5925 # Check that the image name is set to the temporary filename used
5926 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5927
5928 # Check the corect data is in the imagename file
5929 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5930
5931 def testMkimageImageNoContent(self):
5932 """Test using mkimage with -n and no data"""
5933 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005934 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005935 self.assertIn('Could not complete processing of contents',
5936 str(exc.exception))
5937
5938 def testMkimageImageBad(self):
5939 """Test using mkimage with imagename node and data-to-imagename"""
5940 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005941 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005942 self.assertIn('Cannot use both imagename node and data-to-imagename',
5943 str(exc.exception))
5944
Simon Glassbd5cd882022-08-13 11:40:50 -06005945 def testCollectionOther(self):
5946 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005947 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005948 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5949 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5950 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5951 data)
5952
5953 def testMkimageCollection(self):
5954 """Test using a collection referring to an entry in a mkimage entry"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005955 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005956 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5957 self.assertEqual(expect, data[:len(expect)])
5958
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005959 def testCompressDtbPrependInvalid(self):
5960 """Test that invalid header is detected"""
5961 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005962 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005963 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5964 "'u-boot-dtb': 'invalid'", str(e.exception))
5965
5966 def testCompressDtbPrependLength(self):
5967 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005968 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005969 image = control.images['image']
5970 entries = image.GetEntries()
5971 self.assertIn('u-boot-dtb', entries)
5972 u_boot_dtb = entries['u-boot-dtb']
5973 self.assertIn('fdtmap', entries)
5974 fdtmap = entries['fdtmap']
5975
5976 image_fname = tools.get_output_filename('image.bin')
5977 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
5978 dtb = fdt.Fdt.FromData(orig)
5979 dtb.Scan()
5980 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
5981 expected = {
5982 'u-boot:size': len(U_BOOT_DATA),
5983 'u-boot-dtb:uncomp-size': len(orig),
5984 'u-boot-dtb:size': u_boot_dtb.size,
5985 'fdtmap:size': fdtmap.size,
5986 'size': len(data),
5987 }
5988 self.assertEqual(expected, props)
5989
5990 # Check implementation
5991 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
5992 rest = data[len(U_BOOT_DATA):]
5993 comp_data_len = struct.unpack('<I', rest[:4])[0]
5994 comp_data = rest[4:4 + comp_data_len]
5995 orig2 = self._decompress(comp_data)
5996 self.assertEqual(orig, orig2)
5997
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02005998 def testInvalidCompress(self):
5999 """Test that invalid compress algorithm is detected"""
6000 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006001 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02006002 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
6003
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006004 def testCompUtilCompressions(self):
6005 """Test compression algorithms"""
6006 for bintool in self.comp_bintools.values():
6007 self._CheckBintool(bintool)
6008 data = bintool.compress(COMPRESS_DATA)
6009 self.assertNotEqual(COMPRESS_DATA, data)
6010 orig = bintool.decompress(data)
6011 self.assertEquals(COMPRESS_DATA, orig)
6012
6013 def testCompUtilVersions(self):
6014 """Test tool version of compression algorithms"""
6015 for bintool in self.comp_bintools.values():
6016 self._CheckBintool(bintool)
6017 version = bintool.version()
6018 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
6019
6020 def testCompUtilPadding(self):
6021 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006022 # Skip zstd because it doesn't support padding
6023 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02006024 self._CheckBintool(bintool)
6025 data = bintool.compress(COMPRESS_DATA)
6026 self.assertNotEqual(COMPRESS_DATA, data)
6027 data += tools.get_bytes(0, 64)
6028 orig = bintool.decompress(data)
6029 self.assertEquals(COMPRESS_DATA, orig)
6030
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006031 def testCompressDtbZstd(self):
6032 """Test that zstd compress of device-tree files failed"""
6033 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02006034 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02006035 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
6036 "requires a length header", str(e.exception))
6037
Quentin Schulz9b5c6482022-09-02 15:10:48 +02006038 def testMkimageMultipleDataFiles(self):
6039 """Test passing multiple files to mkimage in a mkimage entry"""
6040 data = self._DoReadFile('252_mkimage_mult_data.dts')
6041 # Size of files are packed in their 4B big-endian format
6042 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
6043 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
6044 # Size info is always followed by a 4B zero value.
6045 expect += tools.get_bytes(0, 4)
6046 expect += U_BOOT_TPL_DATA
6047 # All but last files are 4B-aligned
6048 align_pad = len(U_BOOT_TPL_DATA) % 4
6049 if align_pad:
6050 expect += tools.get_bytes(0, align_pad)
6051 expect += U_BOOT_SPL_DATA
6052 self.assertEqual(expect, data[-len(expect):])
6053
6054 def testMkimageMultipleNoContent(self):
6055 """Test passing multiple data files to mkimage with one data file having no content"""
6056 with self.assertRaises(ValueError) as exc:
6057 self._DoReadFile('253_mkimage_mult_no_content.dts')
6058 self.assertIn('Could not complete processing of contents',
6059 str(exc.exception))
6060
Quentin Schulz0d3a9262022-09-02 15:10:49 +02006061 def testMkimageFilename(self):
6062 """Test using mkimage to build a binary with a filename"""
6063 retcode = self._DoTestFile('254_mkimage_filename.dts')
6064 self.assertEqual(0, retcode)
6065 fname = tools.get_output_filename('mkimage-test.bin')
6066 self.assertTrue(os.path.exists(fname))
6067
Simon Glass56d05412022-02-28 07:16:54 -07006068 def testVpl(self):
6069 """Test that an image with VPL and its device tree can be created"""
6070 # ELF file with a '__bss_size' symbol
6071 self._SetupVplElf()
6072 data = self._DoReadFile('255_u_boot_vpl.dts')
6073 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
6074
6075 def testVplNoDtb(self):
6076 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
6077 self._SetupVplElf()
6078 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
6079 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
6080 data[:len(U_BOOT_VPL_NODTB_DATA)])
6081
6082 def testExpandedVpl(self):
6083 """Test that an expanded entry type is selected for TPL when needed"""
6084 self._SetupVplElf()
6085
6086 entry_args = {
6087 'vpl-bss-pad': 'y',
6088 'vpl-dtb': 'y',
6089 }
6090 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
6091 entry_args=entry_args)
6092 image = control.images['image']
6093 entries = image.GetEntries()
6094 self.assertEqual(1, len(entries))
6095
6096 # We only have u-boot-vpl, which be expanded
6097 self.assertIn('u-boot-vpl', entries)
6098 entry = entries['u-boot-vpl']
6099 self.assertEqual('u-boot-vpl-expanded', entry.etype)
6100 subent = entry.GetEntries()
6101 self.assertEqual(3, len(subent))
6102 self.assertIn('u-boot-vpl-nodtb', subent)
6103 self.assertIn('u-boot-vpl-bss-pad', subent)
6104 self.assertIn('u-boot-vpl-dtb', subent)
6105
6106 def testVplBssPadMissing(self):
6107 """Test that a missing symbol is detected"""
6108 self._SetupVplElf('u_boot_ucode_ptr')
6109 with self.assertRaises(ValueError) as e:
6110 self._DoReadFile('258_vpl_bss_pad.dts')
6111 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6112 str(e.exception))
6113
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306114 def testSymlink(self):
6115 """Test that image files can be named"""
6116 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6117 self.assertEqual(0, retcode)
6118 image = control.images['test_image']
6119 fname = tools.get_output_filename('test_image.bin')
6120 sname = tools.get_output_filename('symlink_to_test.bin')
6121 self.assertTrue(os.path.islink(sname))
6122 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006123
Simon Glass37f85de2022-10-20 18:22:47 -06006124 def testSymbolsElf(self):
6125 """Test binman can assign symbols embedded in an ELF file"""
6126 if not elf.ELF_TOOLS:
6127 self.skipTest('Python elftools not available')
6128 self._SetupTplElf('u_boot_binman_syms')
6129 self._SetupVplElf('u_boot_binman_syms')
6130 self._SetupSplElf('u_boot_binman_syms')
6131 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6132 image_fname = tools.get_output_filename('image.bin')
6133
6134 image = control.images['image']
6135 entries = image.GetEntries()
6136
6137 for entry in entries.values():
6138 # No symbols in u-boot and it has faked contents anyway
6139 if entry.name == 'u-boot':
6140 continue
6141 edata = data[entry.image_pos:entry.image_pos + entry.size]
6142 efname = tools.get_output_filename(f'edata-{entry.name}')
6143 tools.write_file(efname, edata)
6144
6145 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6146 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6147 for name, sym in syms.items():
6148 msg = 'test'
6149 val = elf.GetSymbolValue(sym, edata, msg)
6150 entry_m = re_name.match(name)
6151 if entry_m:
6152 ename, prop = entry_m.group(1), entry_m.group(3)
6153 entry, entry_name, prop_name = image.LookupEntry(entries,
6154 name, msg)
6155 if prop_name == 'offset':
6156 expect_val = entry.offset
6157 elif prop_name == 'image_pos':
6158 expect_val = entry.image_pos
6159 elif prop_name == 'size':
6160 expect_val = entry.size
6161 self.assertEqual(expect_val, val)
6162
6163 def testSymbolsElfBad(self):
6164 """Check error when trying to write symbols without the elftools lib"""
6165 if not elf.ELF_TOOLS:
6166 self.skipTest('Python elftools not available')
6167 self._SetupTplElf('u_boot_binman_syms')
6168 self._SetupVplElf('u_boot_binman_syms')
6169 self._SetupSplElf('u_boot_binman_syms')
6170 try:
6171 elf.ELF_TOOLS = False
6172 with self.assertRaises(ValueError) as exc:
6173 self._DoReadFileDtb('260_symbols_elf.dts')
6174 finally:
6175 elf.ELF_TOOLS = True
6176 self.assertIn(
6177 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6178 'Cannot write symbols to an ELF file without Python elftools',
6179 str(exc.exception))
6180
Simon Glassde244162023-01-07 14:07:08 -07006181 def testSectionFilename(self):
6182 """Check writing of section contents to a file"""
6183 data = self._DoReadFile('261_section_fname.dts')
6184 expected = (b'&&' + U_BOOT_DATA + b'&&&' +
6185 tools.get_bytes(ord('!'), 7) +
6186 U_BOOT_DATA + tools.get_bytes(ord('&'), 12))
6187 self.assertEqual(expected, data)
6188
6189 sect_fname = tools.get_output_filename('outfile.bin')
6190 self.assertTrue(os.path.exists(sect_fname))
6191 sect_data = tools.read_file(sect_fname)
6192 self.assertEqual(U_BOOT_DATA, sect_data)
6193
Simon Glass1e9e61c2023-01-07 14:07:12 -07006194 def testAbsent(self):
6195 """Check handling of absent entries"""
6196 data = self._DoReadFile('262_absent.dts')
6197 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6198
Simon Glassad5cfe12023-01-07 14:07:14 -07006199 def testPackTeeOsOptional(self):
6200 """Test that an image with an optional TEE binary can be created"""
6201 entry_args = {
6202 'tee-os-path': 'tee.elf',
6203 }
6204 data = self._DoReadFileDtb('263_tee_os_opt.dts',
6205 entry_args=entry_args)[0]
6206 self.assertEqual(U_BOOT_DATA + U_BOOT_IMG_DATA, data)
6207
6208 def checkFitTee(self, dts, tee_fname):
6209 """Check that a tee-os entry works and returns data
6210
6211 Args:
6212 dts (str): Device tree filename to use
6213 tee_fname (str): filename containing tee-os
6214
6215 Returns:
6216 bytes: Image contents
6217 """
6218 if not elf.ELF_TOOLS:
6219 self.skipTest('Python elftools not available')
6220 entry_args = {
6221 'of-list': 'test-fdt1 test-fdt2',
6222 'default-dt': 'test-fdt2',
6223 'tee-os-path': tee_fname,
6224 }
6225 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
6226 data = self._DoReadFileDtb(dts, entry_args=entry_args,
6227 extra_indirs=[test_subdir])[0]
6228 return data
6229
6230 def testFitTeeOsOptionalFit(self):
6231 """Test an image with a FIT with an optional OP-TEE binary"""
6232 data = self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bin')
6233
6234 # There should be only one node, holding the data set up in SetUpClass()
6235 # for tee.bin
6236 dtb = fdt.Fdt.FromData(data)
6237 dtb.Scan()
6238 node = dtb.GetNode('/images/tee-1')
6239 self.assertEqual(TEE_ADDR,
6240 fdt_util.fdt32_to_cpu(node.props['load'].value))
6241 self.assertEqual(TEE_ADDR,
6242 fdt_util.fdt32_to_cpu(node.props['entry'].value))
6243 self.assertEqual(U_BOOT_DATA, node.props['data'].bytes)
6244
6245 def testFitTeeOsOptionalFitBad(self):
6246 """Test an image with a FIT with an optional OP-TEE binary"""
6247 with self.assertRaises(ValueError) as exc:
6248 self.checkFitTee('265_tee_os_opt_fit_bad.dts', 'tee.bin')
6249 self.assertIn(
6250 "Node '/binman/fit': subnode 'images/@tee-SEQ': Failed to read ELF file: Magic number does not match",
6251 str(exc.exception))
6252
6253 def testFitTeeOsBad(self):
6254 """Test an OP-TEE binary with wrong formats"""
6255 self.make_tee_bin('tee.bad1', 123)
6256 with self.assertRaises(ValueError) as exc:
6257 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad1')
6258 self.assertIn(
6259 "Node '/binman/fit/images/@tee-SEQ/tee-os': OP-TEE paged mode not supported",
6260 str(exc.exception))
6261
6262 self.make_tee_bin('tee.bad2', 0, b'extra data')
6263 with self.assertRaises(ValueError) as exc:
6264 self.checkFitTee('264_tee_os_opt_fit.dts', 'tee.bad2')
6265 self.assertIn(
6266 "Node '/binman/fit/images/@tee-SEQ/tee-os': Invalid OP-TEE file: size mismatch (expected 0x4, have 0xe)",
6267 str(exc.exception))
6268
Simon Glass63328f12023-01-07 14:07:15 -07006269 def testExtblobOptional(self):
6270 """Test an image with an external blob that is optional"""
6271 with test_util.capture_sys_output() as (stdout, stderr):
6272 data = self._DoReadFile('266_blob_ext_opt.dts')
6273 self.assertEqual(REFCODE_DATA, data)
6274 err = stderr.getvalue()
6275 self.assertRegex(
6276 err,
6277 "Image '.*' is missing external blobs but is still functional: missing")
6278
Simon Glass7447a9d2023-01-11 16:10:12 -07006279 def testSectionInner(self):
6280 """Test an inner section with a size"""
6281 data = self._DoReadFile('267_section_inner.dts')
6282 expected = U_BOOT_DATA + tools.get_bytes(0, 12)
6283 self.assertEqual(expected, data)
6284
Simon Glassa4948b22023-01-11 16:10:14 -07006285 def testNull(self):
6286 """Test an image with a null entry"""
6287 data = self._DoReadFile('268_null.dts')
6288 self.assertEqual(U_BOOT_DATA + b'\xff\xff\xff\xff' + U_BOOT_IMG_DATA, data)
6289
Simon Glassf1ee03b2023-01-11 16:10:16 -07006290 def testOverlap(self):
6291 """Test an image with a overlapping entry"""
6292 data = self._DoReadFile('269_overlap.dts')
6293 self.assertEqual(U_BOOT_DATA[:1] + b'aa' + U_BOOT_DATA[3:], data)
6294
6295 image = control.images['image']
6296 entries = image.GetEntries()
6297
6298 self.assertIn('inset', entries)
6299 inset = entries['inset']
6300 self.assertEqual(1, inset.offset);
6301 self.assertEqual(1, inset.image_pos);
6302 self.assertEqual(2, inset.size);
6303
6304 def testOverlapNull(self):
6305 """Test an image with a null overlap"""
6306 data = self._DoReadFile('270_overlap_null.dts')
6307 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
6308
6309 # Check the FMAP
6310 fhdr, fentries = fmap_util.DecodeFmap(data[len(U_BOOT_DATA):])
6311 self.assertEqual(4, fhdr.nareas)
6312 fiter = iter(fentries)
6313
6314 fentry = next(fiter)
6315 self.assertEqual(b'SECTION', fentry.name)
6316 self.assertEqual(0, fentry.offset)
6317 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6318 self.assertEqual(0, fentry.flags)
6319
6320 fentry = next(fiter)
6321 self.assertEqual(b'U_BOOT', fentry.name)
6322 self.assertEqual(0, fentry.offset)
6323 self.assertEqual(len(U_BOOT_DATA), fentry.size)
6324 self.assertEqual(0, fentry.flags)
6325
6326 # Make sure that the NULL entry appears in the FMAP
6327 fentry = next(fiter)
6328 self.assertEqual(b'NULL', fentry.name)
6329 self.assertEqual(1, fentry.offset)
6330 self.assertEqual(2, fentry.size)
6331 self.assertEqual(0, fentry.flags)
6332
6333 fentry = next(fiter)
6334 self.assertEqual(b'FMAP', fentry.name)
6335 self.assertEqual(len(U_BOOT_DATA), fentry.offset)
6336
6337 def testOverlapBad(self):
6338 """Test an image with a bad overlapping entry"""
6339 with self.assertRaises(ValueError) as exc:
6340 self._DoReadFile('271_overlap_bad.dts')
6341 self.assertIn(
6342 "Node '/binman/inset': Offset 0x10 (16) ending at 0x12 (18) must overlap with existing entries",
6343 str(exc.exception))
6344
6345 def testOverlapNoOffset(self):
6346 """Test an image with a bad overlapping entry"""
6347 with self.assertRaises(ValueError) as exc:
6348 self._DoReadFile('272_overlap_no_size.dts')
6349 self.assertIn(
6350 "Node '/binman/inset': 'fill' entry is missing properties: size",
6351 str(exc.exception))
6352
Simon Glasse0035c92023-01-11 16:10:17 -07006353 def testBlobSymbol(self):
6354 """Test a blob with symbols read from an ELF file"""
6355 elf_fname = self.ElfTestFile('blob_syms')
6356 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6357 TestFunctional._MakeInputFile('blob_syms.bin',
6358 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6359
6360 data = self._DoReadFile('273_blob_symbol.dts')
6361
6362 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6363 addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6364 self.assertEqual(syms['_binman_sym_magic'].address, addr)
6365 self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
6366 self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
6367
6368 sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
6369 expected = sym_values
6370 self.assertEqual(expected, data[:len(expected)])
6371
Simon Glass49e9c002023-01-11 16:10:19 -07006372 def testOffsetFromElf(self):
6373 """Test a blob with symbols read from an ELF file"""
6374 elf_fname = self.ElfTestFile('blob_syms')
6375 TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname))
6376 TestFunctional._MakeInputFile('blob_syms.bin',
6377 tools.read_file(self.ElfTestFile('blob_syms.bin')))
6378
6379 data = self._DoReadFile('274_offset_from_elf.dts')
6380
6381 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
6382 base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
6383
6384 image = control.images['image']
6385 entries = image.GetEntries()
6386
6387 self.assertIn('inset', entries)
6388 inset = entries['inset']
6389
6390 self.assertEqual(base + 4, inset.offset);
6391 self.assertEqual(base + 4, inset.image_pos);
6392 self.assertEqual(4, inset.size);
6393
6394 self.assertIn('inset2', entries)
6395 inset = entries['inset2']
6396 self.assertEqual(base + 8, inset.offset);
6397 self.assertEqual(base + 8, inset.image_pos);
6398 self.assertEqual(4, inset.size);
6399
Jonas Karlmanc59ea892023-01-21 19:01:39 +00006400 def testFitAlign(self):
6401 """Test an image with an FIT with aligned external data"""
6402 data = self._DoReadFile('275_fit_align.dts')
6403 self.assertEqual(4096, len(data))
6404
6405 dtb = fdt.Fdt.FromData(data)
6406 dtb.Scan()
6407
6408 props = self._GetPropTree(dtb, ['data-position'])
6409 expected = {
6410 'u-boot:data-position': 1024,
6411 'fdt-1:data-position': 2048,
6412 'fdt-2:data-position': 3072,
6413 }
6414 self.assertEqual(expected, props)
6415
Jonas Karlman490f73c2023-01-21 19:02:12 +00006416 def testFitFirmwareLoadables(self):
6417 """Test an image with an FIT that use fit,firmware"""
6418 if not elf.ELF_TOOLS:
6419 self.skipTest('Python elftools not available')
6420 entry_args = {
6421 'of-list': 'test-fdt1',
6422 'default-dt': 'test-fdt1',
6423 'atf-bl31-path': 'bl31.elf',
6424 'tee-os-path': 'missing.bin',
6425 }
6426 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
Simon Glass62f85902023-02-23 18:18:01 -07006427 with test_util.capture_sys_output() as (stdout, stderr):
6428 data = self._DoReadFileDtb(
6429 '276_fit_firmware_loadables.dts',
6430 entry_args=entry_args,
6431 extra_indirs=[test_subdir])[0]
Jonas Karlman490f73c2023-01-21 19:02:12 +00006432
6433 dtb = fdt.Fdt.FromData(data)
6434 dtb.Scan()
6435
6436 node = dtb.GetNode('/configurations/conf-uboot-1')
6437 self.assertEqual('u-boot', node.props['firmware'].value)
6438 self.assertEqual(['atf-1', 'atf-2'],
6439 fdt_util.GetStringList(node, 'loadables'))
6440
6441 node = dtb.GetNode('/configurations/conf-atf-1')
6442 self.assertEqual('atf-1', node.props['firmware'].value)
6443 self.assertEqual(['u-boot', 'atf-2'],
6444 fdt_util.GetStringList(node, 'loadables'))
6445
6446 node = dtb.GetNode('/configurations/conf-missing-uboot-1')
6447 self.assertEqual('u-boot', node.props['firmware'].value)
6448 self.assertEqual(['atf-1', 'atf-2'],
6449 fdt_util.GetStringList(node, 'loadables'))
6450
6451 node = dtb.GetNode('/configurations/conf-missing-atf-1')
6452 self.assertEqual('atf-1', node.props['firmware'].value)
6453 self.assertEqual(['u-boot', 'atf-2'],
6454 fdt_util.GetStringList(node, 'loadables'))
6455
6456 node = dtb.GetNode('/configurations/conf-missing-tee-1')
6457 self.assertEqual('atf-1', node.props['firmware'].value)
6458 self.assertEqual(['u-boot', 'atf-2'],
6459 fdt_util.GetStringList(node, 'loadables'))
6460
Simon Glass9a1c7262023-02-22 12:14:49 -07006461 def testTooldir(self):
6462 """Test that we can specify the tooldir"""
6463 with test_util.capture_sys_output() as (stdout, stderr):
6464 self.assertEqual(0, self._DoBinman('--tooldir', 'fred',
6465 'tool', '-l'))
6466 self.assertEqual('fred', bintool.Bintool.tooldir)
6467
6468 # Check that the toolpath is updated correctly
6469 self.assertEqual(['fred'], tools.tool_search_paths)
6470
6471 # Try with a few toolpaths; the tooldir should be at the end
6472 with test_util.capture_sys_output() as (stdout, stderr):
6473 self.assertEqual(0, self._DoBinman(
6474 '--toolpath', 'mary', '--toolpath', 'anna', '--tooldir', 'fred',
6475 'tool', '-l'))
6476 self.assertEqual(['mary', 'anna', 'fred'], tools.tool_search_paths)
6477
Simon Glass49b77e82023-03-02 17:02:44 -07006478 def testReplaceSectionEntry(self):
6479 """Test replacing an entry in a section"""
6480 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6481 entry_data, expected_fdtmap, image = self._RunReplaceCmd('section/blob',
6482 expect_data, dts='241_replace_section_simple.dts')
6483 self.assertEqual(expect_data, entry_data)
6484
6485 entries = image.GetEntries()
6486 self.assertIn('section', entries)
6487 section = entries['section']
6488
6489 sect_entries = section.GetEntries()
6490 self.assertIn('blob', sect_entries)
6491 entry = sect_entries['blob']
6492 self.assertEqual(len(expect_data), entry.size)
6493
6494 fname = tools.get_output_filename('image-updated.bin')
6495 data = tools.read_file(fname)
6496
6497 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6498 self.assertEqual(expect_data, new_blob_data)
6499
6500 self.assertEqual(U_BOOT_DATA,
6501 data[entry.image_pos + len(expect_data):]
6502 [:len(U_BOOT_DATA)])
6503
6504 def testReplaceSectionDeep(self):
6505 """Test replacing an entry in two levels of sections"""
6506 expect_data = b'w' * len(U_BOOT_DATA + COMPRESS_DATA)
6507 entry_data, expected_fdtmap, image = self._RunReplaceCmd(
6508 'section/section/blob', expect_data,
6509 dts='278_replace_section_deep.dts')
6510 self.assertEqual(expect_data, entry_data)
6511
6512 entries = image.GetEntries()
6513 self.assertIn('section', entries)
6514 section = entries['section']
6515
6516 subentries = section.GetEntries()
6517 self.assertIn('section', subentries)
6518 section = subentries['section']
6519
6520 sect_entries = section.GetEntries()
6521 self.assertIn('blob', sect_entries)
6522 entry = sect_entries['blob']
6523 self.assertEqual(len(expect_data), entry.size)
6524
6525 fname = tools.get_output_filename('image-updated.bin')
6526 data = tools.read_file(fname)
6527
6528 new_blob_data = data[entry.image_pos:entry.image_pos + len(expect_data)]
6529 self.assertEqual(expect_data, new_blob_data)
6530
6531 self.assertEqual(U_BOOT_DATA,
6532 data[entry.image_pos + len(expect_data):]
6533 [:len(U_BOOT_DATA)])
6534
6535 def testReplaceFitSibling(self):
6536 """Test an image with a FIT inside where we replace its sibling"""
6537 fname = TestFunctional._MakeInputFile('once', b'available once')
6538 self._DoReadFileRealDtb('277_replace_fit_sibling.dts')
6539 os.remove(fname)
6540
6541 try:
6542 tmpdir, updated_fname = self._SetupImageInTmpdir()
6543
6544 fname = os.path.join(tmpdir, 'update-blob')
6545 expected = b'w' * (len(COMPRESS_DATA + U_BOOT_DATA) + 1)
6546 tools.write_file(fname, expected)
6547
6548 self._DoBinman('replace', '-i', updated_fname, 'blob', '-f', fname)
6549 data = tools.read_file(updated_fname)
6550 start = len(U_BOOT_DTB_DATA)
6551 self.assertEqual(expected, data[start:start + len(expected)])
6552 map_fname = os.path.join(tmpdir, 'image-updated.map')
6553 self.assertFalse(os.path.exists(map_fname))
6554 finally:
6555 shutil.rmtree(tmpdir)
6556
Simon Glassc3fe97f2023-03-02 17:02:45 -07006557 def testX509Cert(self):
6558 """Test creating an X509 certificate"""
6559 keyfile = self.TestFile('key.key')
6560 entry_args = {
6561 'keyfile': keyfile,
6562 }
6563 data = self._DoReadFileDtb('279_x509_cert.dts',
6564 entry_args=entry_args)[0]
6565 cert = data[:-4]
6566 self.assertEqual(U_BOOT_DATA, data[-4:])
6567
6568 # TODO: verify the signature
6569
6570 def testX509CertMissing(self):
6571 """Test that binman still produces an image if openssl is missing"""
6572 keyfile = self.TestFile('key.key')
6573 entry_args = {
6574 'keyfile': 'keyfile',
6575 }
6576 with test_util.capture_sys_output() as (_, stderr):
6577 self._DoTestFile('279_x509_cert.dts',
6578 force_missing_bintools='openssl',
6579 entry_args=entry_args)
6580 err = stderr.getvalue()
6581 self.assertRegex(err, "Image 'image'.*missing bintools.*: openssl")
6582
Jonas Karlman35305492023-02-25 19:01:33 +00006583 def testPackRockchipTpl(self):
6584 """Test that an image with a Rockchip TPL binary can be created"""
6585 data = self._DoReadFile('277_rockchip_tpl.dts')
6586 self.assertEqual(ROCKCHIP_TPL_DATA, data[:len(ROCKCHIP_TPL_DATA)])
6587
Jonas Karlman1016ec72023-02-25 19:01:35 +00006588 def testMkimageMissingBlobMultiple(self):
6589 """Test missing blob with mkimage entry and multiple-data-files"""
6590 with test_util.capture_sys_output() as (stdout, stderr):
6591 self._DoTestFile('278_mkimage_missing_multiple.dts', allow_missing=True)
6592 err = stderr.getvalue()
6593 self.assertIn("is missing external blobs and is non-functional", err)
6594
6595 with self.assertRaises(ValueError) as e:
6596 self._DoTestFile('278_mkimage_missing_multiple.dts', allow_missing=False)
6597 self.assertIn("not found in input path", str(e.exception))
6598
Ivan Mikhaylov3cfcaa4d2023-03-08 01:13:40 +00006599 def _PrepareSignEnv(self, dts='280_fit_sign.dts'):
6600 """Prepare sign environment
6601
6602 Create private and public keys, add pubkey into dtb.
6603
6604 Returns:
6605 Tuple:
6606 FIT container
6607 Image name
6608 Private key
6609 DTB
6610 """
6611
6612 data = self._DoReadFileRealDtb(dts)
6613 updated_fname = tools.get_output_filename('image-updated.bin')
6614 tools.write_file(updated_fname, data)
6615 dtb = tools.get_output_filename('source.dtb')
6616 private_key = tools.get_output_filename('test_key.key')
6617 public_key = tools.get_output_filename('test_key.crt')
6618 fit = tools.get_output_filename('fit.fit')
6619 key_dir = tools.get_output_dir()
6620
6621 tools.run('openssl', 'req', '-batch' , '-newkey', 'rsa:4096',
6622 '-sha256', '-new', '-nodes', '-x509', '-keyout',
6623 private_key, '-out', public_key)
6624 tools.run('fdt_add_pubkey', '-a', 'sha256,rsa4096', '-k', key_dir,
6625 '-n', 'test_key', '-r', 'conf', dtb)
6626
6627 return fit, updated_fname, private_key, dtb
6628
6629 def testSignSimple(self):
6630 """Test that a FIT container can be signed in image"""
6631 is_signed = False
6632 fit, fname, private_key, dtb = self._PrepareSignEnv()
6633
6634 # do sign with private key
6635 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6636 ['fit'])
6637 is_signed = self._CheckSign(fit, dtb)
6638
6639 self.assertEqual(is_signed, True)
6640
6641 def testSignExactFIT(self):
6642 """Test that a FIT container can be signed and replaced in image"""
6643 is_signed = False
6644 fit, fname, private_key, dtb = self._PrepareSignEnv()
6645
6646 # Make sure we propagate the toolpath, since mkimage may not be on PATH
6647 args = []
6648 if self.toolpath:
6649 for path in self.toolpath:
6650 args += ['--toolpath', path]
6651
6652 # do sign with private key
6653 self._DoBinman(*args, 'sign', '-i', fname, '-k', private_key, '-a',
6654 'sha256,rsa4096', '-f', fit, 'fit')
6655 is_signed = self._CheckSign(fit, dtb)
6656
6657 self.assertEqual(is_signed, True)
6658
6659 def testSignNonFit(self):
6660 """Test a non-FIT entry cannot be signed"""
6661 is_signed = False
6662 fit, fname, private_key, _ = self._PrepareSignEnv(
6663 '281_sign_non_fit.dts')
6664
6665 # do sign with private key
6666 with self.assertRaises(ValueError) as e:
6667 self._DoBinman('sign', '-i', fname, '-k', private_key, '-a',
6668 'sha256,rsa4096', '-f', fit, 'u-boot')
6669 self.assertIn(
6670 "Node '/u-boot': Updating signatures is not supported with this entry type",
6671 str(e.exception))
6672
6673 def testSignMissingMkimage(self):
6674 """Test that FIT signing handles a missing mkimage tool"""
6675 fit, fname, private_key, _ = self._PrepareSignEnv()
6676
6677 # try to sign with a missing mkimage tool
6678 bintool.Bintool.set_missing_list(['mkimage'])
6679 with self.assertRaises(ValueError) as e:
6680 control.SignEntries(fname, None, private_key, 'sha256,rsa4096',
6681 ['fit'])
6682 self.assertIn("Node '/fit': Missing tool: 'mkimage'", str(e.exception))
6683
Simon Glass4abf7842023-07-18 07:23:54 -06006684 def testSymbolNoWrite(self):
6685 """Test disabling of symbol writing"""
6686 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_DATA, 0x1c,
6687 no_write_symbols=True)
6688
6689 def testSymbolNoWriteExpanded(self):
6690 """Test disabling of symbol writing in expanded entries"""
6691 entry_args = {
6692 'spl-dtb': '1',
6693 }
6694 self.checkSymbols('282_symbols_disable.dts', U_BOOT_SPL_NODTB_DATA +
6695 U_BOOT_SPL_DTB_DATA, 0x38,
6696 entry_args=entry_args, use_expanded=True,
6697 no_write_symbols=True)
6698
Simon Glassde244162023-01-07 14:07:08 -07006699
Simon Glassac599912017-11-12 21:52:22 -07006700if __name__ == "__main__":
6701 unittest.main()