blob: 261107b33542b3a33a4c3e26da434b84a08d7733 [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 Glassa997ea52020-04-17 18:09:04 -060037from patman import command
38from patman import test_util
39from patman import tools
40from patman 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'
Simon Glassa435cd12020-09-01 05:13:59 -060093TEST_FDT1_DATA = b'fdt1'
94TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060095ENV_DATA = b'var1=1\nvar2="2"'
Philippe Reynesebe96cb2022-03-28 22:57:04 +020096PRE_LOAD_MAGIC = b'UBSH'
97PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
98PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Simon Glassa435cd12020-09-01 05:13:59 -060099
100# Subdirectory of the input dir to use to put test FDTs
101TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600102
Simon Glass2c6adba2019-07-20 12:23:47 -0600103# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600104EXTRACT_DTB_SIZE = 0x3c9
105
Simon Glass2c6adba2019-07-20 12:23:47 -0600106# Properties expected to be in the device tree when update_dtb is used
107BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
108
Simon Glassfb30e292019-07-20 12:23:51 -0600109# Extra properties expected to be in the device tree when allow-repack is used
110REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
111
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200112# Supported compression bintools
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +0200113COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
Simon Glass57454f42016-11-25 20:15:52 -0700114
115class TestFunctional(unittest.TestCase):
116 """Functional tests for binman
117
118 Most of these use a sample .dts file to build an image and then check
119 that it looks correct. The sample files are in the test/ subdirectory
120 and are numbered.
121
122 For each entry type a very small test file is created using fixed
123 string contents. This makes it easy to test that things look right, and
124 debug problems.
125
126 In some cases a 'real' file must be used - these are also supplied in
127 the test/ diurectory.
128 """
129 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600130 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700131 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600132 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700133
Simon Glass57454f42016-11-25 20:15:52 -0700134 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600135 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
136 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700137
138 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600139 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700140
141 # Create some test files
142 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
143 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
144 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600145 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700146 TestFunctional._MakeInputFile('vpl/u-boot-vpl.bin', U_BOOT_VPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700147 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700148 TestFunctional._MakeInputFile('me.bin', ME_DATA)
149 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600150 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600151
Jagdish Gediya311d4842018-09-03 21:35:08 +0530152 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600153
Simon Glassabab18c2019-08-24 07:22:49 -0600154 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
155 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700156 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600157 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600158 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600159
160 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
161 X86_RESET16_DATA)
162 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
163 X86_RESET16_SPL_DATA)
164 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
165 X86_RESET16_TPL_DATA)
166
Simon Glass57454f42016-11-25 20:15:52 -0700167 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700168 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
169 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600170 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
171 U_BOOT_TPL_NODTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700172 TestFunctional._MakeInputFile('vpl/u-boot-vpl-nodtb.bin',
173 U_BOOT_VPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700174 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
175 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700176 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700177 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600178 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600179 TestFunctional._MakeInputDir('devkeys')
180 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600181 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600182 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600183 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600184 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700185
Simon Glassf6290892019-08-24 07:22:53 -0600186 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
187 elf_test.BuildElfTestFiles(cls._elf_testdir)
188
Simon Glass72232452016-11-25 20:15:53 -0700189 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600190 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700191 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700192
193 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600194 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700195
Simon Glass862f8e22019-08-24 07:22:43 -0600196 shutil.copytree(cls.TestFile('files'),
197 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600198
Simon Glass7ba33592018-09-14 04:57:26 -0600199 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600200 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600201 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200202 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700203 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800204 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500205 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600206
Simon Glassa435cd12020-09-01 05:13:59 -0600207 # Add a few .dtb files for testing
208 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
209 TEST_FDT1_DATA)
210 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
211 TEST_FDT2_DATA)
212
Simon Glassa0729502020-09-06 10:35:33 -0600213 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
214
Simon Glass5f423422022-03-05 20:19:12 -0700215 # ELF file with two sections in different parts of memory, used for both
216 # ATF and OP_TEE
217 TestFunctional._MakeInputFile('bl31.elf',
218 tools.read_file(cls.ElfTestFile('elf_sections')))
219 TestFunctional._MakeInputFile('tee.elf',
220 tools.read_file(cls.ElfTestFile('elf_sections')))
221
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200222 cls.comp_bintools = {}
223 for name in COMP_BINTOOLS:
224 cls.comp_bintools[name] = bintool.Bintool.create(name)
Simon Glass1de34482019-07-08 13:18:53 -0600225
Simon Glass57454f42016-11-25 20:15:52 -0700226 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600227 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700228 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600229 if cls.preserve_indir:
230 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600231 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600232 if cls._indir:
233 shutil.rmtree(cls._indir)
234 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700235
Simon Glass1c420c92019-07-08 13:18:49 -0600236 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600237 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600238 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600239 """Accept arguments controlling test execution
240
241 Args:
242 preserve_indir: Preserve the shared input directory used by all
243 tests in this class.
244 preserve_outdir: Preserve the output directories used by tests. Each
245 test has its own, so this is normally only useful when running a
246 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600247 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600248 """
249 cls.preserve_indir = preserve_indir
250 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600251 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600252 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600253
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200254 def _CheckBintool(self, bintool):
255 if not bintool.is_present():
256 self.skipTest('%s not available' % bintool.name)
257
Simon Glass1de34482019-07-08 13:18:53 -0600258 def _CheckLz4(self):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +0200259 bintool = self.comp_bintools['lz4']
260 self._CheckBintool(bintool)
Simon Glass1de34482019-07-08 13:18:53 -0600261
Simon Glassee9d10d2019-07-20 12:24:09 -0600262 def _CleanupOutputDir(self):
263 """Remove the temporary output directory"""
264 if self.preserve_outdirs:
265 print('Preserving output dir: %s' % tools.outdir)
266 else:
Simon Glass80025522022-01-29 14:14:04 -0700267 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600268
Simon Glass57454f42016-11-25 20:15:52 -0700269 def setUp(self):
270 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700271 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700272 command.test_result = None
273
274 def tearDown(self):
275 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600276 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700277
Simon Glassb3d6fc72019-07-20 12:24:10 -0600278 def _SetupImageInTmpdir(self):
279 """Set up the output image in a new temporary directory
280
281 This is used when an image has been generated in the output directory,
282 but we want to run binman again. This will create a new output
283 directory and fail to delete the original one.
284
285 This creates a new temporary directory, copies the image to it (with a
286 new name) and removes the old output directory.
287
288 Returns:
289 Tuple:
290 Temporary directory to use
291 New image filename
292 """
Simon Glass80025522022-01-29 14:14:04 -0700293 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600294 tmpdir = tempfile.mkdtemp(prefix='binman.')
295 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700296 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600297 self._CleanupOutputDir()
298 return tmpdir, updated_fname
299
Simon Glass8425a1f2018-07-17 13:25:48 -0600300 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600301 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600302 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
303 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
304 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
Simon Glass56d05412022-02-28 07:16:54 -0700305 TestFunctional._MakeInputFile('vpl/u-boot-vpl.dtb', U_BOOT_VPL_DTB_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600306
Simon Glass57454f42016-11-25 20:15:52 -0700307 def _RunBinman(self, *args, **kwargs):
308 """Run binman using the command line
309
310 Args:
311 Arguments to pass, as a list of strings
312 kwargs: Arguments to pass to Command.RunPipe()
313 """
Simon Glass840be732022-01-29 14:14:05 -0700314 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700315 capture=True, capture_stderr=True, raise_on_error=False)
316 if result.return_code and kwargs.get('raise_on_error', True):
317 raise Exception("Error running '%s': %s" % (' '.join(args),
318 result.stdout + result.stderr))
319 return result
320
Simon Glassf46732a2019-07-08 14:25:29 -0600321 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700322 """Run binman using directly (in the same process)
323
324 Args:
325 Arguments to pass, as a list of strings
326 Returns:
327 Return value (0 for success)
328 """
Simon Glassf46732a2019-07-08 14:25:29 -0600329 argv = list(argv)
330 args = cmdline.ParseArgs(argv)
331 args.pager = 'binman-invalid-pager'
332 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700333
334 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600335 # args.verbosity = tout.DEBUG
336 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700337
Simon Glass91710b32018-07-17 13:25:32 -0600338 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600339 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300340 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100341 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700342 test_section_timeout=False, update_fdt_in_elf=None,
343 force_missing_bintools=''):
Simon Glass57454f42016-11-25 20:15:52 -0700344 """Run binman with a given test file
345
346 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600347 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600348 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600349 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600350 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600351 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600352 entry_args: Dict of entry args to supply to binman
353 key: arg name
354 value: value of that arg
355 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600356 use_real_dtb: True to use the test file as the contents of
357 the u-boot-dtb entry. Normally this is not needed and the
358 test contents (the U_BOOT_DTB_DATA string) can be used.
359 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300360 use_expanded: True to use expanded entries where available, e.g.
361 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600362 verbosity: Verbosity level to use (0-3, None=don't set it)
363 allow_missing: Set the '--allow-missing' flag so that missing
364 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100365 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600366 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600367 threads: Number of threads to use (None for default, 0 for
368 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600369 test_section_timeout: True to force the first time to timeout, as
370 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600371 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass66152ce2022-01-09 20:14:09 -0700372 force_missing_tools (str): comma-separated list of bintools to
373 regard as missing
Simon Glass9a798402021-11-03 21:09:17 -0600374
375 Returns:
376 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700377 """
Simon Glassf46732a2019-07-08 14:25:29 -0600378 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700379 if debug:
380 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600381 if verbosity is not None:
382 args.append('-v%d' % verbosity)
383 elif self.verbosity:
384 args.append('-v%d' % self.verbosity)
385 if self.toolpath:
386 for path in self.toolpath:
387 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600388 if threads is not None:
389 args.append('-T%d' % threads)
390 if test_section_timeout:
391 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600392 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600393 if map:
394 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600395 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600396 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600397 if not use_real_dtb:
398 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300399 if not use_expanded:
400 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600401 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600402 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600403 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600404 if allow_missing:
405 args.append('-M')
Heiko Thiery6d451362022-01-06 11:49:41 +0100406 if allow_fake_blobs:
407 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700408 if force_missing_bintools:
409 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600410 if update_fdt_in_elf:
411 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600412 if images:
413 for image in images:
414 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600415 if extra_indirs:
416 for indir in extra_indirs:
417 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700418 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700419
420 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700421 """Set up a new test device-tree file
422
423 The given file is compiled and set up as the device tree to be used
424 for ths test.
425
426 Args:
427 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600428 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700429
430 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600431 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700432 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600433 tmpdir = tempfile.mkdtemp(prefix='binmant.')
434 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600435 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700436 data = fd.read()
437 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600438 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600439 return data
Simon Glass57454f42016-11-25 20:15:52 -0700440
Simon Glass56d05412022-02-28 07:16:54 -0700441 def _GetDtbContentsForSpls(self, dtb_data, name):
442 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600443
444 For testing we don't actually have different versions of the DTB. With
445 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
446 we don't normally have any unwanted nodes.
447
448 We still want the DTBs for SPL and TPL to be different though, since
449 otherwise it is confusing to know which one we are looking at. So add
450 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600451
452 Args:
453 dtb_data: dtb data to modify (this should be a value devicetree)
454 name: Name of a new property to add
455
456 Returns:
457 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600458 """
459 dtb = fdt.Fdt.FromData(dtb_data)
460 dtb.Scan()
461 dtb.GetNode('/binman').AddZeroProp(name)
462 dtb.Sync(auto_resize=True)
463 dtb.Pack()
464 return dtb.GetContents()
465
Simon Glassed930672021-03-18 20:25:05 +1300466 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
467 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600468 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700469 """Run binman and return the resulting image
470
471 This runs binman with a given test file and then reads the resulting
472 output file. It is a shortcut function since most tests need to do
473 these steps.
474
475 Raises an assertion failure if binman returns a non-zero exit code.
476
477 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600478 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700479 use_real_dtb: True to use the test file as the contents of
480 the u-boot-dtb entry. Normally this is not needed and the
481 test contents (the U_BOOT_DTB_DATA string) can be used.
482 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300483 use_expanded: True to use expanded entries where available, e.g.
484 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600485 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600486 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600487 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600488 entry_args: Dict of entry args to supply to binman
489 key: arg name
490 value: value of that arg
491 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
492 function. If reset_dtbs is True, then the original test dtb
493 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600494 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600495 threads: Number of threads to use (None for default, 0 for
496 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700497
498 Returns:
499 Tuple:
500 Resulting image contents
501 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600502 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600503 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700504 """
Simon Glass72232452016-11-25 20:15:53 -0700505 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700506 # Use the compiled test file as the u-boot-dtb input
507 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700508 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600509
510 # For testing purposes, make a copy of the DT for SPL and TPL. Add
511 # a node indicating which it is, so aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700512 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600513 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
514 outfile = os.path.join(self._indir, dtb_fname)
515 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700516 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700517
518 try:
Simon Glass91710b32018-07-17 13:25:32 -0600519 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600520 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600521 use_expanded=use_expanded, extra_indirs=extra_indirs,
522 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700523 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700524 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700525
526 # Find the (only) image, read it and return its contents
527 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700528 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600529 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600530 if map:
Simon Glass80025522022-01-29 14:14:04 -0700531 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600532 with open(map_fname) as fd:
533 map_data = fd.read()
534 else:
535 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600536 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600537 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700538 finally:
539 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600540 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600541 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700542
Simon Glass5b4bce32019-07-08 14:25:26 -0600543 def _DoReadFileRealDtb(self, fname):
544 """Run binman with a real .dtb file and return the resulting data
545
546 Args:
547 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
548
549 Returns:
550 Resulting image contents
551 """
552 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
553
Simon Glass72232452016-11-25 20:15:53 -0700554 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600555 """Helper function which discards the device-tree binary
556
557 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600558 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600559 use_real_dtb: True to use the test file as the contents of
560 the u-boot-dtb entry. Normally this is not needed and the
561 test contents (the U_BOOT_DTB_DATA string) can be used.
562 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600563
564 Returns:
565 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600566 """
Simon Glass72232452016-11-25 20:15:53 -0700567 return self._DoReadFileDtb(fname, use_real_dtb)[0]
568
Simon Glass57454f42016-11-25 20:15:52 -0700569 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600570 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700571 """Create a new test input file, creating directories as needed
572
573 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600574 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700575 contents: File contents to write in to the file
576 Returns:
577 Full pathname of file created
578 """
Simon Glass862f8e22019-08-24 07:22:43 -0600579 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700580 dirname = os.path.dirname(pathname)
581 if dirname and not os.path.exists(dirname):
582 os.makedirs(dirname)
583 with open(pathname, 'wb') as fd:
584 fd.write(contents)
585 return pathname
586
587 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600588 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600589 """Create a new test input directory, creating directories as needed
590
591 Args:
592 dirname: Directory name to create
593
594 Returns:
595 Full pathname of directory created
596 """
Simon Glass862f8e22019-08-24 07:22:43 -0600597 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600598 if not os.path.exists(pathname):
599 os.makedirs(pathname)
600 return pathname
601
602 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600603 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600604 """Set up an ELF file with a '_dt_ucode_base_size' symbol
605
606 Args:
607 Filename of ELF file to use as SPL
608 """
Simon Glass93a806f2019-08-24 07:22:59 -0600609 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700610 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600611
612 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600613 def _SetupTplElf(cls, src_fname='bss_data'):
614 """Set up an ELF file with a '_dt_ucode_base_size' symbol
615
616 Args:
617 Filename of ELF file to use as TPL
618 """
619 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700620 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600621
622 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700623 def _SetupVplElf(cls, src_fname='bss_data'):
624 """Set up an ELF file with a '_dt_ucode_base_size' symbol
625
626 Args:
627 Filename of ELF file to use as VPL
628 """
629 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
630 tools.read_file(cls.ElfTestFile(src_fname)))
631
632 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600633 def _SetupDescriptor(cls):
634 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
635 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
636
637 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600638 def TestFile(cls, fname):
639 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700640
Simon Glassf6290892019-08-24 07:22:53 -0600641 @classmethod
642 def ElfTestFile(cls, fname):
643 return os.path.join(cls._elf_testdir, fname)
644
Simon Glass57454f42016-11-25 20:15:52 -0700645 def AssertInList(self, grep_list, target):
646 """Assert that at least one of a list of things is in a target
647
648 Args:
649 grep_list: List of strings to check
650 target: Target string
651 """
652 for grep in grep_list:
653 if grep in target:
654 return
Simon Glass848cdb52019-05-17 22:00:50 -0600655 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700656
657 def CheckNoGaps(self, entries):
658 """Check that all entries fit together without gaps
659
660 Args:
661 entries: List of entries to check
662 """
Simon Glasse8561af2018-08-01 15:22:37 -0600663 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700664 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600665 self.assertEqual(offset, entry.offset)
666 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700667
Simon Glass72232452016-11-25 20:15:53 -0700668 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600669 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700670
671 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600672 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700673
674 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600675 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700676 """
677 return struct.unpack('>L', dtb[4:8])[0]
678
Simon Glass0f621332019-07-08 14:25:27 -0600679 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600680 def AddNode(node, path):
681 if node.name != '/':
682 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600683 for prop in node.props.values():
684 if prop.name in prop_names:
685 prop_path = path + ':' + prop.name
686 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
687 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600688 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600689 AddNode(subnode, path)
690
691 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600692 AddNode(dtb.GetRoot(), '')
693 return tree
694
Simon Glass57454f42016-11-25 20:15:52 -0700695 def testRun(self):
696 """Test a basic run with valid args"""
697 result = self._RunBinman('-h')
698
699 def testFullHelp(self):
700 """Test that the full help is displayed with -H"""
701 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300702 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500703 # Remove possible extraneous strings
704 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
705 gothelp = result.stdout.replace(extra, '')
706 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700707 self.assertEqual(0, len(result.stderr))
708 self.assertEqual(0, result.return_code)
709
710 def testFullHelpInternal(self):
711 """Test that the full help is displayed with -H"""
712 try:
713 command.test_result = command.CommandResult()
714 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300715 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700716 finally:
717 command.test_result = None
718
719 def testHelp(self):
720 """Test that the basic help is displayed with -h"""
721 result = self._RunBinman('-h')
722 self.assertTrue(len(result.stdout) > 200)
723 self.assertEqual(0, len(result.stderr))
724 self.assertEqual(0, result.return_code)
725
Simon Glass57454f42016-11-25 20:15:52 -0700726 def testBoard(self):
727 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600728 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700729 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300730 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700731 self.assertEqual(0, result)
732
733 def testNeedBoard(self):
734 """Test that we get an error when no board ius supplied"""
735 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600736 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700737 self.assertIn("Must provide a board to process (use -b <board>)",
738 str(e.exception))
739
740 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600741 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700742 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600743 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700744 # We get one error from libfdt, and a different one from fdtget.
745 self.AssertInList(["Couldn't open blob from 'missing_file'",
746 'No such file or directory'], str(e.exception))
747
748 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600749 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700750
751 Since this is a source file it should be compiled and the error
752 will come from the device-tree compiler (dtc).
753 """
754 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600755 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700756 self.assertIn("FATAL ERROR: Unable to parse input tree",
757 str(e.exception))
758
759 def testMissingNode(self):
760 """Test that a device tree without a 'binman' node generates an error"""
761 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600762 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700763 self.assertIn("does not have a 'binman' node", str(e.exception))
764
765 def testEmpty(self):
766 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600767 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700768 self.assertEqual(0, len(result.stderr))
769 self.assertEqual(0, result.return_code)
770
771 def testInvalidEntry(self):
772 """Test that an invalid entry is flagged"""
773 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600774 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600775 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700776 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
777 "'/binman/not-a-valid-type'", str(e.exception))
778
779 def testSimple(self):
780 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600781 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700782 self.assertEqual(U_BOOT_DATA, data)
783
Simon Glass075a45c2017-11-13 18:55:00 -0700784 def testSimpleDebug(self):
785 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600786 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700787
Simon Glass57454f42016-11-25 20:15:52 -0700788 def testDual(self):
789 """Test that we can handle creating two images
790
791 This also tests image padding.
792 """
Simon Glass511f6582018-10-01 12:22:30 -0600793 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700794 self.assertEqual(0, retcode)
795
796 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600797 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700798 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700799 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600800 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700801 data = fd.read()
802 self.assertEqual(U_BOOT_DATA, data)
803
804 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600805 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700806 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700807 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600808 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700809 data = fd.read()
810 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700811 self.assertEqual(tools.get_bytes(0, 3), data[:3])
812 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700813
814 def testBadAlign(self):
815 """Test that an invalid alignment value is detected"""
816 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600817 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700818 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
819 "of two", str(e.exception))
820
821 def testPackSimple(self):
822 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600823 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700824 self.assertEqual(0, retcode)
825 self.assertIn('image', control.images)
826 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600827 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700828 self.assertEqual(5, len(entries))
829
830 # First u-boot
831 self.assertIn('u-boot', entries)
832 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600833 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700834 self.assertEqual(len(U_BOOT_DATA), entry.size)
835
836 # Second u-boot, aligned to 16-byte boundary
837 self.assertIn('u-boot-align', entries)
838 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600839 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700840 self.assertEqual(len(U_BOOT_DATA), entry.size)
841
842 # Third u-boot, size 23 bytes
843 self.assertIn('u-boot-size', entries)
844 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600845 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700846 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
847 self.assertEqual(23, entry.size)
848
849 # Fourth u-boot, placed immediate after the above
850 self.assertIn('u-boot-next', entries)
851 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600852 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700853 self.assertEqual(len(U_BOOT_DATA), entry.size)
854
Simon Glasse8561af2018-08-01 15:22:37 -0600855 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700856 self.assertIn('u-boot-fixed', entries)
857 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600858 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700859 self.assertEqual(len(U_BOOT_DATA), entry.size)
860
Simon Glass39dd2152019-07-08 14:25:47 -0600861 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700862
863 def testPackExtra(self):
864 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600865 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
866 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700867
Simon Glass57454f42016-11-25 20:15:52 -0700868 self.assertIn('image', control.images)
869 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600870 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700871 self.assertEqual(5, len(entries))
872
873 # First u-boot with padding before and after
874 self.assertIn('u-boot', entries)
875 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600876 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700877 self.assertEqual(3, entry.pad_before)
878 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600879 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700880 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
881 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600882 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700883
884 # Second u-boot has an aligned size, but it has no effect
885 self.assertIn('u-boot-align-size-nop', entries)
886 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600887 self.assertEqual(pos, entry.offset)
888 self.assertEqual(len(U_BOOT_DATA), entry.size)
889 self.assertEqual(U_BOOT_DATA, entry.data)
890 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
891 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700892
893 # Third u-boot has an aligned size too
894 self.assertIn('u-boot-align-size', entries)
895 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600896 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700897 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600898 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700899 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600900 data[pos:pos + entry.size])
901 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700902
903 # Fourth u-boot has an aligned end
904 self.assertIn('u-boot-align-end', entries)
905 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600906 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700907 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600908 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700909 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600910 data[pos:pos + entry.size])
911 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700912
913 # Fifth u-boot immediately afterwards
914 self.assertIn('u-boot-align-both', entries)
915 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600916 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700917 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600918 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700919 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600920 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700921
922 self.CheckNoGaps(entries)
Simon Glass39dd2152019-07-08 14:25:47 -0600923 self.assertEqual(128, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700924
Simon Glassafb9caa2020-10-26 17:40:10 -0600925 dtb = fdt.Fdt(out_dtb_fname)
926 dtb.Scan()
927 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
928 expected = {
929 'image-pos': 0,
930 'offset': 0,
931 'size': 128,
932
933 'u-boot:image-pos': 0,
934 'u-boot:offset': 0,
935 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
936
937 'u-boot-align-size-nop:image-pos': 12,
938 'u-boot-align-size-nop:offset': 12,
939 'u-boot-align-size-nop:size': 4,
940
941 'u-boot-align-size:image-pos': 16,
942 'u-boot-align-size:offset': 16,
943 'u-boot-align-size:size': 32,
944
945 'u-boot-align-end:image-pos': 48,
946 'u-boot-align-end:offset': 48,
947 'u-boot-align-end:size': 16,
948
949 'u-boot-align-both:image-pos': 64,
950 'u-boot-align-both:offset': 64,
951 'u-boot-align-both:size': 64,
952 }
953 self.assertEqual(expected, props)
954
Simon Glass57454f42016-11-25 20:15:52 -0700955 def testPackAlignPowerOf2(self):
956 """Test that invalid entry alignment is detected"""
957 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600958 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700959 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
960 "of two", str(e.exception))
961
962 def testPackAlignSizePowerOf2(self):
963 """Test that invalid entry size alignment is detected"""
964 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600965 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700966 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
967 "power of two", str(e.exception))
968
969 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600970 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700971 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600972 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600973 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700974 "align 0x4 (4)", str(e.exception))
975
976 def testPackInvalidSizeAlign(self):
977 """Test that invalid entry size alignment is detected"""
978 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600979 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700980 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
981 "align-size 0x4 (4)", str(e.exception))
982
983 def testPackOverlap(self):
984 """Test that overlapping regions are detected"""
985 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600986 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600987 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700988 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
989 str(e.exception))
990
991 def testPackEntryOverflow(self):
992 """Test that entries that overflow their size are detected"""
993 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600994 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700995 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
996 "but entry size is 0x3 (3)", str(e.exception))
997
998 def testPackImageOverflow(self):
999 """Test that entries which overflow the image size are detected"""
1000 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001001 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001002 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001003 "size 0x3 (3)", str(e.exception))
1004
1005 def testPackImageSize(self):
1006 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001007 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001008 self.assertEqual(0, retcode)
1009 self.assertIn('image', control.images)
1010 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001011 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001012
1013 def testPackImageSizeAlign(self):
1014 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001015 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001016 self.assertEqual(0, retcode)
1017 self.assertIn('image', control.images)
1018 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001019 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001020
1021 def testPackInvalidImageAlign(self):
1022 """Test that invalid image alignment is detected"""
1023 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001024 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001025 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001026 "align-size 0x8 (8)", str(e.exception))
1027
Simon Glass2a0fa982022-02-11 13:23:21 -07001028 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001029 """Test that invalid image alignment is detected"""
1030 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001031 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001032 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001033 "two", str(e.exception))
1034
1035 def testImagePadByte(self):
1036 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001037 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001038 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001039 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001040 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001041
1042 def testImageName(self):
1043 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001044 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001045 self.assertEqual(0, retcode)
1046 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001047 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001048 self.assertTrue(os.path.exists(fname))
1049
1050 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001051 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001052 self.assertTrue(os.path.exists(fname))
1053
1054 def testBlobFilename(self):
1055 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001056 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001057 self.assertEqual(BLOB_DATA, data)
1058
1059 def testPackSorted(self):
1060 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001061 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001062 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001063 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1064 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001065
Simon Glasse8561af2018-08-01 15:22:37 -06001066 def testPackZeroOffset(self):
1067 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -07001068 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001069 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001070 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001071 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1072 str(e.exception))
1073
1074 def testPackUbootDtb(self):
1075 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001076 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001077 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001078
1079 def testPackX86RomNoSize(self):
1080 """Test that the end-at-4gb property requires a size property"""
1081 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001082 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001083 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001084 "using end-at-4gb", str(e.exception))
1085
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301086 def test4gbAndSkipAtStartTogether(self):
1087 """Test that the end-at-4gb and skip-at-size property can't be used
1088 together"""
1089 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001090 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001091 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301092 "'skip-at-start'", str(e.exception))
1093
Simon Glass72232452016-11-25 20:15:53 -07001094 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001095 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -07001096 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001097 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001098 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1099 "is outside the section '/binman' starting at "
1100 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001101 str(e.exception))
1102
1103 def testPackX86Rom(self):
1104 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001105 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001106 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001107 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1108 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001109
1110 def testPackX86RomMeNoDesc(self):
1111 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001112 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001113 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001114 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001115 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001116 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1117 str(e.exception))
1118 finally:
1119 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001120
1121 def testPackX86RomBadDesc(self):
1122 """Test that the Intel requires a descriptor entry"""
1123 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001124 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001125 self.assertIn("Node '/binman/intel-me': No offset set with "
1126 "offset-unset: should another entry provide this correct "
1127 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001128
1129 def testPackX86RomMe(self):
1130 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001131 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001132 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001133 if data[:0x1000] != expected_desc:
1134 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001135 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1136
1137 def testPackVga(self):
1138 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001139 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001140 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1141
1142 def testPackStart16(self):
1143 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001144 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001145 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1146
Jagdish Gediya311d4842018-09-03 21:35:08 +05301147 def testPackPowerpcMpc85xxBootpgResetvec(self):
1148 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1149 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001150 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301151 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1152
Simon Glass6ba679c2018-07-06 10:27:17 -06001153 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001154 """Handle running a test for insertion of microcode
1155
1156 Args:
1157 dts_fname: Name of test .dts file
1158 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001159 ucode_second: True if the microsecond entry is second instead of
1160 third
Simon Glass820af1d2018-07-06 10:27:16 -06001161
1162 Returns:
1163 Tuple:
1164 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001165 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001166 in the above (two 4-byte words)
1167 """
Simon Glass3d274232017-11-12 21:52:27 -07001168 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001169
1170 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001171 if ucode_second:
1172 ucode_content = data[len(nodtb_data):]
1173 ucode_pos = len(nodtb_data)
1174 dtb_with_ucode = ucode_content[16:]
1175 fdt_len = self.GetFdtLen(dtb_with_ucode)
1176 else:
1177 dtb_with_ucode = data[len(nodtb_data):]
1178 fdt_len = self.GetFdtLen(dtb_with_ucode)
1179 ucode_content = dtb_with_ucode[fdt_len:]
1180 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001181 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001182 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001183 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001184 dtb = fdt.FdtScan(fname)
1185 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001186 self.assertTrue(ucode)
1187 for node in ucode.subnodes:
1188 self.assertFalse(node.props.get('data'))
1189
Simon Glass72232452016-11-25 20:15:53 -07001190 # Check that the microcode appears immediately after the Fdt
1191 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001192 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001193 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1194 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001195 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001196
1197 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001198 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001199 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1200 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001201 u_boot = data[:len(nodtb_data)]
1202 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001203
1204 def testPackUbootMicrocode(self):
1205 """Test that x86 microcode can be handled correctly
1206
1207 We expect to see the following in the image, in order:
1208 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1209 place
1210 u-boot.dtb with the microcode removed
1211 the microcode
1212 """
Simon Glass511f6582018-10-01 12:22:30 -06001213 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001214 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001215 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1216 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001217
Simon Glassbac25c82017-05-27 07:38:26 -06001218 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001219 """Test that x86 microcode can be handled correctly
1220
1221 We expect to see the following in the image, in order:
1222 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1223 place
1224 u-boot.dtb with the microcode
1225 an empty microcode region
1226 """
1227 # We need the libfdt library to run this test since only that allows
1228 # finding the offset of a property. This is required by
1229 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001230 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001231
1232 second = data[len(U_BOOT_NODTB_DATA):]
1233
1234 fdt_len = self.GetFdtLen(second)
1235 third = second[fdt_len:]
1236 second = second[:fdt_len]
1237
Simon Glassbac25c82017-05-27 07:38:26 -06001238 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1239 self.assertIn(ucode_data, second)
1240 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001241
Simon Glassbac25c82017-05-27 07:38:26 -06001242 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001243 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001244 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1245 len(ucode_data))
1246 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001247 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1248 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001249
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001250 def testPackUbootSingleMicrocode(self):
1251 """Test that x86 microcode can be handled correctly with fdt_normal.
1252 """
Simon Glassbac25c82017-05-27 07:38:26 -06001253 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001254
Simon Glass996021e2016-11-25 20:15:54 -07001255 def testUBootImg(self):
1256 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001257 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001258 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001259
1260 def testNoMicrocode(self):
1261 """Test that a missing microcode region is detected"""
1262 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001263 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001264 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1265 "node found in ", str(e.exception))
1266
1267 def testMicrocodeWithoutNode(self):
1268 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1269 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001270 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001271 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1272 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1273
1274 def testMicrocodeWithoutNode2(self):
1275 """Test that a missing u-boot-ucode node is detected"""
1276 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001277 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001278 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1279 "microcode region u-boot-ucode", str(e.exception))
1280
1281 def testMicrocodeWithoutPtrInElf(self):
1282 """Test that a U-Boot binary without the microcode symbol is detected"""
1283 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001284 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001285 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001286 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001287
1288 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001289 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001290 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1291 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1292
1293 finally:
1294 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001295 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001296 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001297
1298 def testMicrocodeNotInImage(self):
1299 """Test that microcode must be placed within the image"""
1300 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001301 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001302 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1303 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001304 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001305
1306 def testWithoutMicrocode(self):
1307 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001308 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001309 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001310 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001311
1312 # Now check the device tree has no microcode
1313 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1314 second = data[len(U_BOOT_NODTB_DATA):]
1315
1316 fdt_len = self.GetFdtLen(second)
1317 self.assertEqual(dtb, second[:fdt_len])
1318
1319 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1320 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001321 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001322
1323 def testUnknownPosSize(self):
1324 """Test that microcode must be placed within the image"""
1325 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001326 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001327 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001328 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001329
1330 def testPackFsp(self):
1331 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001332 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001333 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1334
1335 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001336 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001337 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001338 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001339
1340 def testPackVbt(self):
1341 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001342 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001343 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001344
Simon Glass7f94e832017-11-12 21:52:25 -07001345 def testSplBssPad(self):
1346 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001347 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001348 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001349 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001350 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001351 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001352
Simon Glass04cda032018-10-01 21:12:42 -06001353 def testSplBssPadMissing(self):
1354 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001355 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001356 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001357 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001358 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1359 str(e.exception))
1360
Simon Glasse83679d2017-11-12 21:52:26 -07001361 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001362 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001363 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001364 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1365
Simon Glass6ba679c2018-07-06 10:27:17 -06001366 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1367 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001368
1369 We expect to see the following in the image, in order:
1370 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1371 correct place
1372 u-boot.dtb with the microcode removed
1373 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001374
1375 Args:
1376 dts: Device tree file to use for test
1377 ucode_second: True if the microsecond entry is second instead of
1378 third
Simon Glass3d274232017-11-12 21:52:27 -07001379 """
Simon Glass7057d022018-10-01 21:12:47 -06001380 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001381 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1382 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001383 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1384 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001385
Simon Glass6ba679c2018-07-06 10:27:17 -06001386 def testPackUbootSplMicrocode(self):
1387 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001388 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001389
1390 def testPackUbootSplMicrocodeReorder(self):
1391 """Test that order doesn't matter for microcode entries
1392
1393 This is the same as testPackUbootSplMicrocode but when we process the
1394 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1395 entry, so we reply on binman to try later.
1396 """
Simon Glass511f6582018-10-01 12:22:30 -06001397 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001398 ucode_second=True)
1399
Simon Glassa409c932017-11-12 21:52:28 -07001400 def testPackMrc(self):
1401 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001402 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001403 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1404
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001405 def testSplDtb(self):
1406 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001407 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001408 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1409
Simon Glass0a6da312017-11-13 18:54:56 -07001410 def testSplNoDtb(self):
1411 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001412 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001413 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001414 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1415
Simon Glass7098b7f2021-03-21 18:24:30 +13001416 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1417 use_expanded=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001418 """Check the image contains the expected symbol values
1419
1420 Args:
1421 dts: Device tree file to use for test
1422 base_data: Data before and after 'u-boot' section
1423 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001424 entry_args: Dict of entry args to supply to binman
1425 key: arg name
1426 value: value of that arg
1427 use_expanded: True to use expanded entries where available, e.g.
1428 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001429 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001430 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001431 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1432 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001433 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001434 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001435 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001436
Simon Glass7057d022018-10-01 21:12:47 -06001437 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001438 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1439 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001440 # The image should contain the symbols from u_boot_binman_syms.c
1441 # Note that image_pos is adjusted by the base address of the image,
1442 # which is 0x10 in our test image
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001443 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1444 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glass31e04cb2021-03-18 20:24:56 +13001445 0x10 + u_boot_offset, 0x04)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001446 expected = (sym_values + base_data[24:] +
Simon Glass80025522022-01-29 14:14:04 -07001447 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001448 base_data[24:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001449 self.assertEqual(expected, data)
1450
Simon Glass31e04cb2021-03-18 20:24:56 +13001451 def testSymbols(self):
1452 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001453 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001454
1455 def testSymbolsNoDtb(self):
1456 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001457 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001458 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1459 0x38)
1460
Simon Glasse76a3e62018-06-01 09:38:11 -06001461 def testPackUnitAddress(self):
1462 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001463 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001464 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1465
Simon Glassa91e1152018-06-01 09:38:16 -06001466 def testSections(self):
1467 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001468 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001469 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1470 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1471 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001472 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001473
Simon Glass30732662018-06-01 09:38:20 -06001474 def testMap(self):
1475 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001476 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001477 self.assertEqual('''ImagePos Offset Size Name
147800000000 00000000 00000028 main-section
147900000000 00000000 00000010 section@0
148000000000 00000000 00000004 u-boot
148100000010 00000010 00000010 section@1
148200000010 00000000 00000004 u-boot
148300000020 00000020 00000004 section@2
148400000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001485''', map_data)
1486
Simon Glass3b78d532018-06-01 09:38:21 -06001487 def testNamePrefix(self):
1488 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001489 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001490 self.assertEqual('''ImagePos Offset Size Name
149100000000 00000000 00000028 main-section
149200000000 00000000 00000010 section@0
149300000000 00000000 00000004 ro-u-boot
149400000010 00000010 00000010 section@1
149500000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001496''', map_data)
1497
Simon Glass6ba679c2018-07-06 10:27:17 -06001498 def testUnknownContents(self):
1499 """Test that obtaining the contents works as expected"""
1500 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001501 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001502 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001503 "processing of contents: remaining ["
1504 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001505
Simon Glass2e1169f2018-07-06 10:27:19 -06001506 def testBadChangeSize(self):
1507 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001508 try:
1509 state.SetAllowEntryExpansion(False)
1510 with self.assertRaises(ValueError) as e:
1511 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001512 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001513 str(e.exception))
1514 finally:
1515 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001516
Simon Glassa87014e2018-07-06 10:27:42 -06001517 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001518 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001519 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001520 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001521 dtb = fdt.Fdt(out_dtb_fname)
1522 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001523 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001524 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001525 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001526 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001527 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001528 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001529 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001530 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001531 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001532 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001533 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001534 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001535 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001536
Simon Glasse8561af2018-08-01 15:22:37 -06001537 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001538 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001539 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001540 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001541 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001542 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001543 'size': 40
1544 }, props)
1545
1546 def testUpdateFdtBad(self):
1547 """Test that we detect when ProcessFdt never completes"""
1548 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001549 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001550 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001551 '[<binman.etype._testing.Entry__testing',
1552 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001553
Simon Glass91710b32018-07-17 13:25:32 -06001554 def testEntryArgs(self):
1555 """Test passing arguments to entries from the command line"""
1556 entry_args = {
1557 'test-str-arg': 'test1',
1558 'test-int-arg': '456',
1559 }
Simon Glass511f6582018-10-01 12:22:30 -06001560 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001561 self.assertIn('image', control.images)
1562 entry = control.images['image'].GetEntries()['_testing']
1563 self.assertEqual('test0', entry.test_str_fdt)
1564 self.assertEqual('test1', entry.test_str_arg)
1565 self.assertEqual(123, entry.test_int_fdt)
1566 self.assertEqual(456, entry.test_int_arg)
1567
1568 def testEntryArgsMissing(self):
1569 """Test missing arguments and properties"""
1570 entry_args = {
1571 'test-int-arg': '456',
1572 }
Simon Glass511f6582018-10-01 12:22:30 -06001573 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001574 entry = control.images['image'].GetEntries()['_testing']
1575 self.assertEqual('test0', entry.test_str_fdt)
1576 self.assertEqual(None, entry.test_str_arg)
1577 self.assertEqual(None, entry.test_int_fdt)
1578 self.assertEqual(456, entry.test_int_arg)
1579
1580 def testEntryArgsRequired(self):
1581 """Test missing arguments and properties"""
1582 entry_args = {
1583 'test-int-arg': '456',
1584 }
1585 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001586 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001587 self.assertIn("Node '/binman/_testing': "
1588 'Missing required properties/entry args: test-str-arg, '
1589 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001590 str(e.exception))
1591
1592 def testEntryArgsInvalidFormat(self):
1593 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001594 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1595 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001596 with self.assertRaises(ValueError) as e:
1597 self._DoBinman(*args)
1598 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1599
1600 def testEntryArgsInvalidInteger(self):
1601 """Test that an invalid entry-argument integer is detected"""
1602 entry_args = {
1603 'test-int-arg': 'abc',
1604 }
1605 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001606 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001607 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1608 "'test-int-arg' (value 'abc') to integer",
1609 str(e.exception))
1610
1611 def testEntryArgsInvalidDatatype(self):
1612 """Test that an invalid entry-argument datatype is detected
1613
1614 This test could be written in entry_test.py except that it needs
1615 access to control.entry_args, which seems more than that module should
1616 be able to see.
1617 """
1618 entry_args = {
1619 'test-bad-datatype-arg': '12',
1620 }
1621 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001622 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001623 entry_args=entry_args)
1624 self.assertIn('GetArg() internal error: Unknown data type ',
1625 str(e.exception))
1626
Simon Glass2ca52032018-07-17 13:25:33 -06001627 def testText(self):
1628 """Test for a text entry type"""
1629 entry_args = {
1630 'test-id': TEXT_DATA,
1631 'test-id2': TEXT_DATA2,
1632 'test-id3': TEXT_DATA3,
1633 }
Simon Glass511f6582018-10-01 12:22:30 -06001634 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001635 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001636 expected = (tools.to_bytes(TEXT_DATA) +
1637 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1638 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001639 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001640 self.assertEqual(expected, data)
1641
Simon Glass969616c2018-07-17 13:25:36 -06001642 def testEntryDocs(self):
1643 """Test for creation of entry documentation"""
1644 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001645 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001646 self.assertTrue(len(stdout.getvalue()) > 0)
1647
1648 def testEntryDocsMissing(self):
1649 """Test handling of missing entry documentation"""
1650 with self.assertRaises(ValueError) as e:
1651 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001652 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001653 self.assertIn('Documentation is missing for modules: u_boot',
1654 str(e.exception))
1655
Simon Glass704784b2018-07-17 13:25:38 -06001656 def testFmap(self):
1657 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001658 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001659 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001660 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1661 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001662 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001663 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001664 self.assertEqual(1, fhdr.ver_major)
1665 self.assertEqual(0, fhdr.ver_minor)
1666 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001667 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001668 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001669 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001670 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001671 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001672
Simon Glass82059c22021-04-03 11:05:09 +13001673 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001674 self.assertEqual(b'SECTION0', fentry.name)
1675 self.assertEqual(0, fentry.offset)
1676 self.assertEqual(16, fentry.size)
1677 self.assertEqual(0, fentry.flags)
1678
1679 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001680 self.assertEqual(b'RO_U_BOOT', fentry.name)
1681 self.assertEqual(0, fentry.offset)
1682 self.assertEqual(4, fentry.size)
1683 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001684
Simon Glass82059c22021-04-03 11:05:09 +13001685 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001686 self.assertEqual(b'SECTION1', fentry.name)
1687 self.assertEqual(16, fentry.offset)
1688 self.assertEqual(16, fentry.size)
1689 self.assertEqual(0, fentry.flags)
1690
1691 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001692 self.assertEqual(b'RW_U_BOOT', fentry.name)
1693 self.assertEqual(16, fentry.offset)
1694 self.assertEqual(4, fentry.size)
1695 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001696
Simon Glass82059c22021-04-03 11:05:09 +13001697 fentry = next(fiter)
1698 self.assertEqual(b'FMAP', fentry.name)
1699 self.assertEqual(32, fentry.offset)
1700 self.assertEqual(expect_size, fentry.size)
1701 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001702
Simon Glassdb168d42018-07-17 13:25:39 -06001703 def testBlobNamedByArg(self):
1704 """Test we can add a blob with the filename coming from an entry arg"""
1705 entry_args = {
1706 'cros-ec-rw-path': 'ecrw.bin',
1707 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001708 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001709
Simon Glass53f53992018-07-17 13:25:40 -06001710 def testFill(self):
1711 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001712 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001713 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001714 self.assertEqual(expected, data)
1715
1716 def testFillNoSize(self):
1717 """Test for an fill entry type with no size"""
1718 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001719 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001720 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001721 str(e.exception))
1722
Simon Glassc1ae83c2018-07-17 13:25:44 -06001723 def _HandleGbbCommand(self, pipe_list):
1724 """Fake calls to the futility utility"""
1725 if pipe_list[0][0] == 'futility':
1726 fname = pipe_list[0][-1]
1727 # Append our GBB data to the file, which will happen every time the
1728 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001729 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001730 fd.write(GBB_DATA)
1731 return command.CommandResult()
1732
1733 def testGbb(self):
1734 """Test for the Chromium OS Google Binary Block"""
1735 command.test_result = self._HandleGbbCommand
1736 entry_args = {
1737 'keydir': 'devkeys',
1738 'bmpblk': 'bmpblk.bin',
1739 }
Simon Glass511f6582018-10-01 12:22:30 -06001740 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001741
1742 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001743 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1744 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001745 self.assertEqual(expected, data)
1746
1747 def testGbbTooSmall(self):
1748 """Test for the Chromium OS Google Binary Block being large enough"""
1749 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001750 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001751 self.assertIn("Node '/binman/gbb': GBB is too small",
1752 str(e.exception))
1753
1754 def testGbbNoSize(self):
1755 """Test for the Chromium OS Google Binary Block having a size"""
1756 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001757 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001758 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1759 str(e.exception))
1760
Simon Glass66152ce2022-01-09 20:14:09 -07001761 def testGbbMissing(self):
1762 """Test that binman still produces an image if futility is missing"""
1763 entry_args = {
1764 'keydir': 'devkeys',
1765 }
1766 with test_util.capture_sys_output() as (_, stderr):
1767 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1768 entry_args=entry_args)
1769 err = stderr.getvalue()
1770 self.assertRegex(err,
1771 "Image 'main-section'.*missing bintools.*: futility")
1772
Simon Glass5c350162018-07-17 13:25:47 -06001773 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001774 """Fake calls to the futility utility
1775
1776 The expected pipe is:
1777
1778 [('futility', 'vbutil_firmware', '--vblock',
1779 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1780 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1781 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1782 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1783
1784 This writes to the output file (here, 'vblock.vblock'). If
1785 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1786 of the input data (here, 'input.vblock').
1787 """
Simon Glass5c350162018-07-17 13:25:47 -06001788 if pipe_list[0][0] == 'futility':
1789 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001790 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001791 if self._hash_data:
1792 infile = pipe_list[0][11]
1793 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001794 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001795 m.update(data)
1796 fd.write(m.digest())
1797 else:
1798 fd.write(VBLOCK_DATA)
1799
Simon Glass5c350162018-07-17 13:25:47 -06001800 return command.CommandResult()
1801
1802 def testVblock(self):
1803 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001804 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001805 command.test_result = self._HandleVblockCommand
1806 entry_args = {
1807 'keydir': 'devkeys',
1808 }
Simon Glass511f6582018-10-01 12:22:30 -06001809 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001810 entry_args=entry_args)
1811 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1812 self.assertEqual(expected, data)
1813
1814 def testVblockNoContent(self):
1815 """Test we detect a vblock which has no content to sign"""
1816 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001817 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001818 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001819 'property', str(e.exception))
1820
1821 def testVblockBadPhandle(self):
1822 """Test that we detect a vblock with an invalid phandle in contents"""
1823 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001824 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001825 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1826 '1000', str(e.exception))
1827
1828 def testVblockBadEntry(self):
1829 """Test that we detect an entry that points to a non-entry"""
1830 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001831 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001832 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1833 "'other'", str(e.exception))
1834
Simon Glass220c6222021-01-06 21:35:17 -07001835 def testVblockContent(self):
1836 """Test that the vblock signs the right data"""
1837 self._hash_data = True
1838 command.test_result = self._HandleVblockCommand
1839 entry_args = {
1840 'keydir': 'devkeys',
1841 }
1842 data = self._DoReadFileDtb(
1843 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1844 entry_args=entry_args)[0]
1845 hashlen = 32 # SHA256 hash is 32 bytes
1846 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1847 hashval = data[-hashlen:]
1848 dtb = data[len(U_BOOT_DATA):-hashlen]
1849
1850 expected_data = U_BOOT_DATA + dtb
1851
1852 # The hashval should be a hash of the dtb
1853 m = hashlib.sha256()
1854 m.update(expected_data)
1855 expected_hashval = m.digest()
1856 self.assertEqual(expected_hashval, hashval)
1857
Simon Glass66152ce2022-01-09 20:14:09 -07001858 def testVblockMissing(self):
1859 """Test that binman still produces an image if futility is missing"""
1860 entry_args = {
1861 'keydir': 'devkeys',
1862 }
1863 with test_util.capture_sys_output() as (_, stderr):
1864 self._DoTestFile('074_vblock.dts',
1865 force_missing_bintools='futility',
1866 entry_args=entry_args)
1867 err = stderr.getvalue()
1868 self.assertRegex(err,
1869 "Image 'main-section'.*missing bintools.*: futility")
1870
Simon Glass8425a1f2018-07-17 13:25:48 -06001871 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001872 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001873 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001874 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001875 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001876 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1877
Simon Glass24b97442018-07-17 13:25:51 -06001878 def testUsesPos(self):
1879 """Test that the 'pos' property cannot be used anymore"""
1880 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001881 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001882 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1883 "'pos'", str(e.exception))
1884
Simon Glass274bf092018-09-14 04:57:08 -06001885 def testFillZero(self):
1886 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001887 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001888 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001889
Simon Glass267de432018-09-14 04:57:09 -06001890 def testTextMissing(self):
1891 """Test for a text entry type where there is no text"""
1892 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001893 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001894 self.assertIn("Node '/binman/text': No value provided for text label "
1895 "'test-id'", str(e.exception))
1896
Simon Glassed40e962018-09-14 04:57:10 -06001897 def testPackStart16Tpl(self):
1898 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001899 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001900 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1901
Simon Glass3b376c32018-09-14 04:57:12 -06001902 def testSelectImage(self):
1903 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001904 expected = 'Skipping images: image1'
1905
1906 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001907 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001908 with test_util.capture_sys_output() as (stdout, stderr):
1909 retcode = self._DoTestFile('006_dual_image.dts',
1910 verbosity=verbosity,
1911 images=['image2'])
1912 self.assertEqual(0, retcode)
1913 if verbosity:
1914 self.assertIn(expected, stdout.getvalue())
1915 else:
1916 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001917
Simon Glass80025522022-01-29 14:14:04 -07001918 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1919 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001920 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001921
Simon Glasse219aa42018-09-14 04:57:24 -06001922 def testUpdateFdtAll(self):
1923 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001924 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001925
1926 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06001927 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001928 'image-pos': 0,
1929 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06001930 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001931 'section:image-pos': 0,
1932 'section:size': 565,
1933 'section/u-boot-dtb:offset': 0,
1934 'section/u-boot-dtb:image-pos': 0,
1935 'section/u-boot-dtb:size': 565,
1936 'u-boot-spl-dtb:offset': 565,
1937 'u-boot-spl-dtb:image-pos': 565,
1938 'u-boot-spl-dtb:size': 585,
1939 'u-boot-tpl-dtb:offset': 1150,
1940 'u-boot-tpl-dtb:image-pos': 1150,
1941 'u-boot-tpl-dtb:size': 585,
1942 'u-boot-vpl-dtb:image-pos': 1735,
1943 'u-boot-vpl-dtb:offset': 1735,
1944 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06001945 }
1946
1947 # We expect three device-tree files in the output, one after the other.
1948 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1949 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1950 # main U-Boot tree. All three should have the same postions and offset.
1951 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07001952 self.maxDiff = None
1953 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06001954 dtb = fdt.Fdt.FromData(data[start:])
1955 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001956 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07001957 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001958 expected = dict(base_expected)
1959 if item:
1960 expected[item] = 0
1961 self.assertEqual(expected, props)
1962 start += dtb._fdt_obj.totalsize()
1963
1964 def testUpdateFdtOutput(self):
1965 """Test that output DTB files are updated"""
1966 try:
Simon Glass511f6582018-10-01 12:22:30 -06001967 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001968 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1969
1970 # Unfortunately, compiling a source file always results in a file
1971 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001972 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001973 # binman as a file called u-boot.dtb. To fix this, copy the file
1974 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001975 start = 0
1976 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07001977 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06001978 dtb = fdt.Fdt.FromData(data[start:])
1979 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07001980 pathname = tools.get_output_filename(os.path.split(fname)[1])
1981 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06001982 name = os.path.split(fname)[0]
1983
1984 if name:
Simon Glass56d05412022-02-28 07:16:54 -07001985 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06001986 else:
1987 orig_indata = dtb_data
1988 self.assertNotEqual(outdata, orig_indata,
1989 "Expected output file '%s' be updated" % pathname)
1990 self.assertEqual(outdata, data[start:start + size],
1991 "Expected output file '%s' to match output image" %
1992 pathname)
1993 start += size
1994 finally:
1995 self._ResetDtbs()
1996
Simon Glass7ba33592018-09-14 04:57:26 -06001997 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02001998 bintool = self.comp_bintools['lz4']
1999 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002000
2001 def testCompress(self):
2002 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002003 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002004 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002005 use_real_dtb=True, update_dtb=True)
2006 dtb = fdt.Fdt(out_dtb_fname)
2007 dtb.Scan()
2008 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2009 orig = self._decompress(data)
2010 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002011
2012 # Do a sanity check on various fields
2013 image = control.images['image']
2014 entries = image.GetEntries()
2015 self.assertEqual(1, len(entries))
2016
2017 entry = entries['blob']
2018 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2019 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2020 orig = self._decompress(entry.data)
2021 self.assertEqual(orig, entry.uncomp_data)
2022
Simon Glass72eeff12020-10-26 17:40:16 -06002023 self.assertEqual(image.data, entry.data)
2024
Simon Glass7ba33592018-09-14 04:57:26 -06002025 expected = {
2026 'blob:uncomp-size': len(COMPRESS_DATA),
2027 'blob:size': len(data),
2028 'size': len(data),
2029 }
2030 self.assertEqual(expected, props)
2031
Simon Glassac6328c2018-09-14 04:57:28 -06002032 def testFiles(self):
2033 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002034 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002035 self.assertEqual(FILES_DATA, data)
2036
2037 def testFilesCompress(self):
2038 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002039 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002040 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002041
2042 image = control.images['image']
2043 entries = image.GetEntries()
2044 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002045 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002046
Simon Glass303f62f2019-05-17 22:00:46 -06002047 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002048 for i in range(1, 3):
2049 key = '%d.dat' % i
2050 start = entries[key].image_pos
2051 len = entries[key].size
2052 chunk = data[start:start + len]
2053 orig += self._decompress(chunk)
2054
2055 self.assertEqual(FILES_DATA, orig)
2056
2057 def testFilesMissing(self):
2058 """Test missing files"""
2059 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002060 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002061 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2062 'no files', str(e.exception))
2063
2064 def testFilesNoPattern(self):
2065 """Test missing files"""
2066 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002067 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002068 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2069 str(e.exception))
2070
Simon Glassdd156a42022-03-05 20:18:59 -07002071 def testExtendSize(self):
2072 """Test an extending entry"""
2073 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002074 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002075 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2076 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2077 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2078 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002079 self.assertEqual(expect, data)
2080 self.assertEqual('''ImagePos Offset Size Name
208100000000 00000000 00000028 main-section
208200000000 00000000 00000008 fill
208300000008 00000008 00000004 u-boot
20840000000c 0000000c 00000004 section
20850000000c 00000000 00000003 intel-mrc
208600000010 00000010 00000004 u-boot2
208700000014 00000014 0000000c section2
208800000014 00000000 00000008 fill
20890000001c 00000008 00000004 u-boot
209000000020 00000020 00000008 fill2
2091''', map_data)
2092
Simon Glassdd156a42022-03-05 20:18:59 -07002093 def testExtendSizeBad(self):
2094 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002095 with test_util.capture_sys_output() as (stdout, stderr):
2096 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002097 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002098 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2099 'expanding entry', str(e.exception))
2100
Simon Glassae7cf032018-09-14 04:57:31 -06002101 def testHash(self):
2102 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002103 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002104 use_real_dtb=True, update_dtb=True)
2105 dtb = fdt.Fdt(out_dtb_fname)
2106 dtb.Scan()
2107 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2108 m = hashlib.sha256()
2109 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002110 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002111
2112 def testHashNoAlgo(self):
2113 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002114 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002115 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2116 'hash node', str(e.exception))
2117
2118 def testHashBadAlgo(self):
2119 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002120 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002121 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002122 str(e.exception))
2123
2124 def testHashSection(self):
2125 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002126 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002127 use_real_dtb=True, update_dtb=True)
2128 dtb = fdt.Fdt(out_dtb_fname)
2129 dtb.Scan()
2130 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2131 m = hashlib.sha256()
2132 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002133 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002134 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002135
Simon Glass3fb4f422018-09-14 04:57:32 -06002136 def testPackUBootTplMicrocode(self):
2137 """Test that x86 microcode can be handled correctly in TPL
2138
2139 We expect to see the following in the image, in order:
2140 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2141 place
2142 u-boot-tpl.dtb with the microcode removed
2143 the microcode
2144 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002145 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002146 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002147 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002148 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2149 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002150
Simon Glassc64aea52018-09-14 04:57:34 -06002151 def testFmapX86(self):
2152 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002153 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002154 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002155 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002156 self.assertEqual(expected, data[:32])
2157 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2158
2159 self.assertEqual(0x100, fhdr.image_size)
2160
2161 self.assertEqual(0, fentries[0].offset)
2162 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002163 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002164
2165 self.assertEqual(4, fentries[1].offset)
2166 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002167 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002168
2169 self.assertEqual(32, fentries[2].offset)
2170 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2171 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002172 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002173
2174 def testFmapX86Section(self):
2175 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002176 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002177 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002178 self.assertEqual(expected, data[:32])
2179 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2180
Simon Glassb1d414c2021-04-03 11:05:10 +13002181 self.assertEqual(0x180, fhdr.image_size)
2182 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002183 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002184
Simon Glass82059c22021-04-03 11:05:09 +13002185 fentry = next(fiter)
2186 self.assertEqual(b'U_BOOT', fentry.name)
2187 self.assertEqual(0, fentry.offset)
2188 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002189
Simon Glass82059c22021-04-03 11:05:09 +13002190 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002191 self.assertEqual(b'SECTION', fentry.name)
2192 self.assertEqual(4, fentry.offset)
2193 self.assertEqual(0x20 + expect_size, fentry.size)
2194
2195 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002196 self.assertEqual(b'INTEL_MRC', fentry.name)
2197 self.assertEqual(4, fentry.offset)
2198 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002199
Simon Glass82059c22021-04-03 11:05:09 +13002200 fentry = next(fiter)
2201 self.assertEqual(b'FMAP', fentry.name)
2202 self.assertEqual(36, fentry.offset)
2203 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002204
Simon Glassb1714232018-09-14 04:57:35 -06002205 def testElf(self):
2206 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002207 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002208 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002209 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002210 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002211 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002212
Simon Glass0d673792019-07-08 13:18:25 -06002213 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002214 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002215 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002216 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002217 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002218 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002219
Simon Glasscd817d52018-09-14 04:57:36 -06002220 def testPackOverlapMap(self):
2221 """Test that overlapping regions are detected"""
2222 with test_util.capture_sys_output() as (stdout, stderr):
2223 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002224 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002225 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002226 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2227 stdout.getvalue())
2228
2229 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002230 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002231 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002232 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002233 self.assertEqual('''ImagePos Offset Size Name
Simon Glassd99850b2020-10-26 17:40:24 -06002234<none> 00000000 00000008 main-section
Simon Glasscd817d52018-09-14 04:57:36 -06002235<none> 00000000 00000004 u-boot
2236<none> 00000003 00000004 u-boot-align
2237''', map_data)
2238
Simon Glass0d673792019-07-08 13:18:25 -06002239 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002240 """Test that an image with an Intel Reference code binary works"""
2241 data = self._DoReadFile('100_intel_refcode.dts')
2242 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2243
Simon Glasseb023b32019-04-25 21:58:39 -06002244 def testSectionOffset(self):
2245 """Tests use of a section with an offset"""
2246 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2247 map=True)
2248 self.assertEqual('''ImagePos Offset Size Name
224900000000 00000000 00000038 main-section
225000000004 00000004 00000010 section@0
225100000004 00000000 00000004 u-boot
225200000018 00000018 00000010 section@1
225300000018 00000000 00000004 u-boot
22540000002c 0000002c 00000004 section@2
22550000002c 00000000 00000004 u-boot
2256''', map_data)
2257 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002258 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2259 tools.get_bytes(0x21, 12) +
2260 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2261 tools.get_bytes(0x61, 12) +
2262 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2263 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002264
Simon Glass1de34482019-07-08 13:18:53 -06002265 def testCbfsRaw(self):
2266 """Test base handling of a Coreboot Filesystem (CBFS)
2267
2268 The exact contents of the CBFS is verified by similar tests in
2269 cbfs_util_test.py. The tests here merely check that the files added to
2270 the CBFS can be found in the final image.
2271 """
2272 data = self._DoReadFile('102_cbfs_raw.dts')
2273 size = 0xb0
2274
2275 cbfs = cbfs_util.CbfsReader(data)
2276 self.assertEqual(size, cbfs.rom_size)
2277
2278 self.assertIn('u-boot-dtb', cbfs.files)
2279 cfile = cbfs.files['u-boot-dtb']
2280 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2281
2282 def testCbfsArch(self):
2283 """Test on non-x86 architecture"""
2284 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2285 size = 0x100
2286
2287 cbfs = cbfs_util.CbfsReader(data)
2288 self.assertEqual(size, cbfs.rom_size)
2289
2290 self.assertIn('u-boot-dtb', cbfs.files)
2291 cfile = cbfs.files['u-boot-dtb']
2292 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2293
2294 def testCbfsStage(self):
2295 """Tests handling of a Coreboot Filesystem (CBFS)"""
2296 if not elf.ELF_TOOLS:
2297 self.skipTest('Python elftools not available')
2298 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2299 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2300 size = 0xb0
2301
2302 data = self._DoReadFile('104_cbfs_stage.dts')
2303 cbfs = cbfs_util.CbfsReader(data)
2304 self.assertEqual(size, cbfs.rom_size)
2305
2306 self.assertIn('u-boot', cbfs.files)
2307 cfile = cbfs.files['u-boot']
2308 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2309
2310 def testCbfsRawCompress(self):
2311 """Test handling of compressing raw files"""
2312 self._CheckLz4()
2313 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2314 size = 0x140
2315
2316 cbfs = cbfs_util.CbfsReader(data)
2317 self.assertIn('u-boot', cbfs.files)
2318 cfile = cbfs.files['u-boot']
2319 self.assertEqual(COMPRESS_DATA, cfile.data)
2320
2321 def testCbfsBadArch(self):
2322 """Test handling of a bad architecture"""
2323 with self.assertRaises(ValueError) as e:
2324 self._DoReadFile('106_cbfs_bad_arch.dts')
2325 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2326
2327 def testCbfsNoSize(self):
2328 """Test handling of a missing size property"""
2329 with self.assertRaises(ValueError) as e:
2330 self._DoReadFile('107_cbfs_no_size.dts')
2331 self.assertIn('entry must have a size property', str(e.exception))
2332
Simon Glass3e28f4f2021-11-23 11:03:54 -07002333 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002334 """Test handling of a CBFS entry which does not provide contentsy"""
2335 with self.assertRaises(ValueError) as e:
2336 self._DoReadFile('108_cbfs_no_contents.dts')
2337 self.assertIn('Could not complete processing of contents',
2338 str(e.exception))
2339
2340 def testCbfsBadCompress(self):
2341 """Test handling of a bad architecture"""
2342 with self.assertRaises(ValueError) as e:
2343 self._DoReadFile('109_cbfs_bad_compress.dts')
2344 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2345 str(e.exception))
2346
2347 def testCbfsNamedEntries(self):
2348 """Test handling of named entries"""
2349 data = self._DoReadFile('110_cbfs_name.dts')
2350
2351 cbfs = cbfs_util.CbfsReader(data)
2352 self.assertIn('FRED', cbfs.files)
2353 cfile1 = cbfs.files['FRED']
2354 self.assertEqual(U_BOOT_DATA, cfile1.data)
2355
2356 self.assertIn('hello', cbfs.files)
2357 cfile2 = cbfs.files['hello']
2358 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2359
Simon Glass759af872019-07-08 13:18:54 -06002360 def _SetupIfwi(self, fname):
2361 """Set up to run an IFWI test
2362
2363 Args:
2364 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2365 """
2366 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002367 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002368
2369 # Intel Integrated Firmware Image (IFWI) file
2370 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2371 data = fd.read()
2372 TestFunctional._MakeInputFile(fname,data)
2373
2374 def _CheckIfwi(self, data):
2375 """Check that an image with an IFWI contains the correct output
2376
2377 Args:
2378 data: Conents of output file
2379 """
Simon Glass80025522022-01-29 14:14:04 -07002380 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002381 if data[:0x1000] != expected_desc:
2382 self.fail('Expected descriptor binary at start of image')
2383
2384 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002385 image_fname = tools.get_output_filename('image.bin')
2386 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002387 ifwitool = bintool.Bintool.create('ifwitool')
2388 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002389
Simon Glass80025522022-01-29 14:14:04 -07002390 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002391 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002392
2393 def testPackX86RomIfwi(self):
2394 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2395 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002396 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002397 self._CheckIfwi(data)
2398
2399 def testPackX86RomIfwiNoDesc(self):
2400 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2401 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002402 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002403 self._CheckIfwi(data)
2404
2405 def testPackX86RomIfwiNoData(self):
2406 """Test that an x86 ROM with IFWI handles missing data"""
2407 self._SetupIfwi('ifwi.bin')
2408 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002409 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002410 self.assertIn('Could not complete processing of contents',
2411 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002412
Simon Glass66152ce2022-01-09 20:14:09 -07002413 def testIfwiMissing(self):
2414 """Test that binman still produces an image if ifwitool is missing"""
2415 self._SetupIfwi('fitimage.bin')
2416 with test_util.capture_sys_output() as (_, stderr):
2417 self._DoTestFile('111_x86_rom_ifwi.dts',
2418 force_missing_bintools='ifwitool')
2419 err = stderr.getvalue()
2420 self.assertRegex(err,
2421 "Image 'main-section'.*missing bintools.*: ifwitool")
2422
Simon Glassc2f1aed2019-07-08 13:18:56 -06002423 def testCbfsOffset(self):
2424 """Test a CBFS with files at particular offsets
2425
2426 Like all CFBS tests, this is just checking the logic that calls
2427 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2428 """
2429 data = self._DoReadFile('114_cbfs_offset.dts')
2430 size = 0x200
2431
2432 cbfs = cbfs_util.CbfsReader(data)
2433 self.assertEqual(size, cbfs.rom_size)
2434
2435 self.assertIn('u-boot', cbfs.files)
2436 cfile = cbfs.files['u-boot']
2437 self.assertEqual(U_BOOT_DATA, cfile.data)
2438 self.assertEqual(0x40, cfile.cbfs_offset)
2439
2440 self.assertIn('u-boot-dtb', cbfs.files)
2441 cfile2 = cbfs.files['u-boot-dtb']
2442 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2443 self.assertEqual(0x140, cfile2.cbfs_offset)
2444
Simon Glass0f621332019-07-08 14:25:27 -06002445 def testFdtmap(self):
2446 """Test an FDT map can be inserted in the image"""
2447 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2448 fdtmap_data = data[len(U_BOOT_DATA):]
2449 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002450 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002451 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002452
2453 fdt_data = fdtmap_data[16:]
2454 dtb = fdt.Fdt.FromData(fdt_data)
2455 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002456 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002457 self.assertEqual({
2458 'image-pos': 0,
2459 'offset': 0,
2460 'u-boot:offset': 0,
2461 'u-boot:size': len(U_BOOT_DATA),
2462 'u-boot:image-pos': 0,
2463 'fdtmap:image-pos': 4,
2464 'fdtmap:offset': 4,
2465 'fdtmap:size': len(fdtmap_data),
2466 'size': len(data),
2467 }, props)
2468
2469 def testFdtmapNoMatch(self):
2470 """Check handling of an FDT map when the section cannot be found"""
2471 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2472
2473 # Mangle the section name, which should cause a mismatch between the
2474 # correct FDT path and the one expected by the section
2475 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002476 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002477 entries = image.GetEntries()
2478 fdtmap = entries['fdtmap']
2479 with self.assertRaises(ValueError) as e:
2480 fdtmap._GetFdtmap()
2481 self.assertIn("Cannot locate node for path '/binman-suffix'",
2482 str(e.exception))
2483
Simon Glasscec34ba2019-07-08 14:25:28 -06002484 def testFdtmapHeader(self):
2485 """Test an FDT map and image header can be inserted in the image"""
2486 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2487 fdtmap_pos = len(U_BOOT_DATA)
2488 fdtmap_data = data[fdtmap_pos:]
2489 fdt_data = fdtmap_data[16:]
2490 dtb = fdt.Fdt.FromData(fdt_data)
2491 fdt_size = dtb.GetFdtObj().totalsize()
2492 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002493 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002494 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2495 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2496
2497 def testFdtmapHeaderStart(self):
2498 """Test an image header can be inserted at the image start"""
2499 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2500 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2501 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002502 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002503 offset = struct.unpack('<I', hdr_data[4:])[0]
2504 self.assertEqual(fdtmap_pos, offset)
2505
2506 def testFdtmapHeaderPos(self):
2507 """Test an image header can be inserted at a chosen position"""
2508 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2509 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2510 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002511 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002512 offset = struct.unpack('<I', hdr_data[4:])[0]
2513 self.assertEqual(fdtmap_pos, offset)
2514
2515 def testHeaderMissingFdtmap(self):
2516 """Test an image header requires an fdtmap"""
2517 with self.assertRaises(ValueError) as e:
2518 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2519 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2520 str(e.exception))
2521
2522 def testHeaderNoLocation(self):
2523 """Test an image header with a no specified location is detected"""
2524 with self.assertRaises(ValueError) as e:
2525 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2526 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2527 str(e.exception))
2528
Simon Glasse61b6f62019-07-08 14:25:37 -06002529 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002530 """Test extending an entry after it is packed"""
2531 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002532 self.assertEqual(b'aaa', data[:3])
2533 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2534 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002535
Simon Glassdd156a42022-03-05 20:18:59 -07002536 def testEntryExtendBad(self):
2537 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002538 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002539 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002540 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002541 str(e.exception))
2542
Simon Glassdd156a42022-03-05 20:18:59 -07002543 def testEntryExtendSection(self):
2544 """Test extending an entry within a section after it is packed"""
2545 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002546 self.assertEqual(b'aaa', data[:3])
2547 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2548 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002549
Simon Glass90d29682019-07-08 14:25:38 -06002550 def testCompressDtb(self):
2551 """Test that compress of device-tree files is supported"""
2552 self._CheckLz4()
2553 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2554 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2555 comp_data = data[len(U_BOOT_DATA):]
2556 orig = self._decompress(comp_data)
2557 dtb = fdt.Fdt.FromData(orig)
2558 dtb.Scan()
2559 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2560 expected = {
2561 'u-boot:size': len(U_BOOT_DATA),
2562 'u-boot-dtb:uncomp-size': len(orig),
2563 'u-boot-dtb:size': len(comp_data),
2564 'size': len(data),
2565 }
2566 self.assertEqual(expected, props)
2567
Simon Glass151bbbf2019-07-08 14:25:41 -06002568 def testCbfsUpdateFdt(self):
2569 """Test that we can update the device tree with CBFS offset/size info"""
2570 self._CheckLz4()
2571 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2572 update_dtb=True)
2573 dtb = fdt.Fdt(out_dtb_fname)
2574 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002575 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002576 del props['cbfs/u-boot:size']
2577 self.assertEqual({
2578 'offset': 0,
2579 'size': len(data),
2580 'image-pos': 0,
2581 'cbfs:offset': 0,
2582 'cbfs:size': len(data),
2583 'cbfs:image-pos': 0,
2584 'cbfs/u-boot:offset': 0x38,
2585 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2586 'cbfs/u-boot:image-pos': 0x38,
2587 'cbfs/u-boot-dtb:offset': 0xb8,
2588 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2589 'cbfs/u-boot-dtb:image-pos': 0xb8,
2590 }, props)
2591
Simon Glass3c9b4f22019-07-08 14:25:42 -06002592 def testCbfsBadType(self):
2593 """Test an image header with a no specified location is detected"""
2594 with self.assertRaises(ValueError) as e:
2595 self._DoReadFile('126_cbfs_bad_type.dts')
2596 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2597
Simon Glass6b156f82019-07-08 14:25:43 -06002598 def testList(self):
2599 """Test listing the files in an image"""
2600 self._CheckLz4()
2601 data = self._DoReadFile('127_list.dts')
2602 image = control.images['image']
2603 entries = image.BuildEntryList()
2604 self.assertEqual(7, len(entries))
2605
2606 ent = entries[0]
2607 self.assertEqual(0, ent.indent)
2608 self.assertEqual('main-section', ent.name)
2609 self.assertEqual('section', ent.etype)
2610 self.assertEqual(len(data), ent.size)
2611 self.assertEqual(0, ent.image_pos)
2612 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002613 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002614
2615 ent = entries[1]
2616 self.assertEqual(1, ent.indent)
2617 self.assertEqual('u-boot', ent.name)
2618 self.assertEqual('u-boot', ent.etype)
2619 self.assertEqual(len(U_BOOT_DATA), ent.size)
2620 self.assertEqual(0, ent.image_pos)
2621 self.assertEqual(None, ent.uncomp_size)
2622 self.assertEqual(0, ent.offset)
2623
2624 ent = entries[2]
2625 self.assertEqual(1, ent.indent)
2626 self.assertEqual('section', ent.name)
2627 self.assertEqual('section', ent.etype)
2628 section_size = ent.size
2629 self.assertEqual(0x100, ent.image_pos)
2630 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002631 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002632
2633 ent = entries[3]
2634 self.assertEqual(2, ent.indent)
2635 self.assertEqual('cbfs', ent.name)
2636 self.assertEqual('cbfs', ent.etype)
2637 self.assertEqual(0x400, ent.size)
2638 self.assertEqual(0x100, ent.image_pos)
2639 self.assertEqual(None, ent.uncomp_size)
2640 self.assertEqual(0, ent.offset)
2641
2642 ent = entries[4]
2643 self.assertEqual(3, ent.indent)
2644 self.assertEqual('u-boot', ent.name)
2645 self.assertEqual('u-boot', ent.etype)
2646 self.assertEqual(len(U_BOOT_DATA), ent.size)
2647 self.assertEqual(0x138, ent.image_pos)
2648 self.assertEqual(None, ent.uncomp_size)
2649 self.assertEqual(0x38, ent.offset)
2650
2651 ent = entries[5]
2652 self.assertEqual(3, ent.indent)
2653 self.assertEqual('u-boot-dtb', ent.name)
2654 self.assertEqual('text', ent.etype)
2655 self.assertGreater(len(COMPRESS_DATA), ent.size)
2656 self.assertEqual(0x178, ent.image_pos)
2657 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2658 self.assertEqual(0x78, ent.offset)
2659
2660 ent = entries[6]
2661 self.assertEqual(2, ent.indent)
2662 self.assertEqual('u-boot-dtb', ent.name)
2663 self.assertEqual('u-boot-dtb', ent.etype)
2664 self.assertEqual(0x500, ent.image_pos)
2665 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2666 dtb_size = ent.size
2667 # Compressing this data expands it since headers are added
2668 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2669 self.assertEqual(0x400, ent.offset)
2670
2671 self.assertEqual(len(data), 0x100 + section_size)
2672 self.assertEqual(section_size, 0x400 + dtb_size)
2673
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002674 def testFindFdtmap(self):
2675 """Test locating an FDT map in an image"""
2676 self._CheckLz4()
2677 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2678 image = control.images['image']
2679 entries = image.GetEntries()
2680 entry = entries['fdtmap']
2681 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2682
2683 def testFindFdtmapMissing(self):
2684 """Test failing to locate an FDP map"""
2685 data = self._DoReadFile('005_simple.dts')
2686 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2687
Simon Glassed39a3c2019-07-08 14:25:45 -06002688 def testFindImageHeader(self):
2689 """Test locating a image header"""
2690 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002691 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002692 image = control.images['image']
2693 entries = image.GetEntries()
2694 entry = entries['fdtmap']
2695 # The header should point to the FDT map
2696 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2697
2698 def testFindImageHeaderStart(self):
2699 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002700 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002701 image = control.images['image']
2702 entries = image.GetEntries()
2703 entry = entries['fdtmap']
2704 # The header should point to the FDT map
2705 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2706
2707 def testFindImageHeaderMissing(self):
2708 """Test failing to locate an image header"""
2709 data = self._DoReadFile('005_simple.dts')
2710 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2711
Simon Glassb8424fa2019-07-08 14:25:46 -06002712 def testReadImage(self):
2713 """Test reading an image and accessing its FDT map"""
2714 self._CheckLz4()
2715 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002716 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002717 orig_image = control.images['image']
2718 image = Image.FromFile(image_fname)
2719 self.assertEqual(orig_image.GetEntries().keys(),
2720 image.GetEntries().keys())
2721
2722 orig_entry = orig_image.GetEntries()['fdtmap']
2723 entry = image.GetEntries()['fdtmap']
2724 self.assertEquals(orig_entry.offset, entry.offset)
2725 self.assertEquals(orig_entry.size, entry.size)
2726 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2727
2728 def testReadImageNoHeader(self):
2729 """Test accessing an image's FDT map without an image header"""
2730 self._CheckLz4()
2731 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002732 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002733 image = Image.FromFile(image_fname)
2734 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002735 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002736
2737 def testReadImageFail(self):
2738 """Test failing to read an image image's FDT map"""
2739 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002740 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002741 with self.assertRaises(ValueError) as e:
2742 image = Image.FromFile(image_fname)
2743 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002744
Simon Glassb2fd11d2019-07-08 14:25:48 -06002745 def testListCmd(self):
2746 """Test listing the files in an image using an Fdtmap"""
2747 self._CheckLz4()
2748 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2749
2750 # lz4 compression size differs depending on the version
2751 image = control.images['image']
2752 entries = image.GetEntries()
2753 section_size = entries['section'].size
2754 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2755 fdtmap_offset = entries['fdtmap'].offset
2756
Simon Glassb3d6fc72019-07-20 12:24:10 -06002757 try:
2758 tmpdir, updated_fname = self._SetupImageInTmpdir()
2759 with test_util.capture_sys_output() as (stdout, stderr):
2760 self._DoBinman('ls', '-i', updated_fname)
2761 finally:
2762 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002763 lines = stdout.getvalue().splitlines()
2764 expected = [
2765'Name Image-pos Size Entry-type Offset Uncomp-size',
2766'----------------------------------------------------------------------',
2767'main-section 0 c00 section 0',
2768' u-boot 0 4 u-boot 0',
2769' section 100 %x section 100' % section_size,
2770' cbfs 100 400 cbfs 0',
2771' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002772' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002773' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002774' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002775 (fdtmap_offset, fdtmap_offset),
2776' image-header bf8 8 image-header bf8',
2777 ]
2778 self.assertEqual(expected, lines)
2779
2780 def testListCmdFail(self):
2781 """Test failing to list an image"""
2782 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002783 try:
2784 tmpdir, updated_fname = self._SetupImageInTmpdir()
2785 with self.assertRaises(ValueError) as e:
2786 self._DoBinman('ls', '-i', updated_fname)
2787 finally:
2788 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002789 self.assertIn("Cannot find FDT map in image", str(e.exception))
2790
2791 def _RunListCmd(self, paths, expected):
2792 """List out entries and check the result
2793
2794 Args:
2795 paths: List of paths to pass to the list command
2796 expected: Expected list of filenames to be returned, in order
2797 """
2798 self._CheckLz4()
2799 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002800 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002801 image = Image.FromFile(image_fname)
2802 lines = image.GetListEntries(paths)[1]
2803 files = [line[0].strip() for line in lines[1:]]
2804 self.assertEqual(expected, files)
2805
2806 def testListCmdSection(self):
2807 """Test listing the files in a section"""
2808 self._RunListCmd(['section'],
2809 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2810
2811 def testListCmdFile(self):
2812 """Test listing a particular file"""
2813 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2814
2815 def testListCmdWildcard(self):
2816 """Test listing a wildcarded file"""
2817 self._RunListCmd(['*boot*'],
2818 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2819
2820 def testListCmdWildcardMulti(self):
2821 """Test listing a wildcarded file"""
2822 self._RunListCmd(['*cb*', '*head*'],
2823 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2824
2825 def testListCmdEmpty(self):
2826 """Test listing a wildcarded file"""
2827 self._RunListCmd(['nothing'], [])
2828
2829 def testListCmdPath(self):
2830 """Test listing the files in a sub-entry of a section"""
2831 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2832
Simon Glass4c613bf2019-07-08 14:25:50 -06002833 def _RunExtractCmd(self, entry_name, decomp=True):
2834 """Extract an entry from an image
2835
2836 Args:
2837 entry_name: Entry name to extract
2838 decomp: True to decompress the data if compressed, False to leave
2839 it in its raw uncompressed format
2840
2841 Returns:
2842 data from entry
2843 """
2844 self._CheckLz4()
2845 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002846 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002847 return control.ReadEntry(image_fname, entry_name, decomp)
2848
2849 def testExtractSimple(self):
2850 """Test extracting a single file"""
2851 data = self._RunExtractCmd('u-boot')
2852 self.assertEqual(U_BOOT_DATA, data)
2853
Simon Glass980a2842019-07-08 14:25:52 -06002854 def testExtractSection(self):
2855 """Test extracting the files in a section"""
2856 data = self._RunExtractCmd('section')
2857 cbfs_data = data[:0x400]
2858 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002859 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002860 dtb_data = data[0x400:]
2861 dtb = self._decompress(dtb_data)
2862 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2863
2864 def testExtractCompressed(self):
2865 """Test extracting compressed data"""
2866 data = self._RunExtractCmd('section/u-boot-dtb')
2867 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2868
2869 def testExtractRaw(self):
2870 """Test extracting compressed data without decompressing it"""
2871 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2872 dtb = self._decompress(data)
2873 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2874
2875 def testExtractCbfs(self):
2876 """Test extracting CBFS data"""
2877 data = self._RunExtractCmd('section/cbfs/u-boot')
2878 self.assertEqual(U_BOOT_DATA, data)
2879
2880 def testExtractCbfsCompressed(self):
2881 """Test extracting CBFS compressed data"""
2882 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2883 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2884
2885 def testExtractCbfsRaw(self):
2886 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002887 bintool = self.comp_bintools['lzma_alone']
2888 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06002889 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002890 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06002891 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2892
Simon Glass4c613bf2019-07-08 14:25:50 -06002893 def testExtractBadEntry(self):
2894 """Test extracting a bad section path"""
2895 with self.assertRaises(ValueError) as e:
2896 self._RunExtractCmd('section/does-not-exist')
2897 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2898 str(e.exception))
2899
2900 def testExtractMissingFile(self):
2901 """Test extracting file that does not exist"""
2902 with self.assertRaises(IOError) as e:
2903 control.ReadEntry('missing-file', 'name')
2904
2905 def testExtractBadFile(self):
2906 """Test extracting an invalid file"""
2907 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002908 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002909 with self.assertRaises(ValueError) as e:
2910 control.ReadEntry(fname, 'name')
2911
Simon Glass980a2842019-07-08 14:25:52 -06002912 def testExtractCmd(self):
2913 """Test extracting a file fron an image on the command line"""
2914 self._CheckLz4()
2915 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002916 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002917 try:
2918 tmpdir, updated_fname = self._SetupImageInTmpdir()
2919 with test_util.capture_sys_output() as (stdout, stderr):
2920 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2921 '-f', fname)
2922 finally:
2923 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07002924 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002925 self.assertEqual(U_BOOT_DATA, data)
2926
2927 def testExtractOneEntry(self):
2928 """Test extracting a single entry fron an image """
2929 self._CheckLz4()
2930 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002931 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002932 fname = os.path.join(self._indir, 'output.extact')
2933 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07002934 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002935 self.assertEqual(U_BOOT_DATA, data)
2936
2937 def _CheckExtractOutput(self, decomp):
2938 """Helper to test file output with and without decompression
2939
2940 Args:
2941 decomp: True to decompress entry data, False to output it raw
2942 """
2943 def _CheckPresent(entry_path, expect_data, expect_size=None):
2944 """Check and remove expected file
2945
2946 This checks the data/size of a file and removes the file both from
2947 the outfiles set and from the output directory. Once all files are
2948 processed, both the set and directory should be empty.
2949
2950 Args:
2951 entry_path: Entry path
2952 expect_data: Data to expect in file, or None to skip check
2953 expect_size: Size of data to expect in file, or None to skip
2954 """
2955 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07002956 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06002957 os.remove(path)
2958 if expect_data:
2959 self.assertEqual(expect_data, data)
2960 elif expect_size:
2961 self.assertEqual(expect_size, len(data))
2962 outfiles.remove(path)
2963
2964 def _CheckDirPresent(name):
2965 """Remove expected directory
2966
2967 This gives an error if the directory does not exist as expected
2968
2969 Args:
2970 name: Name of directory to remove
2971 """
2972 path = os.path.join(outdir, name)
2973 os.rmdir(path)
2974
2975 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002976 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002977 outdir = os.path.join(self._indir, 'extract')
2978 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2979
2980 # Create a set of all file that were output (should be 9)
2981 outfiles = set()
2982 for root, dirs, files in os.walk(outdir):
2983 outfiles |= set([os.path.join(root, fname) for fname in files])
2984 self.assertEqual(9, len(outfiles))
2985 self.assertEqual(9, len(einfos))
2986
2987 image = control.images['image']
2988 entries = image.GetEntries()
2989
2990 # Check the 9 files in various ways
2991 section = entries['section']
2992 section_entries = section.GetEntries()
2993 cbfs_entries = section_entries['cbfs'].GetEntries()
2994 _CheckPresent('u-boot', U_BOOT_DATA)
2995 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2996 dtb_len = EXTRACT_DTB_SIZE
2997 if not decomp:
2998 dtb_len = cbfs_entries['u-boot-dtb'].size
2999 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3000 if not decomp:
3001 dtb_len = section_entries['u-boot-dtb'].size
3002 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3003
3004 fdtmap = entries['fdtmap']
3005 _CheckPresent('fdtmap', fdtmap.data)
3006 hdr = entries['image-header']
3007 _CheckPresent('image-header', hdr.data)
3008
3009 _CheckPresent('section/root', section.data)
3010 cbfs = section_entries['cbfs']
3011 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003012 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003013 _CheckPresent('root', data)
3014
3015 # There should be no files left. Remove all the directories to check.
3016 # If there are any files/dirs remaining, one of these checks will fail.
3017 self.assertEqual(0, len(outfiles))
3018 _CheckDirPresent('section/cbfs')
3019 _CheckDirPresent('section')
3020 _CheckDirPresent('')
3021 self.assertFalse(os.path.exists(outdir))
3022
3023 def testExtractAllEntries(self):
3024 """Test extracting all entries"""
3025 self._CheckLz4()
3026 self._CheckExtractOutput(decomp=True)
3027
3028 def testExtractAllEntriesRaw(self):
3029 """Test extracting all entries without decompressing them"""
3030 self._CheckLz4()
3031 self._CheckExtractOutput(decomp=False)
3032
3033 def testExtractSelectedEntries(self):
3034 """Test extracting some entries"""
3035 self._CheckLz4()
3036 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003037 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003038 outdir = os.path.join(self._indir, 'extract')
3039 einfos = control.ExtractEntries(image_fname, None, outdir,
3040 ['*cb*', '*head*'])
3041
3042 # File output is tested by testExtractAllEntries(), so just check that
3043 # the expected entries are selected
3044 names = [einfo.name for einfo in einfos]
3045 self.assertEqual(names,
3046 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3047
3048 def testExtractNoEntryPaths(self):
3049 """Test extracting some entries"""
3050 self._CheckLz4()
3051 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003052 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003053 with self.assertRaises(ValueError) as e:
3054 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003055 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003056 str(e.exception))
3057
3058 def testExtractTooManyEntryPaths(self):
3059 """Test extracting some entries"""
3060 self._CheckLz4()
3061 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003062 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003063 with self.assertRaises(ValueError) as e:
3064 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003065 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003066 str(e.exception))
3067
Simon Glass52d06212019-07-08 14:25:53 -06003068 def testPackAlignSection(self):
3069 """Test that sections can have alignment"""
3070 self._DoReadFile('131_pack_align_section.dts')
3071
3072 self.assertIn('image', control.images)
3073 image = control.images['image']
3074 entries = image.GetEntries()
3075 self.assertEqual(3, len(entries))
3076
3077 # First u-boot
3078 self.assertIn('u-boot', entries)
3079 entry = entries['u-boot']
3080 self.assertEqual(0, entry.offset)
3081 self.assertEqual(0, entry.image_pos)
3082 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3083 self.assertEqual(len(U_BOOT_DATA), entry.size)
3084
3085 # Section0
3086 self.assertIn('section0', entries)
3087 section0 = entries['section0']
3088 self.assertEqual(0x10, section0.offset)
3089 self.assertEqual(0x10, section0.image_pos)
3090 self.assertEqual(len(U_BOOT_DATA), section0.size)
3091
3092 # Second u-boot
3093 section_entries = section0.GetEntries()
3094 self.assertIn('u-boot', section_entries)
3095 entry = section_entries['u-boot']
3096 self.assertEqual(0, entry.offset)
3097 self.assertEqual(0x10, entry.image_pos)
3098 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3099 self.assertEqual(len(U_BOOT_DATA), entry.size)
3100
3101 # Section1
3102 self.assertIn('section1', entries)
3103 section1 = entries['section1']
3104 self.assertEqual(0x14, section1.offset)
3105 self.assertEqual(0x14, section1.image_pos)
3106 self.assertEqual(0x20, section1.size)
3107
3108 # Second u-boot
3109 section_entries = section1.GetEntries()
3110 self.assertIn('u-boot', section_entries)
3111 entry = section_entries['u-boot']
3112 self.assertEqual(0, entry.offset)
3113 self.assertEqual(0x14, entry.image_pos)
3114 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3115 self.assertEqual(len(U_BOOT_DATA), entry.size)
3116
3117 # Section2
3118 self.assertIn('section2', section_entries)
3119 section2 = section_entries['section2']
3120 self.assertEqual(0x4, section2.offset)
3121 self.assertEqual(0x18, section2.image_pos)
3122 self.assertEqual(4, section2.size)
3123
3124 # Third u-boot
3125 section_entries = section2.GetEntries()
3126 self.assertIn('u-boot', section_entries)
3127 entry = section_entries['u-boot']
3128 self.assertEqual(0, entry.offset)
3129 self.assertEqual(0x18, entry.image_pos)
3130 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3131 self.assertEqual(len(U_BOOT_DATA), entry.size)
3132
Simon Glassf8a54bc2019-07-20 12:23:56 -06003133 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3134 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003135 """Replace an entry in an image
3136
3137 This writes the entry data to update it, then opens the updated file and
3138 returns the value that it now finds there.
3139
3140 Args:
3141 entry_name: Entry name to replace
3142 data: Data to replace it with
3143 decomp: True to compress the data if needed, False if data is
3144 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003145 allow_resize: True to allow entries to change size, False to raise
3146 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003147
3148 Returns:
3149 Tuple:
3150 data from entry
3151 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003152 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003153 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003154 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003155 update_dtb=True)[1]
3156
3157 self.assertIn('image', control.images)
3158 image = control.images['image']
3159 entries = image.GetEntries()
3160 orig_dtb_data = entries['u-boot-dtb'].data
3161 orig_fdtmap_data = entries['fdtmap'].data
3162
Simon Glass80025522022-01-29 14:14:04 -07003163 image_fname = tools.get_output_filename('image.bin')
3164 updated_fname = tools.get_output_filename('image-updated.bin')
3165 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003166 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3167 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003168 data = control.ReadEntry(updated_fname, entry_name, decomp)
3169
Simon Glassf8a54bc2019-07-20 12:23:56 -06003170 # The DT data should not change unless resized:
3171 if not allow_resize:
3172 new_dtb_data = entries['u-boot-dtb'].data
3173 self.assertEqual(new_dtb_data, orig_dtb_data)
3174 new_fdtmap_data = entries['fdtmap'].data
3175 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003176
Simon Glassf8a54bc2019-07-20 12:23:56 -06003177 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003178
3179 def testReplaceSimple(self):
3180 """Test replacing a single file"""
3181 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003182 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3183 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003184 self.assertEqual(expected, data)
3185
3186 # Test that the state looks right. There should be an FDT for the fdtmap
3187 # that we jsut read back in, and it should match what we find in the
3188 # 'control' tables. Checking for an FDT that does not exist should
3189 # return None.
3190 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003191 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003192 self.assertEqual(expected_fdtmap, fdtmap)
3193
3194 dtb = state.GetFdtForEtype('fdtmap')
3195 self.assertEqual(dtb.GetContents(), fdtmap)
3196
3197 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3198 self.assertIsNone(missing_path)
3199 self.assertIsNone(missing_fdtmap)
3200
3201 missing_dtb = state.GetFdtForEtype('missing')
3202 self.assertIsNone(missing_dtb)
3203
3204 self.assertEqual('/binman', state.fdt_path_prefix)
3205
3206 def testReplaceResizeFail(self):
3207 """Test replacing a file by something larger"""
3208 expected = U_BOOT_DATA + b'x'
3209 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003210 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3211 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003212 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3213 str(e.exception))
3214
3215 def testReplaceMulti(self):
3216 """Test replacing entry data where multiple images are generated"""
3217 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3218 update_dtb=True)[0]
3219 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003220 updated_fname = tools.get_output_filename('image-updated.bin')
3221 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003222 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003223 control.WriteEntry(updated_fname, entry_name, expected,
3224 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003225 data = control.ReadEntry(updated_fname, entry_name)
3226 self.assertEqual(expected, data)
3227
3228 # Check the state looks right.
3229 self.assertEqual('/binman/image', state.fdt_path_prefix)
3230
3231 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003232 image_fname = tools.get_output_filename('first-image.bin')
3233 updated_fname = tools.get_output_filename('first-updated.bin')
3234 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003235 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003236 control.WriteEntry(updated_fname, entry_name, expected,
3237 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003238 data = control.ReadEntry(updated_fname, entry_name)
3239 self.assertEqual(expected, data)
3240
3241 # Check the state looks right.
3242 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003243
Simon Glassfb30e292019-07-20 12:23:51 -06003244 def testUpdateFdtAllRepack(self):
3245 """Test that all device trees are updated with offset/size info"""
3246 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3247 SECTION_SIZE = 0x300
3248 DTB_SIZE = 602
3249 FDTMAP_SIZE = 608
3250 base_expected = {
3251 'offset': 0,
3252 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3253 'image-pos': 0,
3254 'section:offset': 0,
3255 'section:size': SECTION_SIZE,
3256 'section:image-pos': 0,
3257 'section/u-boot-dtb:offset': 4,
3258 'section/u-boot-dtb:size': 636,
3259 'section/u-boot-dtb:image-pos': 4,
3260 'u-boot-spl-dtb:offset': SECTION_SIZE,
3261 'u-boot-spl-dtb:size': DTB_SIZE,
3262 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3263 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3264 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3265 'u-boot-tpl-dtb:size': DTB_SIZE,
3266 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3267 'fdtmap:size': FDTMAP_SIZE,
3268 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3269 }
3270 main_expected = {
3271 'section:orig-size': SECTION_SIZE,
3272 'section/u-boot-dtb:orig-offset': 4,
3273 }
3274
3275 # We expect three device-tree files in the output, with the first one
3276 # within a fixed-size section.
3277 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3278 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3279 # main U-Boot tree. All three should have the same positions and offset
3280 # except that the main tree should include the main_expected properties
3281 start = 4
3282 for item in ['', 'spl', 'tpl', None]:
3283 if item is None:
3284 start += 16 # Move past fdtmap header
3285 dtb = fdt.Fdt.FromData(data[start:])
3286 dtb.Scan()
3287 props = self._GetPropTree(dtb,
3288 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3289 prefix='/' if item is None else '/binman/')
3290 expected = dict(base_expected)
3291 if item:
3292 expected[item] = 0
3293 else:
3294 # Main DTB and fdtdec should include the 'orig-' properties
3295 expected.update(main_expected)
3296 # Helpful for debugging:
3297 #for prop in sorted(props):
3298 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3299 self.assertEqual(expected, props)
3300 if item == '':
3301 start = SECTION_SIZE
3302 else:
3303 start += dtb._fdt_obj.totalsize()
3304
Simon Glass11453762019-07-20 12:23:55 -06003305 def testFdtmapHeaderMiddle(self):
3306 """Test an FDT map in the middle of an image when it should be at end"""
3307 with self.assertRaises(ValueError) as e:
3308 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3309 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3310 str(e.exception))
3311
3312 def testFdtmapHeaderStartBad(self):
3313 """Test an FDT map in middle of an image when it should be at start"""
3314 with self.assertRaises(ValueError) as e:
3315 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3316 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3317 str(e.exception))
3318
3319 def testFdtmapHeaderEndBad(self):
3320 """Test an FDT map at the start of an image when it should be at end"""
3321 with self.assertRaises(ValueError) as e:
3322 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3323 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3324 str(e.exception))
3325
3326 def testFdtmapHeaderNoSize(self):
3327 """Test an image header at the end of an image with undefined size"""
3328 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3329
Simon Glassf8a54bc2019-07-20 12:23:56 -06003330 def testReplaceResize(self):
3331 """Test replacing a single file in an entry with a larger file"""
3332 expected = U_BOOT_DATA + b'x'
3333 data, _, image = self._RunReplaceCmd('u-boot', expected,
3334 dts='139_replace_repack.dts')
3335 self.assertEqual(expected, data)
3336
3337 entries = image.GetEntries()
3338 dtb_data = entries['u-boot-dtb'].data
3339 dtb = fdt.Fdt.FromData(dtb_data)
3340 dtb.Scan()
3341
3342 # The u-boot section should now be larger in the dtb
3343 node = dtb.GetNode('/binman/u-boot')
3344 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3345
3346 # Same for the fdtmap
3347 fdata = entries['fdtmap'].data
3348 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3349 fdtb.Scan()
3350 fnode = fdtb.GetNode('/u-boot')
3351 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3352
3353 def testReplaceResizeNoRepack(self):
3354 """Test replacing an entry with a larger file when not allowed"""
3355 expected = U_BOOT_DATA + b'x'
3356 with self.assertRaises(ValueError) as e:
3357 self._RunReplaceCmd('u-boot', expected)
3358 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3359 str(e.exception))
3360
Simon Glass9d8ee322019-07-20 12:23:58 -06003361 def testEntryShrink(self):
3362 """Test contracting an entry after it is packed"""
3363 try:
3364 state.SetAllowEntryContraction(True)
3365 data = self._DoReadFileDtb('140_entry_shrink.dts',
3366 update_dtb=True)[0]
3367 finally:
3368 state.SetAllowEntryContraction(False)
3369 self.assertEqual(b'a', data[:1])
3370 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3371 self.assertEqual(b'a', data[-1:])
3372
3373 def testEntryShrinkFail(self):
3374 """Test not being allowed to contract an entry after it is packed"""
3375 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3376
3377 # In this case there is a spare byte at the end of the data. The size of
3378 # the contents is only 1 byte but we still have the size before it
3379 # shrunk.
3380 self.assertEqual(b'a\0', data[:2])
3381 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3382 self.assertEqual(b'a\0', data[-2:])
3383
Simon Glass70e32982019-07-20 12:24:01 -06003384 def testDescriptorOffset(self):
3385 """Test that the Intel descriptor is always placed at at the start"""
3386 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3387 image = control.images['image']
3388 entries = image.GetEntries()
3389 desc = entries['intel-descriptor']
3390 self.assertEqual(0xff800000, desc.offset);
3391 self.assertEqual(0xff800000, desc.image_pos);
3392
Simon Glass37fdd142019-07-20 12:24:06 -06003393 def testReplaceCbfs(self):
3394 """Test replacing a single file in CBFS without changing the size"""
3395 self._CheckLz4()
3396 expected = b'x' * len(U_BOOT_DATA)
3397 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003398 updated_fname = tools.get_output_filename('image-updated.bin')
3399 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003400 entry_name = 'section/cbfs/u-boot'
3401 control.WriteEntry(updated_fname, entry_name, expected,
3402 allow_resize=True)
3403 data = control.ReadEntry(updated_fname, entry_name)
3404 self.assertEqual(expected, data)
3405
3406 def testReplaceResizeCbfs(self):
3407 """Test replacing a single file in CBFS with one of a different size"""
3408 self._CheckLz4()
3409 expected = U_BOOT_DATA + b'x'
3410 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003411 updated_fname = tools.get_output_filename('image-updated.bin')
3412 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003413 entry_name = 'section/cbfs/u-boot'
3414 control.WriteEntry(updated_fname, entry_name, expected,
3415 allow_resize=True)
3416 data = control.ReadEntry(updated_fname, entry_name)
3417 self.assertEqual(expected, data)
3418
Simon Glass30033c22019-07-20 12:24:15 -06003419 def _SetupForReplace(self):
3420 """Set up some files to use to replace entries
3421
3422 This generates an image, copies it to a new file, extracts all the files
3423 in it and updates some of them
3424
3425 Returns:
3426 List
3427 Image filename
3428 Output directory
3429 Expected values for updated entries, each a string
3430 """
3431 data = self._DoReadFileRealDtb('143_replace_all.dts')
3432
Simon Glass80025522022-01-29 14:14:04 -07003433 updated_fname = tools.get_output_filename('image-updated.bin')
3434 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003435
3436 outdir = os.path.join(self._indir, 'extract')
3437 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3438
3439 expected1 = b'x' + U_BOOT_DATA + b'y'
3440 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003441 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003442
3443 expected2 = b'a' + U_BOOT_DATA + b'b'
3444 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003445 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003446
3447 expected_text = b'not the same text'
3448 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003449 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003450
3451 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3452 dtb = fdt.FdtScan(dtb_fname)
3453 node = dtb.GetNode('/binman/text')
3454 node.AddString('my-property', 'the value')
3455 dtb.Sync(auto_resize=True)
3456 dtb.Flush()
3457
3458 return updated_fname, outdir, expected1, expected2, expected_text
3459
3460 def _CheckReplaceMultiple(self, entry_paths):
3461 """Handle replacing the contents of multiple entries
3462
3463 Args:
3464 entry_paths: List of entry paths to replace
3465
3466 Returns:
3467 List
3468 Dict of entries in the image:
3469 key: Entry name
3470 Value: Entry object
3471 Expected values for updated entries, each a string
3472 """
3473 updated_fname, outdir, expected1, expected2, expected_text = (
3474 self._SetupForReplace())
3475 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3476
3477 image = Image.FromFile(updated_fname)
3478 image.LoadData()
3479 return image.GetEntries(), expected1, expected2, expected_text
3480
3481 def testReplaceAll(self):
3482 """Test replacing the contents of all entries"""
3483 entries, expected1, expected2, expected_text = (
3484 self._CheckReplaceMultiple([]))
3485 data = entries['u-boot'].data
3486 self.assertEqual(expected1, data)
3487
3488 data = entries['u-boot2'].data
3489 self.assertEqual(expected2, data)
3490
3491 data = entries['text'].data
3492 self.assertEqual(expected_text, data)
3493
3494 # Check that the device tree is updated
3495 data = entries['u-boot-dtb'].data
3496 dtb = fdt.Fdt.FromData(data)
3497 dtb.Scan()
3498 node = dtb.GetNode('/binman/text')
3499 self.assertEqual('the value', node.props['my-property'].value)
3500
3501 def testReplaceSome(self):
3502 """Test replacing the contents of a few entries"""
3503 entries, expected1, expected2, expected_text = (
3504 self._CheckReplaceMultiple(['u-boot2', 'text']))
3505
3506 # This one should not change
3507 data = entries['u-boot'].data
3508 self.assertEqual(U_BOOT_DATA, data)
3509
3510 data = entries['u-boot2'].data
3511 self.assertEqual(expected2, data)
3512
3513 data = entries['text'].data
3514 self.assertEqual(expected_text, data)
3515
3516 def testReplaceCmd(self):
3517 """Test replacing a file fron an image on the command line"""
3518 self._DoReadFileRealDtb('143_replace_all.dts')
3519
3520 try:
3521 tmpdir, updated_fname = self._SetupImageInTmpdir()
3522
3523 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3524 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003525 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003526
3527 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003528 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003529 self.assertEqual(expected, data[:len(expected)])
3530 map_fname = os.path.join(tmpdir, 'image-updated.map')
3531 self.assertFalse(os.path.exists(map_fname))
3532 finally:
3533 shutil.rmtree(tmpdir)
3534
3535 def testReplaceCmdSome(self):
3536 """Test replacing some files fron an image on the command line"""
3537 updated_fname, outdir, expected1, expected2, expected_text = (
3538 self._SetupForReplace())
3539
3540 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3541 'u-boot2', 'text')
3542
Simon Glass80025522022-01-29 14:14:04 -07003543 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003544 image = Image.FromFile(updated_fname)
3545 image.LoadData()
3546 entries = image.GetEntries()
3547
3548 # This one should not change
3549 data = entries['u-boot'].data
3550 self.assertEqual(U_BOOT_DATA, data)
3551
3552 data = entries['u-boot2'].data
3553 self.assertEqual(expected2, data)
3554
3555 data = entries['text'].data
3556 self.assertEqual(expected_text, data)
3557
3558 def testReplaceMissing(self):
3559 """Test replacing entries where the file is missing"""
3560 updated_fname, outdir, expected1, expected2, expected_text = (
3561 self._SetupForReplace())
3562
3563 # Remove one of the files, to generate a warning
3564 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3565 os.remove(u_boot_fname1)
3566
3567 with test_util.capture_sys_output() as (stdout, stderr):
3568 control.ReplaceEntries(updated_fname, None, outdir, [])
3569 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003570 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003571
3572 def testReplaceCmdMap(self):
3573 """Test replacing a file fron an image on the command line"""
3574 self._DoReadFileRealDtb('143_replace_all.dts')
3575
3576 try:
3577 tmpdir, updated_fname = self._SetupImageInTmpdir()
3578
3579 fname = os.path.join(self._indir, 'update-u-boot.bin')
3580 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003581 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003582
3583 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3584 '-f', fname, '-m')
3585 map_fname = os.path.join(tmpdir, 'image-updated.map')
3586 self.assertTrue(os.path.exists(map_fname))
3587 finally:
3588 shutil.rmtree(tmpdir)
3589
3590 def testReplaceNoEntryPaths(self):
3591 """Test replacing an entry without an entry path"""
3592 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003593 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003594 with self.assertRaises(ValueError) as e:
3595 control.ReplaceEntries(image_fname, 'fname', None, [])
3596 self.assertIn('Must specify an entry path to read with -f',
3597 str(e.exception))
3598
3599 def testReplaceTooManyEntryPaths(self):
3600 """Test extracting some entries"""
3601 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003602 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003603 with self.assertRaises(ValueError) as e:
3604 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3605 self.assertIn('Must specify exactly one entry path to write with -f',
3606 str(e.exception))
3607
Simon Glass0b074d62019-08-24 07:22:48 -06003608 def testPackReset16(self):
3609 """Test that an image with an x86 reset16 region can be created"""
3610 data = self._DoReadFile('144_x86_reset16.dts')
3611 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3612
3613 def testPackReset16Spl(self):
3614 """Test that an image with an x86 reset16-spl region can be created"""
3615 data = self._DoReadFile('145_x86_reset16_spl.dts')
3616 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3617
3618 def testPackReset16Tpl(self):
3619 """Test that an image with an x86 reset16-tpl region can be created"""
3620 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3621 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3622
Simon Glass232f90c2019-08-24 07:22:50 -06003623 def testPackIntelFit(self):
3624 """Test that an image with an Intel FIT and pointer can be created"""
3625 data = self._DoReadFile('147_intel_fit.dts')
3626 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3627 fit = data[16:32];
3628 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3629 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3630
3631 image = control.images['image']
3632 entries = image.GetEntries()
3633 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3634 self.assertEqual(expected_ptr, ptr)
3635
3636 def testPackIntelFitMissing(self):
3637 """Test detection of a FIT pointer with not FIT region"""
3638 with self.assertRaises(ValueError) as e:
3639 self._DoReadFile('148_intel_fit_missing.dts')
3640 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3641 str(e.exception))
3642
Simon Glass72555fa2019-11-06 17:22:44 -07003643 def _CheckSymbolsTplSection(self, dts, expected_vals):
3644 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003645 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003646 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003647 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003648 self.assertEqual(expected1, data[:upto1])
3649
3650 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003651 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003652 self.assertEqual(expected2, data[upto1:upto2])
3653
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003654 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003655 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003656 self.assertEqual(expected3, data[upto2:upto3])
3657
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003658 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003659 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3660
3661 def testSymbolsTplSection(self):
3662 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3663 self._SetupSplElf('u_boot_binman_syms')
3664 self._SetupTplElf('u_boot_binman_syms')
3665 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003666 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003667
3668 def testSymbolsTplSectionX86(self):
3669 """Test binman can assign symbols in a section with end-at-4gb"""
3670 self._SetupSplElf('u_boot_binman_syms_x86')
3671 self._SetupTplElf('u_boot_binman_syms_x86')
3672 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003673 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003674 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003675
Simon Glass98c59572019-08-24 07:23:03 -06003676 def testPackX86RomIfwiSectiom(self):
3677 """Test that a section can be placed in an IFWI region"""
3678 self._SetupIfwi('fitimage.bin')
3679 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3680 self._CheckIfwi(data)
3681
Simon Glassba7985d2019-08-24 07:23:07 -06003682 def testPackFspM(self):
3683 """Test that an image with a FSP memory-init binary can be created"""
3684 data = self._DoReadFile('152_intel_fsp_m.dts')
3685 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3686
Simon Glass4d9086d2019-10-20 21:31:35 -06003687 def testPackFspS(self):
3688 """Test that an image with a FSP silicon-init binary can be created"""
3689 data = self._DoReadFile('153_intel_fsp_s.dts')
3690 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003691
Simon Glass9ea87b22019-10-20 21:31:36 -06003692 def testPackFspT(self):
3693 """Test that an image with a FSP temp-ram-init binary can be created"""
3694 data = self._DoReadFile('154_intel_fsp_t.dts')
3695 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3696
Simon Glass48f3aad2020-07-09 18:39:31 -06003697 def testMkimage(self):
3698 """Test using mkimage to build an image"""
3699 data = self._DoReadFile('156_mkimage.dts')
3700
3701 # Just check that the data appears in the file somewhere
3702 self.assertIn(U_BOOT_SPL_DATA, data)
3703
Simon Glass66152ce2022-01-09 20:14:09 -07003704 def testMkimageMissing(self):
3705 """Test that binman still produces an image if mkimage is missing"""
3706 with test_util.capture_sys_output() as (_, stderr):
3707 self._DoTestFile('156_mkimage.dts',
3708 force_missing_bintools='mkimage')
3709 err = stderr.getvalue()
3710 self.assertRegex(err,
3711 "Image 'main-section'.*missing bintools.*: mkimage")
3712
Simon Glass5e560182020-07-09 18:39:36 -06003713 def testExtblob(self):
3714 """Test an image with an external blob"""
3715 data = self._DoReadFile('157_blob_ext.dts')
3716 self.assertEqual(REFCODE_DATA, data)
3717
3718 def testExtblobMissing(self):
3719 """Test an image with a missing external blob"""
3720 with self.assertRaises(ValueError) as e:
3721 self._DoReadFile('158_blob_ext_missing.dts')
3722 self.assertIn("Filename 'missing-file' not found in input path",
3723 str(e.exception))
3724
Simon Glass5d94cc62020-07-09 18:39:38 -06003725 def testExtblobMissingOk(self):
3726 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003727 with test_util.capture_sys_output() as (stdout, stderr):
3728 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3729 err = stderr.getvalue()
3730 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3731
3732 def testExtblobMissingOkSect(self):
3733 """Test an image with an missing external blob that is allowed"""
3734 with test_util.capture_sys_output() as (stdout, stderr):
3735 self._DoTestFile('159_blob_ext_missing_sect.dts',
3736 allow_missing=True)
3737 err = stderr.getvalue()
3738 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3739 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003740
Simon Glasse88cef92020-07-09 18:39:41 -06003741 def testPackX86RomMeMissingDesc(self):
3742 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003743 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003744 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003745 err = stderr.getvalue()
3746 self.assertRegex(err,
3747 "Image 'main-section'.*missing.*: intel-descriptor")
3748
3749 def testPackX86RomMissingIfwi(self):
3750 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3751 self._SetupIfwi('fitimage.bin')
3752 pathname = os.path.join(self._indir, 'fitimage.bin')
3753 os.remove(pathname)
3754 with test_util.capture_sys_output() as (stdout, stderr):
3755 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3756 err = stderr.getvalue()
3757 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3758
Simon Glass2a0fa982022-02-11 13:23:21 -07003759 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003760 """Test that zero-size overlapping regions are ignored"""
3761 self._DoTestFile('160_pack_overlap_zero.dts')
3762
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003763 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003764 # The data should be inside the FIT
3765 dtb = fdt.Fdt.FromData(fit_data)
3766 dtb.Scan()
3767 fnode = dtb.GetNode('/images/kernel')
3768 self.assertIn('data', fnode.props)
3769
3770 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003771 tools.write_file(fname, fit_data)
3772 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003773
3774 # Check a few features to make sure the plumbing works. We don't need
3775 # to test the operation of mkimage or dumpimage here. First convert the
3776 # output into a dict where the keys are the fields printed by dumpimage
3777 # and the values are a list of values for each field
3778 lines = out.splitlines()
3779
3780 # Converts "Compression: gzip compressed" into two groups:
3781 # 'Compression' and 'gzip compressed'
3782 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3783 vals = collections.defaultdict(list)
3784 for line in lines:
3785 mat = re_line.match(line)
3786 vals[mat.group(1)].append(mat.group(2))
3787
3788 self.assertEquals('FIT description: test-desc', lines[0])
3789 self.assertIn('Created:', lines[1])
3790 self.assertIn('Image 0 (kernel)', vals)
3791 self.assertIn('Hash value', vals)
3792 data_sizes = vals.get('Data Size')
3793 self.assertIsNotNone(data_sizes)
3794 self.assertEqual(2, len(data_sizes))
3795 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003796 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3797 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3798
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003799 # Check if entry listing correctly omits /images/
3800 image = control.images['image']
3801 fit_entry = image.GetEntries()['fit']
3802 subentries = list(fit_entry.GetEntries().keys())
3803 expected = ['kernel', 'fdt-1']
3804 self.assertEqual(expected, subentries)
3805
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003806 def testSimpleFit(self):
3807 """Test an image with a FIT inside"""
3808 data = self._DoReadFile('161_fit.dts')
3809 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3810 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3811 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3812
3813 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3814
3815 def testSimpleFitExpandsSubentries(self):
3816 """Test that FIT images expand their subentries"""
3817 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3818 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3819 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3820 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3821
3822 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003823
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003824 def testSimpleFitImagePos(self):
3825 """Test that we have correct image-pos for FIT subentries"""
3826 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3827 update_dtb=True)
3828 dtb = fdt.Fdt(out_dtb_fname)
3829 dtb.Scan()
3830 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3831
Simon Glassb7bad182022-03-05 20:19:01 -07003832 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003833 self.assertEqual({
3834 'image-pos': 0,
3835 'offset': 0,
3836 'size': 1890,
3837
3838 'u-boot:image-pos': 0,
3839 'u-boot:offset': 0,
3840 'u-boot:size': 4,
3841
3842 'fit:image-pos': 4,
3843 'fit:offset': 4,
3844 'fit:size': 1840,
3845
Simon Glassb7bad182022-03-05 20:19:01 -07003846 'fit/images/kernel:image-pos': 304,
3847 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003848 'fit/images/kernel:size': 4,
3849
Simon Glassb7bad182022-03-05 20:19:01 -07003850 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003851 'fit/images/kernel/u-boot:offset': 0,
3852 'fit/images/kernel/u-boot:size': 4,
3853
Simon Glassb7bad182022-03-05 20:19:01 -07003854 'fit/images/fdt-1:image-pos': 552,
3855 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003856 'fit/images/fdt-1:size': 6,
3857
Simon Glassb7bad182022-03-05 20:19:01 -07003858 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003859 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3860 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3861
3862 'u-boot-nodtb:image-pos': 1844,
3863 'u-boot-nodtb:offset': 1844,
3864 'u-boot-nodtb:size': 46,
3865 }, props)
3866
3867 # Actually check the data is where we think it is
3868 for node, expected in [
3869 ("u-boot", U_BOOT_DATA),
3870 ("fit/images/kernel", U_BOOT_DATA),
3871 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3872 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3873 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3874 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3875 ]:
3876 image_pos = props[f"{node}:image-pos"]
3877 size = props[f"{node}:size"]
3878 self.assertEqual(len(expected), size)
3879 self.assertEqual(expected, data[image_pos:image_pos+size])
3880
Simon Glass45d556d2020-07-09 18:39:45 -06003881 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003882 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003883 data = self._DoReadFile('162_fit_external.dts')
3884 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3885
Simon Glass7932c882022-01-09 20:13:39 -07003886 # Size of the external-data region as set up by mkimage
3887 external_data_size = len(U_BOOT_DATA) + 2
3888 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003889 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003890 len(U_BOOT_NODTB_DATA))
3891
Simon Glass45d556d2020-07-09 18:39:45 -06003892 # The data should be outside the FIT
3893 dtb = fdt.Fdt.FromData(fit_data)
3894 dtb.Scan()
3895 fnode = dtb.GetNode('/images/kernel')
3896 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003897 self.assertEqual(len(U_BOOT_DATA),
3898 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3899 fit_pos = 0x400;
3900 self.assertEqual(
3901 fit_pos,
3902 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3903
3904 self.assertEquals(expected_size, len(data))
3905 actual_pos = len(U_BOOT_DATA) + fit_pos
3906 self.assertEqual(U_BOOT_DATA + b'aa',
3907 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003908
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003909 def testFitExternalImagePos(self):
3910 """Test that we have correct image-pos for external FIT subentries"""
3911 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3912 update_dtb=True)
3913 dtb = fdt.Fdt(out_dtb_fname)
3914 dtb.Scan()
3915 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3916
3917 self.assertEqual({
3918 'image-pos': 0,
3919 'offset': 0,
3920 'size': 1082,
3921
3922 'u-boot:image-pos': 0,
3923 'u-boot:offset': 0,
3924 'u-boot:size': 4,
3925
3926 'fit:size': 1032,
3927 'fit:offset': 4,
3928 'fit:image-pos': 4,
3929
3930 'fit/images/kernel:size': 4,
3931 'fit/images/kernel:offset': 1024,
3932 'fit/images/kernel:image-pos': 1028,
3933
3934 'fit/images/kernel/u-boot:size': 4,
3935 'fit/images/kernel/u-boot:offset': 0,
3936 'fit/images/kernel/u-boot:image-pos': 1028,
3937
3938 'fit/images/fdt-1:size': 2,
3939 'fit/images/fdt-1:offset': 1028,
3940 'fit/images/fdt-1:image-pos': 1032,
3941
3942 'fit/images/fdt-1/_testing:size': 2,
3943 'fit/images/fdt-1/_testing:offset': 0,
3944 'fit/images/fdt-1/_testing:image-pos': 1032,
3945
3946 'u-boot-nodtb:image-pos': 1036,
3947 'u-boot-nodtb:offset': 1036,
3948 'u-boot-nodtb:size': 46,
3949 }, props)
3950
3951 # Actually check the data is where we think it is
3952 for node, expected in [
3953 ("u-boot", U_BOOT_DATA),
3954 ("fit/images/kernel", U_BOOT_DATA),
3955 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3956 ("fit/images/fdt-1", b'aa'),
3957 ("fit/images/fdt-1/_testing", b'aa'),
3958 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3959 ]:
3960 image_pos = props[f"{node}:image-pos"]
3961 size = props[f"{node}:size"]
3962 self.assertEqual(len(expected), size)
3963 self.assertEqual(expected, data[image_pos:image_pos+size])
3964
Simon Glass66152ce2022-01-09 20:14:09 -07003965 def testFitMissing(self):
3966 """Test that binman still produces a FIT image if mkimage is missing"""
3967 with test_util.capture_sys_output() as (_, stderr):
3968 self._DoTestFile('162_fit_external.dts',
3969 force_missing_bintools='mkimage')
3970 err = stderr.getvalue()
3971 self.assertRegex(err,
3972 "Image 'main-section'.*missing bintools.*: mkimage")
3973
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003974 def testSectionIgnoreHashSignature(self):
3975 """Test that sections ignore hash, signature nodes for its data"""
3976 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3977 expected = (U_BOOT_DATA + U_BOOT_DATA)
3978 self.assertEqual(expected, data)
3979
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003980 def testPadInSections(self):
3981 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06003982 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3983 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07003984 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
3985 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003986 U_BOOT_DATA)
3987 self.assertEqual(expected, data)
3988
Simon Glassd12599d2020-10-26 17:40:09 -06003989 dtb = fdt.Fdt(out_dtb_fname)
3990 dtb.Scan()
3991 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3992 expected = {
3993 'image-pos': 0,
3994 'offset': 0,
3995 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3996
3997 'section:image-pos': 0,
3998 'section:offset': 0,
3999 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4000
4001 'section/before:image-pos': 0,
4002 'section/before:offset': 0,
4003 'section/before:size': len(U_BOOT_DATA),
4004
4005 'section/u-boot:image-pos': 4,
4006 'section/u-boot:offset': 4,
4007 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4008
4009 'section/after:image-pos': 26,
4010 'section/after:offset': 26,
4011 'section/after:size': len(U_BOOT_DATA),
4012 }
4013 self.assertEqual(expected, props)
4014
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004015 def testFitImageSubentryAlignment(self):
4016 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004017 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004018 entry_args = {
4019 'test-id': TEXT_DATA,
4020 }
4021 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4022 entry_args=entry_args)
4023 dtb = fdt.Fdt.FromData(data)
4024 dtb.Scan()
4025
4026 node = dtb.GetNode('/images/kernel')
4027 data = dtb.GetProps(node)["data"].bytes
4028 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004029 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4030 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004031 self.assertEqual(expected, data)
4032
4033 node = dtb.GetNode('/images/fdt-1')
4034 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004035 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4036 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004037 U_BOOT_DTB_DATA)
4038 self.assertEqual(expected, data)
4039
4040 def testFitExtblobMissingOk(self):
4041 """Test a FIT with a missing external blob that is allowed"""
4042 with test_util.capture_sys_output() as (stdout, stderr):
4043 self._DoTestFile('168_fit_missing_blob.dts',
4044 allow_missing=True)
4045 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06004046 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004047
Simon Glass21db0ff2020-09-01 05:13:54 -06004048 def testBlobNamedByArgMissing(self):
4049 """Test handling of a missing entry arg"""
4050 with self.assertRaises(ValueError) as e:
4051 self._DoReadFile('068_blob_named_by_arg.dts')
4052 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4053 str(e.exception))
4054
Simon Glass559c4de2020-09-01 05:13:58 -06004055 def testPackBl31(self):
4056 """Test that an image with an ATF BL31 binary can be created"""
4057 data = self._DoReadFile('169_atf_bl31.dts')
4058 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4059
Samuel Holland9d8cc632020-10-21 21:12:15 -05004060 def testPackScp(self):
4061 """Test that an image with an SCP binary can be created"""
4062 data = self._DoReadFile('172_scp.dts')
4063 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4064
Simon Glassa435cd12020-09-01 05:13:59 -06004065 def testFitFdt(self):
4066 """Test an image with an FIT with multiple FDT images"""
4067 def _CheckFdt(seq, expected_data):
4068 """Check the FDT nodes
4069
4070 Args:
4071 seq: Sequence number to check (0 or 1)
4072 expected_data: Expected contents of 'data' property
4073 """
4074 name = 'fdt-%d' % seq
4075 fnode = dtb.GetNode('/images/%s' % name)
4076 self.assertIsNotNone(fnode)
4077 self.assertEqual({'description','type', 'compression', 'data'},
4078 set(fnode.props.keys()))
4079 self.assertEqual(expected_data, fnode.props['data'].bytes)
4080 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4081 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004082 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004083
4084 def _CheckConfig(seq, expected_data):
4085 """Check the configuration nodes
4086
4087 Args:
4088 seq: Sequence number to check (0 or 1)
4089 expected_data: Expected contents of 'data' property
4090 """
4091 cnode = dtb.GetNode('/configurations')
4092 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004093 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004094
4095 name = 'config-%d' % seq
4096 fnode = dtb.GetNode('/configurations/%s' % name)
4097 self.assertIsNotNone(fnode)
4098 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4099 set(fnode.props.keys()))
4100 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4101 fnode.props['description'].value)
4102 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4103
4104 entry_args = {
4105 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004106 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004107 }
4108 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004109 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004110 entry_args=entry_args,
4111 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4112 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4113 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4114
4115 dtb = fdt.Fdt.FromData(fit_data)
4116 dtb.Scan()
4117 fnode = dtb.GetNode('/images/kernel')
4118 self.assertIn('data', fnode.props)
4119
4120 # Check all the properties in fdt-1 and fdt-2
4121 _CheckFdt(1, TEST_FDT1_DATA)
4122 _CheckFdt(2, TEST_FDT2_DATA)
4123
4124 # Check configurations
4125 _CheckConfig(1, TEST_FDT1_DATA)
4126 _CheckConfig(2, TEST_FDT2_DATA)
4127
4128 def testFitFdtMissingList(self):
4129 """Test handling of a missing 'of-list' entry arg"""
4130 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004131 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004132 self.assertIn("Generator node requires 'of-list' entry argument",
4133 str(e.exception))
4134
4135 def testFitFdtEmptyList(self):
4136 """Test handling of an empty 'of-list' entry arg"""
4137 entry_args = {
4138 'of-list': '',
4139 }
4140 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4141
4142 def testFitFdtMissingProp(self):
4143 """Test handling of a missing 'fit,fdt-list' property"""
4144 with self.assertRaises(ValueError) as e:
4145 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4146 self.assertIn("Generator node requires 'fit,fdt-list' property",
4147 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004148
Simon Glass1032acc2020-09-06 10:39:08 -06004149 def testFitFdtMissing(self):
4150 """Test handling of a missing 'default-dt' entry arg"""
4151 entry_args = {
4152 'of-list': 'test-fdt1 test-fdt2',
4153 }
4154 with self.assertRaises(ValueError) as e:
4155 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004156 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004157 entry_args=entry_args,
4158 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4159 self.assertIn("Generated 'default' node requires default-dt entry argument",
4160 str(e.exception))
4161
4162 def testFitFdtNotInList(self):
4163 """Test handling of a default-dt that is not in the of-list"""
4164 entry_args = {
4165 'of-list': 'test-fdt1 test-fdt2',
4166 'default-dt': 'test-fdt3',
4167 }
4168 with self.assertRaises(ValueError) as e:
4169 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004170 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004171 entry_args=entry_args,
4172 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4173 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4174 str(e.exception))
4175
Simon Glassa820af72020-09-06 10:39:09 -06004176 def testFitExtblobMissingHelp(self):
4177 """Test display of help messages when an external blob is missing"""
4178 control.missing_blob_help = control._ReadMissingBlobHelp()
4179 control.missing_blob_help['wibble'] = 'Wibble test'
4180 control.missing_blob_help['another'] = 'Another test'
4181 with test_util.capture_sys_output() as (stdout, stderr):
4182 self._DoTestFile('168_fit_missing_blob.dts',
4183 allow_missing=True)
4184 err = stderr.getvalue()
4185
4186 # We can get the tag from the name, the type or the missing-msg
4187 # property. Check all three.
4188 self.assertIn('You may need to build ARM Trusted', err)
4189 self.assertIn('Wibble test', err)
4190 self.assertIn('Another test', err)
4191
Simon Glass6f1f4d42020-09-06 10:35:32 -06004192 def testMissingBlob(self):
4193 """Test handling of a blob containing a missing file"""
4194 with self.assertRaises(ValueError) as e:
4195 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4196 self.assertIn("Filename 'missing' not found in input path",
4197 str(e.exception))
4198
Simon Glassa0729502020-09-06 10:35:33 -06004199 def testEnvironment(self):
4200 """Test adding a U-Boot environment"""
4201 data = self._DoReadFile('174_env.dts')
4202 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4203 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4204 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4205 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4206 env)
4207
4208 def testEnvironmentNoSize(self):
4209 """Test that a missing 'size' property is detected"""
4210 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004211 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004212 self.assertIn("'u-boot-env' entry must have a size property",
4213 str(e.exception))
4214
4215 def testEnvironmentTooSmall(self):
4216 """Test handling of an environment that does not fit"""
4217 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004218 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004219
4220 # checksum, start byte, environment with \0 terminator, final \0
4221 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4222 short = need - 0x8
4223 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4224 str(e.exception))
4225
Simon Glassd1fdf752020-10-26 17:40:01 -06004226 def testSkipAtStart(self):
4227 """Test handling of skip-at-start section"""
4228 data = self._DoReadFile('177_skip_at_start.dts')
4229 self.assertEqual(U_BOOT_DATA, data)
4230
4231 image = control.images['image']
4232 entries = image.GetEntries()
4233 section = entries['section']
4234 self.assertEqual(0, section.offset)
4235 self.assertEqual(len(U_BOOT_DATA), section.size)
4236 self.assertEqual(U_BOOT_DATA, section.GetData())
4237
4238 entry = section.GetEntries()['u-boot']
4239 self.assertEqual(16, entry.offset)
4240 self.assertEqual(len(U_BOOT_DATA), entry.size)
4241 self.assertEqual(U_BOOT_DATA, entry.data)
4242
4243 def testSkipAtStartPad(self):
4244 """Test handling of skip-at-start section with padded entry"""
4245 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004246 before = tools.get_bytes(0, 8)
4247 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004248 all = before + U_BOOT_DATA + after
4249 self.assertEqual(all, data)
4250
4251 image = control.images['image']
4252 entries = image.GetEntries()
4253 section = entries['section']
4254 self.assertEqual(0, section.offset)
4255 self.assertEqual(len(all), section.size)
4256 self.assertEqual(all, section.GetData())
4257
4258 entry = section.GetEntries()['u-boot']
4259 self.assertEqual(16, entry.offset)
4260 self.assertEqual(len(all), entry.size)
4261 self.assertEqual(U_BOOT_DATA, entry.data)
4262
4263 def testSkipAtStartSectionPad(self):
4264 """Test handling of skip-at-start section with padding"""
4265 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004266 before = tools.get_bytes(0, 8)
4267 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004268 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004269 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004270
4271 image = control.images['image']
4272 entries = image.GetEntries()
4273 section = entries['section']
4274 self.assertEqual(0, section.offset)
4275 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004276 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004277 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004278
4279 entry = section.GetEntries()['u-boot']
4280 self.assertEqual(16, entry.offset)
4281 self.assertEqual(len(U_BOOT_DATA), entry.size)
4282 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004283
Simon Glassbb395742020-10-26 17:40:14 -06004284 def testSectionPad(self):
4285 """Testing padding with sections"""
4286 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004287 expected = (tools.get_bytes(ord('&'), 3) +
4288 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004289 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004290 tools.get_bytes(ord('!'), 1) +
4291 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004292 self.assertEqual(expected, data)
4293
4294 def testSectionAlign(self):
4295 """Testing alignment with sections"""
4296 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4297 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004298 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004299 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004300 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004301 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004302 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4303 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004304 self.assertEqual(expected, data)
4305
Simon Glassd92c8362020-10-26 17:40:25 -06004306 def testCompressImage(self):
4307 """Test compression of the entire image"""
4308 self._CheckLz4()
4309 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4310 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4311 dtb = fdt.Fdt(out_dtb_fname)
4312 dtb.Scan()
4313 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4314 'uncomp-size'])
4315 orig = self._decompress(data)
4316 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4317
4318 # Do a sanity check on various fields
4319 image = control.images['image']
4320 entries = image.GetEntries()
4321 self.assertEqual(2, len(entries))
4322
4323 entry = entries['blob']
4324 self.assertEqual(COMPRESS_DATA, entry.data)
4325 self.assertEqual(len(COMPRESS_DATA), entry.size)
4326
4327 entry = entries['u-boot']
4328 self.assertEqual(U_BOOT_DATA, entry.data)
4329 self.assertEqual(len(U_BOOT_DATA), entry.size)
4330
4331 self.assertEqual(len(data), image.size)
4332 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4333 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4334 orig = self._decompress(image.data)
4335 self.assertEqual(orig, image.uncomp_data)
4336
4337 expected = {
4338 'blob:offset': 0,
4339 'blob:size': len(COMPRESS_DATA),
4340 'u-boot:offset': len(COMPRESS_DATA),
4341 'u-boot:size': len(U_BOOT_DATA),
4342 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4343 'offset': 0,
4344 'image-pos': 0,
4345 'size': len(data),
4346 }
4347 self.assertEqual(expected, props)
4348
4349 def testCompressImageLess(self):
4350 """Test compression where compression reduces the image size"""
4351 self._CheckLz4()
4352 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4353 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4354 dtb = fdt.Fdt(out_dtb_fname)
4355 dtb.Scan()
4356 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4357 'uncomp-size'])
4358 orig = self._decompress(data)
4359
4360 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4361
4362 # Do a sanity check on various fields
4363 image = control.images['image']
4364 entries = image.GetEntries()
4365 self.assertEqual(2, len(entries))
4366
4367 entry = entries['blob']
4368 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4369 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4370
4371 entry = entries['u-boot']
4372 self.assertEqual(U_BOOT_DATA, entry.data)
4373 self.assertEqual(len(U_BOOT_DATA), entry.size)
4374
4375 self.assertEqual(len(data), image.size)
4376 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4377 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4378 image.uncomp_size)
4379 orig = self._decompress(image.data)
4380 self.assertEqual(orig, image.uncomp_data)
4381
4382 expected = {
4383 'blob:offset': 0,
4384 'blob:size': len(COMPRESS_DATA_BIG),
4385 'u-boot:offset': len(COMPRESS_DATA_BIG),
4386 'u-boot:size': len(U_BOOT_DATA),
4387 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4388 'offset': 0,
4389 'image-pos': 0,
4390 'size': len(data),
4391 }
4392 self.assertEqual(expected, props)
4393
4394 def testCompressSectionSize(self):
4395 """Test compression of a section with a fixed size"""
4396 self._CheckLz4()
4397 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4398 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4399 dtb = fdt.Fdt(out_dtb_fname)
4400 dtb.Scan()
4401 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4402 'uncomp-size'])
4403 orig = self._decompress(data)
4404 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4405 expected = {
4406 'section/blob:offset': 0,
4407 'section/blob:size': len(COMPRESS_DATA),
4408 'section/u-boot:offset': len(COMPRESS_DATA),
4409 'section/u-boot:size': len(U_BOOT_DATA),
4410 'section:offset': 0,
4411 'section:image-pos': 0,
4412 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4413 'section:size': 0x30,
4414 'offset': 0,
4415 'image-pos': 0,
4416 'size': 0x30,
4417 }
4418 self.assertEqual(expected, props)
4419
4420 def testCompressSection(self):
4421 """Test compression of a section with no fixed size"""
4422 self._CheckLz4()
4423 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4424 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4425 dtb = fdt.Fdt(out_dtb_fname)
4426 dtb.Scan()
4427 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4428 'uncomp-size'])
4429 orig = self._decompress(data)
4430 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4431 expected = {
4432 'section/blob:offset': 0,
4433 'section/blob:size': len(COMPRESS_DATA),
4434 'section/u-boot:offset': len(COMPRESS_DATA),
4435 'section/u-boot:size': len(U_BOOT_DATA),
4436 'section:offset': 0,
4437 'section:image-pos': 0,
4438 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4439 'section:size': len(data),
4440 'offset': 0,
4441 'image-pos': 0,
4442 'size': len(data),
4443 }
4444 self.assertEqual(expected, props)
4445
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004446 def testLz4Missing(self):
4447 """Test that binman still produces an image if lz4 is missing"""
4448 with test_util.capture_sys_output() as (_, stderr):
4449 self._DoTestFile('185_compress_section.dts',
4450 force_missing_bintools='lz4')
4451 err = stderr.getvalue()
4452 self.assertRegex(err,
4453 "Image 'main-section'.*missing bintools.*: lz4")
4454
Simon Glassd92c8362020-10-26 17:40:25 -06004455 def testCompressExtra(self):
4456 """Test compression of a section with no fixed size"""
4457 self._CheckLz4()
4458 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4459 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4460 dtb = fdt.Fdt(out_dtb_fname)
4461 dtb.Scan()
4462 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4463 'uncomp-size'])
4464
4465 base = data[len(U_BOOT_DATA):]
4466 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4467 rest = base[len(U_BOOT_DATA):]
4468
4469 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004470 bintool = self.comp_bintools['lz4']
4471 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004472 data1 = rest[:len(expect1)]
4473 section1 = self._decompress(data1)
4474 self.assertEquals(expect1, data1)
Simon Glassd92c8362020-10-26 17:40:25 -06004475 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4476 rest1 = rest[len(expect1):]
4477
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004478 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004479 data2 = rest1[:len(expect2)]
4480 section2 = self._decompress(data2)
4481 self.assertEquals(expect2, data2)
Simon Glassd92c8362020-10-26 17:40:25 -06004482 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4483 rest2 = rest1[len(expect2):]
4484
4485 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4486 len(expect2) + len(U_BOOT_DATA))
4487 #self.assertEquals(expect_size, len(data))
4488
4489 #self.assertEquals(U_BOOT_DATA, rest2)
4490
4491 self.maxDiff = None
4492 expected = {
4493 'u-boot:offset': 0,
4494 'u-boot:image-pos': 0,
4495 'u-boot:size': len(U_BOOT_DATA),
4496
4497 'base:offset': len(U_BOOT_DATA),
4498 'base:image-pos': len(U_BOOT_DATA),
4499 'base:size': len(data) - len(U_BOOT_DATA),
4500 'base/u-boot:offset': 0,
4501 'base/u-boot:image-pos': len(U_BOOT_DATA),
4502 'base/u-boot:size': len(U_BOOT_DATA),
4503 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4504 len(expect2),
4505 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4506 len(expect2),
4507 'base/u-boot2:size': len(U_BOOT_DATA),
4508
4509 'base/section:offset': len(U_BOOT_DATA),
4510 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4511 'base/section:size': len(expect1),
4512 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4513 'base/section/blob:offset': 0,
4514 'base/section/blob:size': len(COMPRESS_DATA),
4515 'base/section/u-boot:offset': len(COMPRESS_DATA),
4516 'base/section/u-boot:size': len(U_BOOT_DATA),
4517
4518 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4519 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4520 'base/section2:size': len(expect2),
4521 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4522 'base/section2/blob:offset': 0,
4523 'base/section2/blob:size': len(COMPRESS_DATA),
4524 'base/section2/blob2:offset': len(COMPRESS_DATA),
4525 'base/section2/blob2:size': len(COMPRESS_DATA),
4526
4527 'offset': 0,
4528 'image-pos': 0,
4529 'size': len(data),
4530 }
4531 self.assertEqual(expected, props)
4532
Simon Glassecbe4732021-01-06 21:35:15 -07004533 def testSymbolsSubsection(self):
4534 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004535 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004536
Simon Glass3fb25402021-01-06 21:35:16 -07004537 def testReadImageEntryArg(self):
4538 """Test reading an image that would need an entry arg to generate"""
4539 entry_args = {
4540 'cros-ec-rw-path': 'ecrw.bin',
4541 }
4542 data = self.data = self._DoReadFileDtb(
4543 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4544 entry_args=entry_args)
4545
Simon Glass80025522022-01-29 14:14:04 -07004546 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004547 orig_image = control.images['image']
4548
4549 # This should not generate an error about the missing 'cros-ec-rw-path'
4550 # since we are reading the image from a file. Compare with
4551 # testEntryArgsRequired()
4552 image = Image.FromFile(image_fname)
4553 self.assertEqual(orig_image.GetEntries().keys(),
4554 image.GetEntries().keys())
4555
Simon Glassa2af7302021-01-06 21:35:18 -07004556 def testFilesAlign(self):
4557 """Test alignment with files"""
4558 data = self._DoReadFile('190_files_align.dts')
4559
4560 # The first string is 15 bytes so will align to 16
4561 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4562 self.assertEqual(expect, data)
4563
Simon Glassdb84b562021-01-06 21:35:19 -07004564 def testReadImageSkip(self):
4565 """Test reading an image and accessing its FDT map"""
4566 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004567 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004568 orig_image = control.images['image']
4569 image = Image.FromFile(image_fname)
4570 self.assertEqual(orig_image.GetEntries().keys(),
4571 image.GetEntries().keys())
4572
4573 orig_entry = orig_image.GetEntries()['fdtmap']
4574 entry = image.GetEntries()['fdtmap']
4575 self.assertEqual(orig_entry.offset, entry.offset)
4576 self.assertEqual(orig_entry.size, entry.size)
4577 self.assertEqual(16, entry.image_pos)
4578
4579 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4580
4581 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4582
Simon Glassc98de972021-03-18 20:24:57 +13004583 def testTplNoDtb(self):
4584 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004585 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004586 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4587 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4588 data[:len(U_BOOT_TPL_NODTB_DATA)])
4589
Simon Glass63f41d42021-03-18 20:24:58 +13004590 def testTplBssPad(self):
4591 """Test that we can pad TPL's BSS with zeros"""
4592 # ELF file with a '__bss_size' symbol
4593 self._SetupTplElf()
4594 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004595 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004596 data)
4597
4598 def testTplBssPadMissing(self):
4599 """Test that a missing symbol is detected"""
4600 self._SetupTplElf('u_boot_ucode_ptr')
4601 with self.assertRaises(ValueError) as e:
4602 self._DoReadFile('193_tpl_bss_pad.dts')
4603 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4604 str(e.exception))
4605
Simon Glass718b5292021-03-18 20:25:07 +13004606 def checkDtbSizes(self, data, pad_len, start):
4607 """Check the size arguments in a dtb embedded in an image
4608
4609 Args:
4610 data: The image data
4611 pad_len: Length of the pad section in the image, in bytes
4612 start: Start offset of the devicetree to examine, within the image
4613
4614 Returns:
4615 Size of the devicetree in bytes
4616 """
4617 dtb_data = data[start:]
4618 dtb = fdt.Fdt.FromData(dtb_data)
4619 fdt_size = dtb.GetFdtObj().totalsize()
4620 dtb.Scan()
4621 props = self._GetPropTree(dtb, 'size')
4622 self.assertEqual({
4623 'size': len(data),
4624 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4625 'u-boot-spl/u-boot-spl-dtb:size': 801,
4626 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4627 'u-boot-spl:size': 860,
4628 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4629 'u-boot/u-boot-dtb:size': 781,
4630 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4631 'u-boot:size': 827,
4632 }, props)
4633 return fdt_size
4634
4635 def testExpanded(self):
4636 """Test that an expanded entry type is selected when needed"""
4637 self._SetupSplElf()
4638 self._SetupTplElf()
4639
4640 # SPL has a devicetree, TPL does not
4641 entry_args = {
4642 'spl-dtb': '1',
4643 'spl-bss-pad': 'y',
4644 'tpl-dtb': '',
4645 }
4646 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4647 entry_args=entry_args)
4648 image = control.images['image']
4649 entries = image.GetEntries()
4650 self.assertEqual(3, len(entries))
4651
4652 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4653 self.assertIn('u-boot', entries)
4654 entry = entries['u-boot']
4655 self.assertEqual('u-boot-expanded', entry.etype)
4656 subent = entry.GetEntries()
4657 self.assertEqual(2, len(subent))
4658 self.assertIn('u-boot-nodtb', subent)
4659 self.assertIn('u-boot-dtb', subent)
4660
4661 # Second, u-boot-spl, which should be expanded into three parts
4662 self.assertIn('u-boot-spl', entries)
4663 entry = entries['u-boot-spl']
4664 self.assertEqual('u-boot-spl-expanded', entry.etype)
4665 subent = entry.GetEntries()
4666 self.assertEqual(3, len(subent))
4667 self.assertIn('u-boot-spl-nodtb', subent)
4668 self.assertIn('u-boot-spl-bss-pad', subent)
4669 self.assertIn('u-boot-spl-dtb', subent)
4670
4671 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4672 # devicetree
4673 self.assertIn('u-boot-tpl', entries)
4674 entry = entries['u-boot-tpl']
4675 self.assertEqual('u-boot-tpl', entry.etype)
4676 self.assertEqual(None, entry.GetEntries())
4677
4678 def testExpandedTpl(self):
4679 """Test that an expanded entry type is selected for TPL when needed"""
4680 self._SetupTplElf()
4681
4682 entry_args = {
4683 'tpl-bss-pad': 'y',
4684 'tpl-dtb': 'y',
4685 }
4686 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4687 entry_args=entry_args)
4688 image = control.images['image']
4689 entries = image.GetEntries()
4690 self.assertEqual(1, len(entries))
4691
4692 # We only have u-boot-tpl, which be expanded
4693 self.assertIn('u-boot-tpl', entries)
4694 entry = entries['u-boot-tpl']
4695 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4696 subent = entry.GetEntries()
4697 self.assertEqual(3, len(subent))
4698 self.assertIn('u-boot-tpl-nodtb', subent)
4699 self.assertIn('u-boot-tpl-bss-pad', subent)
4700 self.assertIn('u-boot-tpl-dtb', subent)
4701
4702 def testExpandedNoPad(self):
4703 """Test an expanded entry without BSS pad enabled"""
4704 self._SetupSplElf()
4705 self._SetupTplElf()
4706
4707 # SPL has a devicetree, TPL does not
4708 entry_args = {
4709 'spl-dtb': 'something',
4710 'spl-bss-pad': 'n',
4711 'tpl-dtb': '',
4712 }
4713 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4714 entry_args=entry_args)
4715 image = control.images['image']
4716 entries = image.GetEntries()
4717
4718 # Just check u-boot-spl, which should be expanded into two 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(2, len(subent))
4724 self.assertIn('u-boot-spl-nodtb', subent)
4725 self.assertIn('u-boot-spl-dtb', subent)
4726
4727 def testExpandedTplNoPad(self):
4728 """Test that an expanded entry type with padding disabled in TPL"""
4729 self._SetupTplElf()
4730
4731 entry_args = {
4732 'tpl-bss-pad': '',
4733 'tpl-dtb': 'y',
4734 }
4735 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4736 entry_args=entry_args)
4737 image = control.images['image']
4738 entries = image.GetEntries()
4739 self.assertEqual(1, len(entries))
4740
4741 # We only have u-boot-tpl, which be expanded
4742 self.assertIn('u-boot-tpl', entries)
4743 entry = entries['u-boot-tpl']
4744 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4745 subent = entry.GetEntries()
4746 self.assertEqual(2, len(subent))
4747 self.assertIn('u-boot-tpl-nodtb', subent)
4748 self.assertIn('u-boot-tpl-dtb', subent)
4749
4750 def testFdtInclude(self):
4751 """Test that an Fdt is update within all binaries"""
4752 self._SetupSplElf()
4753 self._SetupTplElf()
4754
4755 # SPL has a devicetree, TPL does not
4756 self.maxDiff = None
4757 entry_args = {
4758 'spl-dtb': '1',
4759 'spl-bss-pad': 'y',
4760 'tpl-dtb': '',
4761 }
4762 # Build the image. It includes two separate devicetree binaries, each
4763 # with their own contents, but all contain the binman definition.
4764 data = self._DoReadFileDtb(
4765 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4766 update_dtb=True, entry_args=entry_args)[0]
4767 pad_len = 10
4768
4769 # Check the U-Boot dtb
4770 start = len(U_BOOT_NODTB_DATA)
4771 fdt_size = self.checkDtbSizes(data, pad_len, start)
4772
4773 # Now check SPL
4774 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4775 fdt_size = self.checkDtbSizes(data, pad_len, start)
4776
4777 # TPL has no devicetree
4778 start += fdt_size + len(U_BOOT_TPL_DATA)
4779 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004780
Simon Glass7098b7f2021-03-21 18:24:30 +13004781 def testSymbolsExpanded(self):
4782 """Test binman can assign symbols in expanded entries"""
4783 entry_args = {
4784 'spl-dtb': '1',
4785 }
4786 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4787 U_BOOT_SPL_DTB_DATA, 0x38,
4788 entry_args=entry_args, use_expanded=True)
4789
Simon Glasse1915782021-03-21 18:24:31 +13004790 def testCollection(self):
4791 """Test a collection"""
4792 data = self._DoReadFile('198_collection.dts')
4793 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004794 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4795 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004796 data)
4797
Simon Glass27a7f772021-03-21 18:24:32 +13004798 def testCollectionSection(self):
4799 """Test a collection where a section must be built first"""
4800 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004801 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004802 # building the contents, producing an error is anything is still
4803 # missing.
4804 data = self._DoReadFile('199_collection_section.dts')
4805 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004806 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4807 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004808 data)
4809
Simon Glassf427c5f2021-03-21 18:24:33 +13004810 def testAlignDefault(self):
4811 """Test that default alignment works on sections"""
4812 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004813 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004814 U_BOOT_DATA)
4815 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004816 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004817 # No alignment within the nested section
4818 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4819 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004820 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004821 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004822
Bin Mengc0b15742021-05-10 20:23:33 +08004823 def testPackOpenSBI(self):
4824 """Test that an image with an OpenSBI binary can be created"""
4825 data = self._DoReadFile('201_opensbi.dts')
4826 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4827
Simon Glass76f496d2021-07-06 10:36:37 -06004828 def testSectionsSingleThread(self):
4829 """Test sections without multithreading"""
4830 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004831 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4832 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4833 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004834 self.assertEqual(expected, data)
4835
4836 def testThreadTimeout(self):
4837 """Test handling a thread that takes too long"""
4838 with self.assertRaises(ValueError) as e:
4839 self._DoTestFile('202_section_timeout.dts',
4840 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004841 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004842
Simon Glass748a1d42021-07-06 10:36:41 -06004843 def testTiming(self):
4844 """Test output of timing information"""
4845 data = self._DoReadFile('055_sections.dts')
4846 with test_util.capture_sys_output() as (stdout, stderr):
4847 state.TimingShow()
4848 self.assertIn('read:', stdout.getvalue())
4849 self.assertIn('compress:', stdout.getvalue())
4850
Simon Glassadfb8492021-11-03 21:09:18 -06004851 def testUpdateFdtInElf(self):
4852 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004853 if not elf.ELF_TOOLS:
4854 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004855 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4856 outfile = os.path.join(self._indir, 'u-boot.out')
4857 begin_sym = 'dtb_embed_begin'
4858 end_sym = 'dtb_embed_end'
4859 retcode = self._DoTestFile(
4860 '060_fdt_update.dts', update_dtb=True,
4861 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4862 self.assertEqual(0, retcode)
4863
4864 # Check that the output file does in fact contact a dtb with the binman
4865 # definition in the correct place
4866 syms = elf.GetSymbolFileOffset(infile,
4867 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004868 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004869 dtb_data = data[syms['dtb_embed_begin'].offset:
4870 syms['dtb_embed_end'].offset]
4871
4872 dtb = fdt.Fdt.FromData(dtb_data)
4873 dtb.Scan()
4874 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4875 self.assertEqual({
4876 'image-pos': 0,
4877 'offset': 0,
4878 '_testing:offset': 32,
4879 '_testing:size': 2,
4880 '_testing:image-pos': 32,
4881 'section@0/u-boot:offset': 0,
4882 'section@0/u-boot:size': len(U_BOOT_DATA),
4883 'section@0/u-boot:image-pos': 0,
4884 'section@0:offset': 0,
4885 'section@0:size': 16,
4886 'section@0:image-pos': 0,
4887
4888 'section@1/u-boot:offset': 0,
4889 'section@1/u-boot:size': len(U_BOOT_DATA),
4890 'section@1/u-boot:image-pos': 16,
4891 'section@1:offset': 16,
4892 'section@1:size': 16,
4893 'section@1:image-pos': 16,
4894 'size': 40
4895 }, props)
4896
4897 def testUpdateFdtInElfInvalid(self):
4898 """Test that invalid args are detected with --update-fdt-in-elf"""
4899 with self.assertRaises(ValueError) as e:
4900 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4901 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4902 str(e.exception))
4903
4904 def testUpdateFdtInElfNoSyms(self):
4905 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004906 if not elf.ELF_TOOLS:
4907 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004908 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4909 outfile = ''
4910 begin_sym = 'wrong_begin'
4911 end_sym = 'wrong_end'
4912 with self.assertRaises(ValueError) as e:
4913 self._DoTestFile(
4914 '060_fdt_update.dts',
4915 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4916 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4917 str(e.exception))
4918
4919 def testUpdateFdtInElfTooSmall(self):
4920 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004921 if not elf.ELF_TOOLS:
4922 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004923 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4924 outfile = os.path.join(self._indir, 'u-boot.out')
4925 begin_sym = 'dtb_embed_begin'
4926 end_sym = 'dtb_embed_end'
4927 with self.assertRaises(ValueError) as e:
4928 self._DoTestFile(
4929 '060_fdt_update.dts', update_dtb=True,
4930 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4931 self.assertRegex(
4932 str(e.exception),
4933 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4934
Simon Glass88e04da2021-11-23 11:03:42 -07004935 def testVersion(self):
4936 """Test we can get the binman version"""
4937 version = '(unreleased)'
4938 self.assertEqual(version, state.GetVersion(self._indir))
4939
4940 with self.assertRaises(SystemExit):
4941 with test_util.capture_sys_output() as (_, stderr):
4942 self._DoBinman('-V')
4943 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4944
4945 # Try running the tool too, just to be safe
4946 result = self._RunBinman('-V')
4947 self.assertEqual('Binman %s\n' % version, result.stderr)
4948
4949 # Set up a version file to make sure that works
4950 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07004951 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07004952 binary=False)
4953 self.assertEqual(version, state.GetVersion(self._indir))
4954
Simon Glass637958f2021-11-23 21:09:50 -07004955 def testAltFormat(self):
4956 """Test that alternative formats can be used to extract"""
4957 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4958
4959 try:
4960 tmpdir, updated_fname = self._SetupImageInTmpdir()
4961 with test_util.capture_sys_output() as (stdout, _):
4962 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4963 self.assertEqual(
4964 '''Flag (-F) Entry type Description
4965fdt fdtmap Extract the devicetree blob from the fdtmap
4966''',
4967 stdout.getvalue())
4968
4969 dtb = os.path.join(tmpdir, 'fdt.dtb')
4970 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4971 dtb, 'fdtmap')
4972
4973 # Check that we can read it and it can be scanning, meaning it does
4974 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07004975 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07004976 dtb = fdt.Fdt.FromData(data)
4977 dtb.Scan()
4978
4979 # Now check u-boot which has no alt_format
4980 fname = os.path.join(tmpdir, 'fdt.dtb')
4981 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4982 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07004983 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07004984 self.assertEqual(U_BOOT_DATA, data)
4985
4986 finally:
4987 shutil.rmtree(tmpdir)
4988
Simon Glass0b00ae62021-11-23 21:09:52 -07004989 def testExtblobList(self):
4990 """Test an image with an external blob list"""
4991 data = self._DoReadFile('215_blob_ext_list.dts')
4992 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4993
4994 def testExtblobListMissing(self):
4995 """Test an image with a missing external blob"""
4996 with self.assertRaises(ValueError) as e:
4997 self._DoReadFile('216_blob_ext_list_missing.dts')
4998 self.assertIn("Filename 'missing-file' not found in input path",
4999 str(e.exception))
5000
5001 def testExtblobListMissingOk(self):
5002 """Test an image with an missing external blob that is allowed"""
5003 with test_util.capture_sys_output() as (stdout, stderr):
5004 self._DoTestFile('216_blob_ext_list_missing.dts',
5005 allow_missing=True)
5006 err = stderr.getvalue()
5007 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
5008
Simon Glass3efb2972021-11-23 21:08:59 -07005009 def testFip(self):
5010 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5011 data = self._DoReadFile('203_fip.dts')
5012 hdr, fents = fip_util.decode_fip(data)
5013 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5014 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5015 self.assertEqual(0x123, hdr.flags)
5016
5017 self.assertEqual(2, len(fents))
5018
5019 fent = fents[0]
5020 self.assertEqual(
5021 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5022 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5023 self.assertEqual('soc-fw', fent.fip_type)
5024 self.assertEqual(0x88, fent.offset)
5025 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5026 self.assertEqual(0x123456789abcdef, fent.flags)
5027 self.assertEqual(ATF_BL31_DATA, fent.data)
5028 self.assertEqual(True, fent.valid)
5029
5030 fent = fents[1]
5031 self.assertEqual(
5032 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5033 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5034 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5035 self.assertEqual(0x8c, fent.offset)
5036 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5037 self.assertEqual(0, fent.flags)
5038 self.assertEqual(ATF_BL2U_DATA, fent.data)
5039 self.assertEqual(True, fent.valid)
5040
5041 def testFipOther(self):
5042 """Basic FIP with something that isn't a external blob"""
5043 data = self._DoReadFile('204_fip_other.dts')
5044 hdr, fents = fip_util.decode_fip(data)
5045
5046 self.assertEqual(2, len(fents))
5047 fent = fents[1]
5048 self.assertEqual('rot-cert', fent.fip_type)
5049 self.assertEqual(b'aa', fent.data)
5050
Simon Glass3efb2972021-11-23 21:08:59 -07005051 def testFipNoType(self):
5052 """FIP with an entry of an unknown type"""
5053 with self.assertRaises(ValueError) as e:
5054 self._DoReadFile('205_fip_no_type.dts')
5055 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5056 str(e.exception))
5057
5058 def testFipUuid(self):
5059 """Basic FIP with a manual uuid"""
5060 data = self._DoReadFile('206_fip_uuid.dts')
5061 hdr, fents = fip_util.decode_fip(data)
5062
5063 self.assertEqual(2, len(fents))
5064 fent = fents[1]
5065 self.assertEqual(None, fent.fip_type)
5066 self.assertEqual(
5067 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5068 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5069 fent.uuid)
5070 self.assertEqual(U_BOOT_DATA, fent.data)
5071
5072 def testFipLs(self):
5073 """Test listing a FIP"""
5074 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5075 hdr, fents = fip_util.decode_fip(data)
5076
5077 try:
5078 tmpdir, updated_fname = self._SetupImageInTmpdir()
5079 with test_util.capture_sys_output() as (stdout, stderr):
5080 self._DoBinman('ls', '-i', updated_fname)
5081 finally:
5082 shutil.rmtree(tmpdir)
5083 lines = stdout.getvalue().splitlines()
5084 expected = [
5085'Name Image-pos Size Entry-type Offset Uncomp-size',
5086'----------------------------------------------------------------',
5087'main-section 0 2d3 section 0',
5088' atf-fip 0 90 atf-fip 0',
5089' soc-fw 88 4 blob-ext 88',
5090' u-boot 8c 4 u-boot 8c',
5091' fdtmap 90 243 fdtmap 90',
5092]
5093 self.assertEqual(expected, lines)
5094
5095 image = control.images['image']
5096 entries = image.GetEntries()
5097 fdtmap = entries['fdtmap']
5098
5099 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5100 magic = fdtmap_data[:8]
5101 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005102 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005103
5104 fdt_data = fdtmap_data[16:]
5105 dtb = fdt.Fdt.FromData(fdt_data)
5106 dtb.Scan()
5107 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5108 self.assertEqual({
5109 'atf-fip/soc-fw:image-pos': 136,
5110 'atf-fip/soc-fw:offset': 136,
5111 'atf-fip/soc-fw:size': 4,
5112 'atf-fip/u-boot:image-pos': 140,
5113 'atf-fip/u-boot:offset': 140,
5114 'atf-fip/u-boot:size': 4,
5115 'atf-fip:image-pos': 0,
5116 'atf-fip:offset': 0,
5117 'atf-fip:size': 144,
5118 'image-pos': 0,
5119 'offset': 0,
5120 'fdtmap:image-pos': fdtmap.image_pos,
5121 'fdtmap:offset': fdtmap.offset,
5122 'fdtmap:size': len(fdtmap_data),
5123 'size': len(data),
5124 }, props)
5125
5126 def testFipExtractOneEntry(self):
5127 """Test extracting a single entry fron an FIP"""
5128 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005129 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005130 fname = os.path.join(self._indir, 'output.extact')
5131 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005132 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005133 self.assertEqual(U_BOOT_DATA, data)
5134
5135 def testFipReplace(self):
5136 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005137 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005138 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005139 updated_fname = tools.get_output_filename('image-updated.bin')
5140 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005141 entry_name = 'atf-fip/u-boot'
5142 control.WriteEntry(updated_fname, entry_name, expected,
5143 allow_resize=True)
5144 actual = control.ReadEntry(updated_fname, entry_name)
5145 self.assertEqual(expected, actual)
5146
Simon Glass80025522022-01-29 14:14:04 -07005147 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005148 hdr, fents = fip_util.decode_fip(new_data)
5149
5150 self.assertEqual(2, len(fents))
5151
5152 # Check that the FIP entry is updated
5153 fent = fents[1]
5154 self.assertEqual(0x8c, fent.offset)
5155 self.assertEqual(len(expected), fent.size)
5156 self.assertEqual(0, fent.flags)
5157 self.assertEqual(expected, fent.data)
5158 self.assertEqual(True, fent.valid)
5159
5160 def testFipMissing(self):
5161 with test_util.capture_sys_output() as (stdout, stderr):
5162 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5163 err = stderr.getvalue()
5164 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
5165
5166 def testFipSize(self):
5167 """Test a FIP with a size property"""
5168 data = self._DoReadFile('210_fip_size.dts')
5169 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5170 hdr, fents = fip_util.decode_fip(data)
5171 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5172 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5173
5174 self.assertEqual(1, len(fents))
5175
5176 fent = fents[0]
5177 self.assertEqual('soc-fw', fent.fip_type)
5178 self.assertEqual(0x60, fent.offset)
5179 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5180 self.assertEqual(ATF_BL31_DATA, fent.data)
5181 self.assertEqual(True, fent.valid)
5182
5183 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005184 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005185
5186 def testFipBadAlign(self):
5187 """Test that an invalid alignment value in a FIP is detected"""
5188 with self.assertRaises(ValueError) as e:
5189 self._DoTestFile('211_fip_bad_align.dts')
5190 self.assertIn(
5191 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5192 str(e.exception))
5193
5194 def testFipCollection(self):
5195 """Test using a FIP in a collection"""
5196 data = self._DoReadFile('212_fip_collection.dts')
5197 entry1 = control.images['image'].GetEntries()['collection']
5198 data1 = data[:entry1.size]
5199 hdr1, fents2 = fip_util.decode_fip(data1)
5200
5201 entry2 = control.images['image'].GetEntries()['atf-fip']
5202 data2 = data[entry2.offset:entry2.offset + entry2.size]
5203 hdr1, fents2 = fip_util.decode_fip(data2)
5204
5205 # The 'collection' entry should have U-Boot included at the end
5206 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5207 self.assertEqual(data1, data2 + U_BOOT_DATA)
5208 self.assertEqual(U_BOOT_DATA, data1[-4:])
5209
5210 # There should be a U-Boot after the final FIP
5211 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005212
Simon Glassccae6862022-01-12 13:10:35 -07005213 def testFakeBlob(self):
5214 """Test handling of faking an external blob"""
5215 with test_util.capture_sys_output() as (stdout, stderr):
5216 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5217 allow_fake_blobs=True)
5218 err = stderr.getvalue()
5219 self.assertRegex(
5220 err,
5221 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005222
Simon Glassceb5f912022-01-09 20:13:46 -07005223 def testExtblobListFaked(self):
5224 """Test an extblob with missing external blob that are faked"""
5225 with test_util.capture_sys_output() as (stdout, stderr):
5226 self._DoTestFile('216_blob_ext_list_missing.dts',
5227 allow_fake_blobs=True)
5228 err = stderr.getvalue()
5229 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
5230
Simon Glass162017b2022-01-09 20:13:57 -07005231 def testListBintools(self):
5232 args = ['tool', '--list']
5233 with test_util.capture_sys_output() as (stdout, _):
5234 self._DoBinman(*args)
5235 out = stdout.getvalue().splitlines()
5236 self.assertTrue(len(out) >= 2)
5237
5238 def testFetchBintools(self):
5239 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005240 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005241 raise urllib.error.URLError('my error')
5242
5243 args = ['tool']
5244 with self.assertRaises(ValueError) as e:
5245 self._DoBinman(*args)
5246 self.assertIn("Invalid arguments to 'tool' subcommand",
5247 str(e.exception))
5248
5249 args = ['tool', '--fetch']
5250 with self.assertRaises(ValueError) as e:
5251 self._DoBinman(*args)
5252 self.assertIn('Please specify bintools to fetch', str(e.exception))
5253
5254 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005255 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005256 side_effect=fail_download):
5257 with test_util.capture_sys_output() as (stdout, _):
5258 self._DoBinman(*args)
5259 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5260
Simon Glass620c4462022-01-09 20:14:11 -07005261 def testBintoolDocs(self):
5262 """Test for creation of bintool documentation"""
5263 with test_util.capture_sys_output() as (stdout, stderr):
5264 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5265 self.assertTrue(len(stdout.getvalue()) > 0)
5266
5267 def testBintoolDocsMissing(self):
5268 """Test handling of missing bintool documentation"""
5269 with self.assertRaises(ValueError) as e:
5270 with test_util.capture_sys_output() as (stdout, stderr):
5271 control.write_bintool_docs(
5272 control.bintool.Bintool.get_tool_list(), 'mkimage')
5273 self.assertIn('Documentation is missing for modules: mkimage',
5274 str(e.exception))
5275
Jan Kiszka58c407f2022-01-28 20:37:53 +01005276 def testListWithGenNode(self):
5277 """Check handling of an FDT map when the section cannot be found"""
5278 entry_args = {
5279 'of-list': 'test-fdt1 test-fdt2',
5280 }
5281 data = self._DoReadFileDtb(
5282 '219_fit_gennode.dts',
5283 entry_args=entry_args,
5284 use_real_dtb=True,
5285 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5286
5287 try:
5288 tmpdir, updated_fname = self._SetupImageInTmpdir()
5289 with test_util.capture_sys_output() as (stdout, stderr):
5290 self._RunBinman('ls', '-i', updated_fname)
5291 finally:
5292 shutil.rmtree(tmpdir)
5293
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005294 def testFitSubentryUsesBintool(self):
5295 """Test that binman FIT subentries can use bintools"""
5296 command.test_result = self._HandleGbbCommand
5297 entry_args = {
5298 'keydir': 'devkeys',
5299 'bmpblk': 'bmpblk.bin',
5300 }
5301 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5302 entry_args=entry_args)
5303
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005304 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5305 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005306 self.assertIn(expected, data)
5307
5308 def testFitSubentryMissingBintool(self):
5309 """Test that binman reports missing bintools for FIT subentries"""
5310 entry_args = {
5311 'keydir': 'devkeys',
5312 }
5313 with test_util.capture_sys_output() as (_, stderr):
5314 self._DoTestFile('220_fit_subentry_bintool.dts',
5315 force_missing_bintools='futility', entry_args=entry_args)
5316 err = stderr.getvalue()
5317 self.assertRegex(err,
5318 "Image 'main-section'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005319
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005320 def testFitSubentryHashSubnode(self):
5321 """Test an image with a FIT inside"""
5322 data, _, _, out_dtb_name = self._DoReadFileDtb(
5323 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5324
5325 mkimage_dtb = fdt.Fdt.FromData(data)
5326 mkimage_dtb.Scan()
5327 binman_dtb = fdt.Fdt(out_dtb_name)
5328 binman_dtb.Scan()
5329
5330 # Check that binman didn't add hash values
5331 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5332 self.assertNotIn('value', fnode.props)
5333
5334 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5335 self.assertNotIn('value', fnode.props)
5336
5337 # Check that mkimage added hash values
5338 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5339 self.assertIn('value', fnode.props)
5340
5341 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5342 self.assertIn('value', fnode.props)
5343
Roger Quadros5cdcea02022-02-19 20:50:04 +02005344 def testPackTeeOs(self):
5345 """Test that an image with an TEE binary can be created"""
5346 data = self._DoReadFile('222_tee_os.dts')
5347 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5348
Simon Glass912339f2022-02-08 11:50:03 -07005349 def testFitFdtOper(self):
5350 """Check handling of a specified FIT operation"""
5351 entry_args = {
5352 'of-list': 'test-fdt1 test-fdt2',
5353 'default-dt': 'test-fdt2',
5354 }
5355 self._DoReadFileDtb(
5356 '223_fit_fdt_oper.dts',
5357 entry_args=entry_args,
5358 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5359
5360 def testFitFdtBadOper(self):
5361 """Check handling of an FDT map when the section cannot be found"""
5362 with self.assertRaises(ValueError) as exc:
5363 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005364 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005365 str(exc.exception))
5366
Simon Glassdd156a42022-03-05 20:18:59 -07005367 def test_uses_expand_size(self):
5368 """Test that the 'expand-size' property cannot be used anymore"""
5369 with self.assertRaises(ValueError) as e:
5370 data = self._DoReadFile('225_expand_size_bad.dts')
5371 self.assertIn(
5372 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5373 str(e.exception))
5374
Simon Glass5f423422022-03-05 20:19:12 -07005375 def testFitSplitElf(self):
5376 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005377 if not elf.ELF_TOOLS:
5378 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005379 entry_args = {
5380 'of-list': 'test-fdt1 test-fdt2',
5381 'default-dt': 'test-fdt2',
5382 'atf-bl31-path': 'bl31.elf',
5383 'tee-os-path': 'tee.elf',
5384 }
5385 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5386 data = self._DoReadFileDtb(
5387 '226_fit_split_elf.dts',
5388 entry_args=entry_args,
5389 extra_indirs=[test_subdir])[0]
5390
5391 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5392 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5393
5394 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5395 'data', 'load'}
5396 dtb = fdt.Fdt.FromData(fit_data)
5397 dtb.Scan()
5398
5399 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5400 segments, entry = elf.read_loadable_segments(elf_data)
5401
5402 # We assume there are two segments
5403 self.assertEquals(2, len(segments))
5404
5405 atf1 = dtb.GetNode('/images/atf-1')
5406 _, start, data = segments[0]
5407 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5408 self.assertEqual(entry,
5409 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5410 self.assertEqual(start,
5411 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5412 self.assertEqual(data, atf1.props['data'].bytes)
5413
5414 atf2 = dtb.GetNode('/images/atf-2')
5415 self.assertEqual(base_keys, atf2.props.keys())
5416 _, start, data = segments[1]
5417 self.assertEqual(start,
5418 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5419 self.assertEqual(data, atf2.props['data'].bytes)
5420
5421 conf = dtb.GetNode('/configurations')
5422 self.assertEqual({'default'}, conf.props.keys())
5423
5424 for subnode in conf.subnodes:
5425 self.assertEqual({'description', 'fdt', 'loadables'},
5426 subnode.props.keys())
5427 self.assertEqual(
5428 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5429 fdt_util.GetStringList(subnode, 'loadables'))
5430
5431 def _check_bad_fit(self, dts):
5432 """Check a bad FIT
5433
5434 This runs with the given dts and returns the assertion raised
5435
5436 Args:
5437 dts (str): dts filename to use
5438
5439 Returns:
5440 str: Assertion string raised
5441 """
5442 entry_args = {
5443 'of-list': 'test-fdt1 test-fdt2',
5444 'default-dt': 'test-fdt2',
5445 'atf-bl31-path': 'bl31.elf',
5446 'tee-os-path': 'tee.elf',
5447 }
5448 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5449 with self.assertRaises(ValueError) as exc:
5450 self._DoReadFileDtb(dts, entry_args=entry_args,
5451 extra_indirs=[test_subdir])[0]
5452 return str(exc.exception)
5453
5454 def testFitSplitElfBadElf(self):
5455 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005456 if not elf.ELF_TOOLS:
5457 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005458 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5459 entry_args = {
5460 'of-list': 'test-fdt1 test-fdt2',
5461 'default-dt': 'test-fdt2',
5462 'atf-bl31-path': 'bad.elf',
5463 'tee-os-path': 'tee.elf',
5464 }
5465 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5466 with self.assertRaises(ValueError) as exc:
5467 self._DoReadFileDtb(
5468 '226_fit_split_elf.dts',
5469 entry_args=entry_args,
5470 extra_indirs=[test_subdir])[0]
5471 self.assertIn(
5472 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5473 str(exc.exception))
5474
Simon Glass5f423422022-03-05 20:19:12 -07005475 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005476 """Test an split-elf FIT with a missing ELF file
5477
5478 Args:
5479 kwargs (dict of str): Arguments to pass to _DoTestFile()
5480
5481 Returns:
5482 tuple:
5483 str: stdout result
5484 str: stderr result
5485 """
Simon Glass5f423422022-03-05 20:19:12 -07005486 entry_args = {
5487 'of-list': 'test-fdt1 test-fdt2',
5488 'default-dt': 'test-fdt2',
5489 'atf-bl31-path': 'bl31.elf',
5490 'tee-os-path': 'missing.elf',
5491 }
5492 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5493 with test_util.capture_sys_output() as (stdout, stderr):
5494 self._DoTestFile(
5495 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005496 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5497 out = stdout.getvalue()
5498 err = stderr.getvalue()
5499 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005500
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005501 def testFitSplitElfBadDirective(self):
5502 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5503 if not elf.ELF_TOOLS:
5504 self.skipTest('Python elftools not available')
5505 err = self._check_bad_fit('227_fit_bad_dir.dts')
5506 self.assertIn(
5507 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5508 err)
5509
5510 def testFitSplitElfBadDirectiveConfig(self):
5511 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5512 if not elf.ELF_TOOLS:
5513 self.skipTest('Python elftools not available')
5514 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5515 self.assertEqual(
5516 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5517 err)
5518
5519
Simon Glass5f423422022-03-05 20:19:12 -07005520 def testFitSplitElfMissing(self):
5521 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005522 if not elf.ELF_TOOLS:
5523 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005524 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005525 self.assertRegex(
5526 err,
5527 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005528 self.assertNotRegex(out, '.*Faked blob.*')
5529 fname = tools.get_output_filename('binman-fake/missing.elf')
5530 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005531
5532 def testFitSplitElfFaked(self):
5533 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005534 if not elf.ELF_TOOLS:
5535 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005536 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005537 self.assertRegex(
5538 err,
5539 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005540 self.assertRegex(
5541 out,
5542 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5543 fname = tools.get_output_filename('binman-fake/missing.elf')
5544 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005545
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005546 def testMkimageMissingBlob(self):
5547 """Test using mkimage to build an image"""
5548 with test_util.capture_sys_output() as (stdout, stderr):
5549 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5550 allow_fake_blobs=True)
5551 err = stderr.getvalue()
5552 self.assertRegex(
5553 err,
5554 "Image '.*' has faked external blobs and is non-functional: .*")
5555
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005556 def testPreLoad(self):
5557 """Test an image with a pre-load header"""
5558 entry_args = {
5559 'pre-load-key-path': '.',
5560 }
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005561 data, _, _, _ = self._DoReadFileDtb('230_pre_load.dts',
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005562 entry_args=entry_args)
5563 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5564 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5565 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005566 data = self._DoReadFile('230_pre_load.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005567 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5568 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5569 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5570
5571 def testPreLoadPkcs(self):
5572 """Test an image with a pre-load header with padding pkcs"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005573 data = self._DoReadFile('231_pre_load_pkcs.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005574 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5575 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5576 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5577
5578 def testPreLoadPss(self):
5579 """Test an image with a pre-load header with padding pss"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005580 data = self._DoReadFile('232_pre_load_pss.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005581 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5582 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5583 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5584
5585 def testPreLoadInvalidPadding(self):
5586 """Test an image with a pre-load header with an invalid padding"""
5587 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005588 data = self._DoReadFile('233_pre_load_invalid_padding.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005589
5590 def testPreLoadInvalidSha(self):
5591 """Test an image with a pre-load header with an invalid hash"""
5592 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005593 data = self._DoReadFile('234_pre_load_invalid_sha.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005594
5595 def testPreLoadInvalidAlgo(self):
5596 """Test an image with a pre-load header with an invalid algo"""
5597 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005598 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005599
5600 def testPreLoadInvalidKey(self):
5601 """Test an image with a pre-load header with an invalid key"""
5602 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005603 data = self._DoReadFile('236_pre_load_invalid_key.dts')
Roger Quadros5cdcea02022-02-19 20:50:04 +02005604
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005605 def _CheckSafeUniqueNames(self, *images):
5606 """Check all entries of given images for unsafe unique names"""
5607 for image in images:
5608 entries = {}
5609 image._CollectEntries(entries, {}, image)
5610 for entry in entries.values():
5611 uniq = entry.GetUniqueName()
5612
5613 # Used as part of a filename, so must not be absolute paths.
5614 self.assertFalse(os.path.isabs(uniq))
5615
5616 def testSafeUniqueNames(self):
5617 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005618 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005619
5620 orig_image = control.images['image']
5621 image_fname = tools.get_output_filename('image.bin')
5622 image = Image.FromFile(image_fname)
5623
5624 self._CheckSafeUniqueNames(orig_image, image)
5625
5626 def testSafeUniqueNamesMulti(self):
5627 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005628 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005629
5630 orig_image = control.images['image']
5631 image_fname = tools.get_output_filename('image.bin')
5632 image = Image.FromFile(image_fname)
5633
5634 self._CheckSafeUniqueNames(orig_image, image)
5635
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005636 def testReplaceCmdWithBintool(self):
5637 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005638 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005639 expected = U_BOOT_DATA + b'aa'
5640 self.assertEqual(expected, data[:len(expected)])
5641
5642 try:
5643 tmpdir, updated_fname = self._SetupImageInTmpdir()
5644 fname = os.path.join(tmpdir, 'update-testing.bin')
5645 tools.write_file(fname, b'zz')
5646 self._DoBinman('replace', '-i', updated_fname,
5647 '_testing', '-f', fname)
5648
5649 data = tools.read_file(updated_fname)
5650 expected = U_BOOT_DATA + b'zz'
5651 self.assertEqual(expected, data[:len(expected)])
5652 finally:
5653 shutil.rmtree(tmpdir)
5654
5655 def testReplaceCmdOtherWithBintool(self):
5656 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005657 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005658 expected = U_BOOT_DATA + b'aa'
5659 self.assertEqual(expected, data[:len(expected)])
5660
5661 try:
5662 tmpdir, updated_fname = self._SetupImageInTmpdir()
5663 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5664 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5665 self._DoBinman('replace', '-i', updated_fname,
5666 'u-boot', '-f', fname)
5667
5668 data = tools.read_file(updated_fname)
5669 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5670 self.assertEqual(expected, data[:len(expected)])
5671 finally:
5672 shutil.rmtree(tmpdir)
5673
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005674 def testReplaceResizeNoRepackSameSize(self):
5675 """Test replacing entries with same-size data without repacking"""
5676 expected = b'x' * len(U_BOOT_DATA)
5677 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5678 self.assertEqual(expected, data)
5679
5680 path, fdtmap = state.GetFdtContents('fdtmap')
5681 self.assertIsNotNone(path)
5682 self.assertEqual(expected_fdtmap, fdtmap)
5683
5684 def testReplaceResizeNoRepackSmallerSize(self):
5685 """Test replacing entries with smaller-size data without repacking"""
5686 new_data = b'x'
5687 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5688 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5689 self.assertEqual(expected, data)
5690
5691 path, fdtmap = state.GetFdtContents('fdtmap')
5692 self.assertIsNotNone(path)
5693 self.assertEqual(expected_fdtmap, fdtmap)
5694
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005695 def testExtractFit(self):
5696 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005697 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005698 image_fname = tools.get_output_filename('image.bin')
5699
5700 fit_data = control.ReadEntry(image_fname, 'fit')
5701 fit = fdt.Fdt.FromData(fit_data)
5702 fit.Scan()
5703
5704 # Check subentry data inside the extracted fit
5705 for node_path, expected in [
5706 ('/images/kernel', U_BOOT_DATA),
5707 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5708 ('/images/scr-1', COMPRESS_DATA),
5709 ]:
5710 node = fit.GetNode(node_path)
5711 data = fit.GetProps(node)['data'].bytes
5712 self.assertEqual(expected, data)
5713
5714 def testExtractFitSubentries(self):
5715 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005716 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005717 image_fname = tools.get_output_filename('image.bin')
5718
5719 for entry_path, expected in [
5720 ('fit/kernel', U_BOOT_DATA),
5721 ('fit/kernel/u-boot', U_BOOT_DATA),
5722 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5723 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5724 ('fit/scr-1', COMPRESS_DATA),
5725 ('fit/scr-1/blob', COMPRESS_DATA),
5726 ]:
5727 data = control.ReadEntry(image_fname, entry_path)
5728 self.assertEqual(expected, data)
5729
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005730 def testReplaceFitSubentryLeafSameSize(self):
5731 """Test replacing a FIT leaf subentry with same-size data"""
5732 new_data = b'x' * len(U_BOOT_DATA)
5733 data, expected_fdtmap, _ = self._RunReplaceCmd(
5734 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005735 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005736 self.assertEqual(new_data, data)
5737
5738 path, fdtmap = state.GetFdtContents('fdtmap')
5739 self.assertIsNotNone(path)
5740 self.assertEqual(expected_fdtmap, fdtmap)
5741
5742 def testReplaceFitSubentryLeafBiggerSize(self):
5743 """Test replacing a FIT leaf subentry with bigger-size data"""
5744 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5745 data, expected_fdtmap, _ = self._RunReplaceCmd(
5746 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005747 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005748 self.assertEqual(new_data, data)
5749
5750 # Will be repacked, so fdtmap must change
5751 path, fdtmap = state.GetFdtContents('fdtmap')
5752 self.assertIsNotNone(path)
5753 self.assertNotEqual(expected_fdtmap, fdtmap)
5754
5755 def testReplaceFitSubentryLeafSmallerSize(self):
5756 """Test replacing a FIT leaf subentry with smaller-size data"""
5757 new_data = b'x'
5758 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5759 data, expected_fdtmap, _ = self._RunReplaceCmd(
5760 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005761 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005762 self.assertEqual(expected, data)
5763
5764 path, fdtmap = state.GetFdtContents('fdtmap')
5765 self.assertIsNotNone(path)
5766 self.assertEqual(expected_fdtmap, fdtmap)
5767
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005768 def testReplaceSectionSimple(self):
5769 """Test replacing a simple section with arbitrary data"""
5770 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glassc6b283f2022-08-13 11:40:46 -06005771 with self.assertRaises(ValueError) as exc:
5772 self._RunReplaceCmd('section', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005773 dts='241_replace_section_simple.dts')
Simon Glassc6b283f2022-08-13 11:40:46 -06005774 self.assertIn(
5775 "Node '/section': Replacing sections is not implemented yet",
5776 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005777
Simon Glass8fbca772022-08-13 11:40:48 -06005778 def testMkimageImagename(self):
5779 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005780 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005781
5782 # Check that the data appears in the file somewhere
5783 self.assertIn(U_BOOT_SPL_DATA, data)
5784
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005785 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005786 name = data[0x20:0x40]
5787
5788 # Build the filename that we expect to be placed in there, by virtue of
5789 # the -n paraameter
5790 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5791
5792 # Check that the image name is set to the temporary filename used
5793 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5794
Simon Glassb1669752022-08-13 11:40:49 -06005795 def testMkimageImage(self):
5796 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005797 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005798
5799 # Check that the data appears in the file somewhere
5800 self.assertIn(U_BOOT_SPL_DATA, data)
5801
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005802 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06005803 name = data[0x20:0x40]
5804
5805 # Build the filename that we expect to be placed in there, by virtue of
5806 # the -n paraameter
5807 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5808
5809 # Check that the image name is set to the temporary filename used
5810 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5811
5812 # Check the corect data is in the imagename file
5813 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5814
5815 def testMkimageImageNoContent(self):
5816 """Test using mkimage with -n and no data"""
5817 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005818 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005819 self.assertIn('Could not complete processing of contents',
5820 str(exc.exception))
5821
5822 def testMkimageImageBad(self):
5823 """Test using mkimage with imagename node and data-to-imagename"""
5824 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005825 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005826 self.assertIn('Cannot use both imagename node and data-to-imagename',
5827 str(exc.exception))
5828
Simon Glassbd5cd882022-08-13 11:40:50 -06005829 def testCollectionOther(self):
5830 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005831 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005832 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5833 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5834 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5835 data)
5836
5837 def testMkimageCollection(self):
5838 """Test using a collection referring to an entry in a mkimage entry"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005839 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005840 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5841 self.assertEqual(expect, data[:len(expect)])
5842
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005843 def testCompressDtbPrependInvalid(self):
5844 """Test that invalid header is detected"""
5845 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005846 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005847 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5848 "'u-boot-dtb': 'invalid'", str(e.exception))
5849
5850 def testCompressDtbPrependLength(self):
5851 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005852 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005853 image = control.images['image']
5854 entries = image.GetEntries()
5855 self.assertIn('u-boot-dtb', entries)
5856 u_boot_dtb = entries['u-boot-dtb']
5857 self.assertIn('fdtmap', entries)
5858 fdtmap = entries['fdtmap']
5859
5860 image_fname = tools.get_output_filename('image.bin')
5861 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
5862 dtb = fdt.Fdt.FromData(orig)
5863 dtb.Scan()
5864 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
5865 expected = {
5866 'u-boot:size': len(U_BOOT_DATA),
5867 'u-boot-dtb:uncomp-size': len(orig),
5868 'u-boot-dtb:size': u_boot_dtb.size,
5869 'fdtmap:size': fdtmap.size,
5870 'size': len(data),
5871 }
5872 self.assertEqual(expected, props)
5873
5874 # Check implementation
5875 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
5876 rest = data[len(U_BOOT_DATA):]
5877 comp_data_len = struct.unpack('<I', rest[:4])[0]
5878 comp_data = rest[4:4 + comp_data_len]
5879 orig2 = self._decompress(comp_data)
5880 self.assertEqual(orig, orig2)
5881
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02005882 def testInvalidCompress(self):
5883 """Test that invalid compress algorithm is detected"""
5884 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005885 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02005886 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5887
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02005888 def testCompUtilCompressions(self):
5889 """Test compression algorithms"""
5890 for bintool in self.comp_bintools.values():
5891 self._CheckBintool(bintool)
5892 data = bintool.compress(COMPRESS_DATA)
5893 self.assertNotEqual(COMPRESS_DATA, data)
5894 orig = bintool.decompress(data)
5895 self.assertEquals(COMPRESS_DATA, orig)
5896
5897 def testCompUtilVersions(self):
5898 """Test tool version of compression algorithms"""
5899 for bintool in self.comp_bintools.values():
5900 self._CheckBintool(bintool)
5901 version = bintool.version()
5902 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
5903
5904 def testCompUtilPadding(self):
5905 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02005906 # Skip zstd because it doesn't support padding
5907 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02005908 self._CheckBintool(bintool)
5909 data = bintool.compress(COMPRESS_DATA)
5910 self.assertNotEqual(COMPRESS_DATA, data)
5911 data += tools.get_bytes(0, 64)
5912 orig = bintool.decompress(data)
5913 self.assertEquals(COMPRESS_DATA, orig)
5914
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02005915 def testCompressDtbZstd(self):
5916 """Test that zstd compress of device-tree files failed"""
5917 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005918 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02005919 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
5920 "requires a length header", str(e.exception))
5921
Quentin Schulz9b5c6482022-09-02 15:10:48 +02005922 def testMkimageMultipleDataFiles(self):
5923 """Test passing multiple files to mkimage in a mkimage entry"""
5924 data = self._DoReadFile('252_mkimage_mult_data.dts')
5925 # Size of files are packed in their 4B big-endian format
5926 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
5927 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
5928 # Size info is always followed by a 4B zero value.
5929 expect += tools.get_bytes(0, 4)
5930 expect += U_BOOT_TPL_DATA
5931 # All but last files are 4B-aligned
5932 align_pad = len(U_BOOT_TPL_DATA) % 4
5933 if align_pad:
5934 expect += tools.get_bytes(0, align_pad)
5935 expect += U_BOOT_SPL_DATA
5936 self.assertEqual(expect, data[-len(expect):])
5937
5938 def testMkimageMultipleNoContent(self):
5939 """Test passing multiple data files to mkimage with one data file having no content"""
5940 with self.assertRaises(ValueError) as exc:
5941 self._DoReadFile('253_mkimage_mult_no_content.dts')
5942 self.assertIn('Could not complete processing of contents',
5943 str(exc.exception))
5944
Quentin Schulz0d3a9262022-09-02 15:10:49 +02005945 def testMkimageFilename(self):
5946 """Test using mkimage to build a binary with a filename"""
5947 retcode = self._DoTestFile('254_mkimage_filename.dts')
5948 self.assertEqual(0, retcode)
5949 fname = tools.get_output_filename('mkimage-test.bin')
5950 self.assertTrue(os.path.exists(fname))
5951
Simon Glass56d05412022-02-28 07:16:54 -07005952 def testVpl(self):
5953 """Test that an image with VPL and its device tree can be created"""
5954 # ELF file with a '__bss_size' symbol
5955 self._SetupVplElf()
5956 data = self._DoReadFile('255_u_boot_vpl.dts')
5957 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
5958
5959 def testVplNoDtb(self):
5960 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
5961 self._SetupVplElf()
5962 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
5963 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
5964 data[:len(U_BOOT_VPL_NODTB_DATA)])
5965
5966 def testExpandedVpl(self):
5967 """Test that an expanded entry type is selected for TPL when needed"""
5968 self._SetupVplElf()
5969
5970 entry_args = {
5971 'vpl-bss-pad': 'y',
5972 'vpl-dtb': 'y',
5973 }
5974 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
5975 entry_args=entry_args)
5976 image = control.images['image']
5977 entries = image.GetEntries()
5978 self.assertEqual(1, len(entries))
5979
5980 # We only have u-boot-vpl, which be expanded
5981 self.assertIn('u-boot-vpl', entries)
5982 entry = entries['u-boot-vpl']
5983 self.assertEqual('u-boot-vpl-expanded', entry.etype)
5984 subent = entry.GetEntries()
5985 self.assertEqual(3, len(subent))
5986 self.assertIn('u-boot-vpl-nodtb', subent)
5987 self.assertIn('u-boot-vpl-bss-pad', subent)
5988 self.assertIn('u-boot-vpl-dtb', subent)
5989
5990 def testVplBssPadMissing(self):
5991 """Test that a missing symbol is detected"""
5992 self._SetupVplElf('u_boot_ucode_ptr')
5993 with self.assertRaises(ValueError) as e:
5994 self._DoReadFile('258_vpl_bss_pad.dts')
5995 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
5996 str(e.exception))
5997
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005998
Simon Glassac599912017-11-12 21:52:22 -07005999if __name__ == "__main__":
6000 unittest.main()