blob: 62ee86b9b75e349d895724ea0e46e049a622afeb [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,
Simon Glass6bce5dc2022-11-09 19:14:42 -0700343 force_missing_bintools='', ignore_missing=False):
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')
Simon Glass6bce5dc2022-11-09 19:14:42 -0700406 if ignore_missing:
407 args.append('-W')
Heiko Thiery6d451362022-01-06 11:49:41 +0100408 if allow_fake_blobs:
409 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700410 if force_missing_bintools:
411 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600412 if update_fdt_in_elf:
413 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600414 if images:
415 for image in images:
416 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600417 if extra_indirs:
418 for indir in extra_indirs:
419 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700420 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700421
422 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700423 """Set up a new test device-tree file
424
425 The given file is compiled and set up as the device tree to be used
426 for ths test.
427
428 Args:
429 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600430 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700431
432 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600433 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700434 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600435 tmpdir = tempfile.mkdtemp(prefix='binmant.')
436 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600437 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700438 data = fd.read()
439 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600440 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600441 return data
Simon Glass57454f42016-11-25 20:15:52 -0700442
Simon Glass56d05412022-02-28 07:16:54 -0700443 def _GetDtbContentsForSpls(self, dtb_data, name):
444 """Create a version of the main DTB for SPL / TPL / VPL
Simon Glasse219aa42018-09-14 04:57:24 -0600445
446 For testing we don't actually have different versions of the DTB. With
447 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
448 we don't normally have any unwanted nodes.
449
450 We still want the DTBs for SPL and TPL to be different though, since
451 otherwise it is confusing to know which one we are looking at. So add
452 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600453
454 Args:
455 dtb_data: dtb data to modify (this should be a value devicetree)
456 name: Name of a new property to add
457
458 Returns:
459 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600460 """
461 dtb = fdt.Fdt.FromData(dtb_data)
462 dtb.Scan()
463 dtb.GetNode('/binman').AddZeroProp(name)
464 dtb.Sync(auto_resize=True)
465 dtb.Pack()
466 return dtb.GetContents()
467
Simon Glassed930672021-03-18 20:25:05 +1300468 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
469 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600470 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700471 """Run binman and return the resulting image
472
473 This runs binman with a given test file and then reads the resulting
474 output file. It is a shortcut function since most tests need to do
475 these steps.
476
477 Raises an assertion failure if binman returns a non-zero exit code.
478
479 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600480 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700481 use_real_dtb: True to use the test file as the contents of
482 the u-boot-dtb entry. Normally this is not needed and the
483 test contents (the U_BOOT_DTB_DATA string) can be used.
484 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300485 use_expanded: True to use expanded entries where available, e.g.
486 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600487 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600488 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600489 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600490 entry_args: Dict of entry args to supply to binman
491 key: arg name
492 value: value of that arg
493 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
494 function. If reset_dtbs is True, then the original test dtb
495 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600496 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600497 threads: Number of threads to use (None for default, 0 for
498 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700499
500 Returns:
501 Tuple:
502 Resulting image contents
503 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600504 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600505 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700506 """
Simon Glass72232452016-11-25 20:15:53 -0700507 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700508 # Use the compiled test file as the u-boot-dtb input
509 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700510 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600511
512 # For testing purposes, make a copy of the DT for SPL and TPL. Add
513 # a node indicating which it is, so aid verification.
Simon Glass56d05412022-02-28 07:16:54 -0700514 for name in ['spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -0600515 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
516 outfile = os.path.join(self._indir, dtb_fname)
517 TestFunctional._MakeInputFile(dtb_fname,
Simon Glass56d05412022-02-28 07:16:54 -0700518 self._GetDtbContentsForSpls(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700519
520 try:
Simon Glass91710b32018-07-17 13:25:32 -0600521 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600522 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600523 use_expanded=use_expanded, extra_indirs=extra_indirs,
524 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700525 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700526 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700527
528 # Find the (only) image, read it and return its contents
529 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700530 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600531 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600532 if map:
Simon Glass80025522022-01-29 14:14:04 -0700533 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600534 with open(map_fname) as fd:
535 map_data = fd.read()
536 else:
537 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600538 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600539 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700540 finally:
541 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600542 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600543 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700544
Simon Glass5b4bce32019-07-08 14:25:26 -0600545 def _DoReadFileRealDtb(self, fname):
546 """Run binman with a real .dtb file and return the resulting data
547
548 Args:
549 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
550
551 Returns:
552 Resulting image contents
553 """
554 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
555
Simon Glass72232452016-11-25 20:15:53 -0700556 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600557 """Helper function which discards the device-tree binary
558
559 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600560 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600561 use_real_dtb: True to use the test file as the contents of
562 the u-boot-dtb entry. Normally this is not needed and the
563 test contents (the U_BOOT_DTB_DATA string) can be used.
564 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600565
566 Returns:
567 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600568 """
Simon Glass72232452016-11-25 20:15:53 -0700569 return self._DoReadFileDtb(fname, use_real_dtb)[0]
570
Simon Glass57454f42016-11-25 20:15:52 -0700571 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600572 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700573 """Create a new test input file, creating directories as needed
574
575 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600576 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700577 contents: File contents to write in to the file
578 Returns:
579 Full pathname of file created
580 """
Simon Glass862f8e22019-08-24 07:22:43 -0600581 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700582 dirname = os.path.dirname(pathname)
583 if dirname and not os.path.exists(dirname):
584 os.makedirs(dirname)
585 with open(pathname, 'wb') as fd:
586 fd.write(contents)
587 return pathname
588
589 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600590 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600591 """Create a new test input directory, creating directories as needed
592
593 Args:
594 dirname: Directory name to create
595
596 Returns:
597 Full pathname of directory created
598 """
Simon Glass862f8e22019-08-24 07:22:43 -0600599 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600600 if not os.path.exists(pathname):
601 os.makedirs(pathname)
602 return pathname
603
604 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600605 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600606 """Set up an ELF file with a '_dt_ucode_base_size' symbol
607
608 Args:
609 Filename of ELF file to use as SPL
610 """
Simon Glass93a806f2019-08-24 07:22:59 -0600611 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700612 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600613
614 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600615 def _SetupTplElf(cls, src_fname='bss_data'):
616 """Set up an ELF file with a '_dt_ucode_base_size' symbol
617
618 Args:
619 Filename of ELF file to use as TPL
620 """
621 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700622 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600623
624 @classmethod
Simon Glass56d05412022-02-28 07:16:54 -0700625 def _SetupVplElf(cls, src_fname='bss_data'):
626 """Set up an ELF file with a '_dt_ucode_base_size' symbol
627
628 Args:
629 Filename of ELF file to use as VPL
630 """
631 TestFunctional._MakeInputFile('vpl/u-boot-vpl',
632 tools.read_file(cls.ElfTestFile(src_fname)))
633
634 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600635 def _SetupDescriptor(cls):
636 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
637 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
638
639 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600640 def TestFile(cls, fname):
641 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700642
Simon Glassf6290892019-08-24 07:22:53 -0600643 @classmethod
644 def ElfTestFile(cls, fname):
645 return os.path.join(cls._elf_testdir, fname)
646
Simon Glass57454f42016-11-25 20:15:52 -0700647 def AssertInList(self, grep_list, target):
648 """Assert that at least one of a list of things is in a target
649
650 Args:
651 grep_list: List of strings to check
652 target: Target string
653 """
654 for grep in grep_list:
655 if grep in target:
656 return
Simon Glass848cdb52019-05-17 22:00:50 -0600657 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700658
659 def CheckNoGaps(self, entries):
660 """Check that all entries fit together without gaps
661
662 Args:
663 entries: List of entries to check
664 """
Simon Glasse8561af2018-08-01 15:22:37 -0600665 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700666 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600667 self.assertEqual(offset, entry.offset)
668 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700669
Simon Glass72232452016-11-25 20:15:53 -0700670 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600671 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700672
673 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600674 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700675
676 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600677 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700678 """
679 return struct.unpack('>L', dtb[4:8])[0]
680
Simon Glass0f621332019-07-08 14:25:27 -0600681 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600682 def AddNode(node, path):
683 if node.name != '/':
684 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600685 for prop in node.props.values():
686 if prop.name in prop_names:
687 prop_path = path + ':' + prop.name
688 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
689 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600690 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600691 AddNode(subnode, path)
692
693 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600694 AddNode(dtb.GetRoot(), '')
695 return tree
696
Simon Glass57454f42016-11-25 20:15:52 -0700697 def testRun(self):
698 """Test a basic run with valid args"""
699 result = self._RunBinman('-h')
700
701 def testFullHelp(self):
702 """Test that the full help is displayed with -H"""
703 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300704 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500705 # Remove possible extraneous strings
706 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
707 gothelp = result.stdout.replace(extra, '')
708 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700709 self.assertEqual(0, len(result.stderr))
710 self.assertEqual(0, result.return_code)
711
712 def testFullHelpInternal(self):
713 """Test that the full help is displayed with -H"""
714 try:
715 command.test_result = command.CommandResult()
716 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300717 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700718 finally:
719 command.test_result = None
720
721 def testHelp(self):
722 """Test that the basic help is displayed with -h"""
723 result = self._RunBinman('-h')
724 self.assertTrue(len(result.stdout) > 200)
725 self.assertEqual(0, len(result.stderr))
726 self.assertEqual(0, result.return_code)
727
Simon Glass57454f42016-11-25 20:15:52 -0700728 def testBoard(self):
729 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600730 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700731 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300732 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700733 self.assertEqual(0, result)
734
735 def testNeedBoard(self):
736 """Test that we get an error when no board ius supplied"""
737 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600738 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700739 self.assertIn("Must provide a board to process (use -b <board>)",
740 str(e.exception))
741
742 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600743 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700744 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600745 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700746 # We get one error from libfdt, and a different one from fdtget.
747 self.AssertInList(["Couldn't open blob from 'missing_file'",
748 'No such file or directory'], str(e.exception))
749
750 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600751 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700752
753 Since this is a source file it should be compiled and the error
754 will come from the device-tree compiler (dtc).
755 """
756 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600757 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700758 self.assertIn("FATAL ERROR: Unable to parse input tree",
759 str(e.exception))
760
761 def testMissingNode(self):
762 """Test that a device tree without a 'binman' node generates an error"""
763 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600764 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700765 self.assertIn("does not have a 'binman' node", str(e.exception))
766
767 def testEmpty(self):
768 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600769 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700770 self.assertEqual(0, len(result.stderr))
771 self.assertEqual(0, result.return_code)
772
773 def testInvalidEntry(self):
774 """Test that an invalid entry is flagged"""
775 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600776 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600777 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700778 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
779 "'/binman/not-a-valid-type'", str(e.exception))
780
781 def testSimple(self):
782 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600783 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700784 self.assertEqual(U_BOOT_DATA, data)
785
Simon Glass075a45c2017-11-13 18:55:00 -0700786 def testSimpleDebug(self):
787 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600788 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700789
Simon Glass57454f42016-11-25 20:15:52 -0700790 def testDual(self):
791 """Test that we can handle creating two images
792
793 This also tests image padding.
794 """
Simon Glass511f6582018-10-01 12:22:30 -0600795 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700796 self.assertEqual(0, retcode)
797
798 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600799 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700800 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700801 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600802 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700803 data = fd.read()
804 self.assertEqual(U_BOOT_DATA, data)
805
806 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600807 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700808 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700809 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600810 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700811 data = fd.read()
812 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700813 self.assertEqual(tools.get_bytes(0, 3), data[:3])
814 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700815
816 def testBadAlign(self):
817 """Test that an invalid alignment value is detected"""
818 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600819 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700820 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
821 "of two", str(e.exception))
822
823 def testPackSimple(self):
824 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600825 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700826 self.assertEqual(0, retcode)
827 self.assertIn('image', control.images)
828 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600829 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700830 self.assertEqual(5, len(entries))
831
832 # First u-boot
833 self.assertIn('u-boot', entries)
834 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600835 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700836 self.assertEqual(len(U_BOOT_DATA), entry.size)
837
838 # Second u-boot, aligned to 16-byte boundary
839 self.assertIn('u-boot-align', entries)
840 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600841 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700842 self.assertEqual(len(U_BOOT_DATA), entry.size)
843
844 # Third u-boot, size 23 bytes
845 self.assertIn('u-boot-size', entries)
846 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600847 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700848 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
849 self.assertEqual(23, entry.size)
850
851 # Fourth u-boot, placed immediate after the above
852 self.assertIn('u-boot-next', entries)
853 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600854 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700855 self.assertEqual(len(U_BOOT_DATA), entry.size)
856
Simon Glasse8561af2018-08-01 15:22:37 -0600857 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700858 self.assertIn('u-boot-fixed', entries)
859 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600860 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700861 self.assertEqual(len(U_BOOT_DATA), entry.size)
862
Simon Glass39dd2152019-07-08 14:25:47 -0600863 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700864
865 def testPackExtra(self):
866 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600867 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
868 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700869
Simon Glass57454f42016-11-25 20:15:52 -0700870 self.assertIn('image', control.images)
871 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600872 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700873 self.assertEqual(5, len(entries))
874
875 # First u-boot with padding before and after
876 self.assertIn('u-boot', entries)
877 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600878 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700879 self.assertEqual(3, entry.pad_before)
880 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600881 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700882 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
883 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600884 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700885
886 # Second u-boot has an aligned size, but it has no effect
887 self.assertIn('u-boot-align-size-nop', entries)
888 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600889 self.assertEqual(pos, entry.offset)
890 self.assertEqual(len(U_BOOT_DATA), entry.size)
891 self.assertEqual(U_BOOT_DATA, entry.data)
892 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
893 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700894
895 # Third u-boot has an aligned size too
896 self.assertIn('u-boot-align-size', entries)
897 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600898 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700899 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600900 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700901 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600902 data[pos:pos + entry.size])
903 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700904
905 # Fourth u-boot has an aligned end
906 self.assertIn('u-boot-align-end', entries)
907 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600908 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700909 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600910 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700911 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600912 data[pos:pos + entry.size])
913 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700914
915 # Fifth u-boot immediately afterwards
916 self.assertIn('u-boot-align-both', entries)
917 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600918 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700919 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600920 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700921 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600922 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700923
924 self.CheckNoGaps(entries)
Simon Glass39dd2152019-07-08 14:25:47 -0600925 self.assertEqual(128, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700926
Simon Glassafb9caa2020-10-26 17:40:10 -0600927 dtb = fdt.Fdt(out_dtb_fname)
928 dtb.Scan()
929 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
930 expected = {
931 'image-pos': 0,
932 'offset': 0,
933 'size': 128,
934
935 'u-boot:image-pos': 0,
936 'u-boot:offset': 0,
937 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
938
939 'u-boot-align-size-nop:image-pos': 12,
940 'u-boot-align-size-nop:offset': 12,
941 'u-boot-align-size-nop:size': 4,
942
943 'u-boot-align-size:image-pos': 16,
944 'u-boot-align-size:offset': 16,
945 'u-boot-align-size:size': 32,
946
947 'u-boot-align-end:image-pos': 48,
948 'u-boot-align-end:offset': 48,
949 'u-boot-align-end:size': 16,
950
951 'u-boot-align-both:image-pos': 64,
952 'u-boot-align-both:offset': 64,
953 'u-boot-align-both:size': 64,
954 }
955 self.assertEqual(expected, props)
956
Simon Glass57454f42016-11-25 20:15:52 -0700957 def testPackAlignPowerOf2(self):
958 """Test that invalid entry alignment is detected"""
959 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600960 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700961 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
962 "of two", str(e.exception))
963
964 def testPackAlignSizePowerOf2(self):
965 """Test that invalid entry size alignment is detected"""
966 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600967 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700968 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
969 "power of two", str(e.exception))
970
971 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600972 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700973 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600974 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600975 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700976 "align 0x4 (4)", str(e.exception))
977
978 def testPackInvalidSizeAlign(self):
979 """Test that invalid entry size alignment is detected"""
980 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600981 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700982 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
983 "align-size 0x4 (4)", str(e.exception))
984
985 def testPackOverlap(self):
986 """Test that overlapping regions are detected"""
987 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600988 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600989 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700990 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
991 str(e.exception))
992
993 def testPackEntryOverflow(self):
994 """Test that entries that overflow their size are detected"""
995 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600996 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700997 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
998 "but entry size is 0x3 (3)", str(e.exception))
999
1000 def testPackImageOverflow(self):
1001 """Test that entries which overflow the image size are detected"""
1002 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001003 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001004 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -07001005 "size 0x3 (3)", str(e.exception))
1006
1007 def testPackImageSize(self):
1008 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -06001009 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001010 self.assertEqual(0, retcode)
1011 self.assertIn('image', control.images)
1012 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001013 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001014
1015 def testPackImageSizeAlign(self):
1016 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -06001017 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001018 self.assertEqual(0, retcode)
1019 self.assertIn('image', control.images)
1020 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -06001021 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -07001022
1023 def testPackInvalidImageAlign(self):
1024 """Test that invalid image alignment is detected"""
1025 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001026 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001027 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001028 "align-size 0x8 (8)", str(e.exception))
1029
Simon Glass2a0fa982022-02-11 13:23:21 -07001030 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001031 """Test that invalid image alignment is detected"""
1032 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001033 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001034 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001035 "two", str(e.exception))
1036
1037 def testImagePadByte(self):
1038 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001039 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001040 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001041 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001042 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001043
1044 def testImageName(self):
1045 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001046 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001047 self.assertEqual(0, retcode)
1048 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001049 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001050 self.assertTrue(os.path.exists(fname))
1051
1052 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001053 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001054 self.assertTrue(os.path.exists(fname))
1055
1056 def testBlobFilename(self):
1057 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001058 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001059 self.assertEqual(BLOB_DATA, data)
1060
1061 def testPackSorted(self):
1062 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001063 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001064 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001065 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1066 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001067
Simon Glasse8561af2018-08-01 15:22:37 -06001068 def testPackZeroOffset(self):
1069 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -07001070 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001071 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001072 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001073 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1074 str(e.exception))
1075
1076 def testPackUbootDtb(self):
1077 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001078 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001079 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001080
1081 def testPackX86RomNoSize(self):
1082 """Test that the end-at-4gb property requires a size property"""
1083 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001084 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001085 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001086 "using end-at-4gb", str(e.exception))
1087
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301088 def test4gbAndSkipAtStartTogether(self):
1089 """Test that the end-at-4gb and skip-at-size property can't be used
1090 together"""
1091 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001092 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001093 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301094 "'skip-at-start'", str(e.exception))
1095
Simon Glass72232452016-11-25 20:15:53 -07001096 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001097 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -07001098 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001099 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001100 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1101 "is outside the section '/binman' starting at "
1102 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001103 str(e.exception))
1104
1105 def testPackX86Rom(self):
1106 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001107 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001108 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001109 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1110 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001111
1112 def testPackX86RomMeNoDesc(self):
1113 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001114 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001115 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001116 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001117 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001118 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1119 str(e.exception))
1120 finally:
1121 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001122
1123 def testPackX86RomBadDesc(self):
1124 """Test that the Intel requires a descriptor entry"""
1125 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001126 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001127 self.assertIn("Node '/binman/intel-me': No offset set with "
1128 "offset-unset: should another entry provide this correct "
1129 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001130
1131 def testPackX86RomMe(self):
1132 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001133 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001134 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001135 if data[:0x1000] != expected_desc:
1136 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001137 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1138
1139 def testPackVga(self):
1140 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001141 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001142 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1143
1144 def testPackStart16(self):
1145 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001146 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001147 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1148
Jagdish Gediya311d4842018-09-03 21:35:08 +05301149 def testPackPowerpcMpc85xxBootpgResetvec(self):
1150 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1151 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001152 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301153 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1154
Simon Glass6ba679c2018-07-06 10:27:17 -06001155 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001156 """Handle running a test for insertion of microcode
1157
1158 Args:
1159 dts_fname: Name of test .dts file
1160 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001161 ucode_second: True if the microsecond entry is second instead of
1162 third
Simon Glass820af1d2018-07-06 10:27:16 -06001163
1164 Returns:
1165 Tuple:
1166 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001167 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001168 in the above (two 4-byte words)
1169 """
Simon Glass3d274232017-11-12 21:52:27 -07001170 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001171
1172 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001173 if ucode_second:
1174 ucode_content = data[len(nodtb_data):]
1175 ucode_pos = len(nodtb_data)
1176 dtb_with_ucode = ucode_content[16:]
1177 fdt_len = self.GetFdtLen(dtb_with_ucode)
1178 else:
1179 dtb_with_ucode = data[len(nodtb_data):]
1180 fdt_len = self.GetFdtLen(dtb_with_ucode)
1181 ucode_content = dtb_with_ucode[fdt_len:]
1182 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001183 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001184 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001185 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001186 dtb = fdt.FdtScan(fname)
1187 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001188 self.assertTrue(ucode)
1189 for node in ucode.subnodes:
1190 self.assertFalse(node.props.get('data'))
1191
Simon Glass72232452016-11-25 20:15:53 -07001192 # Check that the microcode appears immediately after the Fdt
1193 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001194 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001195 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1196 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001197 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001198
1199 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001200 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001201 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1202 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001203 u_boot = data[:len(nodtb_data)]
1204 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001205
1206 def testPackUbootMicrocode(self):
1207 """Test that x86 microcode can be handled correctly
1208
1209 We expect to see the following in the image, in order:
1210 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1211 place
1212 u-boot.dtb with the microcode removed
1213 the microcode
1214 """
Simon Glass511f6582018-10-01 12:22:30 -06001215 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001216 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001217 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1218 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001219
Simon Glassbac25c82017-05-27 07:38:26 -06001220 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001221 """Test that x86 microcode can be handled correctly
1222
1223 We expect to see the following in the image, in order:
1224 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1225 place
1226 u-boot.dtb with the microcode
1227 an empty microcode region
1228 """
1229 # We need the libfdt library to run this test since only that allows
1230 # finding the offset of a property. This is required by
1231 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001232 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001233
1234 second = data[len(U_BOOT_NODTB_DATA):]
1235
1236 fdt_len = self.GetFdtLen(second)
1237 third = second[fdt_len:]
1238 second = second[:fdt_len]
1239
Simon Glassbac25c82017-05-27 07:38:26 -06001240 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1241 self.assertIn(ucode_data, second)
1242 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001243
Simon Glassbac25c82017-05-27 07:38:26 -06001244 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001245 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001246 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1247 len(ucode_data))
1248 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001249 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1250 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001251
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001252 def testPackUbootSingleMicrocode(self):
1253 """Test that x86 microcode can be handled correctly with fdt_normal.
1254 """
Simon Glassbac25c82017-05-27 07:38:26 -06001255 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001256
Simon Glass996021e2016-11-25 20:15:54 -07001257 def testUBootImg(self):
1258 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001259 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001260 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001261
1262 def testNoMicrocode(self):
1263 """Test that a missing microcode region is detected"""
1264 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001265 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001266 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1267 "node found in ", str(e.exception))
1268
1269 def testMicrocodeWithoutNode(self):
1270 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1271 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001272 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001273 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1274 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1275
1276 def testMicrocodeWithoutNode2(self):
1277 """Test that a missing u-boot-ucode node is detected"""
1278 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001279 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001280 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1281 "microcode region u-boot-ucode", str(e.exception))
1282
1283 def testMicrocodeWithoutPtrInElf(self):
1284 """Test that a U-Boot binary without the microcode symbol is detected"""
1285 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001286 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001287 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001288 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001289
1290 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001291 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001292 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1293 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1294
1295 finally:
1296 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001297 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001298 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001299
1300 def testMicrocodeNotInImage(self):
1301 """Test that microcode must be placed within the image"""
1302 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001303 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001304 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1305 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001306 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001307
1308 def testWithoutMicrocode(self):
1309 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001310 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001311 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001312 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001313
1314 # Now check the device tree has no microcode
1315 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1316 second = data[len(U_BOOT_NODTB_DATA):]
1317
1318 fdt_len = self.GetFdtLen(second)
1319 self.assertEqual(dtb, second[:fdt_len])
1320
1321 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1322 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001323 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001324
1325 def testUnknownPosSize(self):
1326 """Test that microcode must be placed within the image"""
1327 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001328 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001329 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001330 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001331
1332 def testPackFsp(self):
1333 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001334 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001335 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1336
1337 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001338 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001339 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001340 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001341
1342 def testPackVbt(self):
1343 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001344 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001345 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001346
Simon Glass7f94e832017-11-12 21:52:25 -07001347 def testSplBssPad(self):
1348 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001349 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001350 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001351 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001352 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001353 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001354
Simon Glass04cda032018-10-01 21:12:42 -06001355 def testSplBssPadMissing(self):
1356 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001357 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001358 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001359 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001360 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1361 str(e.exception))
1362
Simon Glasse83679d2017-11-12 21:52:26 -07001363 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001364 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001365 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001366 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1367
Simon Glass6ba679c2018-07-06 10:27:17 -06001368 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1369 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001370
1371 We expect to see the following in the image, in order:
1372 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1373 correct place
1374 u-boot.dtb with the microcode removed
1375 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001376
1377 Args:
1378 dts: Device tree file to use for test
1379 ucode_second: True if the microsecond entry is second instead of
1380 third
Simon Glass3d274232017-11-12 21:52:27 -07001381 """
Simon Glass7057d022018-10-01 21:12:47 -06001382 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001383 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1384 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001385 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1386 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001387
Simon Glass6ba679c2018-07-06 10:27:17 -06001388 def testPackUbootSplMicrocode(self):
1389 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001390 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001391
1392 def testPackUbootSplMicrocodeReorder(self):
1393 """Test that order doesn't matter for microcode entries
1394
1395 This is the same as testPackUbootSplMicrocode but when we process the
1396 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1397 entry, so we reply on binman to try later.
1398 """
Simon Glass511f6582018-10-01 12:22:30 -06001399 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001400 ucode_second=True)
1401
Simon Glassa409c932017-11-12 21:52:28 -07001402 def testPackMrc(self):
1403 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001404 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001405 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1406
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001407 def testSplDtb(self):
1408 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001409 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001410 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1411
Simon Glass0a6da312017-11-13 18:54:56 -07001412 def testSplNoDtb(self):
1413 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001414 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001415 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001416 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1417
Simon Glass7098b7f2021-03-21 18:24:30 +13001418 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1419 use_expanded=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001420 """Check the image contains the expected symbol values
1421
1422 Args:
1423 dts: Device tree file to use for test
1424 base_data: Data before and after 'u-boot' section
1425 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001426 entry_args: Dict of entry args to supply to binman
1427 key: arg name
1428 value: value of that arg
1429 use_expanded: True to use expanded entries where available, e.g.
1430 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001431 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001432 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001433 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1434 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001435 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001436 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001437 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001438
Simon Glass7057d022018-10-01 21:12:47 -06001439 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001440 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1441 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001442 # The image should contain the symbols from u_boot_binman_syms.c
1443 # Note that image_pos is adjusted by the base address of the image,
1444 # which is 0x10 in our test image
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001445 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1446 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glass31e04cb2021-03-18 20:24:56 +13001447 0x10 + u_boot_offset, 0x04)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001448 expected = (sym_values + base_data[24:] +
Simon Glass80025522022-01-29 14:14:04 -07001449 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001450 base_data[24:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001451 self.assertEqual(expected, data)
1452
Simon Glass31e04cb2021-03-18 20:24:56 +13001453 def testSymbols(self):
1454 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001455 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001456
1457 def testSymbolsNoDtb(self):
1458 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001459 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001460 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1461 0x38)
1462
Simon Glasse76a3e62018-06-01 09:38:11 -06001463 def testPackUnitAddress(self):
1464 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001465 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001466 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1467
Simon Glassa91e1152018-06-01 09:38:16 -06001468 def testSections(self):
1469 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001470 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001471 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1472 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1473 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001474 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001475
Simon Glass30732662018-06-01 09:38:20 -06001476 def testMap(self):
1477 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001478 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001479 self.assertEqual('''ImagePos Offset Size Name
148000000000 00000000 00000028 main-section
148100000000 00000000 00000010 section@0
148200000000 00000000 00000004 u-boot
148300000010 00000010 00000010 section@1
148400000010 00000000 00000004 u-boot
148500000020 00000020 00000004 section@2
148600000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001487''', map_data)
1488
Simon Glass3b78d532018-06-01 09:38:21 -06001489 def testNamePrefix(self):
1490 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001491 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001492 self.assertEqual('''ImagePos Offset Size Name
149300000000 00000000 00000028 main-section
149400000000 00000000 00000010 section@0
149500000000 00000000 00000004 ro-u-boot
149600000010 00000010 00000010 section@1
149700000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001498''', map_data)
1499
Simon Glass6ba679c2018-07-06 10:27:17 -06001500 def testUnknownContents(self):
1501 """Test that obtaining the contents works as expected"""
1502 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001503 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001504 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001505 "processing of contents: remaining ["
1506 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001507
Simon Glass2e1169f2018-07-06 10:27:19 -06001508 def testBadChangeSize(self):
1509 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001510 try:
1511 state.SetAllowEntryExpansion(False)
1512 with self.assertRaises(ValueError) as e:
1513 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001514 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001515 str(e.exception))
1516 finally:
1517 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001518
Simon Glassa87014e2018-07-06 10:27:42 -06001519 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001520 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001521 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001522 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001523 dtb = fdt.Fdt(out_dtb_fname)
1524 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001525 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001526 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001527 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001528 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001529 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001530 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001531 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001532 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001533 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001534 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001535 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001536 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001537 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001538
Simon Glasse8561af2018-08-01 15:22:37 -06001539 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001540 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001541 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001542 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001543 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001544 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001545 'size': 40
1546 }, props)
1547
1548 def testUpdateFdtBad(self):
1549 """Test that we detect when ProcessFdt never completes"""
1550 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001551 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001552 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001553 '[<binman.etype._testing.Entry__testing',
1554 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001555
Simon Glass91710b32018-07-17 13:25:32 -06001556 def testEntryArgs(self):
1557 """Test passing arguments to entries from the command line"""
1558 entry_args = {
1559 'test-str-arg': 'test1',
1560 'test-int-arg': '456',
1561 }
Simon Glass511f6582018-10-01 12:22:30 -06001562 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001563 self.assertIn('image', control.images)
1564 entry = control.images['image'].GetEntries()['_testing']
1565 self.assertEqual('test0', entry.test_str_fdt)
1566 self.assertEqual('test1', entry.test_str_arg)
1567 self.assertEqual(123, entry.test_int_fdt)
1568 self.assertEqual(456, entry.test_int_arg)
1569
1570 def testEntryArgsMissing(self):
1571 """Test missing arguments and properties"""
1572 entry_args = {
1573 'test-int-arg': '456',
1574 }
Simon Glass511f6582018-10-01 12:22:30 -06001575 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001576 entry = control.images['image'].GetEntries()['_testing']
1577 self.assertEqual('test0', entry.test_str_fdt)
1578 self.assertEqual(None, entry.test_str_arg)
1579 self.assertEqual(None, entry.test_int_fdt)
1580 self.assertEqual(456, entry.test_int_arg)
1581
1582 def testEntryArgsRequired(self):
1583 """Test missing arguments and properties"""
1584 entry_args = {
1585 'test-int-arg': '456',
1586 }
1587 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001588 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001589 self.assertIn("Node '/binman/_testing': "
1590 'Missing required properties/entry args: test-str-arg, '
1591 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001592 str(e.exception))
1593
1594 def testEntryArgsInvalidFormat(self):
1595 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001596 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1597 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001598 with self.assertRaises(ValueError) as e:
1599 self._DoBinman(*args)
1600 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1601
1602 def testEntryArgsInvalidInteger(self):
1603 """Test that an invalid entry-argument integer is detected"""
1604 entry_args = {
1605 'test-int-arg': 'abc',
1606 }
1607 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001608 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001609 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1610 "'test-int-arg' (value 'abc') to integer",
1611 str(e.exception))
1612
1613 def testEntryArgsInvalidDatatype(self):
1614 """Test that an invalid entry-argument datatype is detected
1615
1616 This test could be written in entry_test.py except that it needs
1617 access to control.entry_args, which seems more than that module should
1618 be able to see.
1619 """
1620 entry_args = {
1621 'test-bad-datatype-arg': '12',
1622 }
1623 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001624 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001625 entry_args=entry_args)
1626 self.assertIn('GetArg() internal error: Unknown data type ',
1627 str(e.exception))
1628
Simon Glass2ca52032018-07-17 13:25:33 -06001629 def testText(self):
1630 """Test for a text entry type"""
1631 entry_args = {
1632 'test-id': TEXT_DATA,
1633 'test-id2': TEXT_DATA2,
1634 'test-id3': TEXT_DATA3,
1635 }
Simon Glass511f6582018-10-01 12:22:30 -06001636 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001637 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001638 expected = (tools.to_bytes(TEXT_DATA) +
1639 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1640 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001641 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001642 self.assertEqual(expected, data)
1643
Simon Glass969616c2018-07-17 13:25:36 -06001644 def testEntryDocs(self):
1645 """Test for creation of entry documentation"""
1646 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001647 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001648 self.assertTrue(len(stdout.getvalue()) > 0)
1649
1650 def testEntryDocsMissing(self):
1651 """Test handling of missing entry documentation"""
1652 with self.assertRaises(ValueError) as e:
1653 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001654 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001655 self.assertIn('Documentation is missing for modules: u_boot',
1656 str(e.exception))
1657
Simon Glass704784b2018-07-17 13:25:38 -06001658 def testFmap(self):
1659 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001660 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001661 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001662 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1663 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001664 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001665 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001666 self.assertEqual(1, fhdr.ver_major)
1667 self.assertEqual(0, fhdr.ver_minor)
1668 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001669 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001670 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001671 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001672 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001673 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001674
Simon Glass82059c22021-04-03 11:05:09 +13001675 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001676 self.assertEqual(b'SECTION0', fentry.name)
1677 self.assertEqual(0, fentry.offset)
1678 self.assertEqual(16, fentry.size)
1679 self.assertEqual(0, fentry.flags)
1680
1681 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001682 self.assertEqual(b'RO_U_BOOT', fentry.name)
1683 self.assertEqual(0, fentry.offset)
1684 self.assertEqual(4, fentry.size)
1685 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001686
Simon Glass82059c22021-04-03 11:05:09 +13001687 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001688 self.assertEqual(b'SECTION1', fentry.name)
1689 self.assertEqual(16, fentry.offset)
1690 self.assertEqual(16, fentry.size)
1691 self.assertEqual(0, fentry.flags)
1692
1693 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001694 self.assertEqual(b'RW_U_BOOT', fentry.name)
1695 self.assertEqual(16, fentry.offset)
1696 self.assertEqual(4, fentry.size)
1697 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001698
Simon Glass82059c22021-04-03 11:05:09 +13001699 fentry = next(fiter)
1700 self.assertEqual(b'FMAP', fentry.name)
1701 self.assertEqual(32, fentry.offset)
1702 self.assertEqual(expect_size, fentry.size)
1703 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001704
Simon Glassdb168d42018-07-17 13:25:39 -06001705 def testBlobNamedByArg(self):
1706 """Test we can add a blob with the filename coming from an entry arg"""
1707 entry_args = {
1708 'cros-ec-rw-path': 'ecrw.bin',
1709 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001710 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001711
Simon Glass53f53992018-07-17 13:25:40 -06001712 def testFill(self):
1713 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001714 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001715 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001716 self.assertEqual(expected, data)
1717
1718 def testFillNoSize(self):
1719 """Test for an fill entry type with no size"""
1720 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001721 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001722 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001723 str(e.exception))
1724
Simon Glassc1ae83c2018-07-17 13:25:44 -06001725 def _HandleGbbCommand(self, pipe_list):
1726 """Fake calls to the futility utility"""
1727 if pipe_list[0][0] == 'futility':
1728 fname = pipe_list[0][-1]
1729 # Append our GBB data to the file, which will happen every time the
1730 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001731 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001732 fd.write(GBB_DATA)
1733 return command.CommandResult()
1734
1735 def testGbb(self):
1736 """Test for the Chromium OS Google Binary Block"""
1737 command.test_result = self._HandleGbbCommand
1738 entry_args = {
1739 'keydir': 'devkeys',
1740 'bmpblk': 'bmpblk.bin',
1741 }
Simon Glass511f6582018-10-01 12:22:30 -06001742 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001743
1744 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001745 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1746 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001747 self.assertEqual(expected, data)
1748
1749 def testGbbTooSmall(self):
1750 """Test for the Chromium OS Google Binary Block being large enough"""
1751 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001752 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001753 self.assertIn("Node '/binman/gbb': GBB is too small",
1754 str(e.exception))
1755
1756 def testGbbNoSize(self):
1757 """Test for the Chromium OS Google Binary Block having a size"""
1758 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001759 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001760 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1761 str(e.exception))
1762
Simon Glass66152ce2022-01-09 20:14:09 -07001763 def testGbbMissing(self):
1764 """Test that binman still produces an image if futility is missing"""
1765 entry_args = {
1766 'keydir': 'devkeys',
1767 }
1768 with test_util.capture_sys_output() as (_, stderr):
1769 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1770 entry_args=entry_args)
1771 err = stderr.getvalue()
1772 self.assertRegex(err,
1773 "Image 'main-section'.*missing bintools.*: futility")
1774
Simon Glass5c350162018-07-17 13:25:47 -06001775 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001776 """Fake calls to the futility utility
1777
1778 The expected pipe is:
1779
1780 [('futility', 'vbutil_firmware', '--vblock',
1781 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1782 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1783 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1784 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1785
1786 This writes to the output file (here, 'vblock.vblock'). If
1787 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1788 of the input data (here, 'input.vblock').
1789 """
Simon Glass5c350162018-07-17 13:25:47 -06001790 if pipe_list[0][0] == 'futility':
1791 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001792 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001793 if self._hash_data:
1794 infile = pipe_list[0][11]
1795 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001796 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001797 m.update(data)
1798 fd.write(m.digest())
1799 else:
1800 fd.write(VBLOCK_DATA)
1801
Simon Glass5c350162018-07-17 13:25:47 -06001802 return command.CommandResult()
1803
1804 def testVblock(self):
1805 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001806 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001807 command.test_result = self._HandleVblockCommand
1808 entry_args = {
1809 'keydir': 'devkeys',
1810 }
Simon Glass511f6582018-10-01 12:22:30 -06001811 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001812 entry_args=entry_args)
1813 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1814 self.assertEqual(expected, data)
1815
1816 def testVblockNoContent(self):
1817 """Test we detect a vblock which has no content to sign"""
1818 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001819 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001820 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001821 'property', str(e.exception))
1822
1823 def testVblockBadPhandle(self):
1824 """Test that we detect a vblock with an invalid phandle in contents"""
1825 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001826 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001827 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1828 '1000', str(e.exception))
1829
1830 def testVblockBadEntry(self):
1831 """Test that we detect an entry that points to a non-entry"""
1832 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001833 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001834 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1835 "'other'", str(e.exception))
1836
Simon Glass220c6222021-01-06 21:35:17 -07001837 def testVblockContent(self):
1838 """Test that the vblock signs the right data"""
1839 self._hash_data = True
1840 command.test_result = self._HandleVblockCommand
1841 entry_args = {
1842 'keydir': 'devkeys',
1843 }
1844 data = self._DoReadFileDtb(
1845 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1846 entry_args=entry_args)[0]
1847 hashlen = 32 # SHA256 hash is 32 bytes
1848 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1849 hashval = data[-hashlen:]
1850 dtb = data[len(U_BOOT_DATA):-hashlen]
1851
1852 expected_data = U_BOOT_DATA + dtb
1853
1854 # The hashval should be a hash of the dtb
1855 m = hashlib.sha256()
1856 m.update(expected_data)
1857 expected_hashval = m.digest()
1858 self.assertEqual(expected_hashval, hashval)
1859
Simon Glass66152ce2022-01-09 20:14:09 -07001860 def testVblockMissing(self):
1861 """Test that binman still produces an image if futility is missing"""
1862 entry_args = {
1863 'keydir': 'devkeys',
1864 }
1865 with test_util.capture_sys_output() as (_, stderr):
1866 self._DoTestFile('074_vblock.dts',
1867 force_missing_bintools='futility',
1868 entry_args=entry_args)
1869 err = stderr.getvalue()
1870 self.assertRegex(err,
1871 "Image 'main-section'.*missing bintools.*: futility")
1872
Simon Glass8425a1f2018-07-17 13:25:48 -06001873 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001874 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001875 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001876 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001877 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001878 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1879
Simon Glass24b97442018-07-17 13:25:51 -06001880 def testUsesPos(self):
1881 """Test that the 'pos' property cannot be used anymore"""
1882 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001883 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001884 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1885 "'pos'", str(e.exception))
1886
Simon Glass274bf092018-09-14 04:57:08 -06001887 def testFillZero(self):
1888 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001889 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001890 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001891
Simon Glass267de432018-09-14 04:57:09 -06001892 def testTextMissing(self):
1893 """Test for a text entry type where there is no text"""
1894 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001895 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001896 self.assertIn("Node '/binman/text': No value provided for text label "
1897 "'test-id'", str(e.exception))
1898
Simon Glassed40e962018-09-14 04:57:10 -06001899 def testPackStart16Tpl(self):
1900 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001901 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001902 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1903
Simon Glass3b376c32018-09-14 04:57:12 -06001904 def testSelectImage(self):
1905 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001906 expected = 'Skipping images: image1'
1907
1908 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001909 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001910 with test_util.capture_sys_output() as (stdout, stderr):
1911 retcode = self._DoTestFile('006_dual_image.dts',
1912 verbosity=verbosity,
1913 images=['image2'])
1914 self.assertEqual(0, retcode)
1915 if verbosity:
1916 self.assertIn(expected, stdout.getvalue())
1917 else:
1918 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001919
Simon Glass80025522022-01-29 14:14:04 -07001920 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1921 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001922 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001923
Simon Glasse219aa42018-09-14 04:57:24 -06001924 def testUpdateFdtAll(self):
1925 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001926 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001927
1928 base_expected = {
Simon Glasse219aa42018-09-14 04:57:24 -06001929 'offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001930 'image-pos': 0,
1931 'size': 2320,
Simon Glasse219aa42018-09-14 04:57:24 -06001932 'section:offset': 0,
Simon Glass56d05412022-02-28 07:16:54 -07001933 'section:image-pos': 0,
1934 'section:size': 565,
1935 'section/u-boot-dtb:offset': 0,
1936 'section/u-boot-dtb:image-pos': 0,
1937 'section/u-boot-dtb:size': 565,
1938 'u-boot-spl-dtb:offset': 565,
1939 'u-boot-spl-dtb:image-pos': 565,
1940 'u-boot-spl-dtb:size': 585,
1941 'u-boot-tpl-dtb:offset': 1150,
1942 'u-boot-tpl-dtb:image-pos': 1150,
1943 'u-boot-tpl-dtb:size': 585,
1944 'u-boot-vpl-dtb:image-pos': 1735,
1945 'u-boot-vpl-dtb:offset': 1735,
1946 'u-boot-vpl-dtb:size': 585,
Simon Glasse219aa42018-09-14 04:57:24 -06001947 }
1948
1949 # We expect three device-tree files in the output, one after the other.
1950 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1951 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1952 # main U-Boot tree. All three should have the same postions and offset.
1953 start = 0
Simon Glass56d05412022-02-28 07:16:54 -07001954 self.maxDiff = None
1955 for item in ['', 'spl', 'tpl', 'vpl']:
Simon Glasse219aa42018-09-14 04:57:24 -06001956 dtb = fdt.Fdt.FromData(data[start:])
1957 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001958 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
Simon Glass56d05412022-02-28 07:16:54 -07001959 ['spl', 'tpl', 'vpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001960 expected = dict(base_expected)
1961 if item:
1962 expected[item] = 0
1963 self.assertEqual(expected, props)
1964 start += dtb._fdt_obj.totalsize()
1965
1966 def testUpdateFdtOutput(self):
1967 """Test that output DTB files are updated"""
1968 try:
Simon Glass511f6582018-10-01 12:22:30 -06001969 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001970 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1971
1972 # Unfortunately, compiling a source file always results in a file
1973 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001974 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001975 # binman as a file called u-boot.dtb. To fix this, copy the file
1976 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001977 start = 0
1978 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
Simon Glass56d05412022-02-28 07:16:54 -07001979 'tpl/u-boot-tpl.dtb.out', 'vpl/u-boot-vpl.dtb.out']:
Simon Glasse219aa42018-09-14 04:57:24 -06001980 dtb = fdt.Fdt.FromData(data[start:])
1981 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07001982 pathname = tools.get_output_filename(os.path.split(fname)[1])
1983 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06001984 name = os.path.split(fname)[0]
1985
1986 if name:
Simon Glass56d05412022-02-28 07:16:54 -07001987 orig_indata = self._GetDtbContentsForSpls(dtb_data, name)
Simon Glasse219aa42018-09-14 04:57:24 -06001988 else:
1989 orig_indata = dtb_data
1990 self.assertNotEqual(outdata, orig_indata,
1991 "Expected output file '%s' be updated" % pathname)
1992 self.assertEqual(outdata, data[start:start + size],
1993 "Expected output file '%s' to match output image" %
1994 pathname)
1995 start += size
1996 finally:
1997 self._ResetDtbs()
1998
Simon Glass7ba33592018-09-14 04:57:26 -06001999 def _decompress(self, data):
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002000 bintool = self.comp_bintools['lz4']
2001 return bintool.decompress(data)
Simon Glass7ba33592018-09-14 04:57:26 -06002002
2003 def testCompress(self):
2004 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06002005 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002006 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06002007 use_real_dtb=True, update_dtb=True)
2008 dtb = fdt.Fdt(out_dtb_fname)
2009 dtb.Scan()
2010 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2011 orig = self._decompress(data)
2012 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06002013
2014 # Do a sanity check on various fields
2015 image = control.images['image']
2016 entries = image.GetEntries()
2017 self.assertEqual(1, len(entries))
2018
2019 entry = entries['blob']
2020 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
2021 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
2022 orig = self._decompress(entry.data)
2023 self.assertEqual(orig, entry.uncomp_data)
2024
Simon Glass72eeff12020-10-26 17:40:16 -06002025 self.assertEqual(image.data, entry.data)
2026
Simon Glass7ba33592018-09-14 04:57:26 -06002027 expected = {
2028 'blob:uncomp-size': len(COMPRESS_DATA),
2029 'blob:size': len(data),
2030 'size': len(data),
2031 }
2032 self.assertEqual(expected, props)
2033
Simon Glassac6328c2018-09-14 04:57:28 -06002034 def testFiles(self):
2035 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002036 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002037 self.assertEqual(FILES_DATA, data)
2038
2039 def testFilesCompress(self):
2040 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002041 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002042 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002043
2044 image = control.images['image']
2045 entries = image.GetEntries()
2046 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002047 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002048
Simon Glass303f62f2019-05-17 22:00:46 -06002049 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002050 for i in range(1, 3):
2051 key = '%d.dat' % i
2052 start = entries[key].image_pos
2053 len = entries[key].size
2054 chunk = data[start:start + len]
2055 orig += self._decompress(chunk)
2056
2057 self.assertEqual(FILES_DATA, orig)
2058
2059 def testFilesMissing(self):
2060 """Test missing files"""
2061 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002062 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002063 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2064 'no files', str(e.exception))
2065
2066 def testFilesNoPattern(self):
2067 """Test missing files"""
2068 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002069 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002070 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2071 str(e.exception))
2072
Simon Glassdd156a42022-03-05 20:18:59 -07002073 def testExtendSize(self):
2074 """Test an extending entry"""
2075 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002076 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002077 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2078 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2079 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2080 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002081 self.assertEqual(expect, data)
2082 self.assertEqual('''ImagePos Offset Size Name
208300000000 00000000 00000028 main-section
208400000000 00000000 00000008 fill
208500000008 00000008 00000004 u-boot
20860000000c 0000000c 00000004 section
20870000000c 00000000 00000003 intel-mrc
208800000010 00000010 00000004 u-boot2
208900000014 00000014 0000000c section2
209000000014 00000000 00000008 fill
20910000001c 00000008 00000004 u-boot
209200000020 00000020 00000008 fill2
2093''', map_data)
2094
Simon Glassdd156a42022-03-05 20:18:59 -07002095 def testExtendSizeBad(self):
2096 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002097 with test_util.capture_sys_output() as (stdout, stderr):
2098 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002099 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002100 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2101 'expanding entry', str(e.exception))
2102
Simon Glassae7cf032018-09-14 04:57:31 -06002103 def testHash(self):
2104 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002105 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002106 use_real_dtb=True, update_dtb=True)
2107 dtb = fdt.Fdt(out_dtb_fname)
2108 dtb.Scan()
2109 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2110 m = hashlib.sha256()
2111 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002112 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002113
2114 def testHashNoAlgo(self):
2115 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002116 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002117 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2118 'hash node', str(e.exception))
2119
2120 def testHashBadAlgo(self):
2121 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002122 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002123 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002124 str(e.exception))
2125
2126 def testHashSection(self):
2127 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002128 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002129 use_real_dtb=True, update_dtb=True)
2130 dtb = fdt.Fdt(out_dtb_fname)
2131 dtb.Scan()
2132 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2133 m = hashlib.sha256()
2134 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002135 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002136 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002137
Simon Glass3fb4f422018-09-14 04:57:32 -06002138 def testPackUBootTplMicrocode(self):
2139 """Test that x86 microcode can be handled correctly in TPL
2140
2141 We expect to see the following in the image, in order:
2142 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2143 place
2144 u-boot-tpl.dtb with the microcode removed
2145 the microcode
2146 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002147 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002148 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002149 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002150 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2151 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002152
Simon Glassc64aea52018-09-14 04:57:34 -06002153 def testFmapX86(self):
2154 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002155 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002156 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002157 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002158 self.assertEqual(expected, data[:32])
2159 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2160
2161 self.assertEqual(0x100, fhdr.image_size)
2162
2163 self.assertEqual(0, fentries[0].offset)
2164 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002165 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002166
2167 self.assertEqual(4, fentries[1].offset)
2168 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002169 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002170
2171 self.assertEqual(32, fentries[2].offset)
2172 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2173 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002174 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002175
2176 def testFmapX86Section(self):
2177 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002178 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002179 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002180 self.assertEqual(expected, data[:32])
2181 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2182
Simon Glassb1d414c2021-04-03 11:05:10 +13002183 self.assertEqual(0x180, fhdr.image_size)
2184 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002185 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002186
Simon Glass82059c22021-04-03 11:05:09 +13002187 fentry = next(fiter)
2188 self.assertEqual(b'U_BOOT', fentry.name)
2189 self.assertEqual(0, fentry.offset)
2190 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002191
Simon Glass82059c22021-04-03 11:05:09 +13002192 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002193 self.assertEqual(b'SECTION', fentry.name)
2194 self.assertEqual(4, fentry.offset)
2195 self.assertEqual(0x20 + expect_size, fentry.size)
2196
2197 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002198 self.assertEqual(b'INTEL_MRC', fentry.name)
2199 self.assertEqual(4, fentry.offset)
2200 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002201
Simon Glass82059c22021-04-03 11:05:09 +13002202 fentry = next(fiter)
2203 self.assertEqual(b'FMAP', fentry.name)
2204 self.assertEqual(36, fentry.offset)
2205 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002206
Simon Glassb1714232018-09-14 04:57:35 -06002207 def testElf(self):
2208 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002209 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002210 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002211 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002212 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002213 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002214
Simon Glass0d673792019-07-08 13:18:25 -06002215 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002216 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002217 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002218 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002219 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002220 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002221
Simon Glasscd817d52018-09-14 04:57:36 -06002222 def testPackOverlapMap(self):
2223 """Test that overlapping regions are detected"""
2224 with test_util.capture_sys_output() as (stdout, stderr):
2225 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002226 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002227 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002228 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2229 stdout.getvalue())
2230
2231 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002232 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002233 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002234 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002235 self.assertEqual('''ImagePos Offset Size Name
Simon Glassd99850b2020-10-26 17:40:24 -06002236<none> 00000000 00000008 main-section
Simon Glasscd817d52018-09-14 04:57:36 -06002237<none> 00000000 00000004 u-boot
2238<none> 00000003 00000004 u-boot-align
2239''', map_data)
2240
Simon Glass0d673792019-07-08 13:18:25 -06002241 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002242 """Test that an image with an Intel Reference code binary works"""
2243 data = self._DoReadFile('100_intel_refcode.dts')
2244 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2245
Simon Glasseb023b32019-04-25 21:58:39 -06002246 def testSectionOffset(self):
2247 """Tests use of a section with an offset"""
2248 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2249 map=True)
2250 self.assertEqual('''ImagePos Offset Size Name
225100000000 00000000 00000038 main-section
225200000004 00000004 00000010 section@0
225300000004 00000000 00000004 u-boot
225400000018 00000018 00000010 section@1
225500000018 00000000 00000004 u-boot
22560000002c 0000002c 00000004 section@2
22570000002c 00000000 00000004 u-boot
2258''', map_data)
2259 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002260 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2261 tools.get_bytes(0x21, 12) +
2262 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2263 tools.get_bytes(0x61, 12) +
2264 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2265 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002266
Simon Glass1de34482019-07-08 13:18:53 -06002267 def testCbfsRaw(self):
2268 """Test base handling of a Coreboot Filesystem (CBFS)
2269
2270 The exact contents of the CBFS is verified by similar tests in
2271 cbfs_util_test.py. The tests here merely check that the files added to
2272 the CBFS can be found in the final image.
2273 """
2274 data = self._DoReadFile('102_cbfs_raw.dts')
2275 size = 0xb0
2276
2277 cbfs = cbfs_util.CbfsReader(data)
2278 self.assertEqual(size, cbfs.rom_size)
2279
2280 self.assertIn('u-boot-dtb', cbfs.files)
2281 cfile = cbfs.files['u-boot-dtb']
2282 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2283
2284 def testCbfsArch(self):
2285 """Test on non-x86 architecture"""
2286 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2287 size = 0x100
2288
2289 cbfs = cbfs_util.CbfsReader(data)
2290 self.assertEqual(size, cbfs.rom_size)
2291
2292 self.assertIn('u-boot-dtb', cbfs.files)
2293 cfile = cbfs.files['u-boot-dtb']
2294 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2295
2296 def testCbfsStage(self):
2297 """Tests handling of a Coreboot Filesystem (CBFS)"""
2298 if not elf.ELF_TOOLS:
2299 self.skipTest('Python elftools not available')
2300 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2301 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2302 size = 0xb0
2303
2304 data = self._DoReadFile('104_cbfs_stage.dts')
2305 cbfs = cbfs_util.CbfsReader(data)
2306 self.assertEqual(size, cbfs.rom_size)
2307
2308 self.assertIn('u-boot', cbfs.files)
2309 cfile = cbfs.files['u-boot']
2310 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2311
2312 def testCbfsRawCompress(self):
2313 """Test handling of compressing raw files"""
2314 self._CheckLz4()
2315 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2316 size = 0x140
2317
2318 cbfs = cbfs_util.CbfsReader(data)
2319 self.assertIn('u-boot', cbfs.files)
2320 cfile = cbfs.files['u-boot']
2321 self.assertEqual(COMPRESS_DATA, cfile.data)
2322
2323 def testCbfsBadArch(self):
2324 """Test handling of a bad architecture"""
2325 with self.assertRaises(ValueError) as e:
2326 self._DoReadFile('106_cbfs_bad_arch.dts')
2327 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2328
2329 def testCbfsNoSize(self):
2330 """Test handling of a missing size property"""
2331 with self.assertRaises(ValueError) as e:
2332 self._DoReadFile('107_cbfs_no_size.dts')
2333 self.assertIn('entry must have a size property', str(e.exception))
2334
Simon Glass3e28f4f2021-11-23 11:03:54 -07002335 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002336 """Test handling of a CBFS entry which does not provide contentsy"""
2337 with self.assertRaises(ValueError) as e:
2338 self._DoReadFile('108_cbfs_no_contents.dts')
2339 self.assertIn('Could not complete processing of contents',
2340 str(e.exception))
2341
2342 def testCbfsBadCompress(self):
2343 """Test handling of a bad architecture"""
2344 with self.assertRaises(ValueError) as e:
2345 self._DoReadFile('109_cbfs_bad_compress.dts')
2346 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2347 str(e.exception))
2348
2349 def testCbfsNamedEntries(self):
2350 """Test handling of named entries"""
2351 data = self._DoReadFile('110_cbfs_name.dts')
2352
2353 cbfs = cbfs_util.CbfsReader(data)
2354 self.assertIn('FRED', cbfs.files)
2355 cfile1 = cbfs.files['FRED']
2356 self.assertEqual(U_BOOT_DATA, cfile1.data)
2357
2358 self.assertIn('hello', cbfs.files)
2359 cfile2 = cbfs.files['hello']
2360 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2361
Simon Glass759af872019-07-08 13:18:54 -06002362 def _SetupIfwi(self, fname):
2363 """Set up to run an IFWI test
2364
2365 Args:
2366 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2367 """
2368 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002369 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002370
2371 # Intel Integrated Firmware Image (IFWI) file
2372 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2373 data = fd.read()
2374 TestFunctional._MakeInputFile(fname,data)
2375
2376 def _CheckIfwi(self, data):
2377 """Check that an image with an IFWI contains the correct output
2378
2379 Args:
2380 data: Conents of output file
2381 """
Simon Glass80025522022-01-29 14:14:04 -07002382 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002383 if data[:0x1000] != expected_desc:
2384 self.fail('Expected descriptor binary at start of image')
2385
2386 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002387 image_fname = tools.get_output_filename('image.bin')
2388 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002389 ifwitool = bintool.Bintool.create('ifwitool')
2390 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002391
Simon Glass80025522022-01-29 14:14:04 -07002392 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002393 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002394
2395 def testPackX86RomIfwi(self):
2396 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2397 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002398 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002399 self._CheckIfwi(data)
2400
2401 def testPackX86RomIfwiNoDesc(self):
2402 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2403 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002404 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002405 self._CheckIfwi(data)
2406
2407 def testPackX86RomIfwiNoData(self):
2408 """Test that an x86 ROM with IFWI handles missing data"""
2409 self._SetupIfwi('ifwi.bin')
2410 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002411 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002412 self.assertIn('Could not complete processing of contents',
2413 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002414
Simon Glass66152ce2022-01-09 20:14:09 -07002415 def testIfwiMissing(self):
2416 """Test that binman still produces an image if ifwitool is missing"""
2417 self._SetupIfwi('fitimage.bin')
2418 with test_util.capture_sys_output() as (_, stderr):
2419 self._DoTestFile('111_x86_rom_ifwi.dts',
2420 force_missing_bintools='ifwitool')
2421 err = stderr.getvalue()
2422 self.assertRegex(err,
2423 "Image 'main-section'.*missing bintools.*: ifwitool")
2424
Simon Glassc2f1aed2019-07-08 13:18:56 -06002425 def testCbfsOffset(self):
2426 """Test a CBFS with files at particular offsets
2427
2428 Like all CFBS tests, this is just checking the logic that calls
2429 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2430 """
2431 data = self._DoReadFile('114_cbfs_offset.dts')
2432 size = 0x200
2433
2434 cbfs = cbfs_util.CbfsReader(data)
2435 self.assertEqual(size, cbfs.rom_size)
2436
2437 self.assertIn('u-boot', cbfs.files)
2438 cfile = cbfs.files['u-boot']
2439 self.assertEqual(U_BOOT_DATA, cfile.data)
2440 self.assertEqual(0x40, cfile.cbfs_offset)
2441
2442 self.assertIn('u-boot-dtb', cbfs.files)
2443 cfile2 = cbfs.files['u-boot-dtb']
2444 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2445 self.assertEqual(0x140, cfile2.cbfs_offset)
2446
Simon Glass0f621332019-07-08 14:25:27 -06002447 def testFdtmap(self):
2448 """Test an FDT map can be inserted in the image"""
2449 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2450 fdtmap_data = data[len(U_BOOT_DATA):]
2451 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002452 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002453 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002454
2455 fdt_data = fdtmap_data[16:]
2456 dtb = fdt.Fdt.FromData(fdt_data)
2457 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002458 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002459 self.assertEqual({
2460 'image-pos': 0,
2461 'offset': 0,
2462 'u-boot:offset': 0,
2463 'u-boot:size': len(U_BOOT_DATA),
2464 'u-boot:image-pos': 0,
2465 'fdtmap:image-pos': 4,
2466 'fdtmap:offset': 4,
2467 'fdtmap:size': len(fdtmap_data),
2468 'size': len(data),
2469 }, props)
2470
2471 def testFdtmapNoMatch(self):
2472 """Check handling of an FDT map when the section cannot be found"""
2473 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2474
2475 # Mangle the section name, which should cause a mismatch between the
2476 # correct FDT path and the one expected by the section
2477 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002478 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002479 entries = image.GetEntries()
2480 fdtmap = entries['fdtmap']
2481 with self.assertRaises(ValueError) as e:
2482 fdtmap._GetFdtmap()
2483 self.assertIn("Cannot locate node for path '/binman-suffix'",
2484 str(e.exception))
2485
Simon Glasscec34ba2019-07-08 14:25:28 -06002486 def testFdtmapHeader(self):
2487 """Test an FDT map and image header can be inserted in the image"""
2488 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2489 fdtmap_pos = len(U_BOOT_DATA)
2490 fdtmap_data = data[fdtmap_pos:]
2491 fdt_data = fdtmap_data[16:]
2492 dtb = fdt.Fdt.FromData(fdt_data)
2493 fdt_size = dtb.GetFdtObj().totalsize()
2494 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002495 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002496 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2497 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2498
2499 def testFdtmapHeaderStart(self):
2500 """Test an image header can be inserted at the image start"""
2501 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2502 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2503 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002504 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002505 offset = struct.unpack('<I', hdr_data[4:])[0]
2506 self.assertEqual(fdtmap_pos, offset)
2507
2508 def testFdtmapHeaderPos(self):
2509 """Test an image header can be inserted at a chosen position"""
2510 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2511 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2512 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002513 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002514 offset = struct.unpack('<I', hdr_data[4:])[0]
2515 self.assertEqual(fdtmap_pos, offset)
2516
2517 def testHeaderMissingFdtmap(self):
2518 """Test an image header requires an fdtmap"""
2519 with self.assertRaises(ValueError) as e:
2520 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2521 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2522 str(e.exception))
2523
2524 def testHeaderNoLocation(self):
2525 """Test an image header with a no specified location is detected"""
2526 with self.assertRaises(ValueError) as e:
2527 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2528 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2529 str(e.exception))
2530
Simon Glasse61b6f62019-07-08 14:25:37 -06002531 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002532 """Test extending an entry after it is packed"""
2533 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002534 self.assertEqual(b'aaa', data[:3])
2535 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2536 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002537
Simon Glassdd156a42022-03-05 20:18:59 -07002538 def testEntryExtendBad(self):
2539 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002540 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002541 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002542 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002543 str(e.exception))
2544
Simon Glassdd156a42022-03-05 20:18:59 -07002545 def testEntryExtendSection(self):
2546 """Test extending an entry within a section after it is packed"""
2547 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002548 self.assertEqual(b'aaa', data[:3])
2549 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2550 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002551
Simon Glass90d29682019-07-08 14:25:38 -06002552 def testCompressDtb(self):
2553 """Test that compress of device-tree files is supported"""
2554 self._CheckLz4()
2555 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2556 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2557 comp_data = data[len(U_BOOT_DATA):]
2558 orig = self._decompress(comp_data)
2559 dtb = fdt.Fdt.FromData(orig)
2560 dtb.Scan()
2561 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2562 expected = {
2563 'u-boot:size': len(U_BOOT_DATA),
2564 'u-boot-dtb:uncomp-size': len(orig),
2565 'u-boot-dtb:size': len(comp_data),
2566 'size': len(data),
2567 }
2568 self.assertEqual(expected, props)
2569
Simon Glass151bbbf2019-07-08 14:25:41 -06002570 def testCbfsUpdateFdt(self):
2571 """Test that we can update the device tree with CBFS offset/size info"""
2572 self._CheckLz4()
2573 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2574 update_dtb=True)
2575 dtb = fdt.Fdt(out_dtb_fname)
2576 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002577 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002578 del props['cbfs/u-boot:size']
2579 self.assertEqual({
2580 'offset': 0,
2581 'size': len(data),
2582 'image-pos': 0,
2583 'cbfs:offset': 0,
2584 'cbfs:size': len(data),
2585 'cbfs:image-pos': 0,
2586 'cbfs/u-boot:offset': 0x38,
2587 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2588 'cbfs/u-boot:image-pos': 0x38,
2589 'cbfs/u-boot-dtb:offset': 0xb8,
2590 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2591 'cbfs/u-boot-dtb:image-pos': 0xb8,
2592 }, props)
2593
Simon Glass3c9b4f22019-07-08 14:25:42 -06002594 def testCbfsBadType(self):
2595 """Test an image header with a no specified location is detected"""
2596 with self.assertRaises(ValueError) as e:
2597 self._DoReadFile('126_cbfs_bad_type.dts')
2598 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2599
Simon Glass6b156f82019-07-08 14:25:43 -06002600 def testList(self):
2601 """Test listing the files in an image"""
2602 self._CheckLz4()
2603 data = self._DoReadFile('127_list.dts')
2604 image = control.images['image']
2605 entries = image.BuildEntryList()
2606 self.assertEqual(7, len(entries))
2607
2608 ent = entries[0]
2609 self.assertEqual(0, ent.indent)
2610 self.assertEqual('main-section', ent.name)
2611 self.assertEqual('section', ent.etype)
2612 self.assertEqual(len(data), ent.size)
2613 self.assertEqual(0, ent.image_pos)
2614 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002615 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002616
2617 ent = entries[1]
2618 self.assertEqual(1, ent.indent)
2619 self.assertEqual('u-boot', ent.name)
2620 self.assertEqual('u-boot', ent.etype)
2621 self.assertEqual(len(U_BOOT_DATA), ent.size)
2622 self.assertEqual(0, ent.image_pos)
2623 self.assertEqual(None, ent.uncomp_size)
2624 self.assertEqual(0, ent.offset)
2625
2626 ent = entries[2]
2627 self.assertEqual(1, ent.indent)
2628 self.assertEqual('section', ent.name)
2629 self.assertEqual('section', ent.etype)
2630 section_size = ent.size
2631 self.assertEqual(0x100, ent.image_pos)
2632 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002633 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002634
2635 ent = entries[3]
2636 self.assertEqual(2, ent.indent)
2637 self.assertEqual('cbfs', ent.name)
2638 self.assertEqual('cbfs', ent.etype)
2639 self.assertEqual(0x400, ent.size)
2640 self.assertEqual(0x100, ent.image_pos)
2641 self.assertEqual(None, ent.uncomp_size)
2642 self.assertEqual(0, ent.offset)
2643
2644 ent = entries[4]
2645 self.assertEqual(3, ent.indent)
2646 self.assertEqual('u-boot', ent.name)
2647 self.assertEqual('u-boot', ent.etype)
2648 self.assertEqual(len(U_BOOT_DATA), ent.size)
2649 self.assertEqual(0x138, ent.image_pos)
2650 self.assertEqual(None, ent.uncomp_size)
2651 self.assertEqual(0x38, ent.offset)
2652
2653 ent = entries[5]
2654 self.assertEqual(3, ent.indent)
2655 self.assertEqual('u-boot-dtb', ent.name)
2656 self.assertEqual('text', ent.etype)
2657 self.assertGreater(len(COMPRESS_DATA), ent.size)
2658 self.assertEqual(0x178, ent.image_pos)
2659 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2660 self.assertEqual(0x78, ent.offset)
2661
2662 ent = entries[6]
2663 self.assertEqual(2, ent.indent)
2664 self.assertEqual('u-boot-dtb', ent.name)
2665 self.assertEqual('u-boot-dtb', ent.etype)
2666 self.assertEqual(0x500, ent.image_pos)
2667 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2668 dtb_size = ent.size
2669 # Compressing this data expands it since headers are added
2670 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2671 self.assertEqual(0x400, ent.offset)
2672
2673 self.assertEqual(len(data), 0x100 + section_size)
2674 self.assertEqual(section_size, 0x400 + dtb_size)
2675
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002676 def testFindFdtmap(self):
2677 """Test locating an FDT map in an image"""
2678 self._CheckLz4()
2679 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2680 image = control.images['image']
2681 entries = image.GetEntries()
2682 entry = entries['fdtmap']
2683 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2684
2685 def testFindFdtmapMissing(self):
2686 """Test failing to locate an FDP map"""
2687 data = self._DoReadFile('005_simple.dts')
2688 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2689
Simon Glassed39a3c2019-07-08 14:25:45 -06002690 def testFindImageHeader(self):
2691 """Test locating a image header"""
2692 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002693 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002694 image = control.images['image']
2695 entries = image.GetEntries()
2696 entry = entries['fdtmap']
2697 # The header should point to the FDT map
2698 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2699
2700 def testFindImageHeaderStart(self):
2701 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002702 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002703 image = control.images['image']
2704 entries = image.GetEntries()
2705 entry = entries['fdtmap']
2706 # The header should point to the FDT map
2707 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2708
2709 def testFindImageHeaderMissing(self):
2710 """Test failing to locate an image header"""
2711 data = self._DoReadFile('005_simple.dts')
2712 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2713
Simon Glassb8424fa2019-07-08 14:25:46 -06002714 def testReadImage(self):
2715 """Test reading an image and accessing its FDT map"""
2716 self._CheckLz4()
2717 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002718 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002719 orig_image = control.images['image']
2720 image = Image.FromFile(image_fname)
2721 self.assertEqual(orig_image.GetEntries().keys(),
2722 image.GetEntries().keys())
2723
2724 orig_entry = orig_image.GetEntries()['fdtmap']
2725 entry = image.GetEntries()['fdtmap']
2726 self.assertEquals(orig_entry.offset, entry.offset)
2727 self.assertEquals(orig_entry.size, entry.size)
2728 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2729
2730 def testReadImageNoHeader(self):
2731 """Test accessing an image's FDT map without an image header"""
2732 self._CheckLz4()
2733 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002734 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002735 image = Image.FromFile(image_fname)
2736 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002737 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002738
2739 def testReadImageFail(self):
2740 """Test failing to read an image image's FDT map"""
2741 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002742 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002743 with self.assertRaises(ValueError) as e:
2744 image = Image.FromFile(image_fname)
2745 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002746
Simon Glassb2fd11d2019-07-08 14:25:48 -06002747 def testListCmd(self):
2748 """Test listing the files in an image using an Fdtmap"""
2749 self._CheckLz4()
2750 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2751
2752 # lz4 compression size differs depending on the version
2753 image = control.images['image']
2754 entries = image.GetEntries()
2755 section_size = entries['section'].size
2756 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2757 fdtmap_offset = entries['fdtmap'].offset
2758
Simon Glassb3d6fc72019-07-20 12:24:10 -06002759 try:
2760 tmpdir, updated_fname = self._SetupImageInTmpdir()
2761 with test_util.capture_sys_output() as (stdout, stderr):
2762 self._DoBinman('ls', '-i', updated_fname)
2763 finally:
2764 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002765 lines = stdout.getvalue().splitlines()
2766 expected = [
2767'Name Image-pos Size Entry-type Offset Uncomp-size',
2768'----------------------------------------------------------------------',
2769'main-section 0 c00 section 0',
2770' u-boot 0 4 u-boot 0',
2771' section 100 %x section 100' % section_size,
2772' cbfs 100 400 cbfs 0',
2773' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002774' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002775' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002776' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002777 (fdtmap_offset, fdtmap_offset),
2778' image-header bf8 8 image-header bf8',
2779 ]
2780 self.assertEqual(expected, lines)
2781
2782 def testListCmdFail(self):
2783 """Test failing to list an image"""
2784 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002785 try:
2786 tmpdir, updated_fname = self._SetupImageInTmpdir()
2787 with self.assertRaises(ValueError) as e:
2788 self._DoBinman('ls', '-i', updated_fname)
2789 finally:
2790 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002791 self.assertIn("Cannot find FDT map in image", str(e.exception))
2792
2793 def _RunListCmd(self, paths, expected):
2794 """List out entries and check the result
2795
2796 Args:
2797 paths: List of paths to pass to the list command
2798 expected: Expected list of filenames to be returned, in order
2799 """
2800 self._CheckLz4()
2801 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002802 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002803 image = Image.FromFile(image_fname)
2804 lines = image.GetListEntries(paths)[1]
2805 files = [line[0].strip() for line in lines[1:]]
2806 self.assertEqual(expected, files)
2807
2808 def testListCmdSection(self):
2809 """Test listing the files in a section"""
2810 self._RunListCmd(['section'],
2811 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2812
2813 def testListCmdFile(self):
2814 """Test listing a particular file"""
2815 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2816
2817 def testListCmdWildcard(self):
2818 """Test listing a wildcarded file"""
2819 self._RunListCmd(['*boot*'],
2820 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2821
2822 def testListCmdWildcardMulti(self):
2823 """Test listing a wildcarded file"""
2824 self._RunListCmd(['*cb*', '*head*'],
2825 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2826
2827 def testListCmdEmpty(self):
2828 """Test listing a wildcarded file"""
2829 self._RunListCmd(['nothing'], [])
2830
2831 def testListCmdPath(self):
2832 """Test listing the files in a sub-entry of a section"""
2833 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2834
Simon Glass4c613bf2019-07-08 14:25:50 -06002835 def _RunExtractCmd(self, entry_name, decomp=True):
2836 """Extract an entry from an image
2837
2838 Args:
2839 entry_name: Entry name to extract
2840 decomp: True to decompress the data if compressed, False to leave
2841 it in its raw uncompressed format
2842
2843 Returns:
2844 data from entry
2845 """
2846 self._CheckLz4()
2847 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002848 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002849 return control.ReadEntry(image_fname, entry_name, decomp)
2850
2851 def testExtractSimple(self):
2852 """Test extracting a single file"""
2853 data = self._RunExtractCmd('u-boot')
2854 self.assertEqual(U_BOOT_DATA, data)
2855
Simon Glass980a2842019-07-08 14:25:52 -06002856 def testExtractSection(self):
2857 """Test extracting the files in a section"""
2858 data = self._RunExtractCmd('section')
2859 cbfs_data = data[:0x400]
2860 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002861 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002862 dtb_data = data[0x400:]
2863 dtb = self._decompress(dtb_data)
2864 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2865
2866 def testExtractCompressed(self):
2867 """Test extracting compressed data"""
2868 data = self._RunExtractCmd('section/u-boot-dtb')
2869 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2870
2871 def testExtractRaw(self):
2872 """Test extracting compressed data without decompressing it"""
2873 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2874 dtb = self._decompress(data)
2875 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2876
2877 def testExtractCbfs(self):
2878 """Test extracting CBFS data"""
2879 data = self._RunExtractCmd('section/cbfs/u-boot')
2880 self.assertEqual(U_BOOT_DATA, data)
2881
2882 def testExtractCbfsCompressed(self):
2883 """Test extracting CBFS compressed data"""
2884 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2885 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2886
2887 def testExtractCbfsRaw(self):
2888 """Test extracting CBFS compressed data without decompressing it"""
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002889 bintool = self.comp_bintools['lzma_alone']
2890 self._CheckBintool(bintool)
Simon Glass980a2842019-07-08 14:25:52 -06002891 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02002892 dtb = bintool.decompress(data)
Simon Glass980a2842019-07-08 14:25:52 -06002893 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2894
Simon Glass4c613bf2019-07-08 14:25:50 -06002895 def testExtractBadEntry(self):
2896 """Test extracting a bad section path"""
2897 with self.assertRaises(ValueError) as e:
2898 self._RunExtractCmd('section/does-not-exist')
2899 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2900 str(e.exception))
2901
2902 def testExtractMissingFile(self):
2903 """Test extracting file that does not exist"""
2904 with self.assertRaises(IOError) as e:
2905 control.ReadEntry('missing-file', 'name')
2906
2907 def testExtractBadFile(self):
2908 """Test extracting an invalid file"""
2909 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002910 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002911 with self.assertRaises(ValueError) as e:
2912 control.ReadEntry(fname, 'name')
2913
Simon Glass980a2842019-07-08 14:25:52 -06002914 def testExtractCmd(self):
2915 """Test extracting a file fron an image on the command line"""
2916 self._CheckLz4()
2917 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002918 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002919 try:
2920 tmpdir, updated_fname = self._SetupImageInTmpdir()
2921 with test_util.capture_sys_output() as (stdout, stderr):
2922 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2923 '-f', fname)
2924 finally:
2925 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07002926 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002927 self.assertEqual(U_BOOT_DATA, data)
2928
2929 def testExtractOneEntry(self):
2930 """Test extracting a single entry fron an image """
2931 self._CheckLz4()
2932 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002933 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002934 fname = os.path.join(self._indir, 'output.extact')
2935 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07002936 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002937 self.assertEqual(U_BOOT_DATA, data)
2938
2939 def _CheckExtractOutput(self, decomp):
2940 """Helper to test file output with and without decompression
2941
2942 Args:
2943 decomp: True to decompress entry data, False to output it raw
2944 """
2945 def _CheckPresent(entry_path, expect_data, expect_size=None):
2946 """Check and remove expected file
2947
2948 This checks the data/size of a file and removes the file both from
2949 the outfiles set and from the output directory. Once all files are
2950 processed, both the set and directory should be empty.
2951
2952 Args:
2953 entry_path: Entry path
2954 expect_data: Data to expect in file, or None to skip check
2955 expect_size: Size of data to expect in file, or None to skip
2956 """
2957 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07002958 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06002959 os.remove(path)
2960 if expect_data:
2961 self.assertEqual(expect_data, data)
2962 elif expect_size:
2963 self.assertEqual(expect_size, len(data))
2964 outfiles.remove(path)
2965
2966 def _CheckDirPresent(name):
2967 """Remove expected directory
2968
2969 This gives an error if the directory does not exist as expected
2970
2971 Args:
2972 name: Name of directory to remove
2973 """
2974 path = os.path.join(outdir, name)
2975 os.rmdir(path)
2976
2977 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002978 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002979 outdir = os.path.join(self._indir, 'extract')
2980 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2981
2982 # Create a set of all file that were output (should be 9)
2983 outfiles = set()
2984 for root, dirs, files in os.walk(outdir):
2985 outfiles |= set([os.path.join(root, fname) for fname in files])
2986 self.assertEqual(9, len(outfiles))
2987 self.assertEqual(9, len(einfos))
2988
2989 image = control.images['image']
2990 entries = image.GetEntries()
2991
2992 # Check the 9 files in various ways
2993 section = entries['section']
2994 section_entries = section.GetEntries()
2995 cbfs_entries = section_entries['cbfs'].GetEntries()
2996 _CheckPresent('u-boot', U_BOOT_DATA)
2997 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2998 dtb_len = EXTRACT_DTB_SIZE
2999 if not decomp:
3000 dtb_len = cbfs_entries['u-boot-dtb'].size
3001 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
3002 if not decomp:
3003 dtb_len = section_entries['u-boot-dtb'].size
3004 _CheckPresent('section/u-boot-dtb', None, dtb_len)
3005
3006 fdtmap = entries['fdtmap']
3007 _CheckPresent('fdtmap', fdtmap.data)
3008 hdr = entries['image-header']
3009 _CheckPresent('image-header', hdr.data)
3010
3011 _CheckPresent('section/root', section.data)
3012 cbfs = section_entries['cbfs']
3013 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07003014 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06003015 _CheckPresent('root', data)
3016
3017 # There should be no files left. Remove all the directories to check.
3018 # If there are any files/dirs remaining, one of these checks will fail.
3019 self.assertEqual(0, len(outfiles))
3020 _CheckDirPresent('section/cbfs')
3021 _CheckDirPresent('section')
3022 _CheckDirPresent('')
3023 self.assertFalse(os.path.exists(outdir))
3024
3025 def testExtractAllEntries(self):
3026 """Test extracting all entries"""
3027 self._CheckLz4()
3028 self._CheckExtractOutput(decomp=True)
3029
3030 def testExtractAllEntriesRaw(self):
3031 """Test extracting all entries without decompressing them"""
3032 self._CheckLz4()
3033 self._CheckExtractOutput(decomp=False)
3034
3035 def testExtractSelectedEntries(self):
3036 """Test extracting some entries"""
3037 self._CheckLz4()
3038 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003039 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003040 outdir = os.path.join(self._indir, 'extract')
3041 einfos = control.ExtractEntries(image_fname, None, outdir,
3042 ['*cb*', '*head*'])
3043
3044 # File output is tested by testExtractAllEntries(), so just check that
3045 # the expected entries are selected
3046 names = [einfo.name for einfo in einfos]
3047 self.assertEqual(names,
3048 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3049
3050 def testExtractNoEntryPaths(self):
3051 """Test extracting some entries"""
3052 self._CheckLz4()
3053 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003054 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003055 with self.assertRaises(ValueError) as e:
3056 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003057 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003058 str(e.exception))
3059
3060 def testExtractTooManyEntryPaths(self):
3061 """Test extracting some entries"""
3062 self._CheckLz4()
3063 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003064 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003065 with self.assertRaises(ValueError) as e:
3066 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003067 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003068 str(e.exception))
3069
Simon Glass52d06212019-07-08 14:25:53 -06003070 def testPackAlignSection(self):
3071 """Test that sections can have alignment"""
3072 self._DoReadFile('131_pack_align_section.dts')
3073
3074 self.assertIn('image', control.images)
3075 image = control.images['image']
3076 entries = image.GetEntries()
3077 self.assertEqual(3, len(entries))
3078
3079 # First u-boot
3080 self.assertIn('u-boot', entries)
3081 entry = entries['u-boot']
3082 self.assertEqual(0, entry.offset)
3083 self.assertEqual(0, entry.image_pos)
3084 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3085 self.assertEqual(len(U_BOOT_DATA), entry.size)
3086
3087 # Section0
3088 self.assertIn('section0', entries)
3089 section0 = entries['section0']
3090 self.assertEqual(0x10, section0.offset)
3091 self.assertEqual(0x10, section0.image_pos)
3092 self.assertEqual(len(U_BOOT_DATA), section0.size)
3093
3094 # Second u-boot
3095 section_entries = section0.GetEntries()
3096 self.assertIn('u-boot', section_entries)
3097 entry = section_entries['u-boot']
3098 self.assertEqual(0, entry.offset)
3099 self.assertEqual(0x10, entry.image_pos)
3100 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3101 self.assertEqual(len(U_BOOT_DATA), entry.size)
3102
3103 # Section1
3104 self.assertIn('section1', entries)
3105 section1 = entries['section1']
3106 self.assertEqual(0x14, section1.offset)
3107 self.assertEqual(0x14, section1.image_pos)
3108 self.assertEqual(0x20, section1.size)
3109
3110 # Second u-boot
3111 section_entries = section1.GetEntries()
3112 self.assertIn('u-boot', section_entries)
3113 entry = section_entries['u-boot']
3114 self.assertEqual(0, entry.offset)
3115 self.assertEqual(0x14, entry.image_pos)
3116 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3117 self.assertEqual(len(U_BOOT_DATA), entry.size)
3118
3119 # Section2
3120 self.assertIn('section2', section_entries)
3121 section2 = section_entries['section2']
3122 self.assertEqual(0x4, section2.offset)
3123 self.assertEqual(0x18, section2.image_pos)
3124 self.assertEqual(4, section2.size)
3125
3126 # Third u-boot
3127 section_entries = section2.GetEntries()
3128 self.assertIn('u-boot', section_entries)
3129 entry = section_entries['u-boot']
3130 self.assertEqual(0, entry.offset)
3131 self.assertEqual(0x18, entry.image_pos)
3132 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3133 self.assertEqual(len(U_BOOT_DATA), entry.size)
3134
Simon Glassf8a54bc2019-07-20 12:23:56 -06003135 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3136 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003137 """Replace an entry in an image
3138
3139 This writes the entry data to update it, then opens the updated file and
3140 returns the value that it now finds there.
3141
3142 Args:
3143 entry_name: Entry name to replace
3144 data: Data to replace it with
3145 decomp: True to compress the data if needed, False if data is
3146 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003147 allow_resize: True to allow entries to change size, False to raise
3148 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003149
3150 Returns:
3151 Tuple:
3152 data from entry
3153 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003154 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003155 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003156 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003157 update_dtb=True)[1]
3158
3159 self.assertIn('image', control.images)
3160 image = control.images['image']
3161 entries = image.GetEntries()
3162 orig_dtb_data = entries['u-boot-dtb'].data
3163 orig_fdtmap_data = entries['fdtmap'].data
3164
Simon Glass80025522022-01-29 14:14:04 -07003165 image_fname = tools.get_output_filename('image.bin')
3166 updated_fname = tools.get_output_filename('image-updated.bin')
3167 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003168 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3169 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003170 data = control.ReadEntry(updated_fname, entry_name, decomp)
3171
Simon Glassf8a54bc2019-07-20 12:23:56 -06003172 # The DT data should not change unless resized:
3173 if not allow_resize:
3174 new_dtb_data = entries['u-boot-dtb'].data
3175 self.assertEqual(new_dtb_data, orig_dtb_data)
3176 new_fdtmap_data = entries['fdtmap'].data
3177 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003178
Simon Glassf8a54bc2019-07-20 12:23:56 -06003179 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003180
3181 def testReplaceSimple(self):
3182 """Test replacing a single file"""
3183 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003184 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3185 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003186 self.assertEqual(expected, data)
3187
3188 # Test that the state looks right. There should be an FDT for the fdtmap
3189 # that we jsut read back in, and it should match what we find in the
3190 # 'control' tables. Checking for an FDT that does not exist should
3191 # return None.
3192 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003193 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003194 self.assertEqual(expected_fdtmap, fdtmap)
3195
3196 dtb = state.GetFdtForEtype('fdtmap')
3197 self.assertEqual(dtb.GetContents(), fdtmap)
3198
3199 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3200 self.assertIsNone(missing_path)
3201 self.assertIsNone(missing_fdtmap)
3202
3203 missing_dtb = state.GetFdtForEtype('missing')
3204 self.assertIsNone(missing_dtb)
3205
3206 self.assertEqual('/binman', state.fdt_path_prefix)
3207
3208 def testReplaceResizeFail(self):
3209 """Test replacing a file by something larger"""
3210 expected = U_BOOT_DATA + b'x'
3211 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003212 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3213 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003214 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3215 str(e.exception))
3216
3217 def testReplaceMulti(self):
3218 """Test replacing entry data where multiple images are generated"""
3219 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3220 update_dtb=True)[0]
3221 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003222 updated_fname = tools.get_output_filename('image-updated.bin')
3223 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003224 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003225 control.WriteEntry(updated_fname, entry_name, expected,
3226 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003227 data = control.ReadEntry(updated_fname, entry_name)
3228 self.assertEqual(expected, data)
3229
3230 # Check the state looks right.
3231 self.assertEqual('/binman/image', state.fdt_path_prefix)
3232
3233 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003234 image_fname = tools.get_output_filename('first-image.bin')
3235 updated_fname = tools.get_output_filename('first-updated.bin')
3236 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003237 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003238 control.WriteEntry(updated_fname, entry_name, expected,
3239 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003240 data = control.ReadEntry(updated_fname, entry_name)
3241 self.assertEqual(expected, data)
3242
3243 # Check the state looks right.
3244 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003245
Simon Glassfb30e292019-07-20 12:23:51 -06003246 def testUpdateFdtAllRepack(self):
3247 """Test that all device trees are updated with offset/size info"""
3248 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3249 SECTION_SIZE = 0x300
3250 DTB_SIZE = 602
3251 FDTMAP_SIZE = 608
3252 base_expected = {
3253 'offset': 0,
3254 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3255 'image-pos': 0,
3256 'section:offset': 0,
3257 'section:size': SECTION_SIZE,
3258 'section:image-pos': 0,
3259 'section/u-boot-dtb:offset': 4,
3260 'section/u-boot-dtb:size': 636,
3261 'section/u-boot-dtb:image-pos': 4,
3262 'u-boot-spl-dtb:offset': SECTION_SIZE,
3263 'u-boot-spl-dtb:size': DTB_SIZE,
3264 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3265 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3266 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3267 'u-boot-tpl-dtb:size': DTB_SIZE,
3268 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3269 'fdtmap:size': FDTMAP_SIZE,
3270 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3271 }
3272 main_expected = {
3273 'section:orig-size': SECTION_SIZE,
3274 'section/u-boot-dtb:orig-offset': 4,
3275 }
3276
3277 # We expect three device-tree files in the output, with the first one
3278 # within a fixed-size section.
3279 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3280 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3281 # main U-Boot tree. All three should have the same positions and offset
3282 # except that the main tree should include the main_expected properties
3283 start = 4
3284 for item in ['', 'spl', 'tpl', None]:
3285 if item is None:
3286 start += 16 # Move past fdtmap header
3287 dtb = fdt.Fdt.FromData(data[start:])
3288 dtb.Scan()
3289 props = self._GetPropTree(dtb,
3290 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3291 prefix='/' if item is None else '/binman/')
3292 expected = dict(base_expected)
3293 if item:
3294 expected[item] = 0
3295 else:
3296 # Main DTB and fdtdec should include the 'orig-' properties
3297 expected.update(main_expected)
3298 # Helpful for debugging:
3299 #for prop in sorted(props):
3300 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3301 self.assertEqual(expected, props)
3302 if item == '':
3303 start = SECTION_SIZE
3304 else:
3305 start += dtb._fdt_obj.totalsize()
3306
Simon Glass11453762019-07-20 12:23:55 -06003307 def testFdtmapHeaderMiddle(self):
3308 """Test an FDT map in the middle of an image when it should be at end"""
3309 with self.assertRaises(ValueError) as e:
3310 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3311 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3312 str(e.exception))
3313
3314 def testFdtmapHeaderStartBad(self):
3315 """Test an FDT map in middle of an image when it should be at start"""
3316 with self.assertRaises(ValueError) as e:
3317 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3318 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3319 str(e.exception))
3320
3321 def testFdtmapHeaderEndBad(self):
3322 """Test an FDT map at the start of an image when it should be at end"""
3323 with self.assertRaises(ValueError) as e:
3324 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3325 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3326 str(e.exception))
3327
3328 def testFdtmapHeaderNoSize(self):
3329 """Test an image header at the end of an image with undefined size"""
3330 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3331
Simon Glassf8a54bc2019-07-20 12:23:56 -06003332 def testReplaceResize(self):
3333 """Test replacing a single file in an entry with a larger file"""
3334 expected = U_BOOT_DATA + b'x'
3335 data, _, image = self._RunReplaceCmd('u-boot', expected,
3336 dts='139_replace_repack.dts')
3337 self.assertEqual(expected, data)
3338
3339 entries = image.GetEntries()
3340 dtb_data = entries['u-boot-dtb'].data
3341 dtb = fdt.Fdt.FromData(dtb_data)
3342 dtb.Scan()
3343
3344 # The u-boot section should now be larger in the dtb
3345 node = dtb.GetNode('/binman/u-boot')
3346 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3347
3348 # Same for the fdtmap
3349 fdata = entries['fdtmap'].data
3350 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3351 fdtb.Scan()
3352 fnode = fdtb.GetNode('/u-boot')
3353 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3354
3355 def testReplaceResizeNoRepack(self):
3356 """Test replacing an entry with a larger file when not allowed"""
3357 expected = U_BOOT_DATA + b'x'
3358 with self.assertRaises(ValueError) as e:
3359 self._RunReplaceCmd('u-boot', expected)
3360 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3361 str(e.exception))
3362
Simon Glass9d8ee322019-07-20 12:23:58 -06003363 def testEntryShrink(self):
3364 """Test contracting an entry after it is packed"""
3365 try:
3366 state.SetAllowEntryContraction(True)
3367 data = self._DoReadFileDtb('140_entry_shrink.dts',
3368 update_dtb=True)[0]
3369 finally:
3370 state.SetAllowEntryContraction(False)
3371 self.assertEqual(b'a', data[:1])
3372 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3373 self.assertEqual(b'a', data[-1:])
3374
3375 def testEntryShrinkFail(self):
3376 """Test not being allowed to contract an entry after it is packed"""
3377 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3378
3379 # In this case there is a spare byte at the end of the data. The size of
3380 # the contents is only 1 byte but we still have the size before it
3381 # shrunk.
3382 self.assertEqual(b'a\0', data[:2])
3383 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3384 self.assertEqual(b'a\0', data[-2:])
3385
Simon Glass70e32982019-07-20 12:24:01 -06003386 def testDescriptorOffset(self):
3387 """Test that the Intel descriptor is always placed at at the start"""
3388 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3389 image = control.images['image']
3390 entries = image.GetEntries()
3391 desc = entries['intel-descriptor']
3392 self.assertEqual(0xff800000, desc.offset);
3393 self.assertEqual(0xff800000, desc.image_pos);
3394
Simon Glass37fdd142019-07-20 12:24:06 -06003395 def testReplaceCbfs(self):
3396 """Test replacing a single file in CBFS without changing the size"""
3397 self._CheckLz4()
3398 expected = b'x' * len(U_BOOT_DATA)
3399 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003400 updated_fname = tools.get_output_filename('image-updated.bin')
3401 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003402 entry_name = 'section/cbfs/u-boot'
3403 control.WriteEntry(updated_fname, entry_name, expected,
3404 allow_resize=True)
3405 data = control.ReadEntry(updated_fname, entry_name)
3406 self.assertEqual(expected, data)
3407
3408 def testReplaceResizeCbfs(self):
3409 """Test replacing a single file in CBFS with one of a different size"""
3410 self._CheckLz4()
3411 expected = U_BOOT_DATA + b'x'
3412 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003413 updated_fname = tools.get_output_filename('image-updated.bin')
3414 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003415 entry_name = 'section/cbfs/u-boot'
3416 control.WriteEntry(updated_fname, entry_name, expected,
3417 allow_resize=True)
3418 data = control.ReadEntry(updated_fname, entry_name)
3419 self.assertEqual(expected, data)
3420
Simon Glass30033c22019-07-20 12:24:15 -06003421 def _SetupForReplace(self):
3422 """Set up some files to use to replace entries
3423
3424 This generates an image, copies it to a new file, extracts all the files
3425 in it and updates some of them
3426
3427 Returns:
3428 List
3429 Image filename
3430 Output directory
3431 Expected values for updated entries, each a string
3432 """
3433 data = self._DoReadFileRealDtb('143_replace_all.dts')
3434
Simon Glass80025522022-01-29 14:14:04 -07003435 updated_fname = tools.get_output_filename('image-updated.bin')
3436 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003437
3438 outdir = os.path.join(self._indir, 'extract')
3439 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3440
3441 expected1 = b'x' + U_BOOT_DATA + b'y'
3442 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003443 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003444
3445 expected2 = b'a' + U_BOOT_DATA + b'b'
3446 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003447 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003448
3449 expected_text = b'not the same text'
3450 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003451 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003452
3453 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3454 dtb = fdt.FdtScan(dtb_fname)
3455 node = dtb.GetNode('/binman/text')
3456 node.AddString('my-property', 'the value')
3457 dtb.Sync(auto_resize=True)
3458 dtb.Flush()
3459
3460 return updated_fname, outdir, expected1, expected2, expected_text
3461
3462 def _CheckReplaceMultiple(self, entry_paths):
3463 """Handle replacing the contents of multiple entries
3464
3465 Args:
3466 entry_paths: List of entry paths to replace
3467
3468 Returns:
3469 List
3470 Dict of entries in the image:
3471 key: Entry name
3472 Value: Entry object
3473 Expected values for updated entries, each a string
3474 """
3475 updated_fname, outdir, expected1, expected2, expected_text = (
3476 self._SetupForReplace())
3477 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3478
3479 image = Image.FromFile(updated_fname)
3480 image.LoadData()
3481 return image.GetEntries(), expected1, expected2, expected_text
3482
3483 def testReplaceAll(self):
3484 """Test replacing the contents of all entries"""
3485 entries, expected1, expected2, expected_text = (
3486 self._CheckReplaceMultiple([]))
3487 data = entries['u-boot'].data
3488 self.assertEqual(expected1, data)
3489
3490 data = entries['u-boot2'].data
3491 self.assertEqual(expected2, data)
3492
3493 data = entries['text'].data
3494 self.assertEqual(expected_text, data)
3495
3496 # Check that the device tree is updated
3497 data = entries['u-boot-dtb'].data
3498 dtb = fdt.Fdt.FromData(data)
3499 dtb.Scan()
3500 node = dtb.GetNode('/binman/text')
3501 self.assertEqual('the value', node.props['my-property'].value)
3502
3503 def testReplaceSome(self):
3504 """Test replacing the contents of a few entries"""
3505 entries, expected1, expected2, expected_text = (
3506 self._CheckReplaceMultiple(['u-boot2', 'text']))
3507
3508 # This one should not change
3509 data = entries['u-boot'].data
3510 self.assertEqual(U_BOOT_DATA, data)
3511
3512 data = entries['u-boot2'].data
3513 self.assertEqual(expected2, data)
3514
3515 data = entries['text'].data
3516 self.assertEqual(expected_text, data)
3517
3518 def testReplaceCmd(self):
3519 """Test replacing a file fron an image on the command line"""
3520 self._DoReadFileRealDtb('143_replace_all.dts')
3521
3522 try:
3523 tmpdir, updated_fname = self._SetupImageInTmpdir()
3524
3525 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3526 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003527 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003528
3529 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003530 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003531 self.assertEqual(expected, data[:len(expected)])
3532 map_fname = os.path.join(tmpdir, 'image-updated.map')
3533 self.assertFalse(os.path.exists(map_fname))
3534 finally:
3535 shutil.rmtree(tmpdir)
3536
3537 def testReplaceCmdSome(self):
3538 """Test replacing some files fron an image on the command line"""
3539 updated_fname, outdir, expected1, expected2, expected_text = (
3540 self._SetupForReplace())
3541
3542 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3543 'u-boot2', 'text')
3544
Simon Glass80025522022-01-29 14:14:04 -07003545 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003546 image = Image.FromFile(updated_fname)
3547 image.LoadData()
3548 entries = image.GetEntries()
3549
3550 # This one should not change
3551 data = entries['u-boot'].data
3552 self.assertEqual(U_BOOT_DATA, data)
3553
3554 data = entries['u-boot2'].data
3555 self.assertEqual(expected2, data)
3556
3557 data = entries['text'].data
3558 self.assertEqual(expected_text, data)
3559
3560 def testReplaceMissing(self):
3561 """Test replacing entries where the file is missing"""
3562 updated_fname, outdir, expected1, expected2, expected_text = (
3563 self._SetupForReplace())
3564
3565 # Remove one of the files, to generate a warning
3566 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3567 os.remove(u_boot_fname1)
3568
3569 with test_util.capture_sys_output() as (stdout, stderr):
3570 control.ReplaceEntries(updated_fname, None, outdir, [])
3571 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003572 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003573
3574 def testReplaceCmdMap(self):
3575 """Test replacing a file fron an image on the command line"""
3576 self._DoReadFileRealDtb('143_replace_all.dts')
3577
3578 try:
3579 tmpdir, updated_fname = self._SetupImageInTmpdir()
3580
3581 fname = os.path.join(self._indir, 'update-u-boot.bin')
3582 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003583 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003584
3585 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3586 '-f', fname, '-m')
3587 map_fname = os.path.join(tmpdir, 'image-updated.map')
3588 self.assertTrue(os.path.exists(map_fname))
3589 finally:
3590 shutil.rmtree(tmpdir)
3591
3592 def testReplaceNoEntryPaths(self):
3593 """Test replacing an entry without an entry path"""
3594 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003595 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003596 with self.assertRaises(ValueError) as e:
3597 control.ReplaceEntries(image_fname, 'fname', None, [])
3598 self.assertIn('Must specify an entry path to read with -f',
3599 str(e.exception))
3600
3601 def testReplaceTooManyEntryPaths(self):
3602 """Test extracting some entries"""
3603 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003604 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003605 with self.assertRaises(ValueError) as e:
3606 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3607 self.assertIn('Must specify exactly one entry path to write with -f',
3608 str(e.exception))
3609
Simon Glass0b074d62019-08-24 07:22:48 -06003610 def testPackReset16(self):
3611 """Test that an image with an x86 reset16 region can be created"""
3612 data = self._DoReadFile('144_x86_reset16.dts')
3613 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3614
3615 def testPackReset16Spl(self):
3616 """Test that an image with an x86 reset16-spl region can be created"""
3617 data = self._DoReadFile('145_x86_reset16_spl.dts')
3618 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3619
3620 def testPackReset16Tpl(self):
3621 """Test that an image with an x86 reset16-tpl region can be created"""
3622 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3623 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3624
Simon Glass232f90c2019-08-24 07:22:50 -06003625 def testPackIntelFit(self):
3626 """Test that an image with an Intel FIT and pointer can be created"""
3627 data = self._DoReadFile('147_intel_fit.dts')
3628 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3629 fit = data[16:32];
3630 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3631 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3632
3633 image = control.images['image']
3634 entries = image.GetEntries()
3635 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3636 self.assertEqual(expected_ptr, ptr)
3637
3638 def testPackIntelFitMissing(self):
3639 """Test detection of a FIT pointer with not FIT region"""
3640 with self.assertRaises(ValueError) as e:
3641 self._DoReadFile('148_intel_fit_missing.dts')
3642 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3643 str(e.exception))
3644
Simon Glass72555fa2019-11-06 17:22:44 -07003645 def _CheckSymbolsTplSection(self, dts, expected_vals):
3646 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003647 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003648 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003649 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003650 self.assertEqual(expected1, data[:upto1])
3651
3652 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003653 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003654 self.assertEqual(expected2, data[upto1:upto2])
3655
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003656 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003657 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003658 self.assertEqual(expected3, data[upto2:upto3])
3659
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003660 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003661 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3662
3663 def testSymbolsTplSection(self):
3664 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3665 self._SetupSplElf('u_boot_binman_syms')
3666 self._SetupTplElf('u_boot_binman_syms')
3667 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003668 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003669
3670 def testSymbolsTplSectionX86(self):
3671 """Test binman can assign symbols in a section with end-at-4gb"""
3672 self._SetupSplElf('u_boot_binman_syms_x86')
3673 self._SetupTplElf('u_boot_binman_syms_x86')
3674 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003675 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003676 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003677
Simon Glass98c59572019-08-24 07:23:03 -06003678 def testPackX86RomIfwiSectiom(self):
3679 """Test that a section can be placed in an IFWI region"""
3680 self._SetupIfwi('fitimage.bin')
3681 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3682 self._CheckIfwi(data)
3683
Simon Glassba7985d2019-08-24 07:23:07 -06003684 def testPackFspM(self):
3685 """Test that an image with a FSP memory-init binary can be created"""
3686 data = self._DoReadFile('152_intel_fsp_m.dts')
3687 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3688
Simon Glass4d9086d2019-10-20 21:31:35 -06003689 def testPackFspS(self):
3690 """Test that an image with a FSP silicon-init binary can be created"""
3691 data = self._DoReadFile('153_intel_fsp_s.dts')
3692 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003693
Simon Glass9ea87b22019-10-20 21:31:36 -06003694 def testPackFspT(self):
3695 """Test that an image with a FSP temp-ram-init binary can be created"""
3696 data = self._DoReadFile('154_intel_fsp_t.dts')
3697 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3698
Simon Glass48f3aad2020-07-09 18:39:31 -06003699 def testMkimage(self):
3700 """Test using mkimage to build an image"""
3701 data = self._DoReadFile('156_mkimage.dts')
3702
3703 # Just check that the data appears in the file somewhere
3704 self.assertIn(U_BOOT_SPL_DATA, data)
3705
Simon Glass66152ce2022-01-09 20:14:09 -07003706 def testMkimageMissing(self):
3707 """Test that binman still produces an image if mkimage is missing"""
3708 with test_util.capture_sys_output() as (_, stderr):
3709 self._DoTestFile('156_mkimage.dts',
3710 force_missing_bintools='mkimage')
3711 err = stderr.getvalue()
3712 self.assertRegex(err,
3713 "Image 'main-section'.*missing bintools.*: mkimage")
3714
Simon Glass5e560182020-07-09 18:39:36 -06003715 def testExtblob(self):
3716 """Test an image with an external blob"""
3717 data = self._DoReadFile('157_blob_ext.dts')
3718 self.assertEqual(REFCODE_DATA, data)
3719
3720 def testExtblobMissing(self):
3721 """Test an image with a missing external blob"""
3722 with self.assertRaises(ValueError) as e:
3723 self._DoReadFile('158_blob_ext_missing.dts')
3724 self.assertIn("Filename 'missing-file' not found in input path",
3725 str(e.exception))
3726
Simon Glass5d94cc62020-07-09 18:39:38 -06003727 def testExtblobMissingOk(self):
3728 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003729 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass6bce5dc2022-11-09 19:14:42 -07003730 ret = self._DoTestFile('158_blob_ext_missing.dts',
3731 allow_missing=True)
3732 self.assertEqual(103, ret)
Simon Glassa003cd32020-07-09 18:39:40 -06003733 err = stderr.getvalue()
3734 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
Simon Glass6bce5dc2022-11-09 19:14:42 -07003735 self.assertIn('Some images are invalid', err)
3736
3737 def testExtblobMissingOkFlag(self):
3738 """Test an image with an missing external blob allowed with -W"""
3739 with test_util.capture_sys_output() as (stdout, stderr):
3740 ret = self._DoTestFile('158_blob_ext_missing.dts',
3741 allow_missing=True, ignore_missing=True)
3742 self.assertEqual(0, ret)
3743 err = stderr.getvalue()
3744 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3745 self.assertIn('Some images are invalid', err)
Simon Glassa003cd32020-07-09 18:39:40 -06003746
3747 def testExtblobMissingOkSect(self):
3748 """Test an image with an missing external blob that is allowed"""
3749 with test_util.capture_sys_output() as (stdout, stderr):
3750 self._DoTestFile('159_blob_ext_missing_sect.dts',
3751 allow_missing=True)
3752 err = stderr.getvalue()
3753 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3754 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003755
Simon Glasse88cef92020-07-09 18:39:41 -06003756 def testPackX86RomMeMissingDesc(self):
3757 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003758 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003759 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003760 err = stderr.getvalue()
3761 self.assertRegex(err,
3762 "Image 'main-section'.*missing.*: intel-descriptor")
3763
3764 def testPackX86RomMissingIfwi(self):
3765 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3766 self._SetupIfwi('fitimage.bin')
3767 pathname = os.path.join(self._indir, 'fitimage.bin')
3768 os.remove(pathname)
3769 with test_util.capture_sys_output() as (stdout, stderr):
3770 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3771 err = stderr.getvalue()
3772 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3773
Simon Glass2a0fa982022-02-11 13:23:21 -07003774 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003775 """Test that zero-size overlapping regions are ignored"""
3776 self._DoTestFile('160_pack_overlap_zero.dts')
3777
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003778 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003779 # The data should be inside the FIT
3780 dtb = fdt.Fdt.FromData(fit_data)
3781 dtb.Scan()
3782 fnode = dtb.GetNode('/images/kernel')
3783 self.assertIn('data', fnode.props)
3784
3785 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003786 tools.write_file(fname, fit_data)
3787 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003788
3789 # Check a few features to make sure the plumbing works. We don't need
3790 # to test the operation of mkimage or dumpimage here. First convert the
3791 # output into a dict where the keys are the fields printed by dumpimage
3792 # and the values are a list of values for each field
3793 lines = out.splitlines()
3794
3795 # Converts "Compression: gzip compressed" into two groups:
3796 # 'Compression' and 'gzip compressed'
3797 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3798 vals = collections.defaultdict(list)
3799 for line in lines:
3800 mat = re_line.match(line)
3801 vals[mat.group(1)].append(mat.group(2))
3802
3803 self.assertEquals('FIT description: test-desc', lines[0])
3804 self.assertIn('Created:', lines[1])
3805 self.assertIn('Image 0 (kernel)', vals)
3806 self.assertIn('Hash value', vals)
3807 data_sizes = vals.get('Data Size')
3808 self.assertIsNotNone(data_sizes)
3809 self.assertEqual(2, len(data_sizes))
3810 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003811 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3812 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3813
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003814 # Check if entry listing correctly omits /images/
3815 image = control.images['image']
3816 fit_entry = image.GetEntries()['fit']
3817 subentries = list(fit_entry.GetEntries().keys())
3818 expected = ['kernel', 'fdt-1']
3819 self.assertEqual(expected, subentries)
3820
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003821 def testSimpleFit(self):
3822 """Test an image with a FIT inside"""
3823 data = self._DoReadFile('161_fit.dts')
3824 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3825 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3826 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3827
3828 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3829
3830 def testSimpleFitExpandsSubentries(self):
3831 """Test that FIT images expand their subentries"""
3832 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3833 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3834 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3835 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3836
3837 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003838
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003839 def testSimpleFitImagePos(self):
3840 """Test that we have correct image-pos for FIT subentries"""
3841 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3842 update_dtb=True)
3843 dtb = fdt.Fdt(out_dtb_fname)
3844 dtb.Scan()
3845 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3846
Simon Glassb7bad182022-03-05 20:19:01 -07003847 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003848 self.assertEqual({
3849 'image-pos': 0,
3850 'offset': 0,
3851 'size': 1890,
3852
3853 'u-boot:image-pos': 0,
3854 'u-boot:offset': 0,
3855 'u-boot:size': 4,
3856
3857 'fit:image-pos': 4,
3858 'fit:offset': 4,
3859 'fit:size': 1840,
3860
Simon Glassb7bad182022-03-05 20:19:01 -07003861 'fit/images/kernel:image-pos': 304,
3862 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003863 'fit/images/kernel:size': 4,
3864
Simon Glassb7bad182022-03-05 20:19:01 -07003865 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003866 'fit/images/kernel/u-boot:offset': 0,
3867 'fit/images/kernel/u-boot:size': 4,
3868
Simon Glassb7bad182022-03-05 20:19:01 -07003869 'fit/images/fdt-1:image-pos': 552,
3870 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003871 'fit/images/fdt-1:size': 6,
3872
Simon Glassb7bad182022-03-05 20:19:01 -07003873 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003874 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3875 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3876
3877 'u-boot-nodtb:image-pos': 1844,
3878 'u-boot-nodtb:offset': 1844,
3879 'u-boot-nodtb:size': 46,
3880 }, props)
3881
3882 # Actually check the data is where we think it is
3883 for node, expected in [
3884 ("u-boot", U_BOOT_DATA),
3885 ("fit/images/kernel", U_BOOT_DATA),
3886 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3887 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3888 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3889 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3890 ]:
3891 image_pos = props[f"{node}:image-pos"]
3892 size = props[f"{node}:size"]
3893 self.assertEqual(len(expected), size)
3894 self.assertEqual(expected, data[image_pos:image_pos+size])
3895
Simon Glass45d556d2020-07-09 18:39:45 -06003896 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003897 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003898 data = self._DoReadFile('162_fit_external.dts')
3899 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3900
Simon Glass7932c882022-01-09 20:13:39 -07003901 # Size of the external-data region as set up by mkimage
3902 external_data_size = len(U_BOOT_DATA) + 2
3903 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003904 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003905 len(U_BOOT_NODTB_DATA))
3906
Simon Glass45d556d2020-07-09 18:39:45 -06003907 # The data should be outside the FIT
3908 dtb = fdt.Fdt.FromData(fit_data)
3909 dtb.Scan()
3910 fnode = dtb.GetNode('/images/kernel')
3911 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003912 self.assertEqual(len(U_BOOT_DATA),
3913 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3914 fit_pos = 0x400;
3915 self.assertEqual(
3916 fit_pos,
3917 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3918
3919 self.assertEquals(expected_size, len(data))
3920 actual_pos = len(U_BOOT_DATA) + fit_pos
3921 self.assertEqual(U_BOOT_DATA + b'aa',
3922 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003923
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003924 def testFitExternalImagePos(self):
3925 """Test that we have correct image-pos for external FIT subentries"""
3926 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3927 update_dtb=True)
3928 dtb = fdt.Fdt(out_dtb_fname)
3929 dtb.Scan()
3930 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3931
3932 self.assertEqual({
3933 'image-pos': 0,
3934 'offset': 0,
3935 'size': 1082,
3936
3937 'u-boot:image-pos': 0,
3938 'u-boot:offset': 0,
3939 'u-boot:size': 4,
3940
3941 'fit:size': 1032,
3942 'fit:offset': 4,
3943 'fit:image-pos': 4,
3944
3945 'fit/images/kernel:size': 4,
3946 'fit/images/kernel:offset': 1024,
3947 'fit/images/kernel:image-pos': 1028,
3948
3949 'fit/images/kernel/u-boot:size': 4,
3950 'fit/images/kernel/u-boot:offset': 0,
3951 'fit/images/kernel/u-boot:image-pos': 1028,
3952
3953 'fit/images/fdt-1:size': 2,
3954 'fit/images/fdt-1:offset': 1028,
3955 'fit/images/fdt-1:image-pos': 1032,
3956
3957 'fit/images/fdt-1/_testing:size': 2,
3958 'fit/images/fdt-1/_testing:offset': 0,
3959 'fit/images/fdt-1/_testing:image-pos': 1032,
3960
3961 'u-boot-nodtb:image-pos': 1036,
3962 'u-boot-nodtb:offset': 1036,
3963 'u-boot-nodtb:size': 46,
3964 }, props)
3965
3966 # Actually check the data is where we think it is
3967 for node, expected in [
3968 ("u-boot", U_BOOT_DATA),
3969 ("fit/images/kernel", U_BOOT_DATA),
3970 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3971 ("fit/images/fdt-1", b'aa'),
3972 ("fit/images/fdt-1/_testing", b'aa'),
3973 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3974 ]:
3975 image_pos = props[f"{node}:image-pos"]
3976 size = props[f"{node}:size"]
3977 self.assertEqual(len(expected), size)
3978 self.assertEqual(expected, data[image_pos:image_pos+size])
3979
Simon Glass66152ce2022-01-09 20:14:09 -07003980 def testFitMissing(self):
3981 """Test that binman still produces a FIT image if mkimage is missing"""
3982 with test_util.capture_sys_output() as (_, stderr):
3983 self._DoTestFile('162_fit_external.dts',
3984 force_missing_bintools='mkimage')
3985 err = stderr.getvalue()
3986 self.assertRegex(err,
3987 "Image 'main-section'.*missing bintools.*: mkimage")
3988
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003989 def testSectionIgnoreHashSignature(self):
3990 """Test that sections ignore hash, signature nodes for its data"""
3991 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3992 expected = (U_BOOT_DATA + U_BOOT_DATA)
3993 self.assertEqual(expected, data)
3994
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003995 def testPadInSections(self):
3996 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06003997 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3998 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07003999 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4000 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03004001 U_BOOT_DATA)
4002 self.assertEqual(expected, data)
4003
Simon Glassd12599d2020-10-26 17:40:09 -06004004 dtb = fdt.Fdt(out_dtb_fname)
4005 dtb.Scan()
4006 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
4007 expected = {
4008 'image-pos': 0,
4009 'offset': 0,
4010 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
4011
4012 'section:image-pos': 0,
4013 'section:offset': 0,
4014 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
4015
4016 'section/before:image-pos': 0,
4017 'section/before:offset': 0,
4018 'section/before:size': len(U_BOOT_DATA),
4019
4020 'section/u-boot:image-pos': 4,
4021 'section/u-boot:offset': 4,
4022 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
4023
4024 'section/after:image-pos': 26,
4025 'section/after:offset': 26,
4026 'section/after:size': len(U_BOOT_DATA),
4027 }
4028 self.assertEqual(expected, props)
4029
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004030 def testFitImageSubentryAlignment(self):
4031 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03004032 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004033 entry_args = {
4034 'test-id': TEXT_DATA,
4035 }
4036 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
4037 entry_args=entry_args)
4038 dtb = fdt.Fdt.FromData(data)
4039 dtb.Scan()
4040
4041 node = dtb.GetNode('/images/kernel')
4042 data = dtb.GetProps(node)["data"].bytes
4043 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07004044 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
4045 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004046 self.assertEqual(expected, data)
4047
4048 node = dtb.GetNode('/images/fdt-1')
4049 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004050 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4051 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004052 U_BOOT_DTB_DATA)
4053 self.assertEqual(expected, data)
4054
4055 def testFitExtblobMissingOk(self):
4056 """Test a FIT with a missing external blob that is allowed"""
4057 with test_util.capture_sys_output() as (stdout, stderr):
4058 self._DoTestFile('168_fit_missing_blob.dts',
4059 allow_missing=True)
4060 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06004061 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004062
Simon Glass21db0ff2020-09-01 05:13:54 -06004063 def testBlobNamedByArgMissing(self):
4064 """Test handling of a missing entry arg"""
4065 with self.assertRaises(ValueError) as e:
4066 self._DoReadFile('068_blob_named_by_arg.dts')
4067 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4068 str(e.exception))
4069
Simon Glass559c4de2020-09-01 05:13:58 -06004070 def testPackBl31(self):
4071 """Test that an image with an ATF BL31 binary can be created"""
4072 data = self._DoReadFile('169_atf_bl31.dts')
4073 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4074
Samuel Holland9d8cc632020-10-21 21:12:15 -05004075 def testPackScp(self):
4076 """Test that an image with an SCP binary can be created"""
4077 data = self._DoReadFile('172_scp.dts')
4078 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4079
Simon Glassa435cd12020-09-01 05:13:59 -06004080 def testFitFdt(self):
4081 """Test an image with an FIT with multiple FDT images"""
4082 def _CheckFdt(seq, expected_data):
4083 """Check the FDT nodes
4084
4085 Args:
4086 seq: Sequence number to check (0 or 1)
4087 expected_data: Expected contents of 'data' property
4088 """
4089 name = 'fdt-%d' % seq
4090 fnode = dtb.GetNode('/images/%s' % name)
4091 self.assertIsNotNone(fnode)
4092 self.assertEqual({'description','type', 'compression', 'data'},
4093 set(fnode.props.keys()))
4094 self.assertEqual(expected_data, fnode.props['data'].bytes)
4095 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4096 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004097 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004098
4099 def _CheckConfig(seq, expected_data):
4100 """Check the configuration nodes
4101
4102 Args:
4103 seq: Sequence number to check (0 or 1)
4104 expected_data: Expected contents of 'data' property
4105 """
4106 cnode = dtb.GetNode('/configurations')
4107 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004108 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004109
4110 name = 'config-%d' % seq
4111 fnode = dtb.GetNode('/configurations/%s' % name)
4112 self.assertIsNotNone(fnode)
4113 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4114 set(fnode.props.keys()))
4115 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4116 fnode.props['description'].value)
4117 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4118
4119 entry_args = {
4120 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004121 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004122 }
4123 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004124 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004125 entry_args=entry_args,
4126 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4127 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4128 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4129
4130 dtb = fdt.Fdt.FromData(fit_data)
4131 dtb.Scan()
4132 fnode = dtb.GetNode('/images/kernel')
4133 self.assertIn('data', fnode.props)
4134
4135 # Check all the properties in fdt-1 and fdt-2
4136 _CheckFdt(1, TEST_FDT1_DATA)
4137 _CheckFdt(2, TEST_FDT2_DATA)
4138
4139 # Check configurations
4140 _CheckConfig(1, TEST_FDT1_DATA)
4141 _CheckConfig(2, TEST_FDT2_DATA)
4142
4143 def testFitFdtMissingList(self):
4144 """Test handling of a missing 'of-list' entry arg"""
4145 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004146 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004147 self.assertIn("Generator node requires 'of-list' entry argument",
4148 str(e.exception))
4149
4150 def testFitFdtEmptyList(self):
4151 """Test handling of an empty 'of-list' entry arg"""
4152 entry_args = {
4153 'of-list': '',
4154 }
4155 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4156
4157 def testFitFdtMissingProp(self):
4158 """Test handling of a missing 'fit,fdt-list' property"""
4159 with self.assertRaises(ValueError) as e:
4160 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4161 self.assertIn("Generator node requires 'fit,fdt-list' property",
4162 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004163
Simon Glass1032acc2020-09-06 10:39:08 -06004164 def testFitFdtMissing(self):
4165 """Test handling of a missing 'default-dt' entry arg"""
4166 entry_args = {
4167 'of-list': 'test-fdt1 test-fdt2',
4168 }
4169 with self.assertRaises(ValueError) as e:
4170 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004171 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004172 entry_args=entry_args,
4173 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4174 self.assertIn("Generated 'default' node requires default-dt entry argument",
4175 str(e.exception))
4176
4177 def testFitFdtNotInList(self):
4178 """Test handling of a default-dt that is not in the of-list"""
4179 entry_args = {
4180 'of-list': 'test-fdt1 test-fdt2',
4181 'default-dt': 'test-fdt3',
4182 }
4183 with self.assertRaises(ValueError) as e:
4184 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004185 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004186 entry_args=entry_args,
4187 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4188 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4189 str(e.exception))
4190
Simon Glassa820af72020-09-06 10:39:09 -06004191 def testFitExtblobMissingHelp(self):
4192 """Test display of help messages when an external blob is missing"""
4193 control.missing_blob_help = control._ReadMissingBlobHelp()
4194 control.missing_blob_help['wibble'] = 'Wibble test'
4195 control.missing_blob_help['another'] = 'Another test'
4196 with test_util.capture_sys_output() as (stdout, stderr):
4197 self._DoTestFile('168_fit_missing_blob.dts',
4198 allow_missing=True)
4199 err = stderr.getvalue()
4200
4201 # We can get the tag from the name, the type or the missing-msg
4202 # property. Check all three.
4203 self.assertIn('You may need to build ARM Trusted', err)
4204 self.assertIn('Wibble test', err)
4205 self.assertIn('Another test', err)
4206
Simon Glass6f1f4d42020-09-06 10:35:32 -06004207 def testMissingBlob(self):
4208 """Test handling of a blob containing a missing file"""
4209 with self.assertRaises(ValueError) as e:
4210 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4211 self.assertIn("Filename 'missing' not found in input path",
4212 str(e.exception))
4213
Simon Glassa0729502020-09-06 10:35:33 -06004214 def testEnvironment(self):
4215 """Test adding a U-Boot environment"""
4216 data = self._DoReadFile('174_env.dts')
4217 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4218 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4219 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4220 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4221 env)
4222
4223 def testEnvironmentNoSize(self):
4224 """Test that a missing 'size' property is detected"""
4225 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004226 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004227 self.assertIn("'u-boot-env' entry must have a size property",
4228 str(e.exception))
4229
4230 def testEnvironmentTooSmall(self):
4231 """Test handling of an environment that does not fit"""
4232 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004233 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004234
4235 # checksum, start byte, environment with \0 terminator, final \0
4236 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4237 short = need - 0x8
4238 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4239 str(e.exception))
4240
Simon Glassd1fdf752020-10-26 17:40:01 -06004241 def testSkipAtStart(self):
4242 """Test handling of skip-at-start section"""
4243 data = self._DoReadFile('177_skip_at_start.dts')
4244 self.assertEqual(U_BOOT_DATA, data)
4245
4246 image = control.images['image']
4247 entries = image.GetEntries()
4248 section = entries['section']
4249 self.assertEqual(0, section.offset)
4250 self.assertEqual(len(U_BOOT_DATA), section.size)
4251 self.assertEqual(U_BOOT_DATA, section.GetData())
4252
4253 entry = section.GetEntries()['u-boot']
4254 self.assertEqual(16, entry.offset)
4255 self.assertEqual(len(U_BOOT_DATA), entry.size)
4256 self.assertEqual(U_BOOT_DATA, entry.data)
4257
4258 def testSkipAtStartPad(self):
4259 """Test handling of skip-at-start section with padded entry"""
4260 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004261 before = tools.get_bytes(0, 8)
4262 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004263 all = before + U_BOOT_DATA + after
4264 self.assertEqual(all, data)
4265
4266 image = control.images['image']
4267 entries = image.GetEntries()
4268 section = entries['section']
4269 self.assertEqual(0, section.offset)
4270 self.assertEqual(len(all), section.size)
4271 self.assertEqual(all, section.GetData())
4272
4273 entry = section.GetEntries()['u-boot']
4274 self.assertEqual(16, entry.offset)
4275 self.assertEqual(len(all), entry.size)
4276 self.assertEqual(U_BOOT_DATA, entry.data)
4277
4278 def testSkipAtStartSectionPad(self):
4279 """Test handling of skip-at-start section with padding"""
4280 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004281 before = tools.get_bytes(0, 8)
4282 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004283 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004284 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004285
4286 image = control.images['image']
4287 entries = image.GetEntries()
4288 section = entries['section']
4289 self.assertEqual(0, section.offset)
4290 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004291 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004292 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004293
4294 entry = section.GetEntries()['u-boot']
4295 self.assertEqual(16, entry.offset)
4296 self.assertEqual(len(U_BOOT_DATA), entry.size)
4297 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004298
Simon Glassbb395742020-10-26 17:40:14 -06004299 def testSectionPad(self):
4300 """Testing padding with sections"""
4301 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004302 expected = (tools.get_bytes(ord('&'), 3) +
4303 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004304 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004305 tools.get_bytes(ord('!'), 1) +
4306 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004307 self.assertEqual(expected, data)
4308
4309 def testSectionAlign(self):
4310 """Testing alignment with sections"""
4311 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4312 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004313 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004314 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004315 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004316 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004317 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4318 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004319 self.assertEqual(expected, data)
4320
Simon Glassd92c8362020-10-26 17:40:25 -06004321 def testCompressImage(self):
4322 """Test compression of the entire image"""
4323 self._CheckLz4()
4324 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4325 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4326 dtb = fdt.Fdt(out_dtb_fname)
4327 dtb.Scan()
4328 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4329 'uncomp-size'])
4330 orig = self._decompress(data)
4331 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4332
4333 # Do a sanity check on various fields
4334 image = control.images['image']
4335 entries = image.GetEntries()
4336 self.assertEqual(2, len(entries))
4337
4338 entry = entries['blob']
4339 self.assertEqual(COMPRESS_DATA, entry.data)
4340 self.assertEqual(len(COMPRESS_DATA), entry.size)
4341
4342 entry = entries['u-boot']
4343 self.assertEqual(U_BOOT_DATA, entry.data)
4344 self.assertEqual(len(U_BOOT_DATA), entry.size)
4345
4346 self.assertEqual(len(data), image.size)
4347 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4348 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4349 orig = self._decompress(image.data)
4350 self.assertEqual(orig, image.uncomp_data)
4351
4352 expected = {
4353 'blob:offset': 0,
4354 'blob:size': len(COMPRESS_DATA),
4355 'u-boot:offset': len(COMPRESS_DATA),
4356 'u-boot:size': len(U_BOOT_DATA),
4357 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4358 'offset': 0,
4359 'image-pos': 0,
4360 'size': len(data),
4361 }
4362 self.assertEqual(expected, props)
4363
4364 def testCompressImageLess(self):
4365 """Test compression where compression reduces the image size"""
4366 self._CheckLz4()
4367 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4368 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4369 dtb = fdt.Fdt(out_dtb_fname)
4370 dtb.Scan()
4371 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4372 'uncomp-size'])
4373 orig = self._decompress(data)
4374
4375 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4376
4377 # Do a sanity check on various fields
4378 image = control.images['image']
4379 entries = image.GetEntries()
4380 self.assertEqual(2, len(entries))
4381
4382 entry = entries['blob']
4383 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4384 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4385
4386 entry = entries['u-boot']
4387 self.assertEqual(U_BOOT_DATA, entry.data)
4388 self.assertEqual(len(U_BOOT_DATA), entry.size)
4389
4390 self.assertEqual(len(data), image.size)
4391 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4392 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4393 image.uncomp_size)
4394 orig = self._decompress(image.data)
4395 self.assertEqual(orig, image.uncomp_data)
4396
4397 expected = {
4398 'blob:offset': 0,
4399 'blob:size': len(COMPRESS_DATA_BIG),
4400 'u-boot:offset': len(COMPRESS_DATA_BIG),
4401 'u-boot:size': len(U_BOOT_DATA),
4402 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4403 'offset': 0,
4404 'image-pos': 0,
4405 'size': len(data),
4406 }
4407 self.assertEqual(expected, props)
4408
4409 def testCompressSectionSize(self):
4410 """Test compression of a section with a fixed size"""
4411 self._CheckLz4()
4412 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4413 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4414 dtb = fdt.Fdt(out_dtb_fname)
4415 dtb.Scan()
4416 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4417 'uncomp-size'])
4418 orig = self._decompress(data)
4419 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4420 expected = {
4421 'section/blob:offset': 0,
4422 'section/blob:size': len(COMPRESS_DATA),
4423 'section/u-boot:offset': len(COMPRESS_DATA),
4424 'section/u-boot:size': len(U_BOOT_DATA),
4425 'section:offset': 0,
4426 'section:image-pos': 0,
4427 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4428 'section:size': 0x30,
4429 'offset': 0,
4430 'image-pos': 0,
4431 'size': 0x30,
4432 }
4433 self.assertEqual(expected, props)
4434
4435 def testCompressSection(self):
4436 """Test compression of a section with no fixed size"""
4437 self._CheckLz4()
4438 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4439 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4440 dtb = fdt.Fdt(out_dtb_fname)
4441 dtb.Scan()
4442 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4443 'uncomp-size'])
4444 orig = self._decompress(data)
4445 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4446 expected = {
4447 'section/blob:offset': 0,
4448 'section/blob:size': len(COMPRESS_DATA),
4449 'section/u-boot:offset': len(COMPRESS_DATA),
4450 'section/u-boot:size': len(U_BOOT_DATA),
4451 'section:offset': 0,
4452 'section:image-pos': 0,
4453 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4454 'section:size': len(data),
4455 'offset': 0,
4456 'image-pos': 0,
4457 'size': len(data),
4458 }
4459 self.assertEqual(expected, props)
4460
Stefan Herbrechtsmeier94813a02022-08-19 16:25:31 +02004461 def testLz4Missing(self):
4462 """Test that binman still produces an image if lz4 is missing"""
4463 with test_util.capture_sys_output() as (_, stderr):
4464 self._DoTestFile('185_compress_section.dts',
4465 force_missing_bintools='lz4')
4466 err = stderr.getvalue()
4467 self.assertRegex(err,
4468 "Image 'main-section'.*missing bintools.*: lz4")
4469
Simon Glassd92c8362020-10-26 17:40:25 -06004470 def testCompressExtra(self):
4471 """Test compression of a section with no fixed size"""
4472 self._CheckLz4()
4473 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4474 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4475 dtb = fdt.Fdt(out_dtb_fname)
4476 dtb.Scan()
4477 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4478 'uncomp-size'])
4479
4480 base = data[len(U_BOOT_DATA):]
4481 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4482 rest = base[len(U_BOOT_DATA):]
4483
4484 # Check compressed data
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004485 bintool = self.comp_bintools['lz4']
4486 expect1 = bintool.compress(COMPRESS_DATA + U_BOOT_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004487 data1 = rest[:len(expect1)]
4488 section1 = self._decompress(data1)
4489 self.assertEquals(expect1, data1)
Simon Glassd92c8362020-10-26 17:40:25 -06004490 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4491 rest1 = rest[len(expect1):]
4492
Stefan Herbrechtsmeierb4bfbce2022-08-19 16:25:28 +02004493 expect2 = bintool.compress(COMPRESS_DATA + COMPRESS_DATA)
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004494 data2 = rest1[:len(expect2)]
4495 section2 = self._decompress(data2)
4496 self.assertEquals(expect2, data2)
Simon Glassd92c8362020-10-26 17:40:25 -06004497 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4498 rest2 = rest1[len(expect2):]
4499
4500 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4501 len(expect2) + len(U_BOOT_DATA))
4502 #self.assertEquals(expect_size, len(data))
4503
4504 #self.assertEquals(U_BOOT_DATA, rest2)
4505
4506 self.maxDiff = None
4507 expected = {
4508 'u-boot:offset': 0,
4509 'u-boot:image-pos': 0,
4510 'u-boot:size': len(U_BOOT_DATA),
4511
4512 'base:offset': len(U_BOOT_DATA),
4513 'base:image-pos': len(U_BOOT_DATA),
4514 'base:size': len(data) - len(U_BOOT_DATA),
4515 'base/u-boot:offset': 0,
4516 'base/u-boot:image-pos': len(U_BOOT_DATA),
4517 'base/u-boot:size': len(U_BOOT_DATA),
4518 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4519 len(expect2),
4520 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4521 len(expect2),
4522 'base/u-boot2:size': len(U_BOOT_DATA),
4523
4524 'base/section:offset': len(U_BOOT_DATA),
4525 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4526 'base/section:size': len(expect1),
4527 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4528 'base/section/blob:offset': 0,
4529 'base/section/blob:size': len(COMPRESS_DATA),
4530 'base/section/u-boot:offset': len(COMPRESS_DATA),
4531 'base/section/u-boot:size': len(U_BOOT_DATA),
4532
4533 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4534 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4535 'base/section2:size': len(expect2),
4536 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4537 'base/section2/blob:offset': 0,
4538 'base/section2/blob:size': len(COMPRESS_DATA),
4539 'base/section2/blob2:offset': len(COMPRESS_DATA),
4540 'base/section2/blob2:size': len(COMPRESS_DATA),
4541
4542 'offset': 0,
4543 'image-pos': 0,
4544 'size': len(data),
4545 }
4546 self.assertEqual(expected, props)
4547
Simon Glassecbe4732021-01-06 21:35:15 -07004548 def testSymbolsSubsection(self):
4549 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004550 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004551
Simon Glass3fb25402021-01-06 21:35:16 -07004552 def testReadImageEntryArg(self):
4553 """Test reading an image that would need an entry arg to generate"""
4554 entry_args = {
4555 'cros-ec-rw-path': 'ecrw.bin',
4556 }
4557 data = self.data = self._DoReadFileDtb(
4558 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4559 entry_args=entry_args)
4560
Simon Glass80025522022-01-29 14:14:04 -07004561 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004562 orig_image = control.images['image']
4563
4564 # This should not generate an error about the missing 'cros-ec-rw-path'
4565 # since we are reading the image from a file. Compare with
4566 # testEntryArgsRequired()
4567 image = Image.FromFile(image_fname)
4568 self.assertEqual(orig_image.GetEntries().keys(),
4569 image.GetEntries().keys())
4570
Simon Glassa2af7302021-01-06 21:35:18 -07004571 def testFilesAlign(self):
4572 """Test alignment with files"""
4573 data = self._DoReadFile('190_files_align.dts')
4574
4575 # The first string is 15 bytes so will align to 16
4576 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4577 self.assertEqual(expect, data)
4578
Simon Glassdb84b562021-01-06 21:35:19 -07004579 def testReadImageSkip(self):
4580 """Test reading an image and accessing its FDT map"""
4581 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004582 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004583 orig_image = control.images['image']
4584 image = Image.FromFile(image_fname)
4585 self.assertEqual(orig_image.GetEntries().keys(),
4586 image.GetEntries().keys())
4587
4588 orig_entry = orig_image.GetEntries()['fdtmap']
4589 entry = image.GetEntries()['fdtmap']
4590 self.assertEqual(orig_entry.offset, entry.offset)
4591 self.assertEqual(orig_entry.size, entry.size)
4592 self.assertEqual(16, entry.image_pos)
4593
4594 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4595
4596 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4597
Simon Glassc98de972021-03-18 20:24:57 +13004598 def testTplNoDtb(self):
4599 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004600 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004601 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4602 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4603 data[:len(U_BOOT_TPL_NODTB_DATA)])
4604
Simon Glass63f41d42021-03-18 20:24:58 +13004605 def testTplBssPad(self):
4606 """Test that we can pad TPL's BSS with zeros"""
4607 # ELF file with a '__bss_size' symbol
4608 self._SetupTplElf()
4609 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004610 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004611 data)
4612
4613 def testTplBssPadMissing(self):
4614 """Test that a missing symbol is detected"""
4615 self._SetupTplElf('u_boot_ucode_ptr')
4616 with self.assertRaises(ValueError) as e:
4617 self._DoReadFile('193_tpl_bss_pad.dts')
4618 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4619 str(e.exception))
4620
Simon Glass718b5292021-03-18 20:25:07 +13004621 def checkDtbSizes(self, data, pad_len, start):
4622 """Check the size arguments in a dtb embedded in an image
4623
4624 Args:
4625 data: The image data
4626 pad_len: Length of the pad section in the image, in bytes
4627 start: Start offset of the devicetree to examine, within the image
4628
4629 Returns:
4630 Size of the devicetree in bytes
4631 """
4632 dtb_data = data[start:]
4633 dtb = fdt.Fdt.FromData(dtb_data)
4634 fdt_size = dtb.GetFdtObj().totalsize()
4635 dtb.Scan()
4636 props = self._GetPropTree(dtb, 'size')
4637 self.assertEqual({
4638 'size': len(data),
4639 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4640 'u-boot-spl/u-boot-spl-dtb:size': 801,
4641 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4642 'u-boot-spl:size': 860,
4643 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4644 'u-boot/u-boot-dtb:size': 781,
4645 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4646 'u-boot:size': 827,
4647 }, props)
4648 return fdt_size
4649
4650 def testExpanded(self):
4651 """Test that an expanded entry type is selected when needed"""
4652 self._SetupSplElf()
4653 self._SetupTplElf()
4654
4655 # SPL has a devicetree, TPL does not
4656 entry_args = {
4657 'spl-dtb': '1',
4658 'spl-bss-pad': 'y',
4659 'tpl-dtb': '',
4660 }
4661 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4662 entry_args=entry_args)
4663 image = control.images['image']
4664 entries = image.GetEntries()
4665 self.assertEqual(3, len(entries))
4666
4667 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4668 self.assertIn('u-boot', entries)
4669 entry = entries['u-boot']
4670 self.assertEqual('u-boot-expanded', entry.etype)
4671 subent = entry.GetEntries()
4672 self.assertEqual(2, len(subent))
4673 self.assertIn('u-boot-nodtb', subent)
4674 self.assertIn('u-boot-dtb', subent)
4675
4676 # Second, u-boot-spl, which should be expanded into three parts
4677 self.assertIn('u-boot-spl', entries)
4678 entry = entries['u-boot-spl']
4679 self.assertEqual('u-boot-spl-expanded', entry.etype)
4680 subent = entry.GetEntries()
4681 self.assertEqual(3, len(subent))
4682 self.assertIn('u-boot-spl-nodtb', subent)
4683 self.assertIn('u-boot-spl-bss-pad', subent)
4684 self.assertIn('u-boot-spl-dtb', subent)
4685
4686 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4687 # devicetree
4688 self.assertIn('u-boot-tpl', entries)
4689 entry = entries['u-boot-tpl']
4690 self.assertEqual('u-boot-tpl', entry.etype)
4691 self.assertEqual(None, entry.GetEntries())
4692
4693 def testExpandedTpl(self):
4694 """Test that an expanded entry type is selected for TPL when needed"""
4695 self._SetupTplElf()
4696
4697 entry_args = {
4698 'tpl-bss-pad': 'y',
4699 'tpl-dtb': 'y',
4700 }
4701 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4702 entry_args=entry_args)
4703 image = control.images['image']
4704 entries = image.GetEntries()
4705 self.assertEqual(1, len(entries))
4706
4707 # We only have u-boot-tpl, which be expanded
4708 self.assertIn('u-boot-tpl', entries)
4709 entry = entries['u-boot-tpl']
4710 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4711 subent = entry.GetEntries()
4712 self.assertEqual(3, len(subent))
4713 self.assertIn('u-boot-tpl-nodtb', subent)
4714 self.assertIn('u-boot-tpl-bss-pad', subent)
4715 self.assertIn('u-boot-tpl-dtb', subent)
4716
4717 def testExpandedNoPad(self):
4718 """Test an expanded entry without BSS pad enabled"""
4719 self._SetupSplElf()
4720 self._SetupTplElf()
4721
4722 # SPL has a devicetree, TPL does not
4723 entry_args = {
4724 'spl-dtb': 'something',
4725 'spl-bss-pad': 'n',
4726 'tpl-dtb': '',
4727 }
4728 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4729 entry_args=entry_args)
4730 image = control.images['image']
4731 entries = image.GetEntries()
4732
4733 # Just check u-boot-spl, which should be expanded into two parts
4734 self.assertIn('u-boot-spl', entries)
4735 entry = entries['u-boot-spl']
4736 self.assertEqual('u-boot-spl-expanded', entry.etype)
4737 subent = entry.GetEntries()
4738 self.assertEqual(2, len(subent))
4739 self.assertIn('u-boot-spl-nodtb', subent)
4740 self.assertIn('u-boot-spl-dtb', subent)
4741
4742 def testExpandedTplNoPad(self):
4743 """Test that an expanded entry type with padding disabled in TPL"""
4744 self._SetupTplElf()
4745
4746 entry_args = {
4747 'tpl-bss-pad': '',
4748 'tpl-dtb': 'y',
4749 }
4750 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4751 entry_args=entry_args)
4752 image = control.images['image']
4753 entries = image.GetEntries()
4754 self.assertEqual(1, len(entries))
4755
4756 # We only have u-boot-tpl, which be expanded
4757 self.assertIn('u-boot-tpl', entries)
4758 entry = entries['u-boot-tpl']
4759 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4760 subent = entry.GetEntries()
4761 self.assertEqual(2, len(subent))
4762 self.assertIn('u-boot-tpl-nodtb', subent)
4763 self.assertIn('u-boot-tpl-dtb', subent)
4764
4765 def testFdtInclude(self):
4766 """Test that an Fdt is update within all binaries"""
4767 self._SetupSplElf()
4768 self._SetupTplElf()
4769
4770 # SPL has a devicetree, TPL does not
4771 self.maxDiff = None
4772 entry_args = {
4773 'spl-dtb': '1',
4774 'spl-bss-pad': 'y',
4775 'tpl-dtb': '',
4776 }
4777 # Build the image. It includes two separate devicetree binaries, each
4778 # with their own contents, but all contain the binman definition.
4779 data = self._DoReadFileDtb(
4780 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4781 update_dtb=True, entry_args=entry_args)[0]
4782 pad_len = 10
4783
4784 # Check the U-Boot dtb
4785 start = len(U_BOOT_NODTB_DATA)
4786 fdt_size = self.checkDtbSizes(data, pad_len, start)
4787
4788 # Now check SPL
4789 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4790 fdt_size = self.checkDtbSizes(data, pad_len, start)
4791
4792 # TPL has no devicetree
4793 start += fdt_size + len(U_BOOT_TPL_DATA)
4794 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004795
Simon Glass7098b7f2021-03-21 18:24:30 +13004796 def testSymbolsExpanded(self):
4797 """Test binman can assign symbols in expanded entries"""
4798 entry_args = {
4799 'spl-dtb': '1',
4800 }
4801 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4802 U_BOOT_SPL_DTB_DATA, 0x38,
4803 entry_args=entry_args, use_expanded=True)
4804
Simon Glasse1915782021-03-21 18:24:31 +13004805 def testCollection(self):
4806 """Test a collection"""
4807 data = self._DoReadFile('198_collection.dts')
4808 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004809 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4810 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004811 data)
4812
Simon Glass27a7f772021-03-21 18:24:32 +13004813 def testCollectionSection(self):
4814 """Test a collection where a section must be built first"""
4815 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004816 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004817 # building the contents, producing an error is anything is still
4818 # missing.
4819 data = self._DoReadFile('199_collection_section.dts')
4820 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004821 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4822 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004823 data)
4824
Simon Glassf427c5f2021-03-21 18:24:33 +13004825 def testAlignDefault(self):
4826 """Test that default alignment works on sections"""
4827 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004828 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004829 U_BOOT_DATA)
4830 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004831 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004832 # No alignment within the nested section
4833 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4834 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004835 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004836 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004837
Bin Mengc0b15742021-05-10 20:23:33 +08004838 def testPackOpenSBI(self):
4839 """Test that an image with an OpenSBI binary can be created"""
4840 data = self._DoReadFile('201_opensbi.dts')
4841 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4842
Simon Glass76f496d2021-07-06 10:36:37 -06004843 def testSectionsSingleThread(self):
4844 """Test sections without multithreading"""
4845 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004846 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4847 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4848 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004849 self.assertEqual(expected, data)
4850
4851 def testThreadTimeout(self):
4852 """Test handling a thread that takes too long"""
4853 with self.assertRaises(ValueError) as e:
4854 self._DoTestFile('202_section_timeout.dts',
4855 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004856 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004857
Simon Glass748a1d42021-07-06 10:36:41 -06004858 def testTiming(self):
4859 """Test output of timing information"""
4860 data = self._DoReadFile('055_sections.dts')
4861 with test_util.capture_sys_output() as (stdout, stderr):
4862 state.TimingShow()
4863 self.assertIn('read:', stdout.getvalue())
4864 self.assertIn('compress:', stdout.getvalue())
4865
Simon Glassadfb8492021-11-03 21:09:18 -06004866 def testUpdateFdtInElf(self):
4867 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004868 if not elf.ELF_TOOLS:
4869 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004870 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4871 outfile = os.path.join(self._indir, 'u-boot.out')
4872 begin_sym = 'dtb_embed_begin'
4873 end_sym = 'dtb_embed_end'
4874 retcode = self._DoTestFile(
4875 '060_fdt_update.dts', update_dtb=True,
4876 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4877 self.assertEqual(0, retcode)
4878
4879 # Check that the output file does in fact contact a dtb with the binman
4880 # definition in the correct place
4881 syms = elf.GetSymbolFileOffset(infile,
4882 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004883 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004884 dtb_data = data[syms['dtb_embed_begin'].offset:
4885 syms['dtb_embed_end'].offset]
4886
4887 dtb = fdt.Fdt.FromData(dtb_data)
4888 dtb.Scan()
4889 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4890 self.assertEqual({
4891 'image-pos': 0,
4892 'offset': 0,
4893 '_testing:offset': 32,
4894 '_testing:size': 2,
4895 '_testing:image-pos': 32,
4896 'section@0/u-boot:offset': 0,
4897 'section@0/u-boot:size': len(U_BOOT_DATA),
4898 'section@0/u-boot:image-pos': 0,
4899 'section@0:offset': 0,
4900 'section@0:size': 16,
4901 'section@0:image-pos': 0,
4902
4903 'section@1/u-boot:offset': 0,
4904 'section@1/u-boot:size': len(U_BOOT_DATA),
4905 'section@1/u-boot:image-pos': 16,
4906 'section@1:offset': 16,
4907 'section@1:size': 16,
4908 'section@1:image-pos': 16,
4909 'size': 40
4910 }, props)
4911
4912 def testUpdateFdtInElfInvalid(self):
4913 """Test that invalid args are detected with --update-fdt-in-elf"""
4914 with self.assertRaises(ValueError) as e:
4915 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4916 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4917 str(e.exception))
4918
4919 def testUpdateFdtInElfNoSyms(self):
4920 """Test that missing symbols are 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')
4924 outfile = ''
4925 begin_sym = 'wrong_begin'
4926 end_sym = 'wrong_end'
4927 with self.assertRaises(ValueError) as e:
4928 self._DoTestFile(
4929 '060_fdt_update.dts',
4930 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4931 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4932 str(e.exception))
4933
4934 def testUpdateFdtInElfTooSmall(self):
4935 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004936 if not elf.ELF_TOOLS:
4937 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004938 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4939 outfile = os.path.join(self._indir, 'u-boot.out')
4940 begin_sym = 'dtb_embed_begin'
4941 end_sym = 'dtb_embed_end'
4942 with self.assertRaises(ValueError) as e:
4943 self._DoTestFile(
4944 '060_fdt_update.dts', update_dtb=True,
4945 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4946 self.assertRegex(
4947 str(e.exception),
4948 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4949
Simon Glass88e04da2021-11-23 11:03:42 -07004950 def testVersion(self):
4951 """Test we can get the binman version"""
4952 version = '(unreleased)'
4953 self.assertEqual(version, state.GetVersion(self._indir))
4954
4955 with self.assertRaises(SystemExit):
4956 with test_util.capture_sys_output() as (_, stderr):
4957 self._DoBinman('-V')
4958 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4959
4960 # Try running the tool too, just to be safe
4961 result = self._RunBinman('-V')
4962 self.assertEqual('Binman %s\n' % version, result.stderr)
4963
4964 # Set up a version file to make sure that works
4965 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07004966 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07004967 binary=False)
4968 self.assertEqual(version, state.GetVersion(self._indir))
4969
Simon Glass637958f2021-11-23 21:09:50 -07004970 def testAltFormat(self):
4971 """Test that alternative formats can be used to extract"""
4972 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4973
4974 try:
4975 tmpdir, updated_fname = self._SetupImageInTmpdir()
4976 with test_util.capture_sys_output() as (stdout, _):
4977 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4978 self.assertEqual(
4979 '''Flag (-F) Entry type Description
4980fdt fdtmap Extract the devicetree blob from the fdtmap
4981''',
4982 stdout.getvalue())
4983
4984 dtb = os.path.join(tmpdir, 'fdt.dtb')
4985 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4986 dtb, 'fdtmap')
4987
4988 # Check that we can read it and it can be scanning, meaning it does
4989 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07004990 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07004991 dtb = fdt.Fdt.FromData(data)
4992 dtb.Scan()
4993
4994 # Now check u-boot which has no alt_format
4995 fname = os.path.join(tmpdir, 'fdt.dtb')
4996 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4997 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07004998 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07004999 self.assertEqual(U_BOOT_DATA, data)
5000
5001 finally:
5002 shutil.rmtree(tmpdir)
5003
Simon Glass0b00ae62021-11-23 21:09:52 -07005004 def testExtblobList(self):
5005 """Test an image with an external blob list"""
5006 data = self._DoReadFile('215_blob_ext_list.dts')
5007 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
5008
5009 def testExtblobListMissing(self):
5010 """Test an image with a missing external blob"""
5011 with self.assertRaises(ValueError) as e:
5012 self._DoReadFile('216_blob_ext_list_missing.dts')
5013 self.assertIn("Filename 'missing-file' not found in input path",
5014 str(e.exception))
5015
5016 def testExtblobListMissingOk(self):
5017 """Test an image with an missing external blob that is allowed"""
5018 with test_util.capture_sys_output() as (stdout, stderr):
5019 self._DoTestFile('216_blob_ext_list_missing.dts',
5020 allow_missing=True)
5021 err = stderr.getvalue()
5022 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
5023
Simon Glass3efb2972021-11-23 21:08:59 -07005024 def testFip(self):
5025 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
5026 data = self._DoReadFile('203_fip.dts')
5027 hdr, fents = fip_util.decode_fip(data)
5028 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5029 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5030 self.assertEqual(0x123, hdr.flags)
5031
5032 self.assertEqual(2, len(fents))
5033
5034 fent = fents[0]
5035 self.assertEqual(
5036 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
5037 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
5038 self.assertEqual('soc-fw', fent.fip_type)
5039 self.assertEqual(0x88, fent.offset)
5040 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5041 self.assertEqual(0x123456789abcdef, fent.flags)
5042 self.assertEqual(ATF_BL31_DATA, fent.data)
5043 self.assertEqual(True, fent.valid)
5044
5045 fent = fents[1]
5046 self.assertEqual(
5047 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
5048 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
5049 self.assertEqual('scp-fwu-cfg', fent.fip_type)
5050 self.assertEqual(0x8c, fent.offset)
5051 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5052 self.assertEqual(0, fent.flags)
5053 self.assertEqual(ATF_BL2U_DATA, fent.data)
5054 self.assertEqual(True, fent.valid)
5055
5056 def testFipOther(self):
5057 """Basic FIP with something that isn't a external blob"""
5058 data = self._DoReadFile('204_fip_other.dts')
5059 hdr, fents = fip_util.decode_fip(data)
5060
5061 self.assertEqual(2, len(fents))
5062 fent = fents[1]
5063 self.assertEqual('rot-cert', fent.fip_type)
5064 self.assertEqual(b'aa', fent.data)
5065
Simon Glass3efb2972021-11-23 21:08:59 -07005066 def testFipNoType(self):
5067 """FIP with an entry of an unknown type"""
5068 with self.assertRaises(ValueError) as e:
5069 self._DoReadFile('205_fip_no_type.dts')
5070 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5071 str(e.exception))
5072
5073 def testFipUuid(self):
5074 """Basic FIP with a manual uuid"""
5075 data = self._DoReadFile('206_fip_uuid.dts')
5076 hdr, fents = fip_util.decode_fip(data)
5077
5078 self.assertEqual(2, len(fents))
5079 fent = fents[1]
5080 self.assertEqual(None, fent.fip_type)
5081 self.assertEqual(
5082 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5083 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5084 fent.uuid)
5085 self.assertEqual(U_BOOT_DATA, fent.data)
5086
5087 def testFipLs(self):
5088 """Test listing a FIP"""
5089 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5090 hdr, fents = fip_util.decode_fip(data)
5091
5092 try:
5093 tmpdir, updated_fname = self._SetupImageInTmpdir()
5094 with test_util.capture_sys_output() as (stdout, stderr):
5095 self._DoBinman('ls', '-i', updated_fname)
5096 finally:
5097 shutil.rmtree(tmpdir)
5098 lines = stdout.getvalue().splitlines()
5099 expected = [
5100'Name Image-pos Size Entry-type Offset Uncomp-size',
5101'----------------------------------------------------------------',
5102'main-section 0 2d3 section 0',
5103' atf-fip 0 90 atf-fip 0',
5104' soc-fw 88 4 blob-ext 88',
5105' u-boot 8c 4 u-boot 8c',
5106' fdtmap 90 243 fdtmap 90',
5107]
5108 self.assertEqual(expected, lines)
5109
5110 image = control.images['image']
5111 entries = image.GetEntries()
5112 fdtmap = entries['fdtmap']
5113
5114 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5115 magic = fdtmap_data[:8]
5116 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005117 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005118
5119 fdt_data = fdtmap_data[16:]
5120 dtb = fdt.Fdt.FromData(fdt_data)
5121 dtb.Scan()
5122 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5123 self.assertEqual({
5124 'atf-fip/soc-fw:image-pos': 136,
5125 'atf-fip/soc-fw:offset': 136,
5126 'atf-fip/soc-fw:size': 4,
5127 'atf-fip/u-boot:image-pos': 140,
5128 'atf-fip/u-boot:offset': 140,
5129 'atf-fip/u-boot:size': 4,
5130 'atf-fip:image-pos': 0,
5131 'atf-fip:offset': 0,
5132 'atf-fip:size': 144,
5133 'image-pos': 0,
5134 'offset': 0,
5135 'fdtmap:image-pos': fdtmap.image_pos,
5136 'fdtmap:offset': fdtmap.offset,
5137 'fdtmap:size': len(fdtmap_data),
5138 'size': len(data),
5139 }, props)
5140
5141 def testFipExtractOneEntry(self):
5142 """Test extracting a single entry fron an FIP"""
5143 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005144 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005145 fname = os.path.join(self._indir, 'output.extact')
5146 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005147 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005148 self.assertEqual(U_BOOT_DATA, data)
5149
5150 def testFipReplace(self):
5151 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005152 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005153 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005154 updated_fname = tools.get_output_filename('image-updated.bin')
5155 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005156 entry_name = 'atf-fip/u-boot'
5157 control.WriteEntry(updated_fname, entry_name, expected,
5158 allow_resize=True)
5159 actual = control.ReadEntry(updated_fname, entry_name)
5160 self.assertEqual(expected, actual)
5161
Simon Glass80025522022-01-29 14:14:04 -07005162 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005163 hdr, fents = fip_util.decode_fip(new_data)
5164
5165 self.assertEqual(2, len(fents))
5166
5167 # Check that the FIP entry is updated
5168 fent = fents[1]
5169 self.assertEqual(0x8c, fent.offset)
5170 self.assertEqual(len(expected), fent.size)
5171 self.assertEqual(0, fent.flags)
5172 self.assertEqual(expected, fent.data)
5173 self.assertEqual(True, fent.valid)
5174
5175 def testFipMissing(self):
5176 with test_util.capture_sys_output() as (stdout, stderr):
5177 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5178 err = stderr.getvalue()
5179 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
5180
5181 def testFipSize(self):
5182 """Test a FIP with a size property"""
5183 data = self._DoReadFile('210_fip_size.dts')
5184 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5185 hdr, fents = fip_util.decode_fip(data)
5186 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5187 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5188
5189 self.assertEqual(1, len(fents))
5190
5191 fent = fents[0]
5192 self.assertEqual('soc-fw', fent.fip_type)
5193 self.assertEqual(0x60, fent.offset)
5194 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5195 self.assertEqual(ATF_BL31_DATA, fent.data)
5196 self.assertEqual(True, fent.valid)
5197
5198 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005199 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005200
5201 def testFipBadAlign(self):
5202 """Test that an invalid alignment value in a FIP is detected"""
5203 with self.assertRaises(ValueError) as e:
5204 self._DoTestFile('211_fip_bad_align.dts')
5205 self.assertIn(
5206 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5207 str(e.exception))
5208
5209 def testFipCollection(self):
5210 """Test using a FIP in a collection"""
5211 data = self._DoReadFile('212_fip_collection.dts')
5212 entry1 = control.images['image'].GetEntries()['collection']
5213 data1 = data[:entry1.size]
5214 hdr1, fents2 = fip_util.decode_fip(data1)
5215
5216 entry2 = control.images['image'].GetEntries()['atf-fip']
5217 data2 = data[entry2.offset:entry2.offset + entry2.size]
5218 hdr1, fents2 = fip_util.decode_fip(data2)
5219
5220 # The 'collection' entry should have U-Boot included at the end
5221 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5222 self.assertEqual(data1, data2 + U_BOOT_DATA)
5223 self.assertEqual(U_BOOT_DATA, data1[-4:])
5224
5225 # There should be a U-Boot after the final FIP
5226 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005227
Simon Glassccae6862022-01-12 13:10:35 -07005228 def testFakeBlob(self):
5229 """Test handling of faking an external blob"""
5230 with test_util.capture_sys_output() as (stdout, stderr):
5231 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5232 allow_fake_blobs=True)
5233 err = stderr.getvalue()
5234 self.assertRegex(
5235 err,
5236 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005237
Simon Glassceb5f912022-01-09 20:13:46 -07005238 def testExtblobListFaked(self):
5239 """Test an extblob with missing external blob that are faked"""
5240 with test_util.capture_sys_output() as (stdout, stderr):
5241 self._DoTestFile('216_blob_ext_list_missing.dts',
5242 allow_fake_blobs=True)
5243 err = stderr.getvalue()
5244 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
5245
Simon Glass162017b2022-01-09 20:13:57 -07005246 def testListBintools(self):
5247 args = ['tool', '--list']
5248 with test_util.capture_sys_output() as (stdout, _):
5249 self._DoBinman(*args)
5250 out = stdout.getvalue().splitlines()
5251 self.assertTrue(len(out) >= 2)
5252
5253 def testFetchBintools(self):
5254 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005255 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005256 raise urllib.error.URLError('my error')
5257
5258 args = ['tool']
5259 with self.assertRaises(ValueError) as e:
5260 self._DoBinman(*args)
5261 self.assertIn("Invalid arguments to 'tool' subcommand",
5262 str(e.exception))
5263
5264 args = ['tool', '--fetch']
5265 with self.assertRaises(ValueError) as e:
5266 self._DoBinman(*args)
5267 self.assertIn('Please specify bintools to fetch', str(e.exception))
5268
5269 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005270 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005271 side_effect=fail_download):
5272 with test_util.capture_sys_output() as (stdout, _):
5273 self._DoBinman(*args)
5274 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5275
Simon Glass620c4462022-01-09 20:14:11 -07005276 def testBintoolDocs(self):
5277 """Test for creation of bintool documentation"""
5278 with test_util.capture_sys_output() as (stdout, stderr):
5279 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5280 self.assertTrue(len(stdout.getvalue()) > 0)
5281
5282 def testBintoolDocsMissing(self):
5283 """Test handling of missing bintool documentation"""
5284 with self.assertRaises(ValueError) as e:
5285 with test_util.capture_sys_output() as (stdout, stderr):
5286 control.write_bintool_docs(
5287 control.bintool.Bintool.get_tool_list(), 'mkimage')
5288 self.assertIn('Documentation is missing for modules: mkimage',
5289 str(e.exception))
5290
Jan Kiszka58c407f2022-01-28 20:37:53 +01005291 def testListWithGenNode(self):
5292 """Check handling of an FDT map when the section cannot be found"""
5293 entry_args = {
5294 'of-list': 'test-fdt1 test-fdt2',
5295 }
5296 data = self._DoReadFileDtb(
5297 '219_fit_gennode.dts',
5298 entry_args=entry_args,
5299 use_real_dtb=True,
5300 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5301
5302 try:
5303 tmpdir, updated_fname = self._SetupImageInTmpdir()
5304 with test_util.capture_sys_output() as (stdout, stderr):
5305 self._RunBinman('ls', '-i', updated_fname)
5306 finally:
5307 shutil.rmtree(tmpdir)
5308
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005309 def testFitSubentryUsesBintool(self):
5310 """Test that binman FIT subentries can use bintools"""
5311 command.test_result = self._HandleGbbCommand
5312 entry_args = {
5313 'keydir': 'devkeys',
5314 'bmpblk': 'bmpblk.bin',
5315 }
5316 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5317 entry_args=entry_args)
5318
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005319 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5320 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005321 self.assertIn(expected, data)
5322
5323 def testFitSubentryMissingBintool(self):
5324 """Test that binman reports missing bintools for FIT subentries"""
5325 entry_args = {
5326 'keydir': 'devkeys',
5327 }
5328 with test_util.capture_sys_output() as (_, stderr):
5329 self._DoTestFile('220_fit_subentry_bintool.dts',
5330 force_missing_bintools='futility', entry_args=entry_args)
5331 err = stderr.getvalue()
5332 self.assertRegex(err,
5333 "Image 'main-section'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005334
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005335 def testFitSubentryHashSubnode(self):
5336 """Test an image with a FIT inside"""
5337 data, _, _, out_dtb_name = self._DoReadFileDtb(
5338 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5339
5340 mkimage_dtb = fdt.Fdt.FromData(data)
5341 mkimage_dtb.Scan()
5342 binman_dtb = fdt.Fdt(out_dtb_name)
5343 binman_dtb.Scan()
5344
5345 # Check that binman didn't add hash values
5346 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5347 self.assertNotIn('value', fnode.props)
5348
5349 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5350 self.assertNotIn('value', fnode.props)
5351
5352 # Check that mkimage added hash values
5353 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5354 self.assertIn('value', fnode.props)
5355
5356 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5357 self.assertIn('value', fnode.props)
5358
Roger Quadros5cdcea02022-02-19 20:50:04 +02005359 def testPackTeeOs(self):
5360 """Test that an image with an TEE binary can be created"""
5361 data = self._DoReadFile('222_tee_os.dts')
5362 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5363
Simon Glass912339f2022-02-08 11:50:03 -07005364 def testFitFdtOper(self):
5365 """Check handling of a specified FIT operation"""
5366 entry_args = {
5367 'of-list': 'test-fdt1 test-fdt2',
5368 'default-dt': 'test-fdt2',
5369 }
5370 self._DoReadFileDtb(
5371 '223_fit_fdt_oper.dts',
5372 entry_args=entry_args,
5373 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5374
5375 def testFitFdtBadOper(self):
5376 """Check handling of an FDT map when the section cannot be found"""
5377 with self.assertRaises(ValueError) as exc:
5378 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005379 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005380 str(exc.exception))
5381
Simon Glassdd156a42022-03-05 20:18:59 -07005382 def test_uses_expand_size(self):
5383 """Test that the 'expand-size' property cannot be used anymore"""
5384 with self.assertRaises(ValueError) as e:
5385 data = self._DoReadFile('225_expand_size_bad.dts')
5386 self.assertIn(
5387 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5388 str(e.exception))
5389
Simon Glass5f423422022-03-05 20:19:12 -07005390 def testFitSplitElf(self):
5391 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005392 if not elf.ELF_TOOLS:
5393 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005394 entry_args = {
5395 'of-list': 'test-fdt1 test-fdt2',
5396 'default-dt': 'test-fdt2',
5397 'atf-bl31-path': 'bl31.elf',
5398 'tee-os-path': 'tee.elf',
5399 }
5400 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5401 data = self._DoReadFileDtb(
5402 '226_fit_split_elf.dts',
5403 entry_args=entry_args,
5404 extra_indirs=[test_subdir])[0]
5405
5406 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5407 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5408
5409 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5410 'data', 'load'}
5411 dtb = fdt.Fdt.FromData(fit_data)
5412 dtb.Scan()
5413
5414 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5415 segments, entry = elf.read_loadable_segments(elf_data)
5416
5417 # We assume there are two segments
5418 self.assertEquals(2, len(segments))
5419
5420 atf1 = dtb.GetNode('/images/atf-1')
5421 _, start, data = segments[0]
5422 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5423 self.assertEqual(entry,
5424 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5425 self.assertEqual(start,
5426 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5427 self.assertEqual(data, atf1.props['data'].bytes)
5428
5429 atf2 = dtb.GetNode('/images/atf-2')
5430 self.assertEqual(base_keys, atf2.props.keys())
5431 _, start, data = segments[1]
5432 self.assertEqual(start,
5433 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5434 self.assertEqual(data, atf2.props['data'].bytes)
5435
5436 conf = dtb.GetNode('/configurations')
5437 self.assertEqual({'default'}, conf.props.keys())
5438
5439 for subnode in conf.subnodes:
5440 self.assertEqual({'description', 'fdt', 'loadables'},
5441 subnode.props.keys())
5442 self.assertEqual(
5443 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5444 fdt_util.GetStringList(subnode, 'loadables'))
5445
5446 def _check_bad_fit(self, dts):
5447 """Check a bad FIT
5448
5449 This runs with the given dts and returns the assertion raised
5450
5451 Args:
5452 dts (str): dts filename to use
5453
5454 Returns:
5455 str: Assertion string raised
5456 """
5457 entry_args = {
5458 'of-list': 'test-fdt1 test-fdt2',
5459 'default-dt': 'test-fdt2',
5460 'atf-bl31-path': 'bl31.elf',
5461 'tee-os-path': 'tee.elf',
5462 }
5463 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5464 with self.assertRaises(ValueError) as exc:
5465 self._DoReadFileDtb(dts, entry_args=entry_args,
5466 extra_indirs=[test_subdir])[0]
5467 return str(exc.exception)
5468
5469 def testFitSplitElfBadElf(self):
5470 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005471 if not elf.ELF_TOOLS:
5472 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005473 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5474 entry_args = {
5475 'of-list': 'test-fdt1 test-fdt2',
5476 'default-dt': 'test-fdt2',
5477 'atf-bl31-path': 'bad.elf',
5478 'tee-os-path': 'tee.elf',
5479 }
5480 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5481 with self.assertRaises(ValueError) as exc:
5482 self._DoReadFileDtb(
5483 '226_fit_split_elf.dts',
5484 entry_args=entry_args,
5485 extra_indirs=[test_subdir])[0]
5486 self.assertIn(
5487 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5488 str(exc.exception))
5489
Simon Glass5f423422022-03-05 20:19:12 -07005490 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005491 """Test an split-elf FIT with a missing ELF file
5492
5493 Args:
5494 kwargs (dict of str): Arguments to pass to _DoTestFile()
5495
5496 Returns:
5497 tuple:
5498 str: stdout result
5499 str: stderr result
5500 """
Simon Glass5f423422022-03-05 20:19:12 -07005501 entry_args = {
5502 'of-list': 'test-fdt1 test-fdt2',
5503 'default-dt': 'test-fdt2',
5504 'atf-bl31-path': 'bl31.elf',
5505 'tee-os-path': 'missing.elf',
5506 }
5507 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5508 with test_util.capture_sys_output() as (stdout, stderr):
5509 self._DoTestFile(
5510 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005511 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5512 out = stdout.getvalue()
5513 err = stderr.getvalue()
5514 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005515
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005516 def testFitSplitElfBadDirective(self):
5517 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
5518 if not elf.ELF_TOOLS:
5519 self.skipTest('Python elftools not available')
5520 err = self._check_bad_fit('227_fit_bad_dir.dts')
5521 self.assertIn(
5522 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5523 err)
5524
5525 def testFitSplitElfBadDirectiveConfig(self):
5526 """Test a FIT split-elf with invalid fit,xxx directive in config"""
5527 if not elf.ELF_TOOLS:
5528 self.skipTest('Python elftools not available')
5529 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5530 self.assertEqual(
5531 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5532 err)
5533
5534
Simon Glass5f423422022-03-05 20:19:12 -07005535 def testFitSplitElfMissing(self):
5536 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005537 if not elf.ELF_TOOLS:
5538 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005539 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005540 self.assertRegex(
5541 err,
5542 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005543 self.assertNotRegex(out, '.*Faked blob.*')
5544 fname = tools.get_output_filename('binman-fake/missing.elf')
5545 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005546
5547 def testFitSplitElfFaked(self):
5548 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005549 if not elf.ELF_TOOLS:
5550 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005551 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005552 self.assertRegex(
5553 err,
5554 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005555 self.assertRegex(
5556 out,
5557 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5558 fname = tools.get_output_filename('binman-fake/missing.elf')
5559 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005560
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005561 def testMkimageMissingBlob(self):
5562 """Test using mkimage to build an image"""
5563 with test_util.capture_sys_output() as (stdout, stderr):
5564 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5565 allow_fake_blobs=True)
5566 err = stderr.getvalue()
5567 self.assertRegex(
5568 err,
5569 "Image '.*' has faked external blobs and is non-functional: .*")
5570
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005571 def testPreLoad(self):
5572 """Test an image with a pre-load header"""
5573 entry_args = {
5574 'pre-load-key-path': '.',
5575 }
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005576 data, _, _, _ = self._DoReadFileDtb('230_pre_load.dts',
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005577 entry_args=entry_args)
5578 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5579 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5580 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005581 data = self._DoReadFile('230_pre_load.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005582 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5583 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5584 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5585
5586 def testPreLoadPkcs(self):
5587 """Test an image with a pre-load header with padding pkcs"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005588 data = self._DoReadFile('231_pre_load_pkcs.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005589 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5590 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5591 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5592
5593 def testPreLoadPss(self):
5594 """Test an image with a pre-load header with padding pss"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005595 data = self._DoReadFile('232_pre_load_pss.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005596 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5597 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5598 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5599
5600 def testPreLoadInvalidPadding(self):
5601 """Test an image with a pre-load header with an invalid padding"""
5602 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005603 data = self._DoReadFile('233_pre_load_invalid_padding.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005604
5605 def testPreLoadInvalidSha(self):
5606 """Test an image with a pre-load header with an invalid hash"""
5607 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005608 data = self._DoReadFile('234_pre_load_invalid_sha.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005609
5610 def testPreLoadInvalidAlgo(self):
5611 """Test an image with a pre-load header with an invalid algo"""
5612 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005613 data = self._DoReadFile('235_pre_load_invalid_algo.dts')
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005614
5615 def testPreLoadInvalidKey(self):
5616 """Test an image with a pre-load header with an invalid key"""
5617 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005618 data = self._DoReadFile('236_pre_load_invalid_key.dts')
Roger Quadros5cdcea02022-02-19 20:50:04 +02005619
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005620 def _CheckSafeUniqueNames(self, *images):
5621 """Check all entries of given images for unsafe unique names"""
5622 for image in images:
5623 entries = {}
5624 image._CollectEntries(entries, {}, image)
5625 for entry in entries.values():
5626 uniq = entry.GetUniqueName()
5627
5628 # Used as part of a filename, so must not be absolute paths.
5629 self.assertFalse(os.path.isabs(uniq))
5630
5631 def testSafeUniqueNames(self):
5632 """Test entry unique names are safe in single image configuration"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005633 data = self._DoReadFileRealDtb('237_unique_names.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005634
5635 orig_image = control.images['image']
5636 image_fname = tools.get_output_filename('image.bin')
5637 image = Image.FromFile(image_fname)
5638
5639 self._CheckSafeUniqueNames(orig_image, image)
5640
5641 def testSafeUniqueNamesMulti(self):
5642 """Test entry unique names are safe with multiple images"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005643 data = self._DoReadFileRealDtb('238_unique_names_multi.dts')
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005644
5645 orig_image = control.images['image']
5646 image_fname = tools.get_output_filename('image.bin')
5647 image = Image.FromFile(image_fname)
5648
5649 self._CheckSafeUniqueNames(orig_image, image)
5650
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005651 def testReplaceCmdWithBintool(self):
5652 """Test replacing an entry that needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005653 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005654 expected = U_BOOT_DATA + b'aa'
5655 self.assertEqual(expected, data[:len(expected)])
5656
5657 try:
5658 tmpdir, updated_fname = self._SetupImageInTmpdir()
5659 fname = os.path.join(tmpdir, 'update-testing.bin')
5660 tools.write_file(fname, b'zz')
5661 self._DoBinman('replace', '-i', updated_fname,
5662 '_testing', '-f', fname)
5663
5664 data = tools.read_file(updated_fname)
5665 expected = U_BOOT_DATA + b'zz'
5666 self.assertEqual(expected, data[:len(expected)])
5667 finally:
5668 shutil.rmtree(tmpdir)
5669
5670 def testReplaceCmdOtherWithBintool(self):
5671 """Test replacing an entry when another needs a bintool to pack"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005672 data = self._DoReadFileRealDtb('239_replace_with_bintool.dts')
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005673 expected = U_BOOT_DATA + b'aa'
5674 self.assertEqual(expected, data[:len(expected)])
5675
5676 try:
5677 tmpdir, updated_fname = self._SetupImageInTmpdir()
5678 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5679 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5680 self._DoBinman('replace', '-i', updated_fname,
5681 'u-boot', '-f', fname)
5682
5683 data = tools.read_file(updated_fname)
5684 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5685 self.assertEqual(expected, data[:len(expected)])
5686 finally:
5687 shutil.rmtree(tmpdir)
5688
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005689 def testReplaceResizeNoRepackSameSize(self):
5690 """Test replacing entries with same-size data without repacking"""
5691 expected = b'x' * len(U_BOOT_DATA)
5692 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5693 self.assertEqual(expected, data)
5694
5695 path, fdtmap = state.GetFdtContents('fdtmap')
5696 self.assertIsNotNone(path)
5697 self.assertEqual(expected_fdtmap, fdtmap)
5698
5699 def testReplaceResizeNoRepackSmallerSize(self):
5700 """Test replacing entries with smaller-size data without repacking"""
5701 new_data = b'x'
5702 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5703 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5704 self.assertEqual(expected, data)
5705
5706 path, fdtmap = state.GetFdtContents('fdtmap')
5707 self.assertIsNotNone(path)
5708 self.assertEqual(expected_fdtmap, fdtmap)
5709
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005710 def testExtractFit(self):
5711 """Test extracting a FIT section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005712 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005713 image_fname = tools.get_output_filename('image.bin')
5714
5715 fit_data = control.ReadEntry(image_fname, 'fit')
5716 fit = fdt.Fdt.FromData(fit_data)
5717 fit.Scan()
5718
5719 # Check subentry data inside the extracted fit
5720 for node_path, expected in [
5721 ('/images/kernel', U_BOOT_DATA),
5722 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5723 ('/images/scr-1', COMPRESS_DATA),
5724 ]:
5725 node = fit.GetNode(node_path)
5726 data = fit.GetProps(node)['data'].bytes
5727 self.assertEqual(expected, data)
5728
5729 def testExtractFitSubentries(self):
5730 """Test extracting FIT section subentries"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005731 self._DoReadFileRealDtb('240_fit_extract_replace.dts')
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005732 image_fname = tools.get_output_filename('image.bin')
5733
5734 for entry_path, expected in [
5735 ('fit/kernel', U_BOOT_DATA),
5736 ('fit/kernel/u-boot', U_BOOT_DATA),
5737 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5738 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5739 ('fit/scr-1', COMPRESS_DATA),
5740 ('fit/scr-1/blob', COMPRESS_DATA),
5741 ]:
5742 data = control.ReadEntry(image_fname, entry_path)
5743 self.assertEqual(expected, data)
5744
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005745 def testReplaceFitSubentryLeafSameSize(self):
5746 """Test replacing a FIT leaf subentry with same-size data"""
5747 new_data = b'x' * len(U_BOOT_DATA)
5748 data, expected_fdtmap, _ = self._RunReplaceCmd(
5749 'fit/kernel/u-boot', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005750 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005751 self.assertEqual(new_data, data)
5752
5753 path, fdtmap = state.GetFdtContents('fdtmap')
5754 self.assertIsNotNone(path)
5755 self.assertEqual(expected_fdtmap, fdtmap)
5756
5757 def testReplaceFitSubentryLeafBiggerSize(self):
5758 """Test replacing a FIT leaf subentry with bigger-size data"""
5759 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5760 data, expected_fdtmap, _ = self._RunReplaceCmd(
5761 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005762 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005763 self.assertEqual(new_data, data)
5764
5765 # Will be repacked, so fdtmap must change
5766 path, fdtmap = state.GetFdtContents('fdtmap')
5767 self.assertIsNotNone(path)
5768 self.assertNotEqual(expected_fdtmap, fdtmap)
5769
5770 def testReplaceFitSubentryLeafSmallerSize(self):
5771 """Test replacing a FIT leaf subentry with smaller-size data"""
5772 new_data = b'x'
5773 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5774 data, expected_fdtmap, _ = self._RunReplaceCmd(
5775 'fit/fdt-1/u-boot-nodtb', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005776 dts='240_fit_extract_replace.dts')
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005777 self.assertEqual(expected, data)
5778
5779 path, fdtmap = state.GetFdtContents('fdtmap')
5780 self.assertIsNotNone(path)
5781 self.assertEqual(expected_fdtmap, fdtmap)
5782
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005783 def testReplaceSectionSimple(self):
5784 """Test replacing a simple section with arbitrary data"""
5785 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glassc6b283f2022-08-13 11:40:46 -06005786 with self.assertRaises(ValueError) as exc:
5787 self._RunReplaceCmd('section', new_data,
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005788 dts='241_replace_section_simple.dts')
Simon Glassc6b283f2022-08-13 11:40:46 -06005789 self.assertIn(
5790 "Node '/section': Replacing sections is not implemented yet",
5791 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005792
Simon Glass8fbca772022-08-13 11:40:48 -06005793 def testMkimageImagename(self):
5794 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005795 data = self._DoReadFile('242_mkimage_name.dts')
Simon Glass8fbca772022-08-13 11:40:48 -06005796
5797 # Check that the data appears in the file somewhere
5798 self.assertIn(U_BOOT_SPL_DATA, data)
5799
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005800 # Get struct legacy_img_hdr -> ih_name
Simon Glass8fbca772022-08-13 11:40:48 -06005801 name = data[0x20:0x40]
5802
5803 # Build the filename that we expect to be placed in there, by virtue of
5804 # the -n paraameter
5805 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5806
5807 # Check that the image name is set to the temporary filename used
5808 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5809
Simon Glassb1669752022-08-13 11:40:49 -06005810 def testMkimageImage(self):
5811 """Test using mkimage with -n holding the data too"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005812 data = self._DoReadFile('243_mkimage_image.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005813
5814 # Check that the data appears in the file somewhere
5815 self.assertIn(U_BOOT_SPL_DATA, data)
5816
Simon Glassbb7d3bb2022-09-06 20:26:52 -06005817 # Get struct legacy_img_hdr -> ih_name
Simon Glassb1669752022-08-13 11:40:49 -06005818 name = data[0x20:0x40]
5819
5820 # Build the filename that we expect to be placed in there, by virtue of
5821 # the -n paraameter
5822 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5823
5824 # Check that the image name is set to the temporary filename used
5825 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5826
5827 # Check the corect data is in the imagename file
5828 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5829
5830 def testMkimageImageNoContent(self):
5831 """Test using mkimage with -n and no data"""
5832 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005833 self._DoReadFile('244_mkimage_image_no_content.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005834 self.assertIn('Could not complete processing of contents',
5835 str(exc.exception))
5836
5837 def testMkimageImageBad(self):
5838 """Test using mkimage with imagename node and data-to-imagename"""
5839 with self.assertRaises(ValueError) as exc:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005840 self._DoReadFile('245_mkimage_image_bad.dts')
Simon Glassb1669752022-08-13 11:40:49 -06005841 self.assertIn('Cannot use both imagename node and data-to-imagename',
5842 str(exc.exception))
5843
Simon Glassbd5cd882022-08-13 11:40:50 -06005844 def testCollectionOther(self):
5845 """Test a collection where the data comes from another section"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005846 data = self._DoReadFile('246_collection_other.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005847 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5848 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5849 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5850 data)
5851
5852 def testMkimageCollection(self):
5853 """Test using a collection referring to an entry in a mkimage entry"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005854 data = self._DoReadFile('247_mkimage_coll.dts')
Simon Glassbd5cd882022-08-13 11:40:50 -06005855 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5856 self.assertEqual(expect, data[:len(expect)])
5857
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005858 def testCompressDtbPrependInvalid(self):
5859 """Test that invalid header is detected"""
5860 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005861 self._DoReadFileDtb('248_compress_dtb_prepend_invalid.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005862 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5863 "'u-boot-dtb': 'invalid'", str(e.exception))
5864
5865 def testCompressDtbPrependLength(self):
5866 """Test that compress with length header works as expected"""
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005867 data = self._DoReadFileRealDtb('249_compress_dtb_prepend_length.dts')
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005868 image = control.images['image']
5869 entries = image.GetEntries()
5870 self.assertIn('u-boot-dtb', entries)
5871 u_boot_dtb = entries['u-boot-dtb']
5872 self.assertIn('fdtmap', entries)
5873 fdtmap = entries['fdtmap']
5874
5875 image_fname = tools.get_output_filename('image.bin')
5876 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
5877 dtb = fdt.Fdt.FromData(orig)
5878 dtb.Scan()
5879 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
5880 expected = {
5881 'u-boot:size': len(U_BOOT_DATA),
5882 'u-boot-dtb:uncomp-size': len(orig),
5883 'u-boot-dtb:size': u_boot_dtb.size,
5884 'fdtmap:size': fdtmap.size,
5885 'size': len(data),
5886 }
5887 self.assertEqual(expected, props)
5888
5889 # Check implementation
5890 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
5891 rest = data[len(U_BOOT_DATA):]
5892 comp_data_len = struct.unpack('<I', rest[:4])[0]
5893 comp_data = rest[4:4 + comp_data_len]
5894 orig2 = self._decompress(comp_data)
5895 self.assertEqual(orig, orig2)
5896
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02005897 def testInvalidCompress(self):
5898 """Test that invalid compress algorithm is detected"""
5899 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005900 self._DoTestFile('250_compress_dtb_invalid.dts')
Stefan Herbrechtsmeiera6e0b502022-08-19 16:25:30 +02005901 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5902
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02005903 def testCompUtilCompressions(self):
5904 """Test compression algorithms"""
5905 for bintool in self.comp_bintools.values():
5906 self._CheckBintool(bintool)
5907 data = bintool.compress(COMPRESS_DATA)
5908 self.assertNotEqual(COMPRESS_DATA, data)
5909 orig = bintool.decompress(data)
5910 self.assertEquals(COMPRESS_DATA, orig)
5911
5912 def testCompUtilVersions(self):
5913 """Test tool version of compression algorithms"""
5914 for bintool in self.comp_bintools.values():
5915 self._CheckBintool(bintool)
5916 version = bintool.version()
5917 self.assertRegex(version, '^v?[0-9]+[0-9.]*')
5918
5919 def testCompUtilPadding(self):
5920 """Test padding of compression algorithms"""
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02005921 # Skip zstd because it doesn't support padding
5922 for bintool in [v for k,v in self.comp_bintools.items() if k != 'zstd']:
Stefan Herbrechtsmeiera14bee02022-08-19 16:25:32 +02005923 self._CheckBintool(bintool)
5924 data = bintool.compress(COMPRESS_DATA)
5925 self.assertNotEqual(COMPRESS_DATA, data)
5926 data += tools.get_bytes(0, 64)
5927 orig = bintool.decompress(data)
5928 self.assertEquals(COMPRESS_DATA, orig)
5929
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02005930 def testCompressDtbZstd(self):
5931 """Test that zstd compress of device-tree files failed"""
5932 with self.assertRaises(ValueError) as e:
Stefan Herbrechtsmeier3074bdd2022-08-23 12:46:09 +02005933 self._DoTestFile('251_compress_dtb_zstd.dts')
Stefan Herbrechtsmeiera5e4dcb2022-08-19 16:25:38 +02005934 self.assertIn("Node '/binman/u-boot-dtb': The zstd compression "
5935 "requires a length header", str(e.exception))
5936
Quentin Schulz9b5c6482022-09-02 15:10:48 +02005937 def testMkimageMultipleDataFiles(self):
5938 """Test passing multiple files to mkimage in a mkimage entry"""
5939 data = self._DoReadFile('252_mkimage_mult_data.dts')
5940 # Size of files are packed in their 4B big-endian format
5941 expect = struct.pack('>I', len(U_BOOT_TPL_DATA))
5942 expect += struct.pack('>I', len(U_BOOT_SPL_DATA))
5943 # Size info is always followed by a 4B zero value.
5944 expect += tools.get_bytes(0, 4)
5945 expect += U_BOOT_TPL_DATA
5946 # All but last files are 4B-aligned
5947 align_pad = len(U_BOOT_TPL_DATA) % 4
5948 if align_pad:
5949 expect += tools.get_bytes(0, align_pad)
5950 expect += U_BOOT_SPL_DATA
5951 self.assertEqual(expect, data[-len(expect):])
5952
5953 def testMkimageMultipleNoContent(self):
5954 """Test passing multiple data files to mkimage with one data file having no content"""
5955 with self.assertRaises(ValueError) as exc:
5956 self._DoReadFile('253_mkimage_mult_no_content.dts')
5957 self.assertIn('Could not complete processing of contents',
5958 str(exc.exception))
5959
Quentin Schulz0d3a9262022-09-02 15:10:49 +02005960 def testMkimageFilename(self):
5961 """Test using mkimage to build a binary with a filename"""
5962 retcode = self._DoTestFile('254_mkimage_filename.dts')
5963 self.assertEqual(0, retcode)
5964 fname = tools.get_output_filename('mkimage-test.bin')
5965 self.assertTrue(os.path.exists(fname))
5966
Simon Glass56d05412022-02-28 07:16:54 -07005967 def testVpl(self):
5968 """Test that an image with VPL and its device tree can be created"""
5969 # ELF file with a '__bss_size' symbol
5970 self._SetupVplElf()
5971 data = self._DoReadFile('255_u_boot_vpl.dts')
5972 self.assertEqual(U_BOOT_VPL_DATA + U_BOOT_VPL_DTB_DATA, data)
5973
5974 def testVplNoDtb(self):
5975 """Test that an image with vpl/u-boot-vpl-nodtb.bin can be created"""
5976 self._SetupVplElf()
5977 data = self._DoReadFile('256_u_boot_vpl_nodtb.dts')
5978 self.assertEqual(U_BOOT_VPL_NODTB_DATA,
5979 data[:len(U_BOOT_VPL_NODTB_DATA)])
5980
5981 def testExpandedVpl(self):
5982 """Test that an expanded entry type is selected for TPL when needed"""
5983 self._SetupVplElf()
5984
5985 entry_args = {
5986 'vpl-bss-pad': 'y',
5987 'vpl-dtb': 'y',
5988 }
5989 self._DoReadFileDtb('257_fdt_incl_vpl.dts', use_expanded=True,
5990 entry_args=entry_args)
5991 image = control.images['image']
5992 entries = image.GetEntries()
5993 self.assertEqual(1, len(entries))
5994
5995 # We only have u-boot-vpl, which be expanded
5996 self.assertIn('u-boot-vpl', entries)
5997 entry = entries['u-boot-vpl']
5998 self.assertEqual('u-boot-vpl-expanded', entry.etype)
5999 subent = entry.GetEntries()
6000 self.assertEqual(3, len(subent))
6001 self.assertIn('u-boot-vpl-nodtb', subent)
6002 self.assertIn('u-boot-vpl-bss-pad', subent)
6003 self.assertIn('u-boot-vpl-dtb', subent)
6004
6005 def testVplBssPadMissing(self):
6006 """Test that a missing symbol is detected"""
6007 self._SetupVplElf('u_boot_ucode_ptr')
6008 with self.assertRaises(ValueError) as e:
6009 self._DoReadFile('258_vpl_bss_pad.dts')
6010 self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
6011 str(e.exception))
6012
Neha Malcom Francis3eb4be32022-10-17 16:36:25 +05306013 def testSymlink(self):
6014 """Test that image files can be named"""
6015 retcode = self._DoTestFile('259_symlink.dts', debug=True, map=True)
6016 self.assertEqual(0, retcode)
6017 image = control.images['test_image']
6018 fname = tools.get_output_filename('test_image.bin')
6019 sname = tools.get_output_filename('symlink_to_test.bin')
6020 self.assertTrue(os.path.islink(sname))
6021 self.assertEqual(os.readlink(sname), fname)
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03006022
Simon Glass37f85de2022-10-20 18:22:47 -06006023 def testSymbolsElf(self):
6024 """Test binman can assign symbols embedded in an ELF file"""
6025 if not elf.ELF_TOOLS:
6026 self.skipTest('Python elftools not available')
6027 self._SetupTplElf('u_boot_binman_syms')
6028 self._SetupVplElf('u_boot_binman_syms')
6029 self._SetupSplElf('u_boot_binman_syms')
6030 data = self._DoReadFileDtb('260_symbols_elf.dts')[0]
6031 image_fname = tools.get_output_filename('image.bin')
6032
6033 image = control.images['image']
6034 entries = image.GetEntries()
6035
6036 for entry in entries.values():
6037 # No symbols in u-boot and it has faked contents anyway
6038 if entry.name == 'u-boot':
6039 continue
6040 edata = data[entry.image_pos:entry.image_pos + entry.size]
6041 efname = tools.get_output_filename(f'edata-{entry.name}')
6042 tools.write_file(efname, edata)
6043
6044 syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
6045 re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
6046 for name, sym in syms.items():
6047 msg = 'test'
6048 val = elf.GetSymbolValue(sym, edata, msg)
6049 entry_m = re_name.match(name)
6050 if entry_m:
6051 ename, prop = entry_m.group(1), entry_m.group(3)
6052 entry, entry_name, prop_name = image.LookupEntry(entries,
6053 name, msg)
6054 if prop_name == 'offset':
6055 expect_val = entry.offset
6056 elif prop_name == 'image_pos':
6057 expect_val = entry.image_pos
6058 elif prop_name == 'size':
6059 expect_val = entry.size
6060 self.assertEqual(expect_val, val)
6061
6062 def testSymbolsElfBad(self):
6063 """Check error when trying to write symbols without the elftools lib"""
6064 if not elf.ELF_TOOLS:
6065 self.skipTest('Python elftools not available')
6066 self._SetupTplElf('u_boot_binman_syms')
6067 self._SetupVplElf('u_boot_binman_syms')
6068 self._SetupSplElf('u_boot_binman_syms')
6069 try:
6070 elf.ELF_TOOLS = False
6071 with self.assertRaises(ValueError) as exc:
6072 self._DoReadFileDtb('260_symbols_elf.dts')
6073 finally:
6074 elf.ELF_TOOLS = True
6075 self.assertIn(
6076 "Section '/binman': entry '/binman/u-boot-spl-elf': "
6077 'Cannot write symbols to an ELF file without Python elftools',
6078 str(exc.exception))
6079
Simon Glassac599912017-11-12 21:52:22 -07006080if __name__ == "__main__":
6081 unittest.main()