blob: 7a3e4f8ae0b89f7c8e0ec17e4bfed7254f50454f [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
Simon Glass3ac7d832022-01-09 20:14:03 -070026from binman import comp_util
Simon Glassc585dd42020-04-17 18:09:03 -060027from binman import control
28from binman import elf
29from binman import elf_test
Simon Glass3efb2972021-11-23 21:08:59 -070030from binman import fip_util
Simon Glassc585dd42020-04-17 18:09:03 -060031from binman import fmap_util
Simon Glassc585dd42020-04-17 18:09:03 -060032from binman import state
33from dtoc import fdt
34from dtoc import fdt_util
35from binman.etype import fdtmap
36from binman.etype import image_header
Simon Glass90cd6f02020-08-05 13:27:47 -060037from binman.image import Image
Simon Glassa997ea52020-04-17 18:09:04 -060038from patman import command
39from patman import test_util
40from patman import tools
41from patman import tout
Simon Glass57454f42016-11-25 20:15:52 -070042
43# Contents of test files, corresponding to different entry types
Simon Glass303f62f2019-05-17 22:00:46 -060044U_BOOT_DATA = b'1234'
45U_BOOT_IMG_DATA = b'img'
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +030046U_BOOT_SPL_DATA = b'56780123456789abcdefghijklm'
47U_BOOT_TPL_DATA = b'tpl9876543210fedcbazywvuts'
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'
54X86_START16_DATA = b'start16'
55X86_START16_SPL_DATA = b'start16spl'
56X86_START16_TPL_DATA = b'start16tpl'
Simon Glass0b074d62019-08-24 07:22:48 -060057X86_RESET16_DATA = b'reset16'
58X86_RESET16_SPL_DATA = b'reset16spl'
59X86_RESET16_TPL_DATA = b'reset16tpl'
Simon Glass303f62f2019-05-17 22:00:46 -060060PPC_MPC85XX_BR_DATA = b'ppcmpc85xxbr'
61U_BOOT_NODTB_DATA = b'nodtb with microcode pointer somewhere in here'
62U_BOOT_SPL_NODTB_DATA = b'splnodtb with microcode pointer somewhere in here'
63U_BOOT_TPL_NODTB_DATA = b'tplnodtb with microcode pointer somewhere in here'
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +030064U_BOOT_EXP_DATA = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
65U_BOOT_SPL_EXP_DATA = U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA
66U_BOOT_TPL_EXP_DATA = U_BOOT_TPL_NODTB_DATA + U_BOOT_TPL_DTB_DATA
Simon Glass303f62f2019-05-17 22:00:46 -060067FSP_DATA = b'fsp'
68CMC_DATA = b'cmc'
69VBT_DATA = b'vbt'
70MRC_DATA = b'mrc'
Simon Glass2ca52032018-07-17 13:25:33 -060071TEXT_DATA = 'text'
72TEXT_DATA2 = 'text2'
73TEXT_DATA3 = 'text3'
Simon Glass303f62f2019-05-17 22:00:46 -060074CROS_EC_RW_DATA = b'ecrw'
75GBB_DATA = b'gbbd'
76BMPBLK_DATA = b'bmp'
77VBLOCK_DATA = b'vblk'
78FILES_DATA = (b"sorry I'm late\nOh, don't bother apologising, I'm " +
79 b"sorry you're alive\n")
Simon Glassccec0262019-07-08 13:18:42 -060080COMPRESS_DATA = b'compress xxxxxxxxxxxxxxxxxxxxxx data'
Simon Glassd92c8362020-10-26 17:40:25 -060081COMPRESS_DATA_BIG = COMPRESS_DATA * 2
Simon Glass303f62f2019-05-17 22:00:46 -060082REFCODE_DATA = b'refcode'
Simon Glassba7985d2019-08-24 07:23:07 -060083FSP_M_DATA = b'fsp_m'
Simon Glass4d9086d2019-10-20 21:31:35 -060084FSP_S_DATA = b'fsp_s'
Simon Glass9ea87b22019-10-20 21:31:36 -060085FSP_T_DATA = b'fsp_t'
Simon Glass559c4de2020-09-01 05:13:58 -060086ATF_BL31_DATA = b'bl31'
Roger Quadros5cdcea02022-02-19 20:50:04 +020087TEE_OS_DATA = b'this is some tee OS data'
Simon Glass3efb2972021-11-23 21:08:59 -070088ATF_BL2U_DATA = b'bl2u'
Bin Mengc0b15742021-05-10 20:23:33 +080089OPENSBI_DATA = b'opensbi'
Samuel Holland9d8cc632020-10-21 21:12:15 -050090SCP_DATA = b'scp'
Simon Glassa435cd12020-09-01 05:13:59 -060091TEST_FDT1_DATA = b'fdt1'
92TEST_FDT2_DATA = b'test-fdt2'
Simon Glassa0729502020-09-06 10:35:33 -060093ENV_DATA = b'var1=1\nvar2="2"'
Philippe Reynesebe96cb2022-03-28 22:57:04 +020094PRE_LOAD_MAGIC = b'UBSH'
95PRE_LOAD_VERSION = 0x11223344.to_bytes(4, 'big')
96PRE_LOAD_HDR_SIZE = 0x00001000.to_bytes(4, 'big')
Simon Glassa435cd12020-09-01 05:13:59 -060097
98# Subdirectory of the input dir to use to put test FDTs
99TEST_FDT_SUBDIR = 'fdts'
Simon Glassdb168d42018-07-17 13:25:39 -0600100
Simon Glass2c6adba2019-07-20 12:23:47 -0600101# The expected size for the device tree in some tests
Simon Glass4c613bf2019-07-08 14:25:50 -0600102EXTRACT_DTB_SIZE = 0x3c9
103
Simon Glass2c6adba2019-07-20 12:23:47 -0600104# Properties expected to be in the device tree when update_dtb is used
105BASE_DTB_PROPS = ['offset', 'size', 'image-pos']
106
Simon Glassfb30e292019-07-20 12:23:51 -0600107# Extra properties expected to be in the device tree when allow-repack is used
108REPACK_DTB_PROPS = ['orig-offset', 'orig-size']
109
Simon Glass57454f42016-11-25 20:15:52 -0700110
111class TestFunctional(unittest.TestCase):
112 """Functional tests for binman
113
114 Most of these use a sample .dts file to build an image and then check
115 that it looks correct. The sample files are in the test/ subdirectory
116 and are numbered.
117
118 For each entry type a very small test file is created using fixed
119 string contents. This makes it easy to test that things look right, and
120 debug problems.
121
122 In some cases a 'real' file must be used - these are also supplied in
123 the test/ diurectory.
124 """
125 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600126 def setUpClass(cls):
Simon Glassb3393262017-11-12 21:52:20 -0700127 global entry
Simon Glassc585dd42020-04-17 18:09:03 -0600128 from binman import entry
Simon Glassb3393262017-11-12 21:52:20 -0700129
Simon Glass57454f42016-11-25 20:15:52 -0700130 # Handle the case where argv[0] is 'python'
Simon Glass862f8e22019-08-24 07:22:43 -0600131 cls._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
132 cls._binman_pathname = os.path.join(cls._binman_dir, 'binman')
Simon Glass57454f42016-11-25 20:15:52 -0700133
134 # Create a temporary directory for input files
Simon Glass862f8e22019-08-24 07:22:43 -0600135 cls._indir = tempfile.mkdtemp(prefix='binmant.')
Simon Glass57454f42016-11-25 20:15:52 -0700136
137 # Create some test files
138 TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA)
139 TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA)
140 TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA)
Simon Glass8425a1f2018-07-17 13:25:48 -0600141 TestFunctional._MakeInputFile('tpl/u-boot-tpl.bin', U_BOOT_TPL_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700142 TestFunctional._MakeInputFile('blobfile', BLOB_DATA)
Simon Glass72232452016-11-25 20:15:53 -0700143 TestFunctional._MakeInputFile('me.bin', ME_DATA)
144 TestFunctional._MakeInputFile('vga.bin', VGA_DATA)
Simon Glass862f8e22019-08-24 07:22:43 -0600145 cls._ResetDtbs()
Simon Glass0b074d62019-08-24 07:22:48 -0600146
Jagdish Gediya311d4842018-09-03 21:35:08 +0530147 TestFunctional._MakeInputFile('u-boot-br.bin', PPC_MPC85XX_BR_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600148
Simon Glassabab18c2019-08-24 07:22:49 -0600149 TestFunctional._MakeInputFile('u-boot-x86-start16.bin', X86_START16_DATA)
150 TestFunctional._MakeInputFile('spl/u-boot-x86-start16-spl.bin',
Simon Glasse83679d2017-11-12 21:52:26 -0700151 X86_START16_SPL_DATA)
Simon Glassabab18c2019-08-24 07:22:49 -0600152 TestFunctional._MakeInputFile('tpl/u-boot-x86-start16-tpl.bin',
Simon Glassed40e962018-09-14 04:57:10 -0600153 X86_START16_TPL_DATA)
Simon Glass0b074d62019-08-24 07:22:48 -0600154
155 TestFunctional._MakeInputFile('u-boot-x86-reset16.bin',
156 X86_RESET16_DATA)
157 TestFunctional._MakeInputFile('spl/u-boot-x86-reset16-spl.bin',
158 X86_RESET16_SPL_DATA)
159 TestFunctional._MakeInputFile('tpl/u-boot-x86-reset16-tpl.bin',
160 X86_RESET16_TPL_DATA)
161
Simon Glass57454f42016-11-25 20:15:52 -0700162 TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA)
Simon Glass3d274232017-11-12 21:52:27 -0700163 TestFunctional._MakeInputFile('spl/u-boot-spl-nodtb.bin',
164 U_BOOT_SPL_NODTB_DATA)
Simon Glass3fb4f422018-09-14 04:57:32 -0600165 TestFunctional._MakeInputFile('tpl/u-boot-tpl-nodtb.bin',
166 U_BOOT_TPL_NODTB_DATA)
Simon Glassb4176d42016-11-25 20:15:56 -0700167 TestFunctional._MakeInputFile('fsp.bin', FSP_DATA)
168 TestFunctional._MakeInputFile('cmc.bin', CMC_DATA)
Bin Mengd7bcdf52017-08-15 22:41:54 -0700169 TestFunctional._MakeInputFile('vbt.bin', VBT_DATA)
Simon Glassa409c932017-11-12 21:52:28 -0700170 TestFunctional._MakeInputFile('mrc.bin', MRC_DATA)
Simon Glassdb168d42018-07-17 13:25:39 -0600171 TestFunctional._MakeInputFile('ecrw.bin', CROS_EC_RW_DATA)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600172 TestFunctional._MakeInputDir('devkeys')
173 TestFunctional._MakeInputFile('bmpblk.bin', BMPBLK_DATA)
Simon Glass41902e42018-10-01 12:22:31 -0600174 TestFunctional._MakeInputFile('refcode.bin', REFCODE_DATA)
Simon Glassba7985d2019-08-24 07:23:07 -0600175 TestFunctional._MakeInputFile('fsp_m.bin', FSP_M_DATA)
Simon Glass4d9086d2019-10-20 21:31:35 -0600176 TestFunctional._MakeInputFile('fsp_s.bin', FSP_S_DATA)
Simon Glass9ea87b22019-10-20 21:31:36 -0600177 TestFunctional._MakeInputFile('fsp_t.bin', FSP_T_DATA)
Simon Glass57454f42016-11-25 20:15:52 -0700178
Simon Glassf6290892019-08-24 07:22:53 -0600179 cls._elf_testdir = os.path.join(cls._indir, 'elftest')
180 elf_test.BuildElfTestFiles(cls._elf_testdir)
181
Simon Glass72232452016-11-25 20:15:53 -0700182 # ELF file with a '_dt_ucode_base_size' symbol
Simon Glass4affd4b2019-08-24 07:22:54 -0600183 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -0700184 tools.read_file(cls.ElfTestFile('u_boot_ucode_ptr')))
Simon Glass72232452016-11-25 20:15:53 -0700185
186 # Intel flash descriptor file
Simon Glasse88cef92020-07-09 18:39:41 -0600187 cls._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -0700188
Simon Glass862f8e22019-08-24 07:22:43 -0600189 shutil.copytree(cls.TestFile('files'),
190 os.path.join(cls._indir, 'files'))
Simon Glassac6328c2018-09-14 04:57:28 -0600191
Simon Glass7ba33592018-09-14 04:57:26 -0600192 TestFunctional._MakeInputFile('compress', COMPRESS_DATA)
Simon Glassd92c8362020-10-26 17:40:25 -0600193 TestFunctional._MakeInputFile('compress_big', COMPRESS_DATA_BIG)
Simon Glass559c4de2020-09-01 05:13:58 -0600194 TestFunctional._MakeInputFile('bl31.bin', ATF_BL31_DATA)
Roger Quadros5cdcea02022-02-19 20:50:04 +0200195 TestFunctional._MakeInputFile('tee-pager.bin', TEE_OS_DATA)
Simon Glass3efb2972021-11-23 21:08:59 -0700196 TestFunctional._MakeInputFile('bl2u.bin', ATF_BL2U_DATA)
Bin Mengc0b15742021-05-10 20:23:33 +0800197 TestFunctional._MakeInputFile('fw_dynamic.bin', OPENSBI_DATA)
Samuel Holland9d8cc632020-10-21 21:12:15 -0500198 TestFunctional._MakeInputFile('scp.bin', SCP_DATA)
Simon Glass7ba33592018-09-14 04:57:26 -0600199
Simon Glassa435cd12020-09-01 05:13:59 -0600200 # Add a few .dtb files for testing
201 TestFunctional._MakeInputFile('%s/test-fdt1.dtb' % TEST_FDT_SUBDIR,
202 TEST_FDT1_DATA)
203 TestFunctional._MakeInputFile('%s/test-fdt2.dtb' % TEST_FDT_SUBDIR,
204 TEST_FDT2_DATA)
205
Simon Glassa0729502020-09-06 10:35:33 -0600206 TestFunctional._MakeInputFile('env.txt', ENV_DATA)
207
Simon Glass5f423422022-03-05 20:19:12 -0700208 # ELF file with two sections in different parts of memory, used for both
209 # ATF and OP_TEE
210 TestFunctional._MakeInputFile('bl31.elf',
211 tools.read_file(cls.ElfTestFile('elf_sections')))
212 TestFunctional._MakeInputFile('tee.elf',
213 tools.read_file(cls.ElfTestFile('elf_sections')))
214
Simon Glass9203c162022-01-09 20:14:06 -0700215 cls.have_lz4 = comp_util.HAVE_LZ4
Simon Glass1de34482019-07-08 13:18:53 -0600216
Simon Glass57454f42016-11-25 20:15:52 -0700217 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600218 def tearDownClass(cls):
Simon Glass57454f42016-11-25 20:15:52 -0700219 """Remove the temporary input directory and its contents"""
Simon Glass862f8e22019-08-24 07:22:43 -0600220 if cls.preserve_indir:
221 print('Preserving input dir: %s' % cls._indir)
Simon Glass1c420c92019-07-08 13:18:49 -0600222 else:
Simon Glass862f8e22019-08-24 07:22:43 -0600223 if cls._indir:
224 shutil.rmtree(cls._indir)
225 cls._indir = None
Simon Glass57454f42016-11-25 20:15:52 -0700226
Simon Glass1c420c92019-07-08 13:18:49 -0600227 @classmethod
Simon Glasscebfab22019-07-08 13:18:50 -0600228 def setup_test_args(cls, preserve_indir=False, preserve_outdirs=False,
Simon Glassf46732a2019-07-08 14:25:29 -0600229 toolpath=None, verbosity=None):
Simon Glass1c420c92019-07-08 13:18:49 -0600230 """Accept arguments controlling test execution
231
232 Args:
233 preserve_indir: Preserve the shared input directory used by all
234 tests in this class.
235 preserve_outdir: Preserve the output directories used by tests. Each
236 test has its own, so this is normally only useful when running a
237 single test.
Simon Glasscebfab22019-07-08 13:18:50 -0600238 toolpath: ist of paths to use for tools
Simon Glass1c420c92019-07-08 13:18:49 -0600239 """
240 cls.preserve_indir = preserve_indir
241 cls.preserve_outdirs = preserve_outdirs
Simon Glasscebfab22019-07-08 13:18:50 -0600242 cls.toolpath = toolpath
Simon Glassf46732a2019-07-08 14:25:29 -0600243 cls.verbosity = verbosity
Simon Glass1c420c92019-07-08 13:18:49 -0600244
Simon Glass1de34482019-07-08 13:18:53 -0600245 def _CheckLz4(self):
246 if not self.have_lz4:
247 self.skipTest('lz4 --no-frame-crc not available')
248
Simon Glassee9d10d2019-07-20 12:24:09 -0600249 def _CleanupOutputDir(self):
250 """Remove the temporary output directory"""
251 if self.preserve_outdirs:
252 print('Preserving output dir: %s' % tools.outdir)
253 else:
Simon Glass80025522022-01-29 14:14:04 -0700254 tools._finalise_for_test()
Simon Glassee9d10d2019-07-20 12:24:09 -0600255
Simon Glass57454f42016-11-25 20:15:52 -0700256 def setUp(self):
257 # Enable this to turn on debugging output
Simon Glass011f1b32022-01-29 14:14:15 -0700258 # tout.init(tout.DEBUG)
Simon Glass57454f42016-11-25 20:15:52 -0700259 command.test_result = None
260
261 def tearDown(self):
262 """Remove the temporary output directory"""
Simon Glassee9d10d2019-07-20 12:24:09 -0600263 self._CleanupOutputDir()
Simon Glass57454f42016-11-25 20:15:52 -0700264
Simon Glassb3d6fc72019-07-20 12:24:10 -0600265 def _SetupImageInTmpdir(self):
266 """Set up the output image in a new temporary directory
267
268 This is used when an image has been generated in the output directory,
269 but we want to run binman again. This will create a new output
270 directory and fail to delete the original one.
271
272 This creates a new temporary directory, copies the image to it (with a
273 new name) and removes the old output directory.
274
275 Returns:
276 Tuple:
277 Temporary directory to use
278 New image filename
279 """
Simon Glass80025522022-01-29 14:14:04 -0700280 image_fname = tools.get_output_filename('image.bin')
Simon Glassb3d6fc72019-07-20 12:24:10 -0600281 tmpdir = tempfile.mkdtemp(prefix='binman.')
282 updated_fname = os.path.join(tmpdir, 'image-updated.bin')
Simon Glass80025522022-01-29 14:14:04 -0700283 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassb3d6fc72019-07-20 12:24:10 -0600284 self._CleanupOutputDir()
285 return tmpdir, updated_fname
286
Simon Glass8425a1f2018-07-17 13:25:48 -0600287 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600288 def _ResetDtbs(cls):
Simon Glass8425a1f2018-07-17 13:25:48 -0600289 TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA)
290 TestFunctional._MakeInputFile('spl/u-boot-spl.dtb', U_BOOT_SPL_DTB_DATA)
291 TestFunctional._MakeInputFile('tpl/u-boot-tpl.dtb', U_BOOT_TPL_DTB_DATA)
292
Simon Glass57454f42016-11-25 20:15:52 -0700293 def _RunBinman(self, *args, **kwargs):
294 """Run binman using the command line
295
296 Args:
297 Arguments to pass, as a list of strings
298 kwargs: Arguments to pass to Command.RunPipe()
299 """
Simon Glass840be732022-01-29 14:14:05 -0700300 result = command.run_pipe([[self._binman_pathname] + list(args)],
Simon Glass57454f42016-11-25 20:15:52 -0700301 capture=True, capture_stderr=True, raise_on_error=False)
302 if result.return_code and kwargs.get('raise_on_error', True):
303 raise Exception("Error running '%s': %s" % (' '.join(args),
304 result.stdout + result.stderr))
305 return result
306
Simon Glassf46732a2019-07-08 14:25:29 -0600307 def _DoBinman(self, *argv):
Simon Glass57454f42016-11-25 20:15:52 -0700308 """Run binman using directly (in the same process)
309
310 Args:
311 Arguments to pass, as a list of strings
312 Returns:
313 Return value (0 for success)
314 """
Simon Glassf46732a2019-07-08 14:25:29 -0600315 argv = list(argv)
316 args = cmdline.ParseArgs(argv)
317 args.pager = 'binman-invalid-pager'
318 args.build_dir = self._indir
Simon Glass57454f42016-11-25 20:15:52 -0700319
320 # For testing, you can force an increase in verbosity here
Simon Glassf46732a2019-07-08 14:25:29 -0600321 # args.verbosity = tout.DEBUG
322 return control.Binman(args)
Simon Glass57454f42016-11-25 20:15:52 -0700323
Simon Glass91710b32018-07-17 13:25:32 -0600324 def _DoTestFile(self, fname, debug=False, map=False, update_dtb=False,
Simon Glassb4595d82019-04-25 21:58:34 -0600325 entry_args=None, images=None, use_real_dtb=False,
Simon Glassed930672021-03-18 20:25:05 +1300326 use_expanded=False, verbosity=None, allow_missing=False,
Heiko Thiery6d451362022-01-06 11:49:41 +0100327 allow_fake_blobs=False, extra_indirs=None, threads=None,
Simon Glass66152ce2022-01-09 20:14:09 -0700328 test_section_timeout=False, update_fdt_in_elf=None,
329 force_missing_bintools=''):
Simon Glass57454f42016-11-25 20:15:52 -0700330 """Run binman with a given test file
331
332 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600333 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600334 debug: True to enable debugging output
Simon Glass30732662018-06-01 09:38:20 -0600335 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600336 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600337 tree before packing it into the image
Simon Glass3b376c32018-09-14 04:57:12 -0600338 entry_args: Dict of entry args to supply to binman
339 key: arg name
340 value: value of that arg
341 images: List of image names to build
Simon Glass31ee50f2020-09-01 05:13:55 -0600342 use_real_dtb: True to use the test file as the contents of
343 the u-boot-dtb entry. Normally this is not needed and the
344 test contents (the U_BOOT_DTB_DATA string) can be used.
345 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300346 use_expanded: True to use expanded entries where available, e.g.
347 'u-boot-expanded' instead of 'u-boot'
Simon Glass31ee50f2020-09-01 05:13:55 -0600348 verbosity: Verbosity level to use (0-3, None=don't set it)
349 allow_missing: Set the '--allow-missing' flag so that missing
350 external binaries just produce a warning instead of an error
Heiko Thiery6d451362022-01-06 11:49:41 +0100351 allow_fake_blobs: Set the '--fake-ext-blobs' flag
Simon Glassa435cd12020-09-01 05:13:59 -0600352 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600353 threads: Number of threads to use (None for default, 0 for
354 single-threaded)
Simon Glass9a798402021-11-03 21:09:17 -0600355 test_section_timeout: True to force the first time to timeout, as
356 used in testThreadTimeout()
Simon Glassadfb8492021-11-03 21:09:18 -0600357 update_fdt_in_elf: Value to pass with --update-fdt-in-elf=xxx
Simon Glass66152ce2022-01-09 20:14:09 -0700358 force_missing_tools (str): comma-separated list of bintools to
359 regard as missing
Simon Glass9a798402021-11-03 21:09:17 -0600360
361 Returns:
362 int return code, 0 on success
Simon Glass57454f42016-11-25 20:15:52 -0700363 """
Simon Glassf46732a2019-07-08 14:25:29 -0600364 args = []
Simon Glass075a45c2017-11-13 18:55:00 -0700365 if debug:
366 args.append('-D')
Simon Glassf46732a2019-07-08 14:25:29 -0600367 if verbosity is not None:
368 args.append('-v%d' % verbosity)
369 elif self.verbosity:
370 args.append('-v%d' % self.verbosity)
371 if self.toolpath:
372 for path in self.toolpath:
373 args += ['--toolpath', path]
Simon Glass76f496d2021-07-06 10:36:37 -0600374 if threads is not None:
375 args.append('-T%d' % threads)
376 if test_section_timeout:
377 args.append('--test-section-timeout')
Simon Glassf46732a2019-07-08 14:25:29 -0600378 args += ['build', '-p', '-I', self._indir, '-d', self.TestFile(fname)]
Simon Glass30732662018-06-01 09:38:20 -0600379 if map:
380 args.append('-m')
Simon Glassa87014e2018-07-06 10:27:42 -0600381 if update_dtb:
Simon Glass38a411c2019-07-08 13:18:47 -0600382 args.append('-u')
Simon Glass31402012018-09-14 04:57:23 -0600383 if not use_real_dtb:
384 args.append('--fake-dtb')
Simon Glassed930672021-03-18 20:25:05 +1300385 if not use_expanded:
386 args.append('--no-expanded')
Simon Glass91710b32018-07-17 13:25:32 -0600387 if entry_args:
Simon Glass5f3645b2019-05-14 15:53:41 -0600388 for arg, value in entry_args.items():
Simon Glass91710b32018-07-17 13:25:32 -0600389 args.append('-a%s=%s' % (arg, value))
Simon Glass5d94cc62020-07-09 18:39:38 -0600390 if allow_missing:
391 args.append('-M')
Heiko Thiery6d451362022-01-06 11:49:41 +0100392 if allow_fake_blobs:
393 args.append('--fake-ext-blobs')
Simon Glass66152ce2022-01-09 20:14:09 -0700394 if force_missing_bintools:
395 args += ['--force-missing-bintools', force_missing_bintools]
Simon Glassadfb8492021-11-03 21:09:18 -0600396 if update_fdt_in_elf:
397 args += ['--update-fdt-in-elf', update_fdt_in_elf]
Simon Glass3b376c32018-09-14 04:57:12 -0600398 if images:
399 for image in images:
400 args += ['-i', image]
Simon Glassa435cd12020-09-01 05:13:59 -0600401 if extra_indirs:
402 for indir in extra_indirs:
403 args += ['-I', indir]
Simon Glass075a45c2017-11-13 18:55:00 -0700404 return self._DoBinman(*args)
Simon Glass57454f42016-11-25 20:15:52 -0700405
406 def _SetupDtb(self, fname, outfile='u-boot.dtb'):
Simon Glass72232452016-11-25 20:15:53 -0700407 """Set up a new test device-tree file
408
409 The given file is compiled and set up as the device tree to be used
410 for ths test.
411
412 Args:
413 fname: Filename of .dts file to read
Simon Glass1e324002018-06-01 09:38:19 -0600414 outfile: Output filename for compiled device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700415
416 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600417 Contents of device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700418 """
Simon Glassb8d2daa2019-07-20 12:23:49 -0600419 tmpdir = tempfile.mkdtemp(prefix='binmant.')
420 dtb = fdt_util.EnsureCompiled(self.TestFile(fname), tmpdir)
Simon Glass33486662019-05-14 15:53:42 -0600421 with open(dtb, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700422 data = fd.read()
423 TestFunctional._MakeInputFile(outfile, data)
Simon Glassb8d2daa2019-07-20 12:23:49 -0600424 shutil.rmtree(tmpdir)
Simon Glass752e7552018-10-01 21:12:41 -0600425 return data
Simon Glass57454f42016-11-25 20:15:52 -0700426
Simon Glasse219aa42018-09-14 04:57:24 -0600427 def _GetDtbContentsForSplTpl(self, dtb_data, name):
428 """Create a version of the main DTB for SPL or SPL
429
430 For testing we don't actually have different versions of the DTB. With
431 U-Boot we normally run fdtgrep to remove unwanted nodes, but for tests
432 we don't normally have any unwanted nodes.
433
434 We still want the DTBs for SPL and TPL to be different though, since
435 otherwise it is confusing to know which one we are looking at. So add
436 an 'spl' or 'tpl' property to the top-level node.
Simon Glass31ee50f2020-09-01 05:13:55 -0600437
438 Args:
439 dtb_data: dtb data to modify (this should be a value devicetree)
440 name: Name of a new property to add
441
442 Returns:
443 New dtb data with the property added
Simon Glasse219aa42018-09-14 04:57:24 -0600444 """
445 dtb = fdt.Fdt.FromData(dtb_data)
446 dtb.Scan()
447 dtb.GetNode('/binman').AddZeroProp(name)
448 dtb.Sync(auto_resize=True)
449 dtb.Pack()
450 return dtb.GetContents()
451
Simon Glassed930672021-03-18 20:25:05 +1300452 def _DoReadFileDtb(self, fname, use_real_dtb=False, use_expanded=False,
453 map=False, update_dtb=False, entry_args=None,
Simon Glass76f496d2021-07-06 10:36:37 -0600454 reset_dtbs=True, extra_indirs=None, threads=None):
Simon Glass57454f42016-11-25 20:15:52 -0700455 """Run binman and return the resulting image
456
457 This runs binman with a given test file and then reads the resulting
458 output file. It is a shortcut function since most tests need to do
459 these steps.
460
461 Raises an assertion failure if binman returns a non-zero exit code.
462
463 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600464 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass57454f42016-11-25 20:15:52 -0700465 use_real_dtb: True to use the test file as the contents of
466 the u-boot-dtb entry. Normally this is not needed and the
467 test contents (the U_BOOT_DTB_DATA string) can be used.
468 But in some test we need the real contents.
Simon Glassed930672021-03-18 20:25:05 +1300469 use_expanded: True to use expanded entries where available, e.g.
470 'u-boot-expanded' instead of 'u-boot'
Simon Glass30732662018-06-01 09:38:20 -0600471 map: True to output map files for the images
Simon Glasse8561af2018-08-01 15:22:37 -0600472 update_dtb: Update the offset and size of each entry in the device
Simon Glassa87014e2018-07-06 10:27:42 -0600473 tree before packing it into the image
Simon Glass31ee50f2020-09-01 05:13:55 -0600474 entry_args: Dict of entry args to supply to binman
475 key: arg name
476 value: value of that arg
477 reset_dtbs: With use_real_dtb the test dtb is overwritten by this
478 function. If reset_dtbs is True, then the original test dtb
479 is written back before this function finishes
Simon Glassa435cd12020-09-01 05:13:59 -0600480 extra_indirs: Extra input directories to add using -I
Simon Glass76f496d2021-07-06 10:36:37 -0600481 threads: Number of threads to use (None for default, 0 for
482 single-threaded)
Simon Glass72232452016-11-25 20:15:53 -0700483
484 Returns:
485 Tuple:
486 Resulting image contents
487 Device tree contents
Simon Glass30732662018-06-01 09:38:20 -0600488 Map data showing contents of image (or None if none)
Simon Glassdef77b52018-07-17 13:25:27 -0600489 Output device tree binary filename ('u-boot.dtb' path)
Simon Glass57454f42016-11-25 20:15:52 -0700490 """
Simon Glass72232452016-11-25 20:15:53 -0700491 dtb_data = None
Simon Glass57454f42016-11-25 20:15:52 -0700492 # Use the compiled test file as the u-boot-dtb input
493 if use_real_dtb:
Simon Glass72232452016-11-25 20:15:53 -0700494 dtb_data = self._SetupDtb(fname)
Simon Glasse219aa42018-09-14 04:57:24 -0600495
496 # For testing purposes, make a copy of the DT for SPL and TPL. Add
497 # a node indicating which it is, so aid verification.
498 for name in ['spl', 'tpl']:
499 dtb_fname = '%s/u-boot-%s.dtb' % (name, name)
500 outfile = os.path.join(self._indir, dtb_fname)
501 TestFunctional._MakeInputFile(dtb_fname,
502 self._GetDtbContentsForSplTpl(dtb_data, name))
Simon Glass57454f42016-11-25 20:15:52 -0700503
504 try:
Simon Glass91710b32018-07-17 13:25:32 -0600505 retcode = self._DoTestFile(fname, map=map, update_dtb=update_dtb,
Simon Glassa435cd12020-09-01 05:13:59 -0600506 entry_args=entry_args, use_real_dtb=use_real_dtb,
Simon Glass76f496d2021-07-06 10:36:37 -0600507 use_expanded=use_expanded, extra_indirs=extra_indirs,
508 threads=threads)
Simon Glass57454f42016-11-25 20:15:52 -0700509 self.assertEqual(0, retcode)
Simon Glass80025522022-01-29 14:14:04 -0700510 out_dtb_fname = tools.get_output_filename('u-boot.dtb.out')
Simon Glass57454f42016-11-25 20:15:52 -0700511
512 # Find the (only) image, read it and return its contents
513 image = control.images['image']
Simon Glass80025522022-01-29 14:14:04 -0700514 image_fname = tools.get_output_filename('image.bin')
Simon Glassa87014e2018-07-06 10:27:42 -0600515 self.assertTrue(os.path.exists(image_fname))
Simon Glass30732662018-06-01 09:38:20 -0600516 if map:
Simon Glass80025522022-01-29 14:14:04 -0700517 map_fname = tools.get_output_filename('image.map')
Simon Glass30732662018-06-01 09:38:20 -0600518 with open(map_fname) as fd:
519 map_data = fd.read()
520 else:
521 map_data = None
Simon Glass33486662019-05-14 15:53:42 -0600522 with open(image_fname, 'rb') as fd:
Simon Glassa87014e2018-07-06 10:27:42 -0600523 return fd.read(), dtb_data, map_data, out_dtb_fname
Simon Glass57454f42016-11-25 20:15:52 -0700524 finally:
525 # Put the test file back
Simon Glasse219aa42018-09-14 04:57:24 -0600526 if reset_dtbs and use_real_dtb:
Simon Glass8425a1f2018-07-17 13:25:48 -0600527 self._ResetDtbs()
Simon Glass57454f42016-11-25 20:15:52 -0700528
Simon Glass5b4bce32019-07-08 14:25:26 -0600529 def _DoReadFileRealDtb(self, fname):
530 """Run binman with a real .dtb file and return the resulting data
531
532 Args:
533 fname: DT source filename to use (e.g. 082_fdt_update_all.dts)
534
535 Returns:
536 Resulting image contents
537 """
538 return self._DoReadFileDtb(fname, use_real_dtb=True, update_dtb=True)[0]
539
Simon Glass72232452016-11-25 20:15:53 -0700540 def _DoReadFile(self, fname, use_real_dtb=False):
Simon Glass1e324002018-06-01 09:38:19 -0600541 """Helper function which discards the device-tree binary
542
543 Args:
Simon Glass511f6582018-10-01 12:22:30 -0600544 fname: Device-tree source filename to use (e.g. 005_simple.dts)
Simon Glass1e324002018-06-01 09:38:19 -0600545 use_real_dtb: True to use the test file as the contents of
546 the u-boot-dtb entry. Normally this is not needed and the
547 test contents (the U_BOOT_DTB_DATA string) can be used.
548 But in some test we need the real contents.
Simon Glassdef77b52018-07-17 13:25:27 -0600549
550 Returns:
551 Resulting image contents
Simon Glass1e324002018-06-01 09:38:19 -0600552 """
Simon Glass72232452016-11-25 20:15:53 -0700553 return self._DoReadFileDtb(fname, use_real_dtb)[0]
554
Simon Glass57454f42016-11-25 20:15:52 -0700555 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600556 def _MakeInputFile(cls, fname, contents):
Simon Glass57454f42016-11-25 20:15:52 -0700557 """Create a new test input file, creating directories as needed
558
559 Args:
Simon Glasse8561af2018-08-01 15:22:37 -0600560 fname: Filename to create
Simon Glass57454f42016-11-25 20:15:52 -0700561 contents: File contents to write in to the file
562 Returns:
563 Full pathname of file created
564 """
Simon Glass862f8e22019-08-24 07:22:43 -0600565 pathname = os.path.join(cls._indir, fname)
Simon Glass57454f42016-11-25 20:15:52 -0700566 dirname = os.path.dirname(pathname)
567 if dirname and not os.path.exists(dirname):
568 os.makedirs(dirname)
569 with open(pathname, 'wb') as fd:
570 fd.write(contents)
571 return pathname
572
573 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600574 def _MakeInputDir(cls, dirname):
Simon Glassc1ae83c2018-07-17 13:25:44 -0600575 """Create a new test input directory, creating directories as needed
576
577 Args:
578 dirname: Directory name to create
579
580 Returns:
581 Full pathname of directory created
582 """
Simon Glass862f8e22019-08-24 07:22:43 -0600583 pathname = os.path.join(cls._indir, dirname)
Simon Glassc1ae83c2018-07-17 13:25:44 -0600584 if not os.path.exists(pathname):
585 os.makedirs(pathname)
586 return pathname
587
588 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600589 def _SetupSplElf(cls, src_fname='bss_data'):
Simon Glass7057d022018-10-01 21:12:47 -0600590 """Set up an ELF file with a '_dt_ucode_base_size' symbol
591
592 Args:
593 Filename of ELF file to use as SPL
594 """
Simon Glass93a806f2019-08-24 07:22:59 -0600595 TestFunctional._MakeInputFile('spl/u-boot-spl',
Simon Glass80025522022-01-29 14:14:04 -0700596 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass7057d022018-10-01 21:12:47 -0600597
598 @classmethod
Simon Glass3eb5b202019-08-24 07:23:00 -0600599 def _SetupTplElf(cls, src_fname='bss_data'):
600 """Set up an ELF file with a '_dt_ucode_base_size' symbol
601
602 Args:
603 Filename of ELF file to use as TPL
604 """
605 TestFunctional._MakeInputFile('tpl/u-boot-tpl',
Simon Glass80025522022-01-29 14:14:04 -0700606 tools.read_file(cls.ElfTestFile(src_fname)))
Simon Glass3eb5b202019-08-24 07:23:00 -0600607
608 @classmethod
Simon Glasse88cef92020-07-09 18:39:41 -0600609 def _SetupDescriptor(cls):
610 with open(cls.TestFile('descriptor.bin'), 'rb') as fd:
611 TestFunctional._MakeInputFile('descriptor.bin', fd.read())
612
613 @classmethod
Simon Glass862f8e22019-08-24 07:22:43 -0600614 def TestFile(cls, fname):
615 return os.path.join(cls._binman_dir, 'test', fname)
Simon Glass57454f42016-11-25 20:15:52 -0700616
Simon Glassf6290892019-08-24 07:22:53 -0600617 @classmethod
618 def ElfTestFile(cls, fname):
619 return os.path.join(cls._elf_testdir, fname)
620
Simon Glass57454f42016-11-25 20:15:52 -0700621 def AssertInList(self, grep_list, target):
622 """Assert that at least one of a list of things is in a target
623
624 Args:
625 grep_list: List of strings to check
626 target: Target string
627 """
628 for grep in grep_list:
629 if grep in target:
630 return
Simon Glass848cdb52019-05-17 22:00:50 -0600631 self.fail("Error: '%s' not found in '%s'" % (grep_list, target))
Simon Glass57454f42016-11-25 20:15:52 -0700632
633 def CheckNoGaps(self, entries):
634 """Check that all entries fit together without gaps
635
636 Args:
637 entries: List of entries to check
638 """
Simon Glasse8561af2018-08-01 15:22:37 -0600639 offset = 0
Simon Glass57454f42016-11-25 20:15:52 -0700640 for entry in entries.values():
Simon Glasse8561af2018-08-01 15:22:37 -0600641 self.assertEqual(offset, entry.offset)
642 offset += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700643
Simon Glass72232452016-11-25 20:15:53 -0700644 def GetFdtLen(self, dtb):
Simon Glass1e324002018-06-01 09:38:19 -0600645 """Get the totalsize field from a device-tree binary
Simon Glass72232452016-11-25 20:15:53 -0700646
647 Args:
Simon Glass1e324002018-06-01 09:38:19 -0600648 dtb: Device-tree binary contents
Simon Glass72232452016-11-25 20:15:53 -0700649
650 Returns:
Simon Glass1e324002018-06-01 09:38:19 -0600651 Total size of device-tree binary, from the header
Simon Glass72232452016-11-25 20:15:53 -0700652 """
653 return struct.unpack('>L', dtb[4:8])[0]
654
Simon Glass0f621332019-07-08 14:25:27 -0600655 def _GetPropTree(self, dtb, prop_names, prefix='/binman/'):
Simon Glassa87014e2018-07-06 10:27:42 -0600656 def AddNode(node, path):
657 if node.name != '/':
658 path += '/' + node.name
Simon Glass0f621332019-07-08 14:25:27 -0600659 for prop in node.props.values():
660 if prop.name in prop_names:
661 prop_path = path + ':' + prop.name
662 tree[prop_path[len(prefix):]] = fdt_util.fdt32_to_cpu(
663 prop.value)
Simon Glassa87014e2018-07-06 10:27:42 -0600664 for subnode in node.subnodes:
Simon Glassa87014e2018-07-06 10:27:42 -0600665 AddNode(subnode, path)
666
667 tree = {}
Simon Glassa87014e2018-07-06 10:27:42 -0600668 AddNode(dtb.GetRoot(), '')
669 return tree
670
Simon Glass57454f42016-11-25 20:15:52 -0700671 def testRun(self):
672 """Test a basic run with valid args"""
673 result = self._RunBinman('-h')
674
675 def testFullHelp(self):
676 """Test that the full help is displayed with -H"""
677 result = self._RunBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300678 help_file = os.path.join(self._binman_dir, 'README.rst')
Tom Rinic3c0b6d2018-01-16 15:29:50 -0500679 # Remove possible extraneous strings
680 extra = '::::::::::::::\n' + help_file + '\n::::::::::::::\n'
681 gothelp = result.stdout.replace(extra, '')
682 self.assertEqual(len(gothelp), os.path.getsize(help_file))
Simon Glass57454f42016-11-25 20:15:52 -0700683 self.assertEqual(0, len(result.stderr))
684 self.assertEqual(0, result.return_code)
685
686 def testFullHelpInternal(self):
687 """Test that the full help is displayed with -H"""
688 try:
689 command.test_result = command.CommandResult()
690 result = self._DoBinman('-H')
Simon Glass75ead662021-03-18 20:25:13 +1300691 help_file = os.path.join(self._binman_dir, 'README.rst')
Simon Glass57454f42016-11-25 20:15:52 -0700692 finally:
693 command.test_result = None
694
695 def testHelp(self):
696 """Test that the basic help is displayed with -h"""
697 result = self._RunBinman('-h')
698 self.assertTrue(len(result.stdout) > 200)
699 self.assertEqual(0, len(result.stderr))
700 self.assertEqual(0, result.return_code)
701
Simon Glass57454f42016-11-25 20:15:52 -0700702 def testBoard(self):
703 """Test that we can run it with a specific board"""
Simon Glass511f6582018-10-01 12:22:30 -0600704 self._SetupDtb('005_simple.dts', 'sandbox/u-boot.dtb')
Simon Glass57454f42016-11-25 20:15:52 -0700705 TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA)
Simon Glassed930672021-03-18 20:25:05 +1300706 result = self._DoBinman('build', '-n', '-b', 'sandbox')
Simon Glass57454f42016-11-25 20:15:52 -0700707 self.assertEqual(0, result)
708
709 def testNeedBoard(self):
710 """Test that we get an error when no board ius supplied"""
711 with self.assertRaises(ValueError) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600712 result = self._DoBinman('build')
Simon Glass57454f42016-11-25 20:15:52 -0700713 self.assertIn("Must provide a board to process (use -b <board>)",
714 str(e.exception))
715
716 def testMissingDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600717 """Test that an invalid device-tree file generates an error"""
Simon Glass57454f42016-11-25 20:15:52 -0700718 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600719 self._RunBinman('build', '-d', 'missing_file')
Simon Glass57454f42016-11-25 20:15:52 -0700720 # We get one error from libfdt, and a different one from fdtget.
721 self.AssertInList(["Couldn't open blob from 'missing_file'",
722 'No such file or directory'], str(e.exception))
723
724 def testBrokenDt(self):
Simon Glass1e324002018-06-01 09:38:19 -0600725 """Test that an invalid device-tree source file generates an error
Simon Glass57454f42016-11-25 20:15:52 -0700726
727 Since this is a source file it should be compiled and the error
728 will come from the device-tree compiler (dtc).
729 """
730 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600731 self._RunBinman('build', '-d', self.TestFile('001_invalid.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700732 self.assertIn("FATAL ERROR: Unable to parse input tree",
733 str(e.exception))
734
735 def testMissingNode(self):
736 """Test that a device tree without a 'binman' node generates an error"""
737 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600738 self._DoBinman('build', '-d', self.TestFile('002_missing_node.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700739 self.assertIn("does not have a 'binman' node", str(e.exception))
740
741 def testEmpty(self):
742 """Test that an empty binman node works OK (i.e. does nothing)"""
Simon Glassf46732a2019-07-08 14:25:29 -0600743 result = self._RunBinman('build', '-d', self.TestFile('003_empty.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700744 self.assertEqual(0, len(result.stderr))
745 self.assertEqual(0, result.return_code)
746
747 def testInvalidEntry(self):
748 """Test that an invalid entry is flagged"""
749 with self.assertRaises(Exception) as e:
Simon Glassf46732a2019-07-08 14:25:29 -0600750 result = self._RunBinman('build', '-d',
Simon Glass511f6582018-10-01 12:22:30 -0600751 self.TestFile('004_invalid_entry.dts'))
Simon Glass57454f42016-11-25 20:15:52 -0700752 self.assertIn("Unknown entry type 'not-a-valid-type' in node "
753 "'/binman/not-a-valid-type'", str(e.exception))
754
755 def testSimple(self):
756 """Test a simple binman with a single file"""
Simon Glass511f6582018-10-01 12:22:30 -0600757 data = self._DoReadFile('005_simple.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700758 self.assertEqual(U_BOOT_DATA, data)
759
Simon Glass075a45c2017-11-13 18:55:00 -0700760 def testSimpleDebug(self):
761 """Test a simple binman run with debugging enabled"""
Simon Glass52d06212019-07-08 14:25:53 -0600762 self._DoTestFile('005_simple.dts', debug=True)
Simon Glass075a45c2017-11-13 18:55:00 -0700763
Simon Glass57454f42016-11-25 20:15:52 -0700764 def testDual(self):
765 """Test that we can handle creating two images
766
767 This also tests image padding.
768 """
Simon Glass511f6582018-10-01 12:22:30 -0600769 retcode = self._DoTestFile('006_dual_image.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700770 self.assertEqual(0, retcode)
771
772 image = control.images['image1']
Simon Glass39dd2152019-07-08 14:25:47 -0600773 self.assertEqual(len(U_BOOT_DATA), image.size)
Simon Glass80025522022-01-29 14:14:04 -0700774 fname = tools.get_output_filename('image1.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700775 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600776 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700777 data = fd.read()
778 self.assertEqual(U_BOOT_DATA, data)
779
780 image = control.images['image2']
Simon Glass39dd2152019-07-08 14:25:47 -0600781 self.assertEqual(3 + len(U_BOOT_DATA) + 5, image.size)
Simon Glass80025522022-01-29 14:14:04 -0700782 fname = tools.get_output_filename('image2.bin')
Simon Glass57454f42016-11-25 20:15:52 -0700783 self.assertTrue(os.path.exists(fname))
Simon Glass33486662019-05-14 15:53:42 -0600784 with open(fname, 'rb') as fd:
Simon Glass57454f42016-11-25 20:15:52 -0700785 data = fd.read()
786 self.assertEqual(U_BOOT_DATA, data[3:7])
Simon Glass80025522022-01-29 14:14:04 -0700787 self.assertEqual(tools.get_bytes(0, 3), data[:3])
788 self.assertEqual(tools.get_bytes(0, 5), data[7:])
Simon Glass57454f42016-11-25 20:15:52 -0700789
790 def testBadAlign(self):
791 """Test that an invalid alignment value is detected"""
792 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600793 self._DoTestFile('007_bad_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700794 self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power "
795 "of two", str(e.exception))
796
797 def testPackSimple(self):
798 """Test that packing works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600799 retcode = self._DoTestFile('008_pack.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700800 self.assertEqual(0, retcode)
801 self.assertIn('image', control.images)
802 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600803 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700804 self.assertEqual(5, len(entries))
805
806 # First u-boot
807 self.assertIn('u-boot', entries)
808 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600809 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700810 self.assertEqual(len(U_BOOT_DATA), entry.size)
811
812 # Second u-boot, aligned to 16-byte boundary
813 self.assertIn('u-boot-align', entries)
814 entry = entries['u-boot-align']
Simon Glasse8561af2018-08-01 15:22:37 -0600815 self.assertEqual(16, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700816 self.assertEqual(len(U_BOOT_DATA), entry.size)
817
818 # Third u-boot, size 23 bytes
819 self.assertIn('u-boot-size', entries)
820 entry = entries['u-boot-size']
Simon Glasse8561af2018-08-01 15:22:37 -0600821 self.assertEqual(20, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700822 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
823 self.assertEqual(23, entry.size)
824
825 # Fourth u-boot, placed immediate after the above
826 self.assertIn('u-boot-next', entries)
827 entry = entries['u-boot-next']
Simon Glasse8561af2018-08-01 15:22:37 -0600828 self.assertEqual(43, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700829 self.assertEqual(len(U_BOOT_DATA), entry.size)
830
Simon Glasse8561af2018-08-01 15:22:37 -0600831 # Fifth u-boot, placed at a fixed offset
Simon Glass57454f42016-11-25 20:15:52 -0700832 self.assertIn('u-boot-fixed', entries)
833 entry = entries['u-boot-fixed']
Simon Glasse8561af2018-08-01 15:22:37 -0600834 self.assertEqual(61, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700835 self.assertEqual(len(U_BOOT_DATA), entry.size)
836
Simon Glass39dd2152019-07-08 14:25:47 -0600837 self.assertEqual(65, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700838
839 def testPackExtra(self):
840 """Test that extra packing feature works as expected"""
Simon Glassafb9caa2020-10-26 17:40:10 -0600841 data, _, _, out_dtb_fname = self._DoReadFileDtb('009_pack_extra.dts',
842 update_dtb=True)
Simon Glass57454f42016-11-25 20:15:52 -0700843
Simon Glass57454f42016-11-25 20:15:52 -0700844 self.assertIn('image', control.images)
845 image = control.images['image']
Simon Glasseca32212018-06-01 09:38:12 -0600846 entries = image.GetEntries()
Simon Glass57454f42016-11-25 20:15:52 -0700847 self.assertEqual(5, len(entries))
848
849 # First u-boot with padding before and after
850 self.assertIn('u-boot', entries)
851 entry = entries['u-boot']
Simon Glasse8561af2018-08-01 15:22:37 -0600852 self.assertEqual(0, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700853 self.assertEqual(3, entry.pad_before)
854 self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600855 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700856 self.assertEqual(tools.get_bytes(0, 3) + U_BOOT_DATA +
857 tools.get_bytes(0, 5), data[:entry.size])
Simon Glass187202f2020-10-26 17:40:08 -0600858 pos = entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700859
860 # Second u-boot has an aligned size, but it has no effect
861 self.assertIn('u-boot-align-size-nop', entries)
862 entry = entries['u-boot-align-size-nop']
Simon Glass187202f2020-10-26 17:40:08 -0600863 self.assertEqual(pos, entry.offset)
864 self.assertEqual(len(U_BOOT_DATA), entry.size)
865 self.assertEqual(U_BOOT_DATA, entry.data)
866 self.assertEqual(U_BOOT_DATA, data[pos:pos + entry.size])
867 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700868
869 # Third u-boot has an aligned size too
870 self.assertIn('u-boot-align-size', entries)
871 entry = entries['u-boot-align-size']
Simon Glass187202f2020-10-26 17:40:08 -0600872 self.assertEqual(pos, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700873 self.assertEqual(32, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600874 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glass80025522022-01-29 14:14:04 -0700875 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 32 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600876 data[pos:pos + entry.size])
877 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700878
879 # Fourth u-boot has an aligned end
880 self.assertIn('u-boot-align-end', entries)
881 entry = entries['u-boot-align-end']
Simon Glasse8561af2018-08-01 15:22:37 -0600882 self.assertEqual(48, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700883 self.assertEqual(16, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600884 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700885 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 16 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600886 data[pos:pos + entry.size])
887 pos += entry.size
Simon Glass57454f42016-11-25 20:15:52 -0700888
889 # Fifth u-boot immediately afterwards
890 self.assertIn('u-boot-align-both', entries)
891 entry = entries['u-boot-align-both']
Simon Glasse8561af2018-08-01 15:22:37 -0600892 self.assertEqual(64, entry.offset)
Simon Glass57454f42016-11-25 20:15:52 -0700893 self.assertEqual(64, entry.size)
Simon Glass187202f2020-10-26 17:40:08 -0600894 self.assertEqual(U_BOOT_DATA, entry.data[:len(U_BOOT_DATA)])
Simon Glass80025522022-01-29 14:14:04 -0700895 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 64 - len(U_BOOT_DATA)),
Simon Glass187202f2020-10-26 17:40:08 -0600896 data[pos:pos + entry.size])
Simon Glass57454f42016-11-25 20:15:52 -0700897
898 self.CheckNoGaps(entries)
Simon Glass39dd2152019-07-08 14:25:47 -0600899 self.assertEqual(128, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700900
Simon Glassafb9caa2020-10-26 17:40:10 -0600901 dtb = fdt.Fdt(out_dtb_fname)
902 dtb.Scan()
903 props = self._GetPropTree(dtb, ['size', 'offset', 'image-pos'])
904 expected = {
905 'image-pos': 0,
906 'offset': 0,
907 'size': 128,
908
909 'u-boot:image-pos': 0,
910 'u-boot:offset': 0,
911 'u-boot:size': 3 + 5 + len(U_BOOT_DATA),
912
913 'u-boot-align-size-nop:image-pos': 12,
914 'u-boot-align-size-nop:offset': 12,
915 'u-boot-align-size-nop:size': 4,
916
917 'u-boot-align-size:image-pos': 16,
918 'u-boot-align-size:offset': 16,
919 'u-boot-align-size:size': 32,
920
921 'u-boot-align-end:image-pos': 48,
922 'u-boot-align-end:offset': 48,
923 'u-boot-align-end:size': 16,
924
925 'u-boot-align-both:image-pos': 64,
926 'u-boot-align-both:offset': 64,
927 'u-boot-align-both:size': 64,
928 }
929 self.assertEqual(expected, props)
930
Simon Glass57454f42016-11-25 20:15:52 -0700931 def testPackAlignPowerOf2(self):
932 """Test that invalid entry alignment is detected"""
933 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600934 self._DoTestFile('010_pack_align_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700935 self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power "
936 "of two", str(e.exception))
937
938 def testPackAlignSizePowerOf2(self):
939 """Test that invalid entry size alignment is detected"""
940 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600941 self._DoTestFile('011_pack_align_size_power2.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700942 self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a "
943 "power of two", str(e.exception))
944
945 def testPackInvalidAlign(self):
Simon Glasse8561af2018-08-01 15:22:37 -0600946 """Test detection of an offset that does not match its alignment"""
Simon Glass57454f42016-11-25 20:15:52 -0700947 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600948 self._DoTestFile('012_pack_inv_align.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600949 self.assertIn("Node '/binman/u-boot': Offset 0x5 (5) does not match "
Simon Glass57454f42016-11-25 20:15:52 -0700950 "align 0x4 (4)", str(e.exception))
951
952 def testPackInvalidSizeAlign(self):
953 """Test that invalid entry size alignment is detected"""
954 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600955 self._DoTestFile('013_pack_inv_size_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700956 self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match "
957 "align-size 0x4 (4)", str(e.exception))
958
959 def testPackOverlap(self):
960 """Test that overlapping regions are detected"""
961 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600962 self._DoTestFile('014_pack_overlap.dts')
Simon Glasse8561af2018-08-01 15:22:37 -0600963 self.assertIn("Node '/binman/u-boot-align': Offset 0x3 (3) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -0700964 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
965 str(e.exception))
966
967 def testPackEntryOverflow(self):
968 """Test that entries that overflow their size are detected"""
969 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600970 self._DoTestFile('015_pack_overflow.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700971 self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) "
972 "but entry size is 0x3 (3)", str(e.exception))
973
974 def testPackImageOverflow(self):
975 """Test that entries which overflow the image size are detected"""
976 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -0600977 self._DoTestFile('016_pack_image_overflow.dts')
Simon Glasseca32212018-06-01 09:38:12 -0600978 self.assertIn("Section '/binman': contents size 0x4 (4) exceeds section "
Simon Glass57454f42016-11-25 20:15:52 -0700979 "size 0x3 (3)", str(e.exception))
980
981 def testPackImageSize(self):
982 """Test that the image size can be set"""
Simon Glass511f6582018-10-01 12:22:30 -0600983 retcode = self._DoTestFile('017_pack_image_size.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700984 self.assertEqual(0, retcode)
985 self.assertIn('image', control.images)
986 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600987 self.assertEqual(7, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700988
989 def testPackImageSizeAlign(self):
990 """Test that image size alignemnt works as expected"""
Simon Glass511f6582018-10-01 12:22:30 -0600991 retcode = self._DoTestFile('018_pack_image_align.dts')
Simon Glass57454f42016-11-25 20:15:52 -0700992 self.assertEqual(0, retcode)
993 self.assertIn('image', control.images)
994 image = control.images['image']
Simon Glass39dd2152019-07-08 14:25:47 -0600995 self.assertEqual(16, image.size)
Simon Glass57454f42016-11-25 20:15:52 -0700996
997 def testPackInvalidImageAlign(self):
998 """Test that invalid image alignment is detected"""
999 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001000 self._DoTestFile('019_pack_inv_image_align.dts')
Simon Glasseca32212018-06-01 09:38:12 -06001001 self.assertIn("Section '/binman': Size 0x7 (7) does not match "
Simon Glass57454f42016-11-25 20:15:52 -07001002 "align-size 0x8 (8)", str(e.exception))
1003
Simon Glass2a0fa982022-02-11 13:23:21 -07001004 def testPackAlignPowerOf2Inv(self):
Simon Glass57454f42016-11-25 20:15:52 -07001005 """Test that invalid image alignment is detected"""
1006 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001007 self._DoTestFile('020_pack_inv_image_align_power2.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001008 self.assertIn("Image '/binman': Alignment size 131 must be a power of "
Simon Glass57454f42016-11-25 20:15:52 -07001009 "two", str(e.exception))
1010
1011 def testImagePadByte(self):
1012 """Test that the image pad byte can be specified"""
Simon Glass7057d022018-10-01 21:12:47 -06001013 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001014 data = self._DoReadFile('021_image_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001015 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0xff, 1) +
Simon Glassac0d4952019-05-14 15:53:47 -06001016 U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001017
1018 def testImageName(self):
1019 """Test that image files can be named"""
Simon Glass511f6582018-10-01 12:22:30 -06001020 retcode = self._DoTestFile('022_image_name.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001021 self.assertEqual(0, retcode)
1022 image = control.images['image1']
Simon Glass80025522022-01-29 14:14:04 -07001023 fname = tools.get_output_filename('test-name')
Simon Glass57454f42016-11-25 20:15:52 -07001024 self.assertTrue(os.path.exists(fname))
1025
1026 image = control.images['image2']
Simon Glass80025522022-01-29 14:14:04 -07001027 fname = tools.get_output_filename('test-name.xx')
Simon Glass57454f42016-11-25 20:15:52 -07001028 self.assertTrue(os.path.exists(fname))
1029
1030 def testBlobFilename(self):
1031 """Test that generic blobs can be provided by filename"""
Simon Glass511f6582018-10-01 12:22:30 -06001032 data = self._DoReadFile('023_blob.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001033 self.assertEqual(BLOB_DATA, data)
1034
1035 def testPackSorted(self):
1036 """Test that entries can be sorted"""
Simon Glass7057d022018-10-01 21:12:47 -06001037 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001038 data = self._DoReadFile('024_sorted.dts')
Simon Glass80025522022-01-29 14:14:04 -07001039 self.assertEqual(tools.get_bytes(0, 1) + U_BOOT_SPL_DATA +
1040 tools.get_bytes(0, 2) + U_BOOT_DATA, data)
Simon Glass57454f42016-11-25 20:15:52 -07001041
Simon Glasse8561af2018-08-01 15:22:37 -06001042 def testPackZeroOffset(self):
1043 """Test that an entry at offset 0 is not given a new offset"""
Simon Glass57454f42016-11-25 20:15:52 -07001044 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001045 self._DoTestFile('025_pack_zero_size.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001046 self.assertIn("Node '/binman/u-boot-spl': Offset 0x0 (0) overlaps "
Simon Glass57454f42016-11-25 20:15:52 -07001047 "with previous entry '/binman/u-boot' ending at 0x4 (4)",
1048 str(e.exception))
1049
1050 def testPackUbootDtb(self):
1051 """Test that a device tree can be added to U-Boot"""
Simon Glass511f6582018-10-01 12:22:30 -06001052 data = self._DoReadFile('026_pack_u_boot_dtb.dts')
Simon Glass57454f42016-11-25 20:15:52 -07001053 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data)
Simon Glass72232452016-11-25 20:15:53 -07001054
1055 def testPackX86RomNoSize(self):
1056 """Test that the end-at-4gb property requires a size property"""
1057 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001058 self._DoTestFile('027_pack_4gb_no_size.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001059 self.assertIn("Image '/binman': Section size must be provided when "
Simon Glass72232452016-11-25 20:15:53 -07001060 "using end-at-4gb", str(e.exception))
1061
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301062 def test4gbAndSkipAtStartTogether(self):
1063 """Test that the end-at-4gb and skip-at-size property can't be used
1064 together"""
1065 with self.assertRaises(ValueError) as e:
Simon Glass11f2bd02019-08-24 07:23:02 -06001066 self._DoTestFile('098_4gb_and_skip_at_start_together.dts')
Simon Glass39dd2152019-07-08 14:25:47 -06001067 self.assertIn("Image '/binman': Provide either 'end-at-4gb' or "
Jagdish Gediya0fb978c2018-09-03 21:35:07 +05301068 "'skip-at-start'", str(e.exception))
1069
Simon Glass72232452016-11-25 20:15:53 -07001070 def testPackX86RomOutside(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001071 """Test that the end-at-4gb property checks for offset boundaries"""
Simon Glass72232452016-11-25 20:15:53 -07001072 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001073 self._DoTestFile('028_pack_4gb_outside.dts')
Simon Glassd6179862020-10-26 17:40:05 -06001074 self.assertIn("Node '/binman/u-boot': Offset 0x0 (0) size 0x4 (4) "
1075 "is outside the section '/binman' starting at "
1076 '0xffffffe0 (4294967264) of size 0x20 (32)',
Simon Glass72232452016-11-25 20:15:53 -07001077 str(e.exception))
1078
1079 def testPackX86Rom(self):
1080 """Test that a basic x86 ROM can be created"""
Simon Glass7057d022018-10-01 21:12:47 -06001081 self._SetupSplElf()
Simon Glass1d167762019-08-24 07:23:01 -06001082 data = self._DoReadFile('029_x86_rom.dts')
Simon Glass80025522022-01-29 14:14:04 -07001083 self.assertEqual(U_BOOT_DATA + tools.get_bytes(0, 3) + U_BOOT_SPL_DATA +
1084 tools.get_bytes(0, 2), data)
Simon Glass72232452016-11-25 20:15:53 -07001085
1086 def testPackX86RomMeNoDesc(self):
1087 """Test that an invalid Intel descriptor entry is detected"""
Simon Glasse88cef92020-07-09 18:39:41 -06001088 try:
Simon Glass14c596c2020-07-25 15:11:19 -06001089 TestFunctional._MakeInputFile('descriptor-empty.bin', b'')
Simon Glasse88cef92020-07-09 18:39:41 -06001090 with self.assertRaises(ValueError) as e:
Simon Glass14c596c2020-07-25 15:11:19 -06001091 self._DoTestFile('163_x86_rom_me_empty.dts')
Simon Glasse88cef92020-07-09 18:39:41 -06001092 self.assertIn("Node '/binman/intel-descriptor': Cannot find Intel Flash Descriptor (FD) signature",
1093 str(e.exception))
1094 finally:
1095 self._SetupDescriptor()
Simon Glass72232452016-11-25 20:15:53 -07001096
1097 def testPackX86RomBadDesc(self):
1098 """Test that the Intel requires a descriptor entry"""
1099 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06001100 self._DoTestFile('030_x86_rom_me_no_desc.dts')
Simon Glasse8561af2018-08-01 15:22:37 -06001101 self.assertIn("Node '/binman/intel-me': No offset set with "
1102 "offset-unset: should another entry provide this correct "
1103 "offset?", str(e.exception))
Simon Glass72232452016-11-25 20:15:53 -07001104
1105 def testPackX86RomMe(self):
1106 """Test that an x86 ROM with an ME region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001107 data = self._DoReadFile('031_x86_rom_me.dts')
Simon Glass80025522022-01-29 14:14:04 -07001108 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06001109 if data[:0x1000] != expected_desc:
1110 self.fail('Expected descriptor binary at start of image')
Simon Glass72232452016-11-25 20:15:53 -07001111 self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)])
1112
1113 def testPackVga(self):
1114 """Test that an image with a VGA binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001115 data = self._DoReadFile('032_intel_vga.dts')
Simon Glass72232452016-11-25 20:15:53 -07001116 self.assertEqual(VGA_DATA, data[:len(VGA_DATA)])
1117
1118 def testPackStart16(self):
1119 """Test that an image with an x86 start16 region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001120 data = self._DoReadFile('033_x86_start16.dts')
Simon Glass72232452016-11-25 20:15:53 -07001121 self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)])
1122
Jagdish Gediya311d4842018-09-03 21:35:08 +05301123 def testPackPowerpcMpc85xxBootpgResetvec(self):
1124 """Test that an image with powerpc-mpc85xx-bootpg-resetvec can be
1125 created"""
Simon Glass11f2bd02019-08-24 07:23:02 -06001126 data = self._DoReadFile('150_powerpc_mpc85xx_bootpg_resetvec.dts')
Jagdish Gediya311d4842018-09-03 21:35:08 +05301127 self.assertEqual(PPC_MPC85XX_BR_DATA, data[:len(PPC_MPC85XX_BR_DATA)])
1128
Simon Glass6ba679c2018-07-06 10:27:17 -06001129 def _RunMicrocodeTest(self, dts_fname, nodtb_data, ucode_second=False):
Simon Glass820af1d2018-07-06 10:27:16 -06001130 """Handle running a test for insertion of microcode
1131
1132 Args:
1133 dts_fname: Name of test .dts file
1134 nodtb_data: Data that we expect in the first section
Simon Glass6ba679c2018-07-06 10:27:17 -06001135 ucode_second: True if the microsecond entry is second instead of
1136 third
Simon Glass820af1d2018-07-06 10:27:16 -06001137
1138 Returns:
1139 Tuple:
1140 Contents of first region (U-Boot or SPL)
Simon Glasse8561af2018-08-01 15:22:37 -06001141 Offset and size components of microcode pointer, as inserted
Simon Glass820af1d2018-07-06 10:27:16 -06001142 in the above (two 4-byte words)
1143 """
Simon Glass3d274232017-11-12 21:52:27 -07001144 data = self._DoReadFile(dts_fname, True)
Simon Glass72232452016-11-25 20:15:53 -07001145
1146 # Now check the device tree has no microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001147 if ucode_second:
1148 ucode_content = data[len(nodtb_data):]
1149 ucode_pos = len(nodtb_data)
1150 dtb_with_ucode = ucode_content[16:]
1151 fdt_len = self.GetFdtLen(dtb_with_ucode)
1152 else:
1153 dtb_with_ucode = data[len(nodtb_data):]
1154 fdt_len = self.GetFdtLen(dtb_with_ucode)
1155 ucode_content = dtb_with_ucode[fdt_len:]
1156 ucode_pos = len(nodtb_data) + fdt_len
Simon Glass80025522022-01-29 14:14:04 -07001157 fname = tools.get_output_filename('test.dtb')
Simon Glass72232452016-11-25 20:15:53 -07001158 with open(fname, 'wb') as fd:
Simon Glass820af1d2018-07-06 10:27:16 -06001159 fd.write(dtb_with_ucode)
Simon Glass22c92ca2017-05-27 07:38:29 -06001160 dtb = fdt.FdtScan(fname)
1161 ucode = dtb.GetNode('/microcode')
Simon Glass72232452016-11-25 20:15:53 -07001162 self.assertTrue(ucode)
1163 for node in ucode.subnodes:
1164 self.assertFalse(node.props.get('data'))
1165
Simon Glass72232452016-11-25 20:15:53 -07001166 # Check that the microcode appears immediately after the Fdt
1167 # This matches the concatenation of the data properties in
Simon Glasse83679d2017-11-12 21:52:26 -07001168 # the /microcode/update@xxx nodes in 34_x86_ucode.dts.
Simon Glass72232452016-11-25 20:15:53 -07001169 ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000,
1170 0x78235609)
Simon Glass820af1d2018-07-06 10:27:16 -06001171 self.assertEqual(ucode_data, ucode_content[:len(ucode_data)])
Simon Glass72232452016-11-25 20:15:53 -07001172
1173 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001174 # expected offset and size
Simon Glass72232452016-11-25 20:15:53 -07001175 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1176 len(ucode_data))
Simon Glass6ba679c2018-07-06 10:27:17 -06001177 u_boot = data[:len(nodtb_data)]
1178 return u_boot, pos_and_size
Simon Glass3d274232017-11-12 21:52:27 -07001179
1180 def testPackUbootMicrocode(self):
1181 """Test that x86 microcode can be handled correctly
1182
1183 We expect to see the following in the image, in order:
1184 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1185 place
1186 u-boot.dtb with the microcode removed
1187 the microcode
1188 """
Simon Glass511f6582018-10-01 12:22:30 -06001189 first, pos_and_size = self._RunMicrocodeTest('034_x86_ucode.dts',
Simon Glass3d274232017-11-12 21:52:27 -07001190 U_BOOT_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06001191 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1192 b' somewhere in here', first)
Simon Glass72232452016-11-25 20:15:53 -07001193
Simon Glassbac25c82017-05-27 07:38:26 -06001194 def _RunPackUbootSingleMicrocode(self):
Simon Glass72232452016-11-25 20:15:53 -07001195 """Test that x86 microcode can be handled correctly
1196
1197 We expect to see the following in the image, in order:
1198 u-boot-nodtb.bin with a microcode pointer inserted at the correct
1199 place
1200 u-boot.dtb with the microcode
1201 an empty microcode region
1202 """
1203 # We need the libfdt library to run this test since only that allows
1204 # finding the offset of a property. This is required by
1205 # Entry_u_boot_dtb_with_ucode.ObtainContents().
Simon Glass511f6582018-10-01 12:22:30 -06001206 data = self._DoReadFile('035_x86_single_ucode.dts', True)
Simon Glass72232452016-11-25 20:15:53 -07001207
1208 second = data[len(U_BOOT_NODTB_DATA):]
1209
1210 fdt_len = self.GetFdtLen(second)
1211 third = second[fdt_len:]
1212 second = second[:fdt_len]
1213
Simon Glassbac25c82017-05-27 07:38:26 -06001214 ucode_data = struct.pack('>2L', 0x12345678, 0x12345679)
1215 self.assertIn(ucode_data, second)
1216 ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA)
Simon Glass72232452016-11-25 20:15:53 -07001217
Simon Glassbac25c82017-05-27 07:38:26 -06001218 # Check that the microcode pointer was inserted. It should match the
Simon Glasse8561af2018-08-01 15:22:37 -06001219 # expected offset and size
Simon Glassbac25c82017-05-27 07:38:26 -06001220 pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos,
1221 len(ucode_data))
1222 first = data[:len(U_BOOT_NODTB_DATA)]
Simon Glass303f62f2019-05-17 22:00:46 -06001223 self.assertEqual(b'nodtb with microcode' + pos_and_size +
1224 b' somewhere in here', first)
Simon Glass996021e2016-11-25 20:15:54 -07001225
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001226 def testPackUbootSingleMicrocode(self):
1227 """Test that x86 microcode can be handled correctly with fdt_normal.
1228 """
Simon Glassbac25c82017-05-27 07:38:26 -06001229 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001230
Simon Glass996021e2016-11-25 20:15:54 -07001231 def testUBootImg(self):
1232 """Test that u-boot.img can be put in a file"""
Simon Glass511f6582018-10-01 12:22:30 -06001233 data = self._DoReadFile('036_u_boot_img.dts')
Simon Glass996021e2016-11-25 20:15:54 -07001234 self.assertEqual(U_BOOT_IMG_DATA, data)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001235
1236 def testNoMicrocode(self):
1237 """Test that a missing microcode region is detected"""
1238 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001239 self._DoReadFile('037_x86_no_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001240 self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode "
1241 "node found in ", str(e.exception))
1242
1243 def testMicrocodeWithoutNode(self):
1244 """Test that a missing u-boot-dtb-with-ucode node is detected"""
1245 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001246 self._DoReadFile('038_x86_ucode_missing_node.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001247 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1248 "microcode region u-boot-dtb-with-ucode", str(e.exception))
1249
1250 def testMicrocodeWithoutNode2(self):
1251 """Test that a missing u-boot-ucode node is detected"""
1252 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001253 self._DoReadFile('039_x86_ucode_missing_node2.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001254 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find "
1255 "microcode region u-boot-ucode", str(e.exception))
1256
1257 def testMicrocodeWithoutPtrInElf(self):
1258 """Test that a U-Boot binary without the microcode symbol is detected"""
1259 # ELF file without a '_dt_ucode_base_size' symbol
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001260 try:
Simon Glassfaaaa162019-08-24 07:22:55 -06001261 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001262 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001263
1264 with self.assertRaises(ValueError) as e:
Simon Glassbac25c82017-05-27 07:38:26 -06001265 self._RunPackUbootSingleMicrocode()
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001266 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate "
1267 "_dt_ucode_base_size symbol in u-boot", str(e.exception))
1268
1269 finally:
1270 # Put the original file back
Simon Glass4affd4b2019-08-24 07:22:54 -06001271 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001272 tools.read_file(self.ElfTestFile('u_boot_ucode_ptr')))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001273
1274 def testMicrocodeNotInImage(self):
1275 """Test that microcode must be placed within the image"""
1276 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001277 self._DoReadFile('040_x86_ucode_not_in_image.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001278 self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode "
1279 "pointer _dt_ucode_base_size at fffffe14 is outside the "
Simon Glassad5a7712018-06-01 09:38:14 -06001280 "section ranging from 00000000 to 0000002e", str(e.exception))
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001281
1282 def testWithoutMicrocode(self):
1283 """Test that we can cope with an image without microcode (e.g. qemu)"""
Simon Glassfaaaa162019-08-24 07:22:55 -06001284 TestFunctional._MakeInputFile('u-boot',
Simon Glass80025522022-01-29 14:14:04 -07001285 tools.read_file(self.ElfTestFile('u_boot_no_ucode_ptr')))
Simon Glass511f6582018-10-01 12:22:30 -06001286 data, dtb, _, _ = self._DoReadFileDtb('044_x86_optional_ucode.dts', True)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001287
1288 # Now check the device tree has no microcode
1289 self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)])
1290 second = data[len(U_BOOT_NODTB_DATA):]
1291
1292 fdt_len = self.GetFdtLen(second)
1293 self.assertEqual(dtb, second[:fdt_len])
1294
1295 used_len = len(U_BOOT_NODTB_DATA) + fdt_len
1296 third = data[used_len:]
Simon Glass80025522022-01-29 14:14:04 -07001297 self.assertEqual(tools.get_bytes(0, 0x200 - used_len), third)
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001298
1299 def testUnknownPosSize(self):
1300 """Test that microcode must be placed within the image"""
1301 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001302 self._DoReadFile('041_unknown_pos_size.dts', True)
Simon Glasse8561af2018-08-01 15:22:37 -06001303 self.assertIn("Section '/binman': Unable to set offset/size for unknown "
Simon Glassd2dfb5f2016-11-25 20:15:55 -07001304 "entry 'invalid-entry'", str(e.exception))
Simon Glassb4176d42016-11-25 20:15:56 -07001305
1306 def testPackFsp(self):
1307 """Test that an image with a FSP binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001308 data = self._DoReadFile('042_intel_fsp.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001309 self.assertEqual(FSP_DATA, data[:len(FSP_DATA)])
1310
1311 def testPackCmc(self):
Bin Mengd7bcdf52017-08-15 22:41:54 -07001312 """Test that an image with a CMC binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001313 data = self._DoReadFile('043_intel_cmc.dts')
Simon Glassb4176d42016-11-25 20:15:56 -07001314 self.assertEqual(CMC_DATA, data[:len(CMC_DATA)])
Bin Mengd7bcdf52017-08-15 22:41:54 -07001315
1316 def testPackVbt(self):
1317 """Test that an image with a VBT binary can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001318 data = self._DoReadFile('046_intel_vbt.dts')
Bin Mengd7bcdf52017-08-15 22:41:54 -07001319 self.assertEqual(VBT_DATA, data[:len(VBT_DATA)])
Simon Glassac599912017-11-12 21:52:22 -07001320
Simon Glass7f94e832017-11-12 21:52:25 -07001321 def testSplBssPad(self):
1322 """Test that we can pad SPL's BSS with zeros"""
Simon Glass3d274232017-11-12 21:52:27 -07001323 # ELF file with a '__bss_size' symbol
Simon Glass7057d022018-10-01 21:12:47 -06001324 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001325 data = self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07001326 self.assertEqual(U_BOOT_SPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glassac0d4952019-05-14 15:53:47 -06001327 data)
Simon Glass7f94e832017-11-12 21:52:25 -07001328
Simon Glass04cda032018-10-01 21:12:42 -06001329 def testSplBssPadMissing(self):
1330 """Test that a missing symbol is detected"""
Simon Glass7057d022018-10-01 21:12:47 -06001331 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass24ad3652017-11-13 18:54:54 -07001332 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001333 self._DoReadFile('047_spl_bss_pad.dts')
Simon Glass24ad3652017-11-13 18:54:54 -07001334 self.assertIn('Expected __bss_size symbol in spl/u-boot-spl',
1335 str(e.exception))
1336
Simon Glasse83679d2017-11-12 21:52:26 -07001337 def testPackStart16Spl(self):
Simon Glassed40e962018-09-14 04:57:10 -06001338 """Test that an image with an x86 start16 SPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001339 data = self._DoReadFile('048_x86_start16_spl.dts')
Simon Glasse83679d2017-11-12 21:52:26 -07001340 self.assertEqual(X86_START16_SPL_DATA, data[:len(X86_START16_SPL_DATA)])
1341
Simon Glass6ba679c2018-07-06 10:27:17 -06001342 def _PackUbootSplMicrocode(self, dts, ucode_second=False):
1343 """Helper function for microcode tests
Simon Glass3d274232017-11-12 21:52:27 -07001344
1345 We expect to see the following in the image, in order:
1346 u-boot-spl-nodtb.bin with a microcode pointer inserted at the
1347 correct place
1348 u-boot.dtb with the microcode removed
1349 the microcode
Simon Glass6ba679c2018-07-06 10:27:17 -06001350
1351 Args:
1352 dts: Device tree file to use for test
1353 ucode_second: True if the microsecond entry is second instead of
1354 third
Simon Glass3d274232017-11-12 21:52:27 -07001355 """
Simon Glass7057d022018-10-01 21:12:47 -06001356 self._SetupSplElf('u_boot_ucode_ptr')
Simon Glass6ba679c2018-07-06 10:27:17 -06001357 first, pos_and_size = self._RunMicrocodeTest(dts, U_BOOT_SPL_NODTB_DATA,
1358 ucode_second=ucode_second)
Simon Glass303f62f2019-05-17 22:00:46 -06001359 self.assertEqual(b'splnodtb with microc' + pos_and_size +
1360 b'ter somewhere in here', first)
Simon Glass3d274232017-11-12 21:52:27 -07001361
Simon Glass6ba679c2018-07-06 10:27:17 -06001362 def testPackUbootSplMicrocode(self):
1363 """Test that x86 microcode can be handled correctly in SPL"""
Simon Glass511f6582018-10-01 12:22:30 -06001364 self._PackUbootSplMicrocode('049_x86_ucode_spl.dts')
Simon Glass6ba679c2018-07-06 10:27:17 -06001365
1366 def testPackUbootSplMicrocodeReorder(self):
1367 """Test that order doesn't matter for microcode entries
1368
1369 This is the same as testPackUbootSplMicrocode but when we process the
1370 u-boot-ucode entry we have not yet seen the u-boot-dtb-with-ucode
1371 entry, so we reply on binman to try later.
1372 """
Simon Glass511f6582018-10-01 12:22:30 -06001373 self._PackUbootSplMicrocode('058_x86_ucode_spl_needs_retry.dts',
Simon Glass6ba679c2018-07-06 10:27:17 -06001374 ucode_second=True)
1375
Simon Glassa409c932017-11-12 21:52:28 -07001376 def testPackMrc(self):
1377 """Test that an image with an MRC binary can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001378 data = self._DoReadFile('050_intel_mrc.dts')
Simon Glassa409c932017-11-12 21:52:28 -07001379 self.assertEqual(MRC_DATA, data[:len(MRC_DATA)])
1380
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001381 def testSplDtb(self):
1382 """Test that an image with spl/u-boot-spl.dtb can be created"""
Simon Glass511f6582018-10-01 12:22:30 -06001383 data = self._DoReadFile('051_u_boot_spl_dtb.dts')
Simon Glass9aa6a6f2017-11-13 18:54:55 -07001384 self.assertEqual(U_BOOT_SPL_DTB_DATA, data[:len(U_BOOT_SPL_DTB_DATA)])
1385
Simon Glass0a6da312017-11-13 18:54:56 -07001386 def testSplNoDtb(self):
1387 """Test that an image with spl/u-boot-spl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12001388 self._SetupSplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001389 data = self._DoReadFile('052_u_boot_spl_nodtb.dts')
Simon Glass0a6da312017-11-13 18:54:56 -07001390 self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)])
1391
Simon Glass7098b7f2021-03-21 18:24:30 +13001392 def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None,
1393 use_expanded=False):
Simon Glass31e04cb2021-03-18 20:24:56 +13001394 """Check the image contains the expected symbol values
1395
1396 Args:
1397 dts: Device tree file to use for test
1398 base_data: Data before and after 'u-boot' section
1399 u_boot_offset: Offset of 'u-boot' section in image
Simon Glass7098b7f2021-03-21 18:24:30 +13001400 entry_args: Dict of entry args to supply to binman
1401 key: arg name
1402 value: value of that arg
1403 use_expanded: True to use expanded entries where available, e.g.
1404 'u-boot-expanded' instead of 'u-boot'
Simon Glass31e04cb2021-03-18 20:24:56 +13001405 """
Simon Glass5d0c0262019-08-24 07:22:56 -06001406 elf_fname = self.ElfTestFile('u_boot_binman_syms')
Simon Glass4ca8e042017-11-13 18:55:01 -07001407 syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
1408 addr = elf.GetSymbolAddress(elf_fname, '__image_copy_start')
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001409 self.assertEqual(syms['_binman_sym_magic'].address, addr)
Simon Glass31e04cb2021-03-18 20:24:56 +13001410 self.assertEqual(syms['_binman_u_boot_spl_any_prop_offset'].address,
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001411 addr + 4)
Simon Glass4ca8e042017-11-13 18:55:01 -07001412
Simon Glass7057d022018-10-01 21:12:47 -06001413 self._SetupSplElf('u_boot_binman_syms')
Simon Glass7098b7f2021-03-21 18:24:30 +13001414 data = self._DoReadFileDtb(dts, entry_args=entry_args,
1415 use_expanded=use_expanded)[0]
Simon Glass31e04cb2021-03-18 20:24:56 +13001416 # The image should contain the symbols from u_boot_binman_syms.c
1417 # Note that image_pos is adjusted by the base address of the image,
1418 # which is 0x10 in our test image
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001419 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE,
1420 0x00, u_boot_offset + len(U_BOOT_DATA),
Simon Glass31e04cb2021-03-18 20:24:56 +13001421 0x10 + u_boot_offset, 0x04)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001422 expected = (sym_values + base_data[24:] +
Simon Glass80025522022-01-29 14:14:04 -07001423 tools.get_bytes(0xff, 1) + U_BOOT_DATA + sym_values +
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001424 base_data[24:])
Simon Glass4ca8e042017-11-13 18:55:01 -07001425 self.assertEqual(expected, data)
1426
Simon Glass31e04cb2021-03-18 20:24:56 +13001427 def testSymbols(self):
1428 """Test binman can assign symbols embedded in U-Boot"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03001429 self.checkSymbols('053_symbols.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glass31e04cb2021-03-18 20:24:56 +13001430
1431 def testSymbolsNoDtb(self):
1432 """Test binman can assign symbols embedded in U-Boot SPL"""
Simon Glass3bbc9932021-03-21 18:24:29 +13001433 self.checkSymbols('196_symbols_nodtb.dts',
Simon Glass31e04cb2021-03-18 20:24:56 +13001434 U_BOOT_SPL_NODTB_DATA + U_BOOT_SPL_DTB_DATA,
1435 0x38)
1436
Simon Glasse76a3e62018-06-01 09:38:11 -06001437 def testPackUnitAddress(self):
1438 """Test that we support multiple binaries with the same name"""
Simon Glass511f6582018-10-01 12:22:30 -06001439 data = self._DoReadFile('054_unit_address.dts')
Simon Glasse76a3e62018-06-01 09:38:11 -06001440 self.assertEqual(U_BOOT_DATA + U_BOOT_DATA, data)
1441
Simon Glassa91e1152018-06-01 09:38:16 -06001442 def testSections(self):
1443 """Basic test of sections"""
Simon Glass511f6582018-10-01 12:22:30 -06001444 data = self._DoReadFile('055_sections.dts')
Simon Glass80025522022-01-29 14:14:04 -07001445 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1446 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
1447 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glassa91e1152018-06-01 09:38:16 -06001448 self.assertEqual(expected, data)
Simon Glassac599912017-11-12 21:52:22 -07001449
Simon Glass30732662018-06-01 09:38:20 -06001450 def testMap(self):
1451 """Tests outputting a map of the images"""
Simon Glass511f6582018-10-01 12:22:30 -06001452 _, _, map_data, _ = self._DoReadFileDtb('055_sections.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001453 self.assertEqual('''ImagePos Offset Size Name
145400000000 00000000 00000028 main-section
145500000000 00000000 00000010 section@0
145600000000 00000000 00000004 u-boot
145700000010 00000010 00000010 section@1
145800000010 00000000 00000004 u-boot
145900000020 00000020 00000004 section@2
146000000020 00000000 00000004 u-boot
Simon Glass30732662018-06-01 09:38:20 -06001461''', map_data)
1462
Simon Glass3b78d532018-06-01 09:38:21 -06001463 def testNamePrefix(self):
1464 """Tests that name prefixes are used"""
Simon Glass511f6582018-10-01 12:22:30 -06001465 _, _, map_data, _ = self._DoReadFileDtb('056_name_prefix.dts', map=True)
Simon Glass7eca7922018-07-17 13:25:49 -06001466 self.assertEqual('''ImagePos Offset Size Name
146700000000 00000000 00000028 main-section
146800000000 00000000 00000010 section@0
146900000000 00000000 00000004 ro-u-boot
147000000010 00000010 00000010 section@1
147100000010 00000000 00000004 rw-u-boot
Simon Glass3b78d532018-06-01 09:38:21 -06001472''', map_data)
1473
Simon Glass6ba679c2018-07-06 10:27:17 -06001474 def testUnknownContents(self):
1475 """Test that obtaining the contents works as expected"""
1476 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001477 self._DoReadFile('057_unknown_contents.dts', True)
Simon Glass39dd2152019-07-08 14:25:47 -06001478 self.assertIn("Image '/binman': Internal error: Could not complete "
Simon Glassc585dd42020-04-17 18:09:03 -06001479 "processing of contents: remaining ["
1480 "<binman.etype._testing.Entry__testing ", str(e.exception))
Simon Glass6ba679c2018-07-06 10:27:17 -06001481
Simon Glass2e1169f2018-07-06 10:27:19 -06001482 def testBadChangeSize(self):
1483 """Test that trying to change the size of an entry fails"""
Simon Glasse61b6f62019-07-08 14:25:37 -06001484 try:
1485 state.SetAllowEntryExpansion(False)
1486 with self.assertRaises(ValueError) as e:
1487 self._DoReadFile('059_change_size.dts', True)
Simon Glass8c702fb2019-07-20 12:23:57 -06001488 self.assertIn("Node '/binman/_testing': Cannot update entry size from 2 to 3",
Simon Glasse61b6f62019-07-08 14:25:37 -06001489 str(e.exception))
1490 finally:
1491 state.SetAllowEntryExpansion(True)
Simon Glass2e1169f2018-07-06 10:27:19 -06001492
Simon Glassa87014e2018-07-06 10:27:42 -06001493 def testUpdateFdt(self):
Simon Glasse8561af2018-08-01 15:22:37 -06001494 """Test that we can update the device tree with offset/size info"""
Simon Glass511f6582018-10-01 12:22:30 -06001495 _, _, _, out_dtb_fname = self._DoReadFileDtb('060_fdt_update.dts',
Simon Glassa87014e2018-07-06 10:27:42 -06001496 update_dtb=True)
Simon Glass5463a6a2018-07-17 13:25:52 -06001497 dtb = fdt.Fdt(out_dtb_fname)
1498 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001499 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
Simon Glassa87014e2018-07-06 10:27:42 -06001500 self.assertEqual({
Simon Glass9dcc8612018-08-01 15:22:42 -06001501 'image-pos': 0,
Simon Glass3a9a2b82018-07-17 13:25:28 -06001502 'offset': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001503 '_testing:offset': 32,
Simon Glass8c702fb2019-07-20 12:23:57 -06001504 '_testing:size': 2,
Simon Glass9dcc8612018-08-01 15:22:42 -06001505 '_testing:image-pos': 32,
Simon Glasse8561af2018-08-01 15:22:37 -06001506 'section@0/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001507 'section@0/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001508 'section@0/u-boot:image-pos': 0,
Simon Glasse8561af2018-08-01 15:22:37 -06001509 'section@0:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001510 'section@0:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001511 'section@0:image-pos': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001512
Simon Glasse8561af2018-08-01 15:22:37 -06001513 'section@1/u-boot:offset': 0,
Simon Glassa87014e2018-07-06 10:27:42 -06001514 'section@1/u-boot:size': len(U_BOOT_DATA),
Simon Glass9dcc8612018-08-01 15:22:42 -06001515 'section@1/u-boot:image-pos': 16,
Simon Glasse8561af2018-08-01 15:22:37 -06001516 'section@1:offset': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001517 'section@1:size': 16,
Simon Glass9dcc8612018-08-01 15:22:42 -06001518 'section@1:image-pos': 16,
Simon Glassa87014e2018-07-06 10:27:42 -06001519 'size': 40
1520 }, props)
1521
1522 def testUpdateFdtBad(self):
1523 """Test that we detect when ProcessFdt never completes"""
1524 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001525 self._DoReadFileDtb('061_fdt_update_bad.dts', update_dtb=True)
Simon Glassa87014e2018-07-06 10:27:42 -06001526 self.assertIn('Could not complete processing of Fdt: remaining '
Simon Glassc585dd42020-04-17 18:09:03 -06001527 '[<binman.etype._testing.Entry__testing',
1528 str(e.exception))
Simon Glass2e1169f2018-07-06 10:27:19 -06001529
Simon Glass91710b32018-07-17 13:25:32 -06001530 def testEntryArgs(self):
1531 """Test passing arguments to entries from the command line"""
1532 entry_args = {
1533 'test-str-arg': 'test1',
1534 'test-int-arg': '456',
1535 }
Simon Glass511f6582018-10-01 12:22:30 -06001536 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001537 self.assertIn('image', control.images)
1538 entry = control.images['image'].GetEntries()['_testing']
1539 self.assertEqual('test0', entry.test_str_fdt)
1540 self.assertEqual('test1', entry.test_str_arg)
1541 self.assertEqual(123, entry.test_int_fdt)
1542 self.assertEqual(456, entry.test_int_arg)
1543
1544 def testEntryArgsMissing(self):
1545 """Test missing arguments and properties"""
1546 entry_args = {
1547 'test-int-arg': '456',
1548 }
Simon Glass511f6582018-10-01 12:22:30 -06001549 self._DoReadFileDtb('063_entry_args_missing.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001550 entry = control.images['image'].GetEntries()['_testing']
1551 self.assertEqual('test0', entry.test_str_fdt)
1552 self.assertEqual(None, entry.test_str_arg)
1553 self.assertEqual(None, entry.test_int_fdt)
1554 self.assertEqual(456, entry.test_int_arg)
1555
1556 def testEntryArgsRequired(self):
1557 """Test missing arguments and properties"""
1558 entry_args = {
1559 'test-int-arg': '456',
1560 }
1561 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001562 self._DoReadFileDtb('064_entry_args_required.dts')
Simon Glass21db0ff2020-09-01 05:13:54 -06001563 self.assertIn("Node '/binman/_testing': "
1564 'Missing required properties/entry args: test-str-arg, '
1565 'test-int-fdt, test-int-arg',
Simon Glass91710b32018-07-17 13:25:32 -06001566 str(e.exception))
1567
1568 def testEntryArgsInvalidFormat(self):
1569 """Test that an invalid entry-argument format is detected"""
Simon Glassf46732a2019-07-08 14:25:29 -06001570 args = ['build', '-d', self.TestFile('064_entry_args_required.dts'),
1571 '-ano-value']
Simon Glass91710b32018-07-17 13:25:32 -06001572 with self.assertRaises(ValueError) as e:
1573 self._DoBinman(*args)
1574 self.assertIn("Invalid entry arguemnt 'no-value'", str(e.exception))
1575
1576 def testEntryArgsInvalidInteger(self):
1577 """Test that an invalid entry-argument integer is detected"""
1578 entry_args = {
1579 'test-int-arg': 'abc',
1580 }
1581 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001582 self._DoReadFileDtb('062_entry_args.dts', entry_args=entry_args)
Simon Glass91710b32018-07-17 13:25:32 -06001583 self.assertIn("Node '/binman/_testing': Cannot convert entry arg "
1584 "'test-int-arg' (value 'abc') to integer",
1585 str(e.exception))
1586
1587 def testEntryArgsInvalidDatatype(self):
1588 """Test that an invalid entry-argument datatype is detected
1589
1590 This test could be written in entry_test.py except that it needs
1591 access to control.entry_args, which seems more than that module should
1592 be able to see.
1593 """
1594 entry_args = {
1595 'test-bad-datatype-arg': '12',
1596 }
1597 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001598 self._DoReadFileDtb('065_entry_args_unknown_datatype.dts',
Simon Glass91710b32018-07-17 13:25:32 -06001599 entry_args=entry_args)
1600 self.assertIn('GetArg() internal error: Unknown data type ',
1601 str(e.exception))
1602
Simon Glass2ca52032018-07-17 13:25:33 -06001603 def testText(self):
1604 """Test for a text entry type"""
1605 entry_args = {
1606 'test-id': TEXT_DATA,
1607 'test-id2': TEXT_DATA2,
1608 'test-id3': TEXT_DATA3,
1609 }
Simon Glass511f6582018-10-01 12:22:30 -06001610 data, _, _, _ = self._DoReadFileDtb('066_text.dts',
Simon Glass2ca52032018-07-17 13:25:33 -06001611 entry_args=entry_args)
Simon Glass80025522022-01-29 14:14:04 -07001612 expected = (tools.to_bytes(TEXT_DATA) +
1613 tools.get_bytes(0, 8 - len(TEXT_DATA)) +
1614 tools.to_bytes(TEXT_DATA2) + tools.to_bytes(TEXT_DATA3) +
Simon Glass47f6a622019-07-08 13:18:40 -06001615 b'some text' + b'more text')
Simon Glass2ca52032018-07-17 13:25:33 -06001616 self.assertEqual(expected, data)
1617
Simon Glass969616c2018-07-17 13:25:36 -06001618 def testEntryDocs(self):
1619 """Test for creation of entry documentation"""
1620 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001621 control.WriteEntryDocs(control.GetEntryModules())
Simon Glass969616c2018-07-17 13:25:36 -06001622 self.assertTrue(len(stdout.getvalue()) > 0)
1623
1624 def testEntryDocsMissing(self):
1625 """Test handling of missing entry documentation"""
1626 with self.assertRaises(ValueError) as e:
1627 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass220ff5f2020-08-05 13:27:46 -06001628 control.WriteEntryDocs(control.GetEntryModules(), 'u_boot')
Simon Glass969616c2018-07-17 13:25:36 -06001629 self.assertIn('Documentation is missing for modules: u_boot',
1630 str(e.exception))
1631
Simon Glass704784b2018-07-17 13:25:38 -06001632 def testFmap(self):
1633 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06001634 data = self._DoReadFile('067_fmap.dts')
Simon Glass704784b2018-07-17 13:25:38 -06001635 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07001636 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
1637 U_BOOT_DATA + tools.get_bytes(ord('a'), 12))
Simon Glass704784b2018-07-17 13:25:38 -06001638 self.assertEqual(expected, data[:32])
Simon Glass303f62f2019-05-17 22:00:46 -06001639 self.assertEqual(b'__FMAP__', fhdr.signature)
Simon Glass704784b2018-07-17 13:25:38 -06001640 self.assertEqual(1, fhdr.ver_major)
1641 self.assertEqual(0, fhdr.ver_minor)
1642 self.assertEqual(0, fhdr.base)
Simon Glassb1d414c2021-04-03 11:05:10 +13001643 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 5
Simon Glass82059c22021-04-03 11:05:09 +13001644 self.assertEqual(16 + 16 + expect_size, fhdr.image_size)
Simon Glass303f62f2019-05-17 22:00:46 -06001645 self.assertEqual(b'FMAP', fhdr.name)
Simon Glassb1d414c2021-04-03 11:05:10 +13001646 self.assertEqual(5, fhdr.nareas)
Simon Glass82059c22021-04-03 11:05:09 +13001647 fiter = iter(fentries)
Simon Glass704784b2018-07-17 13:25:38 -06001648
Simon Glass82059c22021-04-03 11:05:09 +13001649 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001650 self.assertEqual(b'SECTION0', fentry.name)
1651 self.assertEqual(0, fentry.offset)
1652 self.assertEqual(16, fentry.size)
1653 self.assertEqual(0, fentry.flags)
1654
1655 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001656 self.assertEqual(b'RO_U_BOOT', fentry.name)
1657 self.assertEqual(0, fentry.offset)
1658 self.assertEqual(4, fentry.size)
1659 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001660
Simon Glass82059c22021-04-03 11:05:09 +13001661 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13001662 self.assertEqual(b'SECTION1', fentry.name)
1663 self.assertEqual(16, fentry.offset)
1664 self.assertEqual(16, fentry.size)
1665 self.assertEqual(0, fentry.flags)
1666
1667 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13001668 self.assertEqual(b'RW_U_BOOT', fentry.name)
1669 self.assertEqual(16, fentry.offset)
1670 self.assertEqual(4, fentry.size)
1671 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001672
Simon Glass82059c22021-04-03 11:05:09 +13001673 fentry = next(fiter)
1674 self.assertEqual(b'FMAP', fentry.name)
1675 self.assertEqual(32, fentry.offset)
1676 self.assertEqual(expect_size, fentry.size)
1677 self.assertEqual(0, fentry.flags)
Simon Glass704784b2018-07-17 13:25:38 -06001678
Simon Glassdb168d42018-07-17 13:25:39 -06001679 def testBlobNamedByArg(self):
1680 """Test we can add a blob with the filename coming from an entry arg"""
1681 entry_args = {
1682 'cros-ec-rw-path': 'ecrw.bin',
1683 }
Simon Glass21db0ff2020-09-01 05:13:54 -06001684 self._DoReadFileDtb('068_blob_named_by_arg.dts', entry_args=entry_args)
Simon Glassdb168d42018-07-17 13:25:39 -06001685
Simon Glass53f53992018-07-17 13:25:40 -06001686 def testFill(self):
1687 """Test for an fill entry type"""
Simon Glass511f6582018-10-01 12:22:30 -06001688 data = self._DoReadFile('069_fill.dts')
Simon Glass80025522022-01-29 14:14:04 -07001689 expected = tools.get_bytes(0xff, 8) + tools.get_bytes(0, 8)
Simon Glass53f53992018-07-17 13:25:40 -06001690 self.assertEqual(expected, data)
1691
1692 def testFillNoSize(self):
1693 """Test for an fill entry type with no size"""
1694 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001695 self._DoReadFile('070_fill_no_size.dts')
Simon Glass0cf5bce2022-08-13 11:40:44 -06001696 self.assertIn("'fill' entry is missing properties: size",
Simon Glass53f53992018-07-17 13:25:40 -06001697 str(e.exception))
1698
Simon Glassc1ae83c2018-07-17 13:25:44 -06001699 def _HandleGbbCommand(self, pipe_list):
1700 """Fake calls to the futility utility"""
1701 if pipe_list[0][0] == 'futility':
1702 fname = pipe_list[0][-1]
1703 # Append our GBB data to the file, which will happen every time the
1704 # futility command is called.
Simon Glass33486662019-05-14 15:53:42 -06001705 with open(fname, 'ab') as fd:
Simon Glassc1ae83c2018-07-17 13:25:44 -06001706 fd.write(GBB_DATA)
1707 return command.CommandResult()
1708
1709 def testGbb(self):
1710 """Test for the Chromium OS Google Binary Block"""
1711 command.test_result = self._HandleGbbCommand
1712 entry_args = {
1713 'keydir': 'devkeys',
1714 'bmpblk': 'bmpblk.bin',
1715 }
Simon Glass511f6582018-10-01 12:22:30 -06001716 data, _, _, _ = self._DoReadFileDtb('071_gbb.dts', entry_args=entry_args)
Simon Glassc1ae83c2018-07-17 13:25:44 -06001717
1718 # Since futility
Simon Glass80025522022-01-29 14:14:04 -07001719 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
1720 tools.get_bytes(0, 0x2180 - 16))
Simon Glassc1ae83c2018-07-17 13:25:44 -06001721 self.assertEqual(expected, data)
1722
1723 def testGbbTooSmall(self):
1724 """Test for the Chromium OS Google Binary Block being large enough"""
1725 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001726 self._DoReadFileDtb('072_gbb_too_small.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001727 self.assertIn("Node '/binman/gbb': GBB is too small",
1728 str(e.exception))
1729
1730 def testGbbNoSize(self):
1731 """Test for the Chromium OS Google Binary Block having a size"""
1732 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001733 self._DoReadFileDtb('073_gbb_no_size.dts')
Simon Glassc1ae83c2018-07-17 13:25:44 -06001734 self.assertIn("Node '/binman/gbb': GBB must have a fixed size",
1735 str(e.exception))
1736
Simon Glass66152ce2022-01-09 20:14:09 -07001737 def testGbbMissing(self):
1738 """Test that binman still produces an image if futility is missing"""
1739 entry_args = {
1740 'keydir': 'devkeys',
1741 }
1742 with test_util.capture_sys_output() as (_, stderr):
1743 self._DoTestFile('071_gbb.dts', force_missing_bintools='futility',
1744 entry_args=entry_args)
1745 err = stderr.getvalue()
1746 self.assertRegex(err,
1747 "Image 'main-section'.*missing bintools.*: futility")
1748
Simon Glass5c350162018-07-17 13:25:47 -06001749 def _HandleVblockCommand(self, pipe_list):
Simon Glass220c6222021-01-06 21:35:17 -07001750 """Fake calls to the futility utility
1751
1752 The expected pipe is:
1753
1754 [('futility', 'vbutil_firmware', '--vblock',
1755 'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
1756 '--signprivate', 'devkeys/firmware_data_key.vbprivk',
1757 '--version', '1', '--fv', 'input.vblock', '--kernelkey',
1758 'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
1759
1760 This writes to the output file (here, 'vblock.vblock'). If
1761 self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
1762 of the input data (here, 'input.vblock').
1763 """
Simon Glass5c350162018-07-17 13:25:47 -06001764 if pipe_list[0][0] == 'futility':
1765 fname = pipe_list[0][3]
Simon Glass639505b2018-09-14 04:57:11 -06001766 with open(fname, 'wb') as fd:
Simon Glass220c6222021-01-06 21:35:17 -07001767 if self._hash_data:
1768 infile = pipe_list[0][11]
1769 m = hashlib.sha256()
Simon Glass80025522022-01-29 14:14:04 -07001770 data = tools.read_file(infile)
Simon Glass220c6222021-01-06 21:35:17 -07001771 m.update(data)
1772 fd.write(m.digest())
1773 else:
1774 fd.write(VBLOCK_DATA)
1775
Simon Glass5c350162018-07-17 13:25:47 -06001776 return command.CommandResult()
1777
1778 def testVblock(self):
1779 """Test for the Chromium OS Verified Boot Block"""
Simon Glass220c6222021-01-06 21:35:17 -07001780 self._hash_data = False
Simon Glass5c350162018-07-17 13:25:47 -06001781 command.test_result = self._HandleVblockCommand
1782 entry_args = {
1783 'keydir': 'devkeys',
1784 }
Simon Glass511f6582018-10-01 12:22:30 -06001785 data, _, _, _ = self._DoReadFileDtb('074_vblock.dts',
Simon Glass5c350162018-07-17 13:25:47 -06001786 entry_args=entry_args)
1787 expected = U_BOOT_DATA + VBLOCK_DATA + U_BOOT_DTB_DATA
1788 self.assertEqual(expected, data)
1789
1790 def testVblockNoContent(self):
1791 """Test we detect a vblock which has no content to sign"""
1792 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001793 self._DoReadFile('075_vblock_no_content.dts')
Simon Glasse1915782021-03-21 18:24:31 +13001794 self.assertIn("Node '/binman/vblock': Collection must have a 'content' "
Simon Glass5c350162018-07-17 13:25:47 -06001795 'property', str(e.exception))
1796
1797 def testVblockBadPhandle(self):
1798 """Test that we detect a vblock with an invalid phandle in contents"""
1799 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001800 self._DoReadFile('076_vblock_bad_phandle.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001801 self.assertIn("Node '/binman/vblock': Cannot find node for phandle "
1802 '1000', str(e.exception))
1803
1804 def testVblockBadEntry(self):
1805 """Test that we detect an entry that points to a non-entry"""
1806 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001807 self._DoReadFile('077_vblock_bad_entry.dts')
Simon Glass5c350162018-07-17 13:25:47 -06001808 self.assertIn("Node '/binman/vblock': Cannot find entry for node "
1809 "'other'", str(e.exception))
1810
Simon Glass220c6222021-01-06 21:35:17 -07001811 def testVblockContent(self):
1812 """Test that the vblock signs the right data"""
1813 self._hash_data = True
1814 command.test_result = self._HandleVblockCommand
1815 entry_args = {
1816 'keydir': 'devkeys',
1817 }
1818 data = self._DoReadFileDtb(
1819 '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
1820 entry_args=entry_args)[0]
1821 hashlen = 32 # SHA256 hash is 32 bytes
1822 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
1823 hashval = data[-hashlen:]
1824 dtb = data[len(U_BOOT_DATA):-hashlen]
1825
1826 expected_data = U_BOOT_DATA + dtb
1827
1828 # The hashval should be a hash of the dtb
1829 m = hashlib.sha256()
1830 m.update(expected_data)
1831 expected_hashval = m.digest()
1832 self.assertEqual(expected_hashval, hashval)
1833
Simon Glass66152ce2022-01-09 20:14:09 -07001834 def testVblockMissing(self):
1835 """Test that binman still produces an image if futility is missing"""
1836 entry_args = {
1837 'keydir': 'devkeys',
1838 }
1839 with test_util.capture_sys_output() as (_, stderr):
1840 self._DoTestFile('074_vblock.dts',
1841 force_missing_bintools='futility',
1842 entry_args=entry_args)
1843 err = stderr.getvalue()
1844 self.assertRegex(err,
1845 "Image 'main-section'.*missing bintools.*: futility")
1846
Simon Glass8425a1f2018-07-17 13:25:48 -06001847 def testTpl(self):
Simon Glass3eb5b202019-08-24 07:23:00 -06001848 """Test that an image with TPL and its device tree can be created"""
Simon Glass8425a1f2018-07-17 13:25:48 -06001849 # ELF file with a '__bss_size' symbol
Simon Glass3eb5b202019-08-24 07:23:00 -06001850 self._SetupTplElf()
Simon Glass511f6582018-10-01 12:22:30 -06001851 data = self._DoReadFile('078_u_boot_tpl.dts')
Simon Glass8425a1f2018-07-17 13:25:48 -06001852 self.assertEqual(U_BOOT_TPL_DATA + U_BOOT_TPL_DTB_DATA, data)
1853
Simon Glass24b97442018-07-17 13:25:51 -06001854 def testUsesPos(self):
1855 """Test that the 'pos' property cannot be used anymore"""
1856 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001857 data = self._DoReadFile('079_uses_pos.dts')
Simon Glass24b97442018-07-17 13:25:51 -06001858 self.assertIn("Node '/binman/u-boot': Please use 'offset' instead of "
1859 "'pos'", str(e.exception))
1860
Simon Glass274bf092018-09-14 04:57:08 -06001861 def testFillZero(self):
1862 """Test for an fill entry type with a size of 0"""
Simon Glass511f6582018-10-01 12:22:30 -06001863 data = self._DoReadFile('080_fill_empty.dts')
Simon Glass80025522022-01-29 14:14:04 -07001864 self.assertEqual(tools.get_bytes(0, 16), data)
Simon Glass274bf092018-09-14 04:57:08 -06001865
Simon Glass267de432018-09-14 04:57:09 -06001866 def testTextMissing(self):
1867 """Test for a text entry type where there is no text"""
1868 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06001869 self._DoReadFileDtb('066_text.dts',)
Simon Glass267de432018-09-14 04:57:09 -06001870 self.assertIn("Node '/binman/text': No value provided for text label "
1871 "'test-id'", str(e.exception))
1872
Simon Glassed40e962018-09-14 04:57:10 -06001873 def testPackStart16Tpl(self):
1874 """Test that an image with an x86 start16 TPL region can be created"""
Simon Glass1d167762019-08-24 07:23:01 -06001875 data = self._DoReadFile('081_x86_start16_tpl.dts')
Simon Glassed40e962018-09-14 04:57:10 -06001876 self.assertEqual(X86_START16_TPL_DATA, data[:len(X86_START16_TPL_DATA)])
1877
Simon Glass3b376c32018-09-14 04:57:12 -06001878 def testSelectImage(self):
1879 """Test that we can select which images to build"""
Simon Glassb4595d82019-04-25 21:58:34 -06001880 expected = 'Skipping images: image1'
1881
1882 # We should only get the expected message in verbose mode
Simon Glass8a50b4a2019-07-08 13:18:48 -06001883 for verbosity in (0, 2):
Simon Glassb4595d82019-04-25 21:58:34 -06001884 with test_util.capture_sys_output() as (stdout, stderr):
1885 retcode = self._DoTestFile('006_dual_image.dts',
1886 verbosity=verbosity,
1887 images=['image2'])
1888 self.assertEqual(0, retcode)
1889 if verbosity:
1890 self.assertIn(expected, stdout.getvalue())
1891 else:
1892 self.assertNotIn(expected, stdout.getvalue())
Simon Glass3b376c32018-09-14 04:57:12 -06001893
Simon Glass80025522022-01-29 14:14:04 -07001894 self.assertFalse(os.path.exists(tools.get_output_filename('image1.bin')))
1895 self.assertTrue(os.path.exists(tools.get_output_filename('image2.bin')))
Simon Glassb3d6fc72019-07-20 12:24:10 -06001896 self._CleanupOutputDir()
Simon Glass3b376c32018-09-14 04:57:12 -06001897
Simon Glasse219aa42018-09-14 04:57:24 -06001898 def testUpdateFdtAll(self):
1899 """Test that all device trees are updated with offset/size info"""
Simon Glass5b4bce32019-07-08 14:25:26 -06001900 data = self._DoReadFileRealDtb('082_fdt_update_all.dts')
Simon Glasse219aa42018-09-14 04:57:24 -06001901
1902 base_expected = {
1903 'section:image-pos': 0,
1904 'u-boot-tpl-dtb:size': 513,
1905 'u-boot-spl-dtb:size': 513,
1906 'u-boot-spl-dtb:offset': 493,
1907 'image-pos': 0,
1908 'section/u-boot-dtb:image-pos': 0,
1909 'u-boot-spl-dtb:image-pos': 493,
1910 'section/u-boot-dtb:size': 493,
1911 'u-boot-tpl-dtb:image-pos': 1006,
1912 'section/u-boot-dtb:offset': 0,
1913 'section:size': 493,
1914 'offset': 0,
1915 'section:offset': 0,
1916 'u-boot-tpl-dtb:offset': 1006,
1917 'size': 1519
1918 }
1919
1920 # We expect three device-tree files in the output, one after the other.
1921 # Read them in sequence. We look for an 'spl' property in the SPL tree,
1922 # and 'tpl' in the TPL tree, to make sure they are distinct from the
1923 # main U-Boot tree. All three should have the same postions and offset.
1924 start = 0
1925 for item in ['', 'spl', 'tpl']:
1926 dtb = fdt.Fdt.FromData(data[start:])
1927 dtb.Scan()
Simon Glassfb30e292019-07-20 12:23:51 -06001928 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS +
1929 ['spl', 'tpl'])
Simon Glasse219aa42018-09-14 04:57:24 -06001930 expected = dict(base_expected)
1931 if item:
1932 expected[item] = 0
1933 self.assertEqual(expected, props)
1934 start += dtb._fdt_obj.totalsize()
1935
1936 def testUpdateFdtOutput(self):
1937 """Test that output DTB files are updated"""
1938 try:
Simon Glass511f6582018-10-01 12:22:30 -06001939 data, dtb_data, _, _ = self._DoReadFileDtb('082_fdt_update_all.dts',
Simon Glasse219aa42018-09-14 04:57:24 -06001940 use_real_dtb=True, update_dtb=True, reset_dtbs=False)
1941
1942 # Unfortunately, compiling a source file always results in a file
1943 # called source.dtb (see fdt_util.EnsureCompiled()). The test
Simon Glass511f6582018-10-01 12:22:30 -06001944 # source file (e.g. test/075_fdt_update_all.dts) thus does not enter
Simon Glasse219aa42018-09-14 04:57:24 -06001945 # binman as a file called u-boot.dtb. To fix this, copy the file
1946 # over to the expected place.
Simon Glasse219aa42018-09-14 04:57:24 -06001947 start = 0
1948 for fname in ['u-boot.dtb.out', 'spl/u-boot-spl.dtb.out',
1949 'tpl/u-boot-tpl.dtb.out']:
1950 dtb = fdt.Fdt.FromData(data[start:])
1951 size = dtb._fdt_obj.totalsize()
Simon Glass80025522022-01-29 14:14:04 -07001952 pathname = tools.get_output_filename(os.path.split(fname)[1])
1953 outdata = tools.read_file(pathname)
Simon Glasse219aa42018-09-14 04:57:24 -06001954 name = os.path.split(fname)[0]
1955
1956 if name:
1957 orig_indata = self._GetDtbContentsForSplTpl(dtb_data, name)
1958 else:
1959 orig_indata = dtb_data
1960 self.assertNotEqual(outdata, orig_indata,
1961 "Expected output file '%s' be updated" % pathname)
1962 self.assertEqual(outdata, data[start:start + size],
1963 "Expected output file '%s' to match output image" %
1964 pathname)
1965 start += size
1966 finally:
1967 self._ResetDtbs()
1968
Simon Glass7ba33592018-09-14 04:57:26 -06001969 def _decompress(self, data):
Simon Glassdd5c14ec2022-01-09 20:14:04 -07001970 return comp_util.decompress(data, 'lz4')
Simon Glass7ba33592018-09-14 04:57:26 -06001971
1972 def testCompress(self):
1973 """Test compression of blobs"""
Simon Glass1de34482019-07-08 13:18:53 -06001974 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06001975 data, _, _, out_dtb_fname = self._DoReadFileDtb('083_compress.dts',
Simon Glass7ba33592018-09-14 04:57:26 -06001976 use_real_dtb=True, update_dtb=True)
1977 dtb = fdt.Fdt(out_dtb_fname)
1978 dtb.Scan()
1979 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
1980 orig = self._decompress(data)
1981 self.assertEquals(COMPRESS_DATA, orig)
Simon Glass789b34402020-10-26 17:40:15 -06001982
1983 # Do a sanity check on various fields
1984 image = control.images['image']
1985 entries = image.GetEntries()
1986 self.assertEqual(1, len(entries))
1987
1988 entry = entries['blob']
1989 self.assertEqual(COMPRESS_DATA, entry.uncomp_data)
1990 self.assertEqual(len(COMPRESS_DATA), entry.uncomp_size)
1991 orig = self._decompress(entry.data)
1992 self.assertEqual(orig, entry.uncomp_data)
1993
Simon Glass72eeff12020-10-26 17:40:16 -06001994 self.assertEqual(image.data, entry.data)
1995
Simon Glass7ba33592018-09-14 04:57:26 -06001996 expected = {
1997 'blob:uncomp-size': len(COMPRESS_DATA),
1998 'blob:size': len(data),
1999 'size': len(data),
2000 }
2001 self.assertEqual(expected, props)
2002
Simon Glassac6328c2018-09-14 04:57:28 -06002003 def testFiles(self):
2004 """Test bringing in multiple files"""
Simon Glass511f6582018-10-01 12:22:30 -06002005 data = self._DoReadFile('084_files.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002006 self.assertEqual(FILES_DATA, data)
2007
2008 def testFilesCompress(self):
2009 """Test bringing in multiple files and compressing them"""
Simon Glass1de34482019-07-08 13:18:53 -06002010 self._CheckLz4()
Simon Glass511f6582018-10-01 12:22:30 -06002011 data = self._DoReadFile('085_files_compress.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002012
2013 image = control.images['image']
2014 entries = image.GetEntries()
2015 files = entries['files']
Simon Glass39dd2152019-07-08 14:25:47 -06002016 entries = files._entries
Simon Glassac6328c2018-09-14 04:57:28 -06002017
Simon Glass303f62f2019-05-17 22:00:46 -06002018 orig = b''
Simon Glassac6328c2018-09-14 04:57:28 -06002019 for i in range(1, 3):
2020 key = '%d.dat' % i
2021 start = entries[key].image_pos
2022 len = entries[key].size
2023 chunk = data[start:start + len]
2024 orig += self._decompress(chunk)
2025
2026 self.assertEqual(FILES_DATA, orig)
2027
2028 def testFilesMissing(self):
2029 """Test missing files"""
2030 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002031 data = self._DoReadFile('086_files_none.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002032 self.assertIn("Node '/binman/files': Pattern \'files/*.none\' matched "
2033 'no files', str(e.exception))
2034
2035 def testFilesNoPattern(self):
2036 """Test missing files"""
2037 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002038 data = self._DoReadFile('087_files_no_pattern.dts')
Simon Glassac6328c2018-09-14 04:57:28 -06002039 self.assertIn("Node '/binman/files': Missing 'pattern' property",
2040 str(e.exception))
2041
Simon Glassdd156a42022-03-05 20:18:59 -07002042 def testExtendSize(self):
2043 """Test an extending entry"""
2044 data, _, map_data, _ = self._DoReadFileDtb('088_extend_size.dts',
Simon Glassfa79a812018-09-14 04:57:29 -06002045 map=True)
Simon Glass80025522022-01-29 14:14:04 -07002046 expect = (tools.get_bytes(ord('a'), 8) + U_BOOT_DATA +
2047 MRC_DATA + tools.get_bytes(ord('b'), 1) + U_BOOT_DATA +
2048 tools.get_bytes(ord('c'), 8) + U_BOOT_DATA +
2049 tools.get_bytes(ord('d'), 8))
Simon Glassfa79a812018-09-14 04:57:29 -06002050 self.assertEqual(expect, data)
2051 self.assertEqual('''ImagePos Offset Size Name
205200000000 00000000 00000028 main-section
205300000000 00000000 00000008 fill
205400000008 00000008 00000004 u-boot
20550000000c 0000000c 00000004 section
20560000000c 00000000 00000003 intel-mrc
205700000010 00000010 00000004 u-boot2
205800000014 00000014 0000000c section2
205900000014 00000000 00000008 fill
20600000001c 00000008 00000004 u-boot
206100000020 00000020 00000008 fill2
2062''', map_data)
2063
Simon Glassdd156a42022-03-05 20:18:59 -07002064 def testExtendSizeBad(self):
2065 """Test an extending entry which fails to provide contents"""
Simon Glasscd817d52018-09-14 04:57:36 -06002066 with test_util.capture_sys_output() as (stdout, stderr):
2067 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002068 self._DoReadFileDtb('089_extend_size_bad.dts', map=True)
Simon Glassfa79a812018-09-14 04:57:29 -06002069 self.assertIn("Node '/binman/_testing': Cannot obtain contents when "
2070 'expanding entry', str(e.exception))
2071
Simon Glassae7cf032018-09-14 04:57:31 -06002072 def testHash(self):
2073 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002074 _, _, _, out_dtb_fname = self._DoReadFileDtb('090_hash.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002075 use_real_dtb=True, update_dtb=True)
2076 dtb = fdt.Fdt(out_dtb_fname)
2077 dtb.Scan()
2078 hash_node = dtb.GetNode('/binman/u-boot/hash').props['value']
2079 m = hashlib.sha256()
2080 m.update(U_BOOT_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002081 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002082
2083 def testHashNoAlgo(self):
2084 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002085 self._DoReadFileDtb('091_hash_no_algo.dts', update_dtb=True)
Simon Glassae7cf032018-09-14 04:57:31 -06002086 self.assertIn("Node \'/binman/u-boot\': Missing \'algo\' property for "
2087 'hash node', str(e.exception))
2088
2089 def testHashBadAlgo(self):
2090 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002091 self._DoReadFileDtb('092_hash_bad_algo.dts', update_dtb=True)
Simon Glass64af7c22022-02-08 10:59:44 -07002092 self.assertIn("Node '/binman/u-boot': Unknown hash algorithm 'invalid'",
Simon Glassae7cf032018-09-14 04:57:31 -06002093 str(e.exception))
2094
2095 def testHashSection(self):
2096 """Test hashing of the contents of an entry"""
Simon Glass511f6582018-10-01 12:22:30 -06002097 _, _, _, out_dtb_fname = self._DoReadFileDtb('099_hash_section.dts',
Simon Glassae7cf032018-09-14 04:57:31 -06002098 use_real_dtb=True, update_dtb=True)
2099 dtb = fdt.Fdt(out_dtb_fname)
2100 dtb.Scan()
2101 hash_node = dtb.GetNode('/binman/section/hash').props['value']
2102 m = hashlib.sha256()
2103 m.update(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07002104 m.update(tools.get_bytes(ord('a'), 16))
Simon Glass303f62f2019-05-17 22:00:46 -06002105 self.assertEqual(m.digest(), b''.join(hash_node.value))
Simon Glassae7cf032018-09-14 04:57:31 -06002106
Simon Glass3fb4f422018-09-14 04:57:32 -06002107 def testPackUBootTplMicrocode(self):
2108 """Test that x86 microcode can be handled correctly in TPL
2109
2110 We expect to see the following in the image, in order:
2111 u-boot-tpl-nodtb.bin with a microcode pointer inserted at the correct
2112 place
2113 u-boot-tpl.dtb with the microcode removed
2114 the microcode
2115 """
Simon Glass3eb5b202019-08-24 07:23:00 -06002116 self._SetupTplElf('u_boot_ucode_ptr')
Simon Glass511f6582018-10-01 12:22:30 -06002117 first, pos_and_size = self._RunMicrocodeTest('093_x86_tpl_ucode.dts',
Simon Glass3fb4f422018-09-14 04:57:32 -06002118 U_BOOT_TPL_NODTB_DATA)
Simon Glass303f62f2019-05-17 22:00:46 -06002119 self.assertEqual(b'tplnodtb with microc' + pos_and_size +
2120 b'ter somewhere in here', first)
Simon Glass3fb4f422018-09-14 04:57:32 -06002121
Simon Glassc64aea52018-09-14 04:57:34 -06002122 def testFmapX86(self):
2123 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002124 data = self._DoReadFile('094_fmap_x86.dts')
Simon Glassc64aea52018-09-14 04:57:34 -06002125 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
Simon Glass80025522022-01-29 14:14:04 -07002126 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('a'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002127 self.assertEqual(expected, data[:32])
2128 fhdr, fentries = fmap_util.DecodeFmap(data[32:])
2129
2130 self.assertEqual(0x100, fhdr.image_size)
2131
2132 self.assertEqual(0, fentries[0].offset)
2133 self.assertEqual(4, fentries[0].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002134 self.assertEqual(b'U_BOOT', fentries[0].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002135
2136 self.assertEqual(4, fentries[1].offset)
2137 self.assertEqual(3, fentries[1].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002138 self.assertEqual(b'INTEL_MRC', fentries[1].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002139
2140 self.assertEqual(32, fentries[2].offset)
2141 self.assertEqual(fmap_util.FMAP_HEADER_LEN +
2142 fmap_util.FMAP_AREA_LEN * 3, fentries[2].size)
Simon Glass303f62f2019-05-17 22:00:46 -06002143 self.assertEqual(b'FMAP', fentries[2].name)
Simon Glassc64aea52018-09-14 04:57:34 -06002144
2145 def testFmapX86Section(self):
2146 """Basic test of generation of a flashrom fmap"""
Simon Glass511f6582018-10-01 12:22:30 -06002147 data = self._DoReadFile('095_fmap_x86_section.dts')
Simon Glass80025522022-01-29 14:14:04 -07002148 expected = U_BOOT_DATA + MRC_DATA + tools.get_bytes(ord('b'), 32 - 7)
Simon Glassc64aea52018-09-14 04:57:34 -06002149 self.assertEqual(expected, data[:32])
2150 fhdr, fentries = fmap_util.DecodeFmap(data[36:])
2151
Simon Glassb1d414c2021-04-03 11:05:10 +13002152 self.assertEqual(0x180, fhdr.image_size)
2153 expect_size = fmap_util.FMAP_HEADER_LEN + fmap_util.FMAP_AREA_LEN * 4
Simon Glass82059c22021-04-03 11:05:09 +13002154 fiter = iter(fentries)
Simon Glassc64aea52018-09-14 04:57:34 -06002155
Simon Glass82059c22021-04-03 11:05:09 +13002156 fentry = next(fiter)
2157 self.assertEqual(b'U_BOOT', fentry.name)
2158 self.assertEqual(0, fentry.offset)
2159 self.assertEqual(4, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002160
Simon Glass82059c22021-04-03 11:05:09 +13002161 fentry = next(fiter)
Simon Glassb1d414c2021-04-03 11:05:10 +13002162 self.assertEqual(b'SECTION', fentry.name)
2163 self.assertEqual(4, fentry.offset)
2164 self.assertEqual(0x20 + expect_size, fentry.size)
2165
2166 fentry = next(fiter)
Simon Glass82059c22021-04-03 11:05:09 +13002167 self.assertEqual(b'INTEL_MRC', fentry.name)
2168 self.assertEqual(4, fentry.offset)
2169 self.assertEqual(3, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002170
Simon Glass82059c22021-04-03 11:05:09 +13002171 fentry = next(fiter)
2172 self.assertEqual(b'FMAP', fentry.name)
2173 self.assertEqual(36, fentry.offset)
2174 self.assertEqual(expect_size, fentry.size)
Simon Glassc64aea52018-09-14 04:57:34 -06002175
Simon Glassb1714232018-09-14 04:57:35 -06002176 def testElf(self):
2177 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002178 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002179 self._SetupTplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002180 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002181 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002182 data = self._DoReadFile('096_elf.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002183
Simon Glass0d673792019-07-08 13:18:25 -06002184 def testElfStrip(self):
Simon Glassb1714232018-09-14 04:57:35 -06002185 """Basic test of ELF entries"""
Simon Glass7057d022018-10-01 21:12:47 -06002186 self._SetupSplElf()
Simon Glassf6290892019-08-24 07:22:53 -06002187 with open(self.ElfTestFile('bss_data'), 'rb') as fd:
Simon Glassb1714232018-09-14 04:57:35 -06002188 TestFunctional._MakeInputFile('-boot', fd.read())
Simon Glass511f6582018-10-01 12:22:30 -06002189 data = self._DoReadFile('097_elf_strip.dts')
Simon Glassb1714232018-09-14 04:57:35 -06002190
Simon Glasscd817d52018-09-14 04:57:36 -06002191 def testPackOverlapMap(self):
2192 """Test that overlapping regions are detected"""
2193 with test_util.capture_sys_output() as (stdout, stderr):
2194 with self.assertRaises(ValueError) as e:
Simon Glass511f6582018-10-01 12:22:30 -06002195 self._DoTestFile('014_pack_overlap.dts', map=True)
Simon Glass80025522022-01-29 14:14:04 -07002196 map_fname = tools.get_output_filename('image.map')
Simon Glasscd817d52018-09-14 04:57:36 -06002197 self.assertEqual("Wrote map file '%s' to show errors\n" % map_fname,
2198 stdout.getvalue())
2199
2200 # We should not get an inmage, but there should be a map file
Simon Glass80025522022-01-29 14:14:04 -07002201 self.assertFalse(os.path.exists(tools.get_output_filename('image.bin')))
Simon Glasscd817d52018-09-14 04:57:36 -06002202 self.assertTrue(os.path.exists(map_fname))
Simon Glass80025522022-01-29 14:14:04 -07002203 map_data = tools.read_file(map_fname, binary=False)
Simon Glasscd817d52018-09-14 04:57:36 -06002204 self.assertEqual('''ImagePos Offset Size Name
Simon Glassd99850b2020-10-26 17:40:24 -06002205<none> 00000000 00000008 main-section
Simon Glasscd817d52018-09-14 04:57:36 -06002206<none> 00000000 00000004 u-boot
2207<none> 00000003 00000004 u-boot-align
2208''', map_data)
2209
Simon Glass0d673792019-07-08 13:18:25 -06002210 def testPackRefCode(self):
Simon Glass41902e42018-10-01 12:22:31 -06002211 """Test that an image with an Intel Reference code binary works"""
2212 data = self._DoReadFile('100_intel_refcode.dts')
2213 self.assertEqual(REFCODE_DATA, data[:len(REFCODE_DATA)])
2214
Simon Glasseb023b32019-04-25 21:58:39 -06002215 def testSectionOffset(self):
2216 """Tests use of a section with an offset"""
2217 data, _, map_data, _ = self._DoReadFileDtb('101_sections_offset.dts',
2218 map=True)
2219 self.assertEqual('''ImagePos Offset Size Name
222000000000 00000000 00000038 main-section
222100000004 00000004 00000010 section@0
222200000004 00000000 00000004 u-boot
222300000018 00000018 00000010 section@1
222400000018 00000000 00000004 u-boot
22250000002c 0000002c 00000004 section@2
22260000002c 00000000 00000004 u-boot
2227''', map_data)
2228 self.assertEqual(data,
Simon Glass80025522022-01-29 14:14:04 -07002229 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2230 tools.get_bytes(0x21, 12) +
2231 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2232 tools.get_bytes(0x61, 12) +
2233 tools.get_bytes(0x26, 4) + U_BOOT_DATA +
2234 tools.get_bytes(0x26, 8))
Simon Glasseb023b32019-04-25 21:58:39 -06002235
Simon Glass1de34482019-07-08 13:18:53 -06002236 def testCbfsRaw(self):
2237 """Test base handling of a Coreboot Filesystem (CBFS)
2238
2239 The exact contents of the CBFS is verified by similar tests in
2240 cbfs_util_test.py. The tests here merely check that the files added to
2241 the CBFS can be found in the final image.
2242 """
2243 data = self._DoReadFile('102_cbfs_raw.dts')
2244 size = 0xb0
2245
2246 cbfs = cbfs_util.CbfsReader(data)
2247 self.assertEqual(size, cbfs.rom_size)
2248
2249 self.assertIn('u-boot-dtb', cbfs.files)
2250 cfile = cbfs.files['u-boot-dtb']
2251 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2252
2253 def testCbfsArch(self):
2254 """Test on non-x86 architecture"""
2255 data = self._DoReadFile('103_cbfs_raw_ppc.dts')
2256 size = 0x100
2257
2258 cbfs = cbfs_util.CbfsReader(data)
2259 self.assertEqual(size, cbfs.rom_size)
2260
2261 self.assertIn('u-boot-dtb', cbfs.files)
2262 cfile = cbfs.files['u-boot-dtb']
2263 self.assertEqual(U_BOOT_DTB_DATA, cfile.data)
2264
2265 def testCbfsStage(self):
2266 """Tests handling of a Coreboot Filesystem (CBFS)"""
2267 if not elf.ELF_TOOLS:
2268 self.skipTest('Python elftools not available')
2269 elf_fname = os.path.join(self._indir, 'cbfs-stage.elf')
2270 elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA)
2271 size = 0xb0
2272
2273 data = self._DoReadFile('104_cbfs_stage.dts')
2274 cbfs = cbfs_util.CbfsReader(data)
2275 self.assertEqual(size, cbfs.rom_size)
2276
2277 self.assertIn('u-boot', cbfs.files)
2278 cfile = cbfs.files['u-boot']
2279 self.assertEqual(U_BOOT_DATA + U_BOOT_DTB_DATA, cfile.data)
2280
2281 def testCbfsRawCompress(self):
2282 """Test handling of compressing raw files"""
2283 self._CheckLz4()
2284 data = self._DoReadFile('105_cbfs_raw_compress.dts')
2285 size = 0x140
2286
2287 cbfs = cbfs_util.CbfsReader(data)
2288 self.assertIn('u-boot', cbfs.files)
2289 cfile = cbfs.files['u-boot']
2290 self.assertEqual(COMPRESS_DATA, cfile.data)
2291
2292 def testCbfsBadArch(self):
2293 """Test handling of a bad architecture"""
2294 with self.assertRaises(ValueError) as e:
2295 self._DoReadFile('106_cbfs_bad_arch.dts')
2296 self.assertIn("Invalid architecture 'bad-arch'", str(e.exception))
2297
2298 def testCbfsNoSize(self):
2299 """Test handling of a missing size property"""
2300 with self.assertRaises(ValueError) as e:
2301 self._DoReadFile('107_cbfs_no_size.dts')
2302 self.assertIn('entry must have a size property', str(e.exception))
2303
Simon Glass3e28f4f2021-11-23 11:03:54 -07002304 def testCbfsNoContents(self):
Simon Glass1de34482019-07-08 13:18:53 -06002305 """Test handling of a CBFS entry which does not provide contentsy"""
2306 with self.assertRaises(ValueError) as e:
2307 self._DoReadFile('108_cbfs_no_contents.dts')
2308 self.assertIn('Could not complete processing of contents',
2309 str(e.exception))
2310
2311 def testCbfsBadCompress(self):
2312 """Test handling of a bad architecture"""
2313 with self.assertRaises(ValueError) as e:
2314 self._DoReadFile('109_cbfs_bad_compress.dts')
2315 self.assertIn("Invalid compression in 'u-boot': 'invalid-algo'",
2316 str(e.exception))
2317
2318 def testCbfsNamedEntries(self):
2319 """Test handling of named entries"""
2320 data = self._DoReadFile('110_cbfs_name.dts')
2321
2322 cbfs = cbfs_util.CbfsReader(data)
2323 self.assertIn('FRED', cbfs.files)
2324 cfile1 = cbfs.files['FRED']
2325 self.assertEqual(U_BOOT_DATA, cfile1.data)
2326
2327 self.assertIn('hello', cbfs.files)
2328 cfile2 = cbfs.files['hello']
2329 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2330
Simon Glass759af872019-07-08 13:18:54 -06002331 def _SetupIfwi(self, fname):
2332 """Set up to run an IFWI test
2333
2334 Args:
2335 fname: Filename of input file to provide (fitimage.bin or ifwi.bin)
2336 """
2337 self._SetupSplElf()
Simon Glass3eb5b202019-08-24 07:23:00 -06002338 self._SetupTplElf()
Simon Glass759af872019-07-08 13:18:54 -06002339
2340 # Intel Integrated Firmware Image (IFWI) file
2341 with gzip.open(self.TestFile('%s.gz' % fname), 'rb') as fd:
2342 data = fd.read()
2343 TestFunctional._MakeInputFile(fname,data)
2344
2345 def _CheckIfwi(self, data):
2346 """Check that an image with an IFWI contains the correct output
2347
2348 Args:
2349 data: Conents of output file
2350 """
Simon Glass80025522022-01-29 14:14:04 -07002351 expected_desc = tools.read_file(self.TestFile('descriptor.bin'))
Simon Glass759af872019-07-08 13:18:54 -06002352 if data[:0x1000] != expected_desc:
2353 self.fail('Expected descriptor binary at start of image')
2354
2355 # We expect to find the TPL wil in subpart IBBP entry IBBL
Simon Glass80025522022-01-29 14:14:04 -07002356 image_fname = tools.get_output_filename('image.bin')
2357 tpl_fname = tools.get_output_filename('tpl.out')
Simon Glass57c7a482022-01-09 20:14:01 -07002358 ifwitool = bintool.Bintool.create('ifwitool')
2359 ifwitool.extract(image_fname, 'IBBP', 'IBBL', tpl_fname)
Simon Glass759af872019-07-08 13:18:54 -06002360
Simon Glass80025522022-01-29 14:14:04 -07002361 tpl_data = tools.read_file(tpl_fname)
Simon Glassf55bd692019-08-24 07:22:51 -06002362 self.assertEqual(U_BOOT_TPL_DATA, tpl_data[:len(U_BOOT_TPL_DATA)])
Simon Glass759af872019-07-08 13:18:54 -06002363
2364 def testPackX86RomIfwi(self):
2365 """Test that an x86 ROM with Integrated Firmware Image can be created"""
2366 self._SetupIfwi('fitimage.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002367 data = self._DoReadFile('111_x86_rom_ifwi.dts')
Simon Glass759af872019-07-08 13:18:54 -06002368 self._CheckIfwi(data)
2369
2370 def testPackX86RomIfwiNoDesc(self):
2371 """Test that an x86 ROM with IFWI can be created from an ifwi.bin file"""
2372 self._SetupIfwi('ifwi.bin')
Simon Glass1d167762019-08-24 07:23:01 -06002373 data = self._DoReadFile('112_x86_rom_ifwi_nodesc.dts')
Simon Glass759af872019-07-08 13:18:54 -06002374 self._CheckIfwi(data)
2375
2376 def testPackX86RomIfwiNoData(self):
2377 """Test that an x86 ROM with IFWI handles missing data"""
2378 self._SetupIfwi('ifwi.bin')
2379 with self.assertRaises(ValueError) as e:
Simon Glass1d167762019-08-24 07:23:01 -06002380 data = self._DoReadFile('113_x86_rom_ifwi_nodata.dts')
Simon Glass759af872019-07-08 13:18:54 -06002381 self.assertIn('Could not complete processing of contents',
2382 str(e.exception))
Simon Glass91710b32018-07-17 13:25:32 -06002383
Simon Glass66152ce2022-01-09 20:14:09 -07002384 def testIfwiMissing(self):
2385 """Test that binman still produces an image if ifwitool is missing"""
2386 self._SetupIfwi('fitimage.bin')
2387 with test_util.capture_sys_output() as (_, stderr):
2388 self._DoTestFile('111_x86_rom_ifwi.dts',
2389 force_missing_bintools='ifwitool')
2390 err = stderr.getvalue()
2391 self.assertRegex(err,
2392 "Image 'main-section'.*missing bintools.*: ifwitool")
2393
Simon Glassc2f1aed2019-07-08 13:18:56 -06002394 def testCbfsOffset(self):
2395 """Test a CBFS with files at particular offsets
2396
2397 Like all CFBS tests, this is just checking the logic that calls
2398 cbfs_util. See cbfs_util_test for fully tests (e.g. test_cbfs_offset()).
2399 """
2400 data = self._DoReadFile('114_cbfs_offset.dts')
2401 size = 0x200
2402
2403 cbfs = cbfs_util.CbfsReader(data)
2404 self.assertEqual(size, cbfs.rom_size)
2405
2406 self.assertIn('u-boot', cbfs.files)
2407 cfile = cbfs.files['u-boot']
2408 self.assertEqual(U_BOOT_DATA, cfile.data)
2409 self.assertEqual(0x40, cfile.cbfs_offset)
2410
2411 self.assertIn('u-boot-dtb', cbfs.files)
2412 cfile2 = cbfs.files['u-boot-dtb']
2413 self.assertEqual(U_BOOT_DTB_DATA, cfile2.data)
2414 self.assertEqual(0x140, cfile2.cbfs_offset)
2415
Simon Glass0f621332019-07-08 14:25:27 -06002416 def testFdtmap(self):
2417 """Test an FDT map can be inserted in the image"""
2418 data = self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2419 fdtmap_data = data[len(U_BOOT_DATA):]
2420 magic = fdtmap_data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002421 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07002422 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass0f621332019-07-08 14:25:27 -06002423
2424 fdt_data = fdtmap_data[16:]
2425 dtb = fdt.Fdt.FromData(fdt_data)
2426 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002427 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
Simon Glass0f621332019-07-08 14:25:27 -06002428 self.assertEqual({
2429 'image-pos': 0,
2430 'offset': 0,
2431 'u-boot:offset': 0,
2432 'u-boot:size': len(U_BOOT_DATA),
2433 'u-boot:image-pos': 0,
2434 'fdtmap:image-pos': 4,
2435 'fdtmap:offset': 4,
2436 'fdtmap:size': len(fdtmap_data),
2437 'size': len(data),
2438 }, props)
2439
2440 def testFdtmapNoMatch(self):
2441 """Check handling of an FDT map when the section cannot be found"""
2442 self.data = self._DoReadFileRealDtb('115_fdtmap.dts')
2443
2444 # Mangle the section name, which should cause a mismatch between the
2445 # correct FDT path and the one expected by the section
2446 image = control.images['image']
Simon Glasscec34ba2019-07-08 14:25:28 -06002447 image._node.path += '-suffix'
Simon Glass0f621332019-07-08 14:25:27 -06002448 entries = image.GetEntries()
2449 fdtmap = entries['fdtmap']
2450 with self.assertRaises(ValueError) as e:
2451 fdtmap._GetFdtmap()
2452 self.assertIn("Cannot locate node for path '/binman-suffix'",
2453 str(e.exception))
2454
Simon Glasscec34ba2019-07-08 14:25:28 -06002455 def testFdtmapHeader(self):
2456 """Test an FDT map and image header can be inserted in the image"""
2457 data = self.data = self._DoReadFileRealDtb('116_fdtmap_hdr.dts')
2458 fdtmap_pos = len(U_BOOT_DATA)
2459 fdtmap_data = data[fdtmap_pos:]
2460 fdt_data = fdtmap_data[16:]
2461 dtb = fdt.Fdt.FromData(fdt_data)
2462 fdt_size = dtb.GetFdtObj().totalsize()
2463 hdr_data = data[-8:]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002464 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002465 offset = struct.unpack('<I', hdr_data[4:])[0] & 0xffffffff
2466 self.assertEqual(fdtmap_pos - 0x400, offset - (1 << 32))
2467
2468 def testFdtmapHeaderStart(self):
2469 """Test an image header can be inserted at the image start"""
2470 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
2471 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2472 hdr_data = data[:8]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002473 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002474 offset = struct.unpack('<I', hdr_data[4:])[0]
2475 self.assertEqual(fdtmap_pos, offset)
2476
2477 def testFdtmapHeaderPos(self):
2478 """Test an image header can be inserted at a chosen position"""
2479 data = self.data = self._DoReadFileRealDtb('118_fdtmap_hdr_pos.dts')
2480 fdtmap_pos = 0x100 + len(U_BOOT_DATA)
2481 hdr_data = data[0x80:0x88]
Simon Glassc5fd10a2019-10-31 07:43:03 -06002482 self.assertEqual(b'BinM', hdr_data[:4])
Simon Glasscec34ba2019-07-08 14:25:28 -06002483 offset = struct.unpack('<I', hdr_data[4:])[0]
2484 self.assertEqual(fdtmap_pos, offset)
2485
2486 def testHeaderMissingFdtmap(self):
2487 """Test an image header requires an fdtmap"""
2488 with self.assertRaises(ValueError) as e:
2489 self.data = self._DoReadFileRealDtb('119_fdtmap_hdr_missing.dts')
2490 self.assertIn("'image_header' section must have an 'fdtmap' sibling",
2491 str(e.exception))
2492
2493 def testHeaderNoLocation(self):
2494 """Test an image header with a no specified location is detected"""
2495 with self.assertRaises(ValueError) as e:
2496 self.data = self._DoReadFileRealDtb('120_hdr_no_location.dts')
2497 self.assertIn("Invalid location 'None', expected 'start' or 'end'",
2498 str(e.exception))
2499
Simon Glasse61b6f62019-07-08 14:25:37 -06002500 def testEntryExpand(self):
Simon Glassdd156a42022-03-05 20:18:59 -07002501 """Test extending an entry after it is packed"""
2502 data = self._DoReadFile('121_entry_extend.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002503 self.assertEqual(b'aaa', data[:3])
2504 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2505 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002506
Simon Glassdd156a42022-03-05 20:18:59 -07002507 def testEntryExtendBad(self):
2508 """Test extending an entry after it is packed, twice"""
Simon Glasse61b6f62019-07-08 14:25:37 -06002509 with self.assertRaises(ValueError) as e:
Simon Glassdd156a42022-03-05 20:18:59 -07002510 self._DoReadFile('122_entry_extend_twice.dts')
Simon Glass9d8ee322019-07-20 12:23:58 -06002511 self.assertIn("Image '/binman': Entries changed size after packing",
Simon Glasse61b6f62019-07-08 14:25:37 -06002512 str(e.exception))
2513
Simon Glassdd156a42022-03-05 20:18:59 -07002514 def testEntryExtendSection(self):
2515 """Test extending an entry within a section after it is packed"""
2516 data = self._DoReadFile('123_entry_extend_section.dts')
Simon Glass8c702fb2019-07-20 12:23:57 -06002517 self.assertEqual(b'aaa', data[:3])
2518 self.assertEqual(U_BOOT_DATA, data[3:3 + len(U_BOOT_DATA)])
2519 self.assertEqual(b'aaa', data[-3:])
Simon Glasse61b6f62019-07-08 14:25:37 -06002520
Simon Glass90d29682019-07-08 14:25:38 -06002521 def testCompressDtb(self):
2522 """Test that compress of device-tree files is supported"""
2523 self._CheckLz4()
2524 data = self.data = self._DoReadFileRealDtb('124_compress_dtb.dts')
2525 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
2526 comp_data = data[len(U_BOOT_DATA):]
2527 orig = self._decompress(comp_data)
2528 dtb = fdt.Fdt.FromData(orig)
2529 dtb.Scan()
2530 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
2531 expected = {
2532 'u-boot:size': len(U_BOOT_DATA),
2533 'u-boot-dtb:uncomp-size': len(orig),
2534 'u-boot-dtb:size': len(comp_data),
2535 'size': len(data),
2536 }
2537 self.assertEqual(expected, props)
2538
Simon Glass151bbbf2019-07-08 14:25:41 -06002539 def testCbfsUpdateFdt(self):
2540 """Test that we can update the device tree with CBFS offset/size info"""
2541 self._CheckLz4()
2542 data, _, _, out_dtb_fname = self._DoReadFileDtb('125_cbfs_update.dts',
2543 update_dtb=True)
2544 dtb = fdt.Fdt(out_dtb_fname)
2545 dtb.Scan()
Simon Glass2c6adba2019-07-20 12:23:47 -06002546 props = self._GetPropTree(dtb, BASE_DTB_PROPS + ['uncomp-size'])
Simon Glass151bbbf2019-07-08 14:25:41 -06002547 del props['cbfs/u-boot:size']
2548 self.assertEqual({
2549 'offset': 0,
2550 'size': len(data),
2551 'image-pos': 0,
2552 'cbfs:offset': 0,
2553 'cbfs:size': len(data),
2554 'cbfs:image-pos': 0,
2555 'cbfs/u-boot:offset': 0x38,
2556 'cbfs/u-boot:uncomp-size': len(U_BOOT_DATA),
2557 'cbfs/u-boot:image-pos': 0x38,
2558 'cbfs/u-boot-dtb:offset': 0xb8,
2559 'cbfs/u-boot-dtb:size': len(U_BOOT_DATA),
2560 'cbfs/u-boot-dtb:image-pos': 0xb8,
2561 }, props)
2562
Simon Glass3c9b4f22019-07-08 14:25:42 -06002563 def testCbfsBadType(self):
2564 """Test an image header with a no specified location is detected"""
2565 with self.assertRaises(ValueError) as e:
2566 self._DoReadFile('126_cbfs_bad_type.dts')
2567 self.assertIn("Unknown cbfs-type 'badtype'", str(e.exception))
2568
Simon Glass6b156f82019-07-08 14:25:43 -06002569 def testList(self):
2570 """Test listing the files in an image"""
2571 self._CheckLz4()
2572 data = self._DoReadFile('127_list.dts')
2573 image = control.images['image']
2574 entries = image.BuildEntryList()
2575 self.assertEqual(7, len(entries))
2576
2577 ent = entries[0]
2578 self.assertEqual(0, ent.indent)
2579 self.assertEqual('main-section', ent.name)
2580 self.assertEqual('section', ent.etype)
2581 self.assertEqual(len(data), ent.size)
2582 self.assertEqual(0, ent.image_pos)
2583 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002584 self.assertEqual(0, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002585
2586 ent = entries[1]
2587 self.assertEqual(1, ent.indent)
2588 self.assertEqual('u-boot', ent.name)
2589 self.assertEqual('u-boot', ent.etype)
2590 self.assertEqual(len(U_BOOT_DATA), ent.size)
2591 self.assertEqual(0, ent.image_pos)
2592 self.assertEqual(None, ent.uncomp_size)
2593 self.assertEqual(0, ent.offset)
2594
2595 ent = entries[2]
2596 self.assertEqual(1, ent.indent)
2597 self.assertEqual('section', ent.name)
2598 self.assertEqual('section', ent.etype)
2599 section_size = ent.size
2600 self.assertEqual(0x100, ent.image_pos)
2601 self.assertEqual(None, ent.uncomp_size)
Simon Glass39dd2152019-07-08 14:25:47 -06002602 self.assertEqual(0x100, ent.offset)
Simon Glass6b156f82019-07-08 14:25:43 -06002603
2604 ent = entries[3]
2605 self.assertEqual(2, ent.indent)
2606 self.assertEqual('cbfs', ent.name)
2607 self.assertEqual('cbfs', ent.etype)
2608 self.assertEqual(0x400, ent.size)
2609 self.assertEqual(0x100, ent.image_pos)
2610 self.assertEqual(None, ent.uncomp_size)
2611 self.assertEqual(0, ent.offset)
2612
2613 ent = entries[4]
2614 self.assertEqual(3, ent.indent)
2615 self.assertEqual('u-boot', ent.name)
2616 self.assertEqual('u-boot', ent.etype)
2617 self.assertEqual(len(U_BOOT_DATA), ent.size)
2618 self.assertEqual(0x138, ent.image_pos)
2619 self.assertEqual(None, ent.uncomp_size)
2620 self.assertEqual(0x38, ent.offset)
2621
2622 ent = entries[5]
2623 self.assertEqual(3, ent.indent)
2624 self.assertEqual('u-boot-dtb', ent.name)
2625 self.assertEqual('text', ent.etype)
2626 self.assertGreater(len(COMPRESS_DATA), ent.size)
2627 self.assertEqual(0x178, ent.image_pos)
2628 self.assertEqual(len(COMPRESS_DATA), ent.uncomp_size)
2629 self.assertEqual(0x78, ent.offset)
2630
2631 ent = entries[6]
2632 self.assertEqual(2, ent.indent)
2633 self.assertEqual('u-boot-dtb', ent.name)
2634 self.assertEqual('u-boot-dtb', ent.etype)
2635 self.assertEqual(0x500, ent.image_pos)
2636 self.assertEqual(len(U_BOOT_DTB_DATA), ent.uncomp_size)
2637 dtb_size = ent.size
2638 # Compressing this data expands it since headers are added
2639 self.assertGreater(dtb_size, len(U_BOOT_DTB_DATA))
2640 self.assertEqual(0x400, ent.offset)
2641
2642 self.assertEqual(len(data), 0x100 + section_size)
2643 self.assertEqual(section_size, 0x400 + dtb_size)
2644
Simon Glass8d8bf4e2019-07-08 14:25:44 -06002645 def testFindFdtmap(self):
2646 """Test locating an FDT map in an image"""
2647 self._CheckLz4()
2648 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
2649 image = control.images['image']
2650 entries = image.GetEntries()
2651 entry = entries['fdtmap']
2652 self.assertEqual(entry.image_pos, fdtmap.LocateFdtmap(data))
2653
2654 def testFindFdtmapMissing(self):
2655 """Test failing to locate an FDP map"""
2656 data = self._DoReadFile('005_simple.dts')
2657 self.assertEqual(None, fdtmap.LocateFdtmap(data))
2658
Simon Glassed39a3c2019-07-08 14:25:45 -06002659 def testFindImageHeader(self):
2660 """Test locating a image header"""
2661 self._CheckLz4()
Simon Glassb8424fa2019-07-08 14:25:46 -06002662 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002663 image = control.images['image']
2664 entries = image.GetEntries()
2665 entry = entries['fdtmap']
2666 # The header should point to the FDT map
2667 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2668
2669 def testFindImageHeaderStart(self):
2670 """Test locating a image header located at the start of an image"""
Simon Glassb8424fa2019-07-08 14:25:46 -06002671 data = self.data = self._DoReadFileRealDtb('117_fdtmap_hdr_start.dts')
Simon Glassed39a3c2019-07-08 14:25:45 -06002672 image = control.images['image']
2673 entries = image.GetEntries()
2674 entry = entries['fdtmap']
2675 # The header should point to the FDT map
2676 self.assertEqual(entry.image_pos, image_header.LocateHeaderOffset(data))
2677
2678 def testFindImageHeaderMissing(self):
2679 """Test failing to locate an image header"""
2680 data = self._DoReadFile('005_simple.dts')
2681 self.assertEqual(None, image_header.LocateHeaderOffset(data))
2682
Simon Glassb8424fa2019-07-08 14:25:46 -06002683 def testReadImage(self):
2684 """Test reading an image and accessing its FDT map"""
2685 self._CheckLz4()
2686 data = self.data = self._DoReadFileRealDtb('128_decode_image.dts')
Simon Glass80025522022-01-29 14:14:04 -07002687 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002688 orig_image = control.images['image']
2689 image = Image.FromFile(image_fname)
2690 self.assertEqual(orig_image.GetEntries().keys(),
2691 image.GetEntries().keys())
2692
2693 orig_entry = orig_image.GetEntries()['fdtmap']
2694 entry = image.GetEntries()['fdtmap']
2695 self.assertEquals(orig_entry.offset, entry.offset)
2696 self.assertEquals(orig_entry.size, entry.size)
2697 self.assertEquals(orig_entry.image_pos, entry.image_pos)
2698
2699 def testReadImageNoHeader(self):
2700 """Test accessing an image's FDT map without an image header"""
2701 self._CheckLz4()
2702 data = self._DoReadFileRealDtb('129_decode_image_nohdr.dts')
Simon Glass80025522022-01-29 14:14:04 -07002703 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002704 image = Image.FromFile(image_fname)
2705 self.assertTrue(isinstance(image, Image))
Simon Glass072959a2019-07-20 12:23:50 -06002706 self.assertEqual('image', image.image_name[-5:])
Simon Glassb8424fa2019-07-08 14:25:46 -06002707
2708 def testReadImageFail(self):
2709 """Test failing to read an image image's FDT map"""
2710 self._DoReadFile('005_simple.dts')
Simon Glass80025522022-01-29 14:14:04 -07002711 image_fname = tools.get_output_filename('image.bin')
Simon Glassb8424fa2019-07-08 14:25:46 -06002712 with self.assertRaises(ValueError) as e:
2713 image = Image.FromFile(image_fname)
2714 self.assertIn("Cannot find FDT map in image", str(e.exception))
Simon Glassc2f1aed2019-07-08 13:18:56 -06002715
Simon Glassb2fd11d2019-07-08 14:25:48 -06002716 def testListCmd(self):
2717 """Test listing the files in an image using an Fdtmap"""
2718 self._CheckLz4()
2719 data = self._DoReadFileRealDtb('130_list_fdtmap.dts')
2720
2721 # lz4 compression size differs depending on the version
2722 image = control.images['image']
2723 entries = image.GetEntries()
2724 section_size = entries['section'].size
2725 fdt_size = entries['section'].GetEntries()['u-boot-dtb'].size
2726 fdtmap_offset = entries['fdtmap'].offset
2727
Simon Glassb3d6fc72019-07-20 12:24:10 -06002728 try:
2729 tmpdir, updated_fname = self._SetupImageInTmpdir()
2730 with test_util.capture_sys_output() as (stdout, stderr):
2731 self._DoBinman('ls', '-i', updated_fname)
2732 finally:
2733 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002734 lines = stdout.getvalue().splitlines()
2735 expected = [
2736'Name Image-pos Size Entry-type Offset Uncomp-size',
2737'----------------------------------------------------------------------',
2738'main-section 0 c00 section 0',
2739' u-boot 0 4 u-boot 0',
2740' section 100 %x section 100' % section_size,
2741' cbfs 100 400 cbfs 0',
2742' u-boot 138 4 u-boot 38',
Simon Glassc5fd10a2019-10-31 07:43:03 -06002743' u-boot-dtb 180 105 u-boot-dtb 80 3c9',
Simon Glassb2fd11d2019-07-08 14:25:48 -06002744' u-boot-dtb 500 %x u-boot-dtb 400 3c9' % fdt_size,
Simon Glassc5fd10a2019-10-31 07:43:03 -06002745' fdtmap %x 3bd fdtmap %x' %
Simon Glassb2fd11d2019-07-08 14:25:48 -06002746 (fdtmap_offset, fdtmap_offset),
2747' image-header bf8 8 image-header bf8',
2748 ]
2749 self.assertEqual(expected, lines)
2750
2751 def testListCmdFail(self):
2752 """Test failing to list an image"""
2753 self._DoReadFile('005_simple.dts')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002754 try:
2755 tmpdir, updated_fname = self._SetupImageInTmpdir()
2756 with self.assertRaises(ValueError) as e:
2757 self._DoBinman('ls', '-i', updated_fname)
2758 finally:
2759 shutil.rmtree(tmpdir)
Simon Glassb2fd11d2019-07-08 14:25:48 -06002760 self.assertIn("Cannot find FDT map in image", str(e.exception))
2761
2762 def _RunListCmd(self, paths, expected):
2763 """List out entries and check the result
2764
2765 Args:
2766 paths: List of paths to pass to the list command
2767 expected: Expected list of filenames to be returned, in order
2768 """
2769 self._CheckLz4()
2770 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002771 image_fname = tools.get_output_filename('image.bin')
Simon Glassb2fd11d2019-07-08 14:25:48 -06002772 image = Image.FromFile(image_fname)
2773 lines = image.GetListEntries(paths)[1]
2774 files = [line[0].strip() for line in lines[1:]]
2775 self.assertEqual(expected, files)
2776
2777 def testListCmdSection(self):
2778 """Test listing the files in a section"""
2779 self._RunListCmd(['section'],
2780 ['section', 'cbfs', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2781
2782 def testListCmdFile(self):
2783 """Test listing a particular file"""
2784 self._RunListCmd(['*u-boot-dtb'], ['u-boot-dtb', 'u-boot-dtb'])
2785
2786 def testListCmdWildcard(self):
2787 """Test listing a wildcarded file"""
2788 self._RunListCmd(['*boot*'],
2789 ['u-boot', 'u-boot', 'u-boot-dtb', 'u-boot-dtb'])
2790
2791 def testListCmdWildcardMulti(self):
2792 """Test listing a wildcarded file"""
2793 self._RunListCmd(['*cb*', '*head*'],
2794 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
2795
2796 def testListCmdEmpty(self):
2797 """Test listing a wildcarded file"""
2798 self._RunListCmd(['nothing'], [])
2799
2800 def testListCmdPath(self):
2801 """Test listing the files in a sub-entry of a section"""
2802 self._RunListCmd(['section/cbfs'], ['cbfs', 'u-boot', 'u-boot-dtb'])
2803
Simon Glass4c613bf2019-07-08 14:25:50 -06002804 def _RunExtractCmd(self, entry_name, decomp=True):
2805 """Extract an entry from an image
2806
2807 Args:
2808 entry_name: Entry name to extract
2809 decomp: True to decompress the data if compressed, False to leave
2810 it in its raw uncompressed format
2811
2812 Returns:
2813 data from entry
2814 """
2815 self._CheckLz4()
2816 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002817 image_fname = tools.get_output_filename('image.bin')
Simon Glass4c613bf2019-07-08 14:25:50 -06002818 return control.ReadEntry(image_fname, entry_name, decomp)
2819
2820 def testExtractSimple(self):
2821 """Test extracting a single file"""
2822 data = self._RunExtractCmd('u-boot')
2823 self.assertEqual(U_BOOT_DATA, data)
2824
Simon Glass980a2842019-07-08 14:25:52 -06002825 def testExtractSection(self):
2826 """Test extracting the files in a section"""
2827 data = self._RunExtractCmd('section')
2828 cbfs_data = data[:0x400]
2829 cbfs = cbfs_util.CbfsReader(cbfs_data)
Simon Glassc5fd10a2019-10-31 07:43:03 -06002830 self.assertEqual(['u-boot', 'u-boot-dtb', ''], list(cbfs.files.keys()))
Simon Glass980a2842019-07-08 14:25:52 -06002831 dtb_data = data[0x400:]
2832 dtb = self._decompress(dtb_data)
2833 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2834
2835 def testExtractCompressed(self):
2836 """Test extracting compressed data"""
2837 data = self._RunExtractCmd('section/u-boot-dtb')
2838 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2839
2840 def testExtractRaw(self):
2841 """Test extracting compressed data without decompressing it"""
2842 data = self._RunExtractCmd('section/u-boot-dtb', decomp=False)
2843 dtb = self._decompress(data)
2844 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2845
2846 def testExtractCbfs(self):
2847 """Test extracting CBFS data"""
2848 data = self._RunExtractCmd('section/cbfs/u-boot')
2849 self.assertEqual(U_BOOT_DATA, data)
2850
2851 def testExtractCbfsCompressed(self):
2852 """Test extracting CBFS compressed data"""
2853 data = self._RunExtractCmd('section/cbfs/u-boot-dtb')
2854 self.assertEqual(EXTRACT_DTB_SIZE, len(data))
2855
2856 def testExtractCbfsRaw(self):
2857 """Test extracting CBFS compressed data without decompressing it"""
2858 data = self._RunExtractCmd('section/cbfs/u-boot-dtb', decomp=False)
Simon Glassdd5c14ec2022-01-09 20:14:04 -07002859 dtb = comp_util.decompress(data, 'lzma', with_header=False)
Simon Glass980a2842019-07-08 14:25:52 -06002860 self.assertEqual(EXTRACT_DTB_SIZE, len(dtb))
2861
Simon Glass4c613bf2019-07-08 14:25:50 -06002862 def testExtractBadEntry(self):
2863 """Test extracting a bad section path"""
2864 with self.assertRaises(ValueError) as e:
2865 self._RunExtractCmd('section/does-not-exist')
2866 self.assertIn("Entry 'does-not-exist' not found in '/section'",
2867 str(e.exception))
2868
2869 def testExtractMissingFile(self):
2870 """Test extracting file that does not exist"""
2871 with self.assertRaises(IOError) as e:
2872 control.ReadEntry('missing-file', 'name')
2873
2874 def testExtractBadFile(self):
2875 """Test extracting an invalid file"""
2876 fname = os.path.join(self._indir, 'badfile')
Simon Glass80025522022-01-29 14:14:04 -07002877 tools.write_file(fname, b'')
Simon Glass4c613bf2019-07-08 14:25:50 -06002878 with self.assertRaises(ValueError) as e:
2879 control.ReadEntry(fname, 'name')
2880
Simon Glass980a2842019-07-08 14:25:52 -06002881 def testExtractCmd(self):
2882 """Test extracting a file fron an image on the command line"""
2883 self._CheckLz4()
2884 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass980a2842019-07-08 14:25:52 -06002885 fname = os.path.join(self._indir, 'output.extact')
Simon Glassb3d6fc72019-07-20 12:24:10 -06002886 try:
2887 tmpdir, updated_fname = self._SetupImageInTmpdir()
2888 with test_util.capture_sys_output() as (stdout, stderr):
2889 self._DoBinman('extract', '-i', updated_fname, 'u-boot',
2890 '-f', fname)
2891 finally:
2892 shutil.rmtree(tmpdir)
Simon Glass80025522022-01-29 14:14:04 -07002893 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002894 self.assertEqual(U_BOOT_DATA, data)
2895
2896 def testExtractOneEntry(self):
2897 """Test extracting a single entry fron an image """
2898 self._CheckLz4()
2899 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002900 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002901 fname = os.path.join(self._indir, 'output.extact')
2902 control.ExtractEntries(image_fname, fname, None, ['u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07002903 data = tools.read_file(fname)
Simon Glass980a2842019-07-08 14:25:52 -06002904 self.assertEqual(U_BOOT_DATA, data)
2905
2906 def _CheckExtractOutput(self, decomp):
2907 """Helper to test file output with and without decompression
2908
2909 Args:
2910 decomp: True to decompress entry data, False to output it raw
2911 """
2912 def _CheckPresent(entry_path, expect_data, expect_size=None):
2913 """Check and remove expected file
2914
2915 This checks the data/size of a file and removes the file both from
2916 the outfiles set and from the output directory. Once all files are
2917 processed, both the set and directory should be empty.
2918
2919 Args:
2920 entry_path: Entry path
2921 expect_data: Data to expect in file, or None to skip check
2922 expect_size: Size of data to expect in file, or None to skip
2923 """
2924 path = os.path.join(outdir, entry_path)
Simon Glass80025522022-01-29 14:14:04 -07002925 data = tools.read_file(path)
Simon Glass980a2842019-07-08 14:25:52 -06002926 os.remove(path)
2927 if expect_data:
2928 self.assertEqual(expect_data, data)
2929 elif expect_size:
2930 self.assertEqual(expect_size, len(data))
2931 outfiles.remove(path)
2932
2933 def _CheckDirPresent(name):
2934 """Remove expected directory
2935
2936 This gives an error if the directory does not exist as expected
2937
2938 Args:
2939 name: Name of directory to remove
2940 """
2941 path = os.path.join(outdir, name)
2942 os.rmdir(path)
2943
2944 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07002945 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06002946 outdir = os.path.join(self._indir, 'extract')
2947 einfos = control.ExtractEntries(image_fname, None, outdir, [], decomp)
2948
2949 # Create a set of all file that were output (should be 9)
2950 outfiles = set()
2951 for root, dirs, files in os.walk(outdir):
2952 outfiles |= set([os.path.join(root, fname) for fname in files])
2953 self.assertEqual(9, len(outfiles))
2954 self.assertEqual(9, len(einfos))
2955
2956 image = control.images['image']
2957 entries = image.GetEntries()
2958
2959 # Check the 9 files in various ways
2960 section = entries['section']
2961 section_entries = section.GetEntries()
2962 cbfs_entries = section_entries['cbfs'].GetEntries()
2963 _CheckPresent('u-boot', U_BOOT_DATA)
2964 _CheckPresent('section/cbfs/u-boot', U_BOOT_DATA)
2965 dtb_len = EXTRACT_DTB_SIZE
2966 if not decomp:
2967 dtb_len = cbfs_entries['u-boot-dtb'].size
2968 _CheckPresent('section/cbfs/u-boot-dtb', None, dtb_len)
2969 if not decomp:
2970 dtb_len = section_entries['u-boot-dtb'].size
2971 _CheckPresent('section/u-boot-dtb', None, dtb_len)
2972
2973 fdtmap = entries['fdtmap']
2974 _CheckPresent('fdtmap', fdtmap.data)
2975 hdr = entries['image-header']
2976 _CheckPresent('image-header', hdr.data)
2977
2978 _CheckPresent('section/root', section.data)
2979 cbfs = section_entries['cbfs']
2980 _CheckPresent('section/cbfs/root', cbfs.data)
Simon Glass80025522022-01-29 14:14:04 -07002981 data = tools.read_file(image_fname)
Simon Glass980a2842019-07-08 14:25:52 -06002982 _CheckPresent('root', data)
2983
2984 # There should be no files left. Remove all the directories to check.
2985 # If there are any files/dirs remaining, one of these checks will fail.
2986 self.assertEqual(0, len(outfiles))
2987 _CheckDirPresent('section/cbfs')
2988 _CheckDirPresent('section')
2989 _CheckDirPresent('')
2990 self.assertFalse(os.path.exists(outdir))
2991
2992 def testExtractAllEntries(self):
2993 """Test extracting all entries"""
2994 self._CheckLz4()
2995 self._CheckExtractOutput(decomp=True)
2996
2997 def testExtractAllEntriesRaw(self):
2998 """Test extracting all entries without decompressing them"""
2999 self._CheckLz4()
3000 self._CheckExtractOutput(decomp=False)
3001
3002 def testExtractSelectedEntries(self):
3003 """Test extracting some entries"""
3004 self._CheckLz4()
3005 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003006 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003007 outdir = os.path.join(self._indir, 'extract')
3008 einfos = control.ExtractEntries(image_fname, None, outdir,
3009 ['*cb*', '*head*'])
3010
3011 # File output is tested by testExtractAllEntries(), so just check that
3012 # the expected entries are selected
3013 names = [einfo.name for einfo in einfos]
3014 self.assertEqual(names,
3015 ['cbfs', 'u-boot', 'u-boot-dtb', 'image-header'])
3016
3017 def testExtractNoEntryPaths(self):
3018 """Test extracting some entries"""
3019 self._CheckLz4()
3020 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003021 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003022 with self.assertRaises(ValueError) as e:
3023 control.ExtractEntries(image_fname, 'fname', None, [])
Simon Glassa772d3f2019-07-20 12:24:14 -06003024 self.assertIn('Must specify an entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003025 str(e.exception))
3026
3027 def testExtractTooManyEntryPaths(self):
3028 """Test extracting some entries"""
3029 self._CheckLz4()
3030 self._DoReadFileRealDtb('130_list_fdtmap.dts')
Simon Glass80025522022-01-29 14:14:04 -07003031 image_fname = tools.get_output_filename('image.bin')
Simon Glass980a2842019-07-08 14:25:52 -06003032 with self.assertRaises(ValueError) as e:
3033 control.ExtractEntries(image_fname, 'fname', None, ['a', 'b'])
Simon Glassa772d3f2019-07-20 12:24:14 -06003034 self.assertIn('Must specify exactly one entry path to write with -f',
Simon Glass980a2842019-07-08 14:25:52 -06003035 str(e.exception))
3036
Simon Glass52d06212019-07-08 14:25:53 -06003037 def testPackAlignSection(self):
3038 """Test that sections can have alignment"""
3039 self._DoReadFile('131_pack_align_section.dts')
3040
3041 self.assertIn('image', control.images)
3042 image = control.images['image']
3043 entries = image.GetEntries()
3044 self.assertEqual(3, len(entries))
3045
3046 # First u-boot
3047 self.assertIn('u-boot', entries)
3048 entry = entries['u-boot']
3049 self.assertEqual(0, entry.offset)
3050 self.assertEqual(0, entry.image_pos)
3051 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3052 self.assertEqual(len(U_BOOT_DATA), entry.size)
3053
3054 # Section0
3055 self.assertIn('section0', entries)
3056 section0 = entries['section0']
3057 self.assertEqual(0x10, section0.offset)
3058 self.assertEqual(0x10, section0.image_pos)
3059 self.assertEqual(len(U_BOOT_DATA), section0.size)
3060
3061 # Second u-boot
3062 section_entries = section0.GetEntries()
3063 self.assertIn('u-boot', section_entries)
3064 entry = section_entries['u-boot']
3065 self.assertEqual(0, entry.offset)
3066 self.assertEqual(0x10, entry.image_pos)
3067 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3068 self.assertEqual(len(U_BOOT_DATA), entry.size)
3069
3070 # Section1
3071 self.assertIn('section1', entries)
3072 section1 = entries['section1']
3073 self.assertEqual(0x14, section1.offset)
3074 self.assertEqual(0x14, section1.image_pos)
3075 self.assertEqual(0x20, section1.size)
3076
3077 # Second u-boot
3078 section_entries = section1.GetEntries()
3079 self.assertIn('u-boot', section_entries)
3080 entry = section_entries['u-boot']
3081 self.assertEqual(0, entry.offset)
3082 self.assertEqual(0x14, entry.image_pos)
3083 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3084 self.assertEqual(len(U_BOOT_DATA), entry.size)
3085
3086 # Section2
3087 self.assertIn('section2', section_entries)
3088 section2 = section_entries['section2']
3089 self.assertEqual(0x4, section2.offset)
3090 self.assertEqual(0x18, section2.image_pos)
3091 self.assertEqual(4, section2.size)
3092
3093 # Third u-boot
3094 section_entries = section2.GetEntries()
3095 self.assertIn('u-boot', section_entries)
3096 entry = section_entries['u-boot']
3097 self.assertEqual(0, entry.offset)
3098 self.assertEqual(0x18, entry.image_pos)
3099 self.assertEqual(len(U_BOOT_DATA), entry.contents_size)
3100 self.assertEqual(len(U_BOOT_DATA), entry.size)
3101
Simon Glassf8a54bc2019-07-20 12:23:56 -06003102 def _RunReplaceCmd(self, entry_name, data, decomp=True, allow_resize=True,
3103 dts='132_replace.dts'):
Simon Glass072959a2019-07-20 12:23:50 -06003104 """Replace an entry in an image
3105
3106 This writes the entry data to update it, then opens the updated file and
3107 returns the value that it now finds there.
3108
3109 Args:
3110 entry_name: Entry name to replace
3111 data: Data to replace it with
3112 decomp: True to compress the data if needed, False if data is
3113 already compressed so should be used as is
Simon Glassf8a54bc2019-07-20 12:23:56 -06003114 allow_resize: True to allow entries to change size, False to raise
3115 an exception
Simon Glass072959a2019-07-20 12:23:50 -06003116
3117 Returns:
3118 Tuple:
3119 data from entry
3120 data from fdtmap (excluding header)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003121 Image object that was modified
Simon Glass072959a2019-07-20 12:23:50 -06003122 """
Simon Glassf8a54bc2019-07-20 12:23:56 -06003123 dtb_data = self._DoReadFileDtb(dts, use_real_dtb=True,
Simon Glass072959a2019-07-20 12:23:50 -06003124 update_dtb=True)[1]
3125
3126 self.assertIn('image', control.images)
3127 image = control.images['image']
3128 entries = image.GetEntries()
3129 orig_dtb_data = entries['u-boot-dtb'].data
3130 orig_fdtmap_data = entries['fdtmap'].data
3131
Simon Glass80025522022-01-29 14:14:04 -07003132 image_fname = tools.get_output_filename('image.bin')
3133 updated_fname = tools.get_output_filename('image-updated.bin')
3134 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glassf8a54bc2019-07-20 12:23:56 -06003135 image = control.WriteEntry(updated_fname, entry_name, data, decomp,
3136 allow_resize)
Simon Glass072959a2019-07-20 12:23:50 -06003137 data = control.ReadEntry(updated_fname, entry_name, decomp)
3138
Simon Glassf8a54bc2019-07-20 12:23:56 -06003139 # The DT data should not change unless resized:
3140 if not allow_resize:
3141 new_dtb_data = entries['u-boot-dtb'].data
3142 self.assertEqual(new_dtb_data, orig_dtb_data)
3143 new_fdtmap_data = entries['fdtmap'].data
3144 self.assertEqual(new_fdtmap_data, orig_fdtmap_data)
Simon Glass072959a2019-07-20 12:23:50 -06003145
Simon Glassf8a54bc2019-07-20 12:23:56 -06003146 return data, orig_fdtmap_data[fdtmap.FDTMAP_HDR_LEN:], image
Simon Glass072959a2019-07-20 12:23:50 -06003147
3148 def testReplaceSimple(self):
3149 """Test replacing a single file"""
3150 expected = b'x' * len(U_BOOT_DATA)
Simon Glassf8a54bc2019-07-20 12:23:56 -06003151 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected,
3152 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003153 self.assertEqual(expected, data)
3154
3155 # Test that the state looks right. There should be an FDT for the fdtmap
3156 # that we jsut read back in, and it should match what we find in the
3157 # 'control' tables. Checking for an FDT that does not exist should
3158 # return None.
3159 path, fdtmap = state.GetFdtContents('fdtmap')
Simon Glassf8a54bc2019-07-20 12:23:56 -06003160 self.assertIsNotNone(path)
Simon Glass072959a2019-07-20 12:23:50 -06003161 self.assertEqual(expected_fdtmap, fdtmap)
3162
3163 dtb = state.GetFdtForEtype('fdtmap')
3164 self.assertEqual(dtb.GetContents(), fdtmap)
3165
3166 missing_path, missing_fdtmap = state.GetFdtContents('missing')
3167 self.assertIsNone(missing_path)
3168 self.assertIsNone(missing_fdtmap)
3169
3170 missing_dtb = state.GetFdtForEtype('missing')
3171 self.assertIsNone(missing_dtb)
3172
3173 self.assertEqual('/binman', state.fdt_path_prefix)
3174
3175 def testReplaceResizeFail(self):
3176 """Test replacing a file by something larger"""
3177 expected = U_BOOT_DATA + b'x'
3178 with self.assertRaises(ValueError) as e:
Simon Glassf8a54bc2019-07-20 12:23:56 -06003179 self._RunReplaceCmd('u-boot', expected, allow_resize=False,
3180 dts='139_replace_repack.dts')
Simon Glass072959a2019-07-20 12:23:50 -06003181 self.assertIn("Node '/u-boot': Entry data size does not match, but resize is disabled",
3182 str(e.exception))
3183
3184 def testReplaceMulti(self):
3185 """Test replacing entry data where multiple images are generated"""
3186 data = self._DoReadFileDtb('133_replace_multi.dts', use_real_dtb=True,
3187 update_dtb=True)[0]
3188 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003189 updated_fname = tools.get_output_filename('image-updated.bin')
3190 tools.write_file(updated_fname, data)
Simon Glass072959a2019-07-20 12:23:50 -06003191 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003192 control.WriteEntry(updated_fname, entry_name, expected,
3193 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003194 data = control.ReadEntry(updated_fname, entry_name)
3195 self.assertEqual(expected, data)
3196
3197 # Check the state looks right.
3198 self.assertEqual('/binman/image', state.fdt_path_prefix)
3199
3200 # Now check we can write the first image
Simon Glass80025522022-01-29 14:14:04 -07003201 image_fname = tools.get_output_filename('first-image.bin')
3202 updated_fname = tools.get_output_filename('first-updated.bin')
3203 tools.write_file(updated_fname, tools.read_file(image_fname))
Simon Glass072959a2019-07-20 12:23:50 -06003204 entry_name = 'u-boot'
Simon Glassf8a54bc2019-07-20 12:23:56 -06003205 control.WriteEntry(updated_fname, entry_name, expected,
3206 allow_resize=False)
Simon Glass072959a2019-07-20 12:23:50 -06003207 data = control.ReadEntry(updated_fname, entry_name)
3208 self.assertEqual(expected, data)
3209
3210 # Check the state looks right.
3211 self.assertEqual('/binman/first-image', state.fdt_path_prefix)
Simon Glass39dd2152019-07-08 14:25:47 -06003212
Simon Glassfb30e292019-07-20 12:23:51 -06003213 def testUpdateFdtAllRepack(self):
3214 """Test that all device trees are updated with offset/size info"""
3215 data = self._DoReadFileRealDtb('134_fdt_update_all_repack.dts')
3216 SECTION_SIZE = 0x300
3217 DTB_SIZE = 602
3218 FDTMAP_SIZE = 608
3219 base_expected = {
3220 'offset': 0,
3221 'size': SECTION_SIZE + DTB_SIZE * 2 + FDTMAP_SIZE,
3222 'image-pos': 0,
3223 'section:offset': 0,
3224 'section:size': SECTION_SIZE,
3225 'section:image-pos': 0,
3226 'section/u-boot-dtb:offset': 4,
3227 'section/u-boot-dtb:size': 636,
3228 'section/u-boot-dtb:image-pos': 4,
3229 'u-boot-spl-dtb:offset': SECTION_SIZE,
3230 'u-boot-spl-dtb:size': DTB_SIZE,
3231 'u-boot-spl-dtb:image-pos': SECTION_SIZE,
3232 'u-boot-tpl-dtb:offset': SECTION_SIZE + DTB_SIZE,
3233 'u-boot-tpl-dtb:image-pos': SECTION_SIZE + DTB_SIZE,
3234 'u-boot-tpl-dtb:size': DTB_SIZE,
3235 'fdtmap:offset': SECTION_SIZE + DTB_SIZE * 2,
3236 'fdtmap:size': FDTMAP_SIZE,
3237 'fdtmap:image-pos': SECTION_SIZE + DTB_SIZE * 2,
3238 }
3239 main_expected = {
3240 'section:orig-size': SECTION_SIZE,
3241 'section/u-boot-dtb:orig-offset': 4,
3242 }
3243
3244 # We expect three device-tree files in the output, with the first one
3245 # within a fixed-size section.
3246 # Read them in sequence. We look for an 'spl' property in the SPL tree,
3247 # and 'tpl' in the TPL tree, to make sure they are distinct from the
3248 # main U-Boot tree. All three should have the same positions and offset
3249 # except that the main tree should include the main_expected properties
3250 start = 4
3251 for item in ['', 'spl', 'tpl', None]:
3252 if item is None:
3253 start += 16 # Move past fdtmap header
3254 dtb = fdt.Fdt.FromData(data[start:])
3255 dtb.Scan()
3256 props = self._GetPropTree(dtb,
3257 BASE_DTB_PROPS + REPACK_DTB_PROPS + ['spl', 'tpl'],
3258 prefix='/' if item is None else '/binman/')
3259 expected = dict(base_expected)
3260 if item:
3261 expected[item] = 0
3262 else:
3263 # Main DTB and fdtdec should include the 'orig-' properties
3264 expected.update(main_expected)
3265 # Helpful for debugging:
3266 #for prop in sorted(props):
3267 #print('prop %s %s %s' % (prop, props[prop], expected[prop]))
3268 self.assertEqual(expected, props)
3269 if item == '':
3270 start = SECTION_SIZE
3271 else:
3272 start += dtb._fdt_obj.totalsize()
3273
Simon Glass11453762019-07-20 12:23:55 -06003274 def testFdtmapHeaderMiddle(self):
3275 """Test an FDT map in the middle of an image when it should be at end"""
3276 with self.assertRaises(ValueError) as e:
3277 self._DoReadFileRealDtb('135_fdtmap_hdr_middle.dts')
3278 self.assertIn("Invalid sibling order 'middle' for image-header: Must be at 'end' to match location",
3279 str(e.exception))
3280
3281 def testFdtmapHeaderStartBad(self):
3282 """Test an FDT map in middle of an image when it should be at start"""
3283 with self.assertRaises(ValueError) as e:
3284 self._DoReadFileRealDtb('136_fdtmap_hdr_startbad.dts')
3285 self.assertIn("Invalid sibling order 'end' for image-header: Must be at 'start' to match location",
3286 str(e.exception))
3287
3288 def testFdtmapHeaderEndBad(self):
3289 """Test an FDT map at the start of an image when it should be at end"""
3290 with self.assertRaises(ValueError) as e:
3291 self._DoReadFileRealDtb('137_fdtmap_hdr_endbad.dts')
3292 self.assertIn("Invalid sibling order 'start' for image-header: Must be at 'end' to match location",
3293 str(e.exception))
3294
3295 def testFdtmapHeaderNoSize(self):
3296 """Test an image header at the end of an image with undefined size"""
3297 self._DoReadFileRealDtb('138_fdtmap_hdr_nosize.dts')
3298
Simon Glassf8a54bc2019-07-20 12:23:56 -06003299 def testReplaceResize(self):
3300 """Test replacing a single file in an entry with a larger file"""
3301 expected = U_BOOT_DATA + b'x'
3302 data, _, image = self._RunReplaceCmd('u-boot', expected,
3303 dts='139_replace_repack.dts')
3304 self.assertEqual(expected, data)
3305
3306 entries = image.GetEntries()
3307 dtb_data = entries['u-boot-dtb'].data
3308 dtb = fdt.Fdt.FromData(dtb_data)
3309 dtb.Scan()
3310
3311 # The u-boot section should now be larger in the dtb
3312 node = dtb.GetNode('/binman/u-boot')
3313 self.assertEqual(len(expected), fdt_util.GetInt(node, 'size'))
3314
3315 # Same for the fdtmap
3316 fdata = entries['fdtmap'].data
3317 fdtb = fdt.Fdt.FromData(fdata[fdtmap.FDTMAP_HDR_LEN:])
3318 fdtb.Scan()
3319 fnode = fdtb.GetNode('/u-boot')
3320 self.assertEqual(len(expected), fdt_util.GetInt(fnode, 'size'))
3321
3322 def testReplaceResizeNoRepack(self):
3323 """Test replacing an entry with a larger file when not allowed"""
3324 expected = U_BOOT_DATA + b'x'
3325 with self.assertRaises(ValueError) as e:
3326 self._RunReplaceCmd('u-boot', expected)
3327 self.assertIn('Entry data size does not match, but allow-repack is not present for this image',
3328 str(e.exception))
3329
Simon Glass9d8ee322019-07-20 12:23:58 -06003330 def testEntryShrink(self):
3331 """Test contracting an entry after it is packed"""
3332 try:
3333 state.SetAllowEntryContraction(True)
3334 data = self._DoReadFileDtb('140_entry_shrink.dts',
3335 update_dtb=True)[0]
3336 finally:
3337 state.SetAllowEntryContraction(False)
3338 self.assertEqual(b'a', data[:1])
3339 self.assertEqual(U_BOOT_DATA, data[1:1 + len(U_BOOT_DATA)])
3340 self.assertEqual(b'a', data[-1:])
3341
3342 def testEntryShrinkFail(self):
3343 """Test not being allowed to contract an entry after it is packed"""
3344 data = self._DoReadFileDtb('140_entry_shrink.dts', update_dtb=True)[0]
3345
3346 # In this case there is a spare byte at the end of the data. The size of
3347 # the contents is only 1 byte but we still have the size before it
3348 # shrunk.
3349 self.assertEqual(b'a\0', data[:2])
3350 self.assertEqual(U_BOOT_DATA, data[2:2 + len(U_BOOT_DATA)])
3351 self.assertEqual(b'a\0', data[-2:])
3352
Simon Glass70e32982019-07-20 12:24:01 -06003353 def testDescriptorOffset(self):
3354 """Test that the Intel descriptor is always placed at at the start"""
3355 data = self._DoReadFileDtb('141_descriptor_offset.dts')
3356 image = control.images['image']
3357 entries = image.GetEntries()
3358 desc = entries['intel-descriptor']
3359 self.assertEqual(0xff800000, desc.offset);
3360 self.assertEqual(0xff800000, desc.image_pos);
3361
Simon Glass37fdd142019-07-20 12:24:06 -06003362 def testReplaceCbfs(self):
3363 """Test replacing a single file in CBFS without changing the size"""
3364 self._CheckLz4()
3365 expected = b'x' * len(U_BOOT_DATA)
3366 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003367 updated_fname = tools.get_output_filename('image-updated.bin')
3368 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003369 entry_name = 'section/cbfs/u-boot'
3370 control.WriteEntry(updated_fname, entry_name, expected,
3371 allow_resize=True)
3372 data = control.ReadEntry(updated_fname, entry_name)
3373 self.assertEqual(expected, data)
3374
3375 def testReplaceResizeCbfs(self):
3376 """Test replacing a single file in CBFS with one of a different size"""
3377 self._CheckLz4()
3378 expected = U_BOOT_DATA + b'x'
3379 data = self._DoReadFileRealDtb('142_replace_cbfs.dts')
Simon Glass80025522022-01-29 14:14:04 -07003380 updated_fname = tools.get_output_filename('image-updated.bin')
3381 tools.write_file(updated_fname, data)
Simon Glass37fdd142019-07-20 12:24:06 -06003382 entry_name = 'section/cbfs/u-boot'
3383 control.WriteEntry(updated_fname, entry_name, expected,
3384 allow_resize=True)
3385 data = control.ReadEntry(updated_fname, entry_name)
3386 self.assertEqual(expected, data)
3387
Simon Glass30033c22019-07-20 12:24:15 -06003388 def _SetupForReplace(self):
3389 """Set up some files to use to replace entries
3390
3391 This generates an image, copies it to a new file, extracts all the files
3392 in it and updates some of them
3393
3394 Returns:
3395 List
3396 Image filename
3397 Output directory
3398 Expected values for updated entries, each a string
3399 """
3400 data = self._DoReadFileRealDtb('143_replace_all.dts')
3401
Simon Glass80025522022-01-29 14:14:04 -07003402 updated_fname = tools.get_output_filename('image-updated.bin')
3403 tools.write_file(updated_fname, data)
Simon Glass30033c22019-07-20 12:24:15 -06003404
3405 outdir = os.path.join(self._indir, 'extract')
3406 einfos = control.ExtractEntries(updated_fname, None, outdir, [])
3407
3408 expected1 = b'x' + U_BOOT_DATA + b'y'
3409 u_boot_fname1 = os.path.join(outdir, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07003410 tools.write_file(u_boot_fname1, expected1)
Simon Glass30033c22019-07-20 12:24:15 -06003411
3412 expected2 = b'a' + U_BOOT_DATA + b'b'
3413 u_boot_fname2 = os.path.join(outdir, 'u-boot2')
Simon Glass80025522022-01-29 14:14:04 -07003414 tools.write_file(u_boot_fname2, expected2)
Simon Glass30033c22019-07-20 12:24:15 -06003415
3416 expected_text = b'not the same text'
3417 text_fname = os.path.join(outdir, 'text')
Simon Glass80025522022-01-29 14:14:04 -07003418 tools.write_file(text_fname, expected_text)
Simon Glass30033c22019-07-20 12:24:15 -06003419
3420 dtb_fname = os.path.join(outdir, 'u-boot-dtb')
3421 dtb = fdt.FdtScan(dtb_fname)
3422 node = dtb.GetNode('/binman/text')
3423 node.AddString('my-property', 'the value')
3424 dtb.Sync(auto_resize=True)
3425 dtb.Flush()
3426
3427 return updated_fname, outdir, expected1, expected2, expected_text
3428
3429 def _CheckReplaceMultiple(self, entry_paths):
3430 """Handle replacing the contents of multiple entries
3431
3432 Args:
3433 entry_paths: List of entry paths to replace
3434
3435 Returns:
3436 List
3437 Dict of entries in the image:
3438 key: Entry name
3439 Value: Entry object
3440 Expected values for updated entries, each a string
3441 """
3442 updated_fname, outdir, expected1, expected2, expected_text = (
3443 self._SetupForReplace())
3444 control.ReplaceEntries(updated_fname, None, outdir, entry_paths)
3445
3446 image = Image.FromFile(updated_fname)
3447 image.LoadData()
3448 return image.GetEntries(), expected1, expected2, expected_text
3449
3450 def testReplaceAll(self):
3451 """Test replacing the contents of all entries"""
3452 entries, expected1, expected2, expected_text = (
3453 self._CheckReplaceMultiple([]))
3454 data = entries['u-boot'].data
3455 self.assertEqual(expected1, data)
3456
3457 data = entries['u-boot2'].data
3458 self.assertEqual(expected2, data)
3459
3460 data = entries['text'].data
3461 self.assertEqual(expected_text, data)
3462
3463 # Check that the device tree is updated
3464 data = entries['u-boot-dtb'].data
3465 dtb = fdt.Fdt.FromData(data)
3466 dtb.Scan()
3467 node = dtb.GetNode('/binman/text')
3468 self.assertEqual('the value', node.props['my-property'].value)
3469
3470 def testReplaceSome(self):
3471 """Test replacing the contents of a few entries"""
3472 entries, expected1, expected2, expected_text = (
3473 self._CheckReplaceMultiple(['u-boot2', 'text']))
3474
3475 # This one should not change
3476 data = entries['u-boot'].data
3477 self.assertEqual(U_BOOT_DATA, data)
3478
3479 data = entries['u-boot2'].data
3480 self.assertEqual(expected2, data)
3481
3482 data = entries['text'].data
3483 self.assertEqual(expected_text, data)
3484
3485 def testReplaceCmd(self):
3486 """Test replacing a file fron an image on the command line"""
3487 self._DoReadFileRealDtb('143_replace_all.dts')
3488
3489 try:
3490 tmpdir, updated_fname = self._SetupImageInTmpdir()
3491
3492 fname = os.path.join(tmpdir, 'update-u-boot.bin')
3493 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003494 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003495
3496 self._DoBinman('replace', '-i', updated_fname, 'u-boot', '-f', fname)
Simon Glass80025522022-01-29 14:14:04 -07003497 data = tools.read_file(updated_fname)
Simon Glass30033c22019-07-20 12:24:15 -06003498 self.assertEqual(expected, data[:len(expected)])
3499 map_fname = os.path.join(tmpdir, 'image-updated.map')
3500 self.assertFalse(os.path.exists(map_fname))
3501 finally:
3502 shutil.rmtree(tmpdir)
3503
3504 def testReplaceCmdSome(self):
3505 """Test replacing some files fron an image on the command line"""
3506 updated_fname, outdir, expected1, expected2, expected_text = (
3507 self._SetupForReplace())
3508
3509 self._DoBinman('replace', '-i', updated_fname, '-I', outdir,
3510 'u-boot2', 'text')
3511
Simon Glass80025522022-01-29 14:14:04 -07003512 tools.prepare_output_dir(None)
Simon Glass30033c22019-07-20 12:24:15 -06003513 image = Image.FromFile(updated_fname)
3514 image.LoadData()
3515 entries = image.GetEntries()
3516
3517 # This one should not change
3518 data = entries['u-boot'].data
3519 self.assertEqual(U_BOOT_DATA, data)
3520
3521 data = entries['u-boot2'].data
3522 self.assertEqual(expected2, data)
3523
3524 data = entries['text'].data
3525 self.assertEqual(expected_text, data)
3526
3527 def testReplaceMissing(self):
3528 """Test replacing entries where the file is missing"""
3529 updated_fname, outdir, expected1, expected2, expected_text = (
3530 self._SetupForReplace())
3531
3532 # Remove one of the files, to generate a warning
3533 u_boot_fname1 = os.path.join(outdir, 'u-boot')
3534 os.remove(u_boot_fname1)
3535
3536 with test_util.capture_sys_output() as (stdout, stderr):
3537 control.ReplaceEntries(updated_fname, None, outdir, [])
3538 self.assertIn("Skipping entry '/u-boot' from missing file",
Simon Glass6e02f7c2020-07-09 18:39:39 -06003539 stderr.getvalue())
Simon Glass30033c22019-07-20 12:24:15 -06003540
3541 def testReplaceCmdMap(self):
3542 """Test replacing a file fron an image on the command line"""
3543 self._DoReadFileRealDtb('143_replace_all.dts')
3544
3545 try:
3546 tmpdir, updated_fname = self._SetupImageInTmpdir()
3547
3548 fname = os.path.join(self._indir, 'update-u-boot.bin')
3549 expected = b'x' * len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003550 tools.write_file(fname, expected)
Simon Glass30033c22019-07-20 12:24:15 -06003551
3552 self._DoBinman('replace', '-i', updated_fname, 'u-boot',
3553 '-f', fname, '-m')
3554 map_fname = os.path.join(tmpdir, 'image-updated.map')
3555 self.assertTrue(os.path.exists(map_fname))
3556 finally:
3557 shutil.rmtree(tmpdir)
3558
3559 def testReplaceNoEntryPaths(self):
3560 """Test replacing an entry without an entry path"""
3561 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003562 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003563 with self.assertRaises(ValueError) as e:
3564 control.ReplaceEntries(image_fname, 'fname', None, [])
3565 self.assertIn('Must specify an entry path to read with -f',
3566 str(e.exception))
3567
3568 def testReplaceTooManyEntryPaths(self):
3569 """Test extracting some entries"""
3570 self._DoReadFileRealDtb('143_replace_all.dts')
Simon Glass80025522022-01-29 14:14:04 -07003571 image_fname = tools.get_output_filename('image.bin')
Simon Glass30033c22019-07-20 12:24:15 -06003572 with self.assertRaises(ValueError) as e:
3573 control.ReplaceEntries(image_fname, 'fname', None, ['a', 'b'])
3574 self.assertIn('Must specify exactly one entry path to write with -f',
3575 str(e.exception))
3576
Simon Glass0b074d62019-08-24 07:22:48 -06003577 def testPackReset16(self):
3578 """Test that an image with an x86 reset16 region can be created"""
3579 data = self._DoReadFile('144_x86_reset16.dts')
3580 self.assertEqual(X86_RESET16_DATA, data[:len(X86_RESET16_DATA)])
3581
3582 def testPackReset16Spl(self):
3583 """Test that an image with an x86 reset16-spl region can be created"""
3584 data = self._DoReadFile('145_x86_reset16_spl.dts')
3585 self.assertEqual(X86_RESET16_SPL_DATA, data[:len(X86_RESET16_SPL_DATA)])
3586
3587 def testPackReset16Tpl(self):
3588 """Test that an image with an x86 reset16-tpl region can be created"""
3589 data = self._DoReadFile('146_x86_reset16_tpl.dts')
3590 self.assertEqual(X86_RESET16_TPL_DATA, data[:len(X86_RESET16_TPL_DATA)])
3591
Simon Glass232f90c2019-08-24 07:22:50 -06003592 def testPackIntelFit(self):
3593 """Test that an image with an Intel FIT and pointer can be created"""
3594 data = self._DoReadFile('147_intel_fit.dts')
3595 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3596 fit = data[16:32];
3597 self.assertEqual(b'_FIT_ \x01\x00\x00\x00\x00\x01\x80}' , fit)
3598 ptr = struct.unpack('<i', data[0x40:0x44])[0]
3599
3600 image = control.images['image']
3601 entries = image.GetEntries()
3602 expected_ptr = entries['intel-fit'].image_pos - (1 << 32)
3603 self.assertEqual(expected_ptr, ptr)
3604
3605 def testPackIntelFitMissing(self):
3606 """Test detection of a FIT pointer with not FIT region"""
3607 with self.assertRaises(ValueError) as e:
3608 self._DoReadFile('148_intel_fit_missing.dts')
3609 self.assertIn("'intel-fit-ptr' section must have an 'intel-fit' sibling",
3610 str(e.exception))
3611
Simon Glass72555fa2019-11-06 17:22:44 -07003612 def _CheckSymbolsTplSection(self, dts, expected_vals):
3613 data = self._DoReadFile(dts)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003614 sym_values = struct.pack('<LLQLL', elf.BINMAN_SYM_MAGIC_VALUE, *expected_vals)
Simon Glass3eb5b202019-08-24 07:23:00 -06003615 upto1 = 4 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003616 expected1 = tools.get_bytes(0xff, 4) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003617 self.assertEqual(expected1, data[:upto1])
3618
3619 upto2 = upto1 + 1 + len(U_BOOT_SPL_DATA)
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003620 expected2 = tools.get_bytes(0xff, 1) + sym_values + U_BOOT_SPL_DATA[24:]
Simon Glass3eb5b202019-08-24 07:23:00 -06003621 self.assertEqual(expected2, data[upto1:upto2])
3622
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003623 upto3 = 0x3c + len(U_BOOT_DATA)
Simon Glass80025522022-01-29 14:14:04 -07003624 expected3 = tools.get_bytes(0xff, 1) + U_BOOT_DATA
Simon Glass3eb5b202019-08-24 07:23:00 -06003625 self.assertEqual(expected3, data[upto2:upto3])
3626
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003627 expected4 = sym_values + U_BOOT_TPL_DATA[24:]
Simon Glass72555fa2019-11-06 17:22:44 -07003628 self.assertEqual(expected4, data[upto3:upto3 + len(U_BOOT_TPL_DATA)])
3629
3630 def testSymbolsTplSection(self):
3631 """Test binman can assign symbols embedded in U-Boot TPL in a section"""
3632 self._SetupSplElf('u_boot_binman_syms')
3633 self._SetupTplElf('u_boot_binman_syms')
3634 self._CheckSymbolsTplSection('149_symbols_tpl.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003635 [0x04, 0x20, 0x10 + 0x3c, 0x04])
Simon Glass72555fa2019-11-06 17:22:44 -07003636
3637 def testSymbolsTplSectionX86(self):
3638 """Test binman can assign symbols in a section with end-at-4gb"""
3639 self._SetupSplElf('u_boot_binman_syms_x86')
3640 self._SetupTplElf('u_boot_binman_syms_x86')
3641 self._CheckSymbolsTplSection('155_symbols_tpl_x86.dts',
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03003642 [0xffffff04, 0xffffff20, 0xffffff3c,
Simon Glass72555fa2019-11-06 17:22:44 -07003643 0x04])
Simon Glass3eb5b202019-08-24 07:23:00 -06003644
Simon Glass98c59572019-08-24 07:23:03 -06003645 def testPackX86RomIfwiSectiom(self):
3646 """Test that a section can be placed in an IFWI region"""
3647 self._SetupIfwi('fitimage.bin')
3648 data = self._DoReadFile('151_x86_rom_ifwi_section.dts')
3649 self._CheckIfwi(data)
3650
Simon Glassba7985d2019-08-24 07:23:07 -06003651 def testPackFspM(self):
3652 """Test that an image with a FSP memory-init binary can be created"""
3653 data = self._DoReadFile('152_intel_fsp_m.dts')
3654 self.assertEqual(FSP_M_DATA, data[:len(FSP_M_DATA)])
3655
Simon Glass4d9086d2019-10-20 21:31:35 -06003656 def testPackFspS(self):
3657 """Test that an image with a FSP silicon-init binary can be created"""
3658 data = self._DoReadFile('153_intel_fsp_s.dts')
3659 self.assertEqual(FSP_S_DATA, data[:len(FSP_S_DATA)])
Simon Glassba7985d2019-08-24 07:23:07 -06003660
Simon Glass9ea87b22019-10-20 21:31:36 -06003661 def testPackFspT(self):
3662 """Test that an image with a FSP temp-ram-init binary can be created"""
3663 data = self._DoReadFile('154_intel_fsp_t.dts')
3664 self.assertEqual(FSP_T_DATA, data[:len(FSP_T_DATA)])
3665
Simon Glass48f3aad2020-07-09 18:39:31 -06003666 def testMkimage(self):
3667 """Test using mkimage to build an image"""
3668 data = self._DoReadFile('156_mkimage.dts')
3669
3670 # Just check that the data appears in the file somewhere
3671 self.assertIn(U_BOOT_SPL_DATA, data)
3672
Simon Glass66152ce2022-01-09 20:14:09 -07003673 def testMkimageMissing(self):
3674 """Test that binman still produces an image if mkimage is missing"""
3675 with test_util.capture_sys_output() as (_, stderr):
3676 self._DoTestFile('156_mkimage.dts',
3677 force_missing_bintools='mkimage')
3678 err = stderr.getvalue()
3679 self.assertRegex(err,
3680 "Image 'main-section'.*missing bintools.*: mkimage")
3681
Simon Glass5e560182020-07-09 18:39:36 -06003682 def testExtblob(self):
3683 """Test an image with an external blob"""
3684 data = self._DoReadFile('157_blob_ext.dts')
3685 self.assertEqual(REFCODE_DATA, data)
3686
3687 def testExtblobMissing(self):
3688 """Test an image with a missing external blob"""
3689 with self.assertRaises(ValueError) as e:
3690 self._DoReadFile('158_blob_ext_missing.dts')
3691 self.assertIn("Filename 'missing-file' not found in input path",
3692 str(e.exception))
3693
Simon Glass5d94cc62020-07-09 18:39:38 -06003694 def testExtblobMissingOk(self):
3695 """Test an image with an missing external blob that is allowed"""
Simon Glassa003cd32020-07-09 18:39:40 -06003696 with test_util.capture_sys_output() as (stdout, stderr):
3697 self._DoTestFile('158_blob_ext_missing.dts', allow_missing=True)
3698 err = stderr.getvalue()
3699 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
3700
3701 def testExtblobMissingOkSect(self):
3702 """Test an image with an missing external blob that is allowed"""
3703 with test_util.capture_sys_output() as (stdout, stderr):
3704 self._DoTestFile('159_blob_ext_missing_sect.dts',
3705 allow_missing=True)
3706 err = stderr.getvalue()
3707 self.assertRegex(err, "Image 'main-section'.*missing.*: "
3708 "blob-ext blob-ext2")
Simon Glass5d94cc62020-07-09 18:39:38 -06003709
Simon Glasse88cef92020-07-09 18:39:41 -06003710 def testPackX86RomMeMissingDesc(self):
3711 """Test that an missing Intel descriptor entry is allowed"""
Simon Glasse88cef92020-07-09 18:39:41 -06003712 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glass14c596c2020-07-25 15:11:19 -06003713 self._DoTestFile('164_x86_rom_me_missing.dts', allow_missing=True)
Simon Glasse88cef92020-07-09 18:39:41 -06003714 err = stderr.getvalue()
3715 self.assertRegex(err,
3716 "Image 'main-section'.*missing.*: intel-descriptor")
3717
3718 def testPackX86RomMissingIfwi(self):
3719 """Test that an x86 ROM with Integrated Firmware Image can be created"""
3720 self._SetupIfwi('fitimage.bin')
3721 pathname = os.path.join(self._indir, 'fitimage.bin')
3722 os.remove(pathname)
3723 with test_util.capture_sys_output() as (stdout, stderr):
3724 self._DoTestFile('111_x86_rom_ifwi.dts', allow_missing=True)
3725 err = stderr.getvalue()
3726 self.assertRegex(err, "Image 'main-section'.*missing.*: intel-ifwi")
3727
Simon Glass2a0fa982022-02-11 13:23:21 -07003728 def testPackOverlapZero(self):
Simon Glassd70829a2020-07-09 18:39:42 -06003729 """Test that zero-size overlapping regions are ignored"""
3730 self._DoTestFile('160_pack_overlap_zero.dts')
3731
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003732 def _CheckSimpleFitData(self, fit_data, kernel_data, fdt1_data):
Simon Glass45d556d2020-07-09 18:39:45 -06003733 # The data should be inside the FIT
3734 dtb = fdt.Fdt.FromData(fit_data)
3735 dtb.Scan()
3736 fnode = dtb.GetNode('/images/kernel')
3737 self.assertIn('data', fnode.props)
3738
3739 fname = os.path.join(self._indir, 'fit_data.fit')
Simon Glass80025522022-01-29 14:14:04 -07003740 tools.write_file(fname, fit_data)
3741 out = tools.run('dumpimage', '-l', fname)
Simon Glass45d556d2020-07-09 18:39:45 -06003742
3743 # Check a few features to make sure the plumbing works. We don't need
3744 # to test the operation of mkimage or dumpimage here. First convert the
3745 # output into a dict where the keys are the fields printed by dumpimage
3746 # and the values are a list of values for each field
3747 lines = out.splitlines()
3748
3749 # Converts "Compression: gzip compressed" into two groups:
3750 # 'Compression' and 'gzip compressed'
3751 re_line = re.compile(r'^ *([^:]*)(?:: *(.*))?$')
3752 vals = collections.defaultdict(list)
3753 for line in lines:
3754 mat = re_line.match(line)
3755 vals[mat.group(1)].append(mat.group(2))
3756
3757 self.assertEquals('FIT description: test-desc', lines[0])
3758 self.assertIn('Created:', lines[1])
3759 self.assertIn('Image 0 (kernel)', vals)
3760 self.assertIn('Hash value', vals)
3761 data_sizes = vals.get('Data Size')
3762 self.assertIsNotNone(data_sizes)
3763 self.assertEqual(2, len(data_sizes))
3764 # Format is "4 Bytes = 0.00 KiB = 0.00 MiB" so take the first word
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003765 self.assertEqual(len(kernel_data), int(data_sizes[0].split()[0]))
3766 self.assertEqual(len(fdt1_data), int(data_sizes[1].split()[0]))
3767
Alper Nebi Yasak1a0ee0f2022-03-27 18:31:47 +03003768 # Check if entry listing correctly omits /images/
3769 image = control.images['image']
3770 fit_entry = image.GetEntries()['fit']
3771 subentries = list(fit_entry.GetEntries().keys())
3772 expected = ['kernel', 'fdt-1']
3773 self.assertEqual(expected, subentries)
3774
Alper Nebi Yasak09fb0612022-02-08 01:08:04 +03003775 def testSimpleFit(self):
3776 """Test an image with a FIT inside"""
3777 data = self._DoReadFile('161_fit.dts')
3778 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
3779 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3780 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
3781
3782 self._CheckSimpleFitData(fit_data, U_BOOT_DATA, U_BOOT_SPL_DTB_DATA)
3783
3784 def testSimpleFitExpandsSubentries(self):
3785 """Test that FIT images expand their subentries"""
3786 data = self._DoReadFileDtb('161_fit.dts', use_expanded=True)[0]
3787 self.assertEqual(U_BOOT_EXP_DATA, data[:len(U_BOOT_EXP_DATA)])
3788 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
3789 fit_data = data[len(U_BOOT_EXP_DATA):-len(U_BOOT_NODTB_DATA)]
3790
3791 self._CheckSimpleFitData(fit_data, U_BOOT_EXP_DATA, U_BOOT_SPL_DTB_DATA)
Simon Glass45d556d2020-07-09 18:39:45 -06003792
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003793 def testSimpleFitImagePos(self):
3794 """Test that we have correct image-pos for FIT subentries"""
3795 data, _, _, out_dtb_fname = self._DoReadFileDtb('161_fit.dts',
3796 update_dtb=True)
3797 dtb = fdt.Fdt(out_dtb_fname)
3798 dtb.Scan()
3799 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3800
Simon Glassb7bad182022-03-05 20:19:01 -07003801 self.maxDiff = None
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003802 self.assertEqual({
3803 'image-pos': 0,
3804 'offset': 0,
3805 'size': 1890,
3806
3807 'u-boot:image-pos': 0,
3808 'u-boot:offset': 0,
3809 'u-boot:size': 4,
3810
3811 'fit:image-pos': 4,
3812 'fit:offset': 4,
3813 'fit:size': 1840,
3814
Simon Glassb7bad182022-03-05 20:19:01 -07003815 'fit/images/kernel:image-pos': 304,
3816 'fit/images/kernel:offset': 300,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003817 'fit/images/kernel:size': 4,
3818
Simon Glassb7bad182022-03-05 20:19:01 -07003819 'fit/images/kernel/u-boot:image-pos': 304,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003820 'fit/images/kernel/u-boot:offset': 0,
3821 'fit/images/kernel/u-boot:size': 4,
3822
Simon Glassb7bad182022-03-05 20:19:01 -07003823 'fit/images/fdt-1:image-pos': 552,
3824 'fit/images/fdt-1:offset': 548,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003825 'fit/images/fdt-1:size': 6,
3826
Simon Glassb7bad182022-03-05 20:19:01 -07003827 'fit/images/fdt-1/u-boot-spl-dtb:image-pos': 552,
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003828 'fit/images/fdt-1/u-boot-spl-dtb:offset': 0,
3829 'fit/images/fdt-1/u-boot-spl-dtb:size': 6,
3830
3831 'u-boot-nodtb:image-pos': 1844,
3832 'u-boot-nodtb:offset': 1844,
3833 'u-boot-nodtb:size': 46,
3834 }, props)
3835
3836 # Actually check the data is where we think it is
3837 for node, expected in [
3838 ("u-boot", U_BOOT_DATA),
3839 ("fit/images/kernel", U_BOOT_DATA),
3840 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3841 ("fit/images/fdt-1", U_BOOT_SPL_DTB_DATA),
3842 ("fit/images/fdt-1/u-boot-spl-dtb", U_BOOT_SPL_DTB_DATA),
3843 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3844 ]:
3845 image_pos = props[f"{node}:image-pos"]
3846 size = props[f"{node}:size"]
3847 self.assertEqual(len(expected), size)
3848 self.assertEqual(expected, data[image_pos:image_pos+size])
3849
Simon Glass45d556d2020-07-09 18:39:45 -06003850 def testFitExternal(self):
Simon Glass31ee50f2020-09-01 05:13:55 -06003851 """Test an image with an FIT with external images"""
Simon Glass45d556d2020-07-09 18:39:45 -06003852 data = self._DoReadFile('162_fit_external.dts')
3853 fit_data = data[len(U_BOOT_DATA):-2] # _testing is 2 bytes
3854
Simon Glass7932c882022-01-09 20:13:39 -07003855 # Size of the external-data region as set up by mkimage
3856 external_data_size = len(U_BOOT_DATA) + 2
3857 expected_size = (len(U_BOOT_DATA) + 0x400 +
Simon Glass80025522022-01-29 14:14:04 -07003858 tools.align(external_data_size, 4) +
Simon Glass7932c882022-01-09 20:13:39 -07003859 len(U_BOOT_NODTB_DATA))
3860
Simon Glass45d556d2020-07-09 18:39:45 -06003861 # The data should be outside the FIT
3862 dtb = fdt.Fdt.FromData(fit_data)
3863 dtb.Scan()
3864 fnode = dtb.GetNode('/images/kernel')
3865 self.assertNotIn('data', fnode.props)
Simon Glass7932c882022-01-09 20:13:39 -07003866 self.assertEqual(len(U_BOOT_DATA),
3867 fdt_util.fdt32_to_cpu(fnode.props['data-size'].value))
3868 fit_pos = 0x400;
3869 self.assertEqual(
3870 fit_pos,
3871 fdt_util.fdt32_to_cpu(fnode.props['data-position'].value))
3872
3873 self.assertEquals(expected_size, len(data))
3874 actual_pos = len(U_BOOT_DATA) + fit_pos
3875 self.assertEqual(U_BOOT_DATA + b'aa',
3876 data[actual_pos:actual_pos + external_data_size])
Simon Glassfb30e292019-07-20 12:23:51 -06003877
Alper Nebi Yasakac873ed2022-02-08 01:08:08 +03003878 def testFitExternalImagePos(self):
3879 """Test that we have correct image-pos for external FIT subentries"""
3880 data, _, _, out_dtb_fname = self._DoReadFileDtb('162_fit_external.dts',
3881 update_dtb=True)
3882 dtb = fdt.Fdt(out_dtb_fname)
3883 dtb.Scan()
3884 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
3885
3886 self.assertEqual({
3887 'image-pos': 0,
3888 'offset': 0,
3889 'size': 1082,
3890
3891 'u-boot:image-pos': 0,
3892 'u-boot:offset': 0,
3893 'u-boot:size': 4,
3894
3895 'fit:size': 1032,
3896 'fit:offset': 4,
3897 'fit:image-pos': 4,
3898
3899 'fit/images/kernel:size': 4,
3900 'fit/images/kernel:offset': 1024,
3901 'fit/images/kernel:image-pos': 1028,
3902
3903 'fit/images/kernel/u-boot:size': 4,
3904 'fit/images/kernel/u-boot:offset': 0,
3905 'fit/images/kernel/u-boot:image-pos': 1028,
3906
3907 'fit/images/fdt-1:size': 2,
3908 'fit/images/fdt-1:offset': 1028,
3909 'fit/images/fdt-1:image-pos': 1032,
3910
3911 'fit/images/fdt-1/_testing:size': 2,
3912 'fit/images/fdt-1/_testing:offset': 0,
3913 'fit/images/fdt-1/_testing:image-pos': 1032,
3914
3915 'u-boot-nodtb:image-pos': 1036,
3916 'u-boot-nodtb:offset': 1036,
3917 'u-boot-nodtb:size': 46,
3918 }, props)
3919
3920 # Actually check the data is where we think it is
3921 for node, expected in [
3922 ("u-boot", U_BOOT_DATA),
3923 ("fit/images/kernel", U_BOOT_DATA),
3924 ("fit/images/kernel/u-boot", U_BOOT_DATA),
3925 ("fit/images/fdt-1", b'aa'),
3926 ("fit/images/fdt-1/_testing", b'aa'),
3927 ("u-boot-nodtb", U_BOOT_NODTB_DATA),
3928 ]:
3929 image_pos = props[f"{node}:image-pos"]
3930 size = props[f"{node}:size"]
3931 self.assertEqual(len(expected), size)
3932 self.assertEqual(expected, data[image_pos:image_pos+size])
3933
Simon Glass66152ce2022-01-09 20:14:09 -07003934 def testFitMissing(self):
3935 """Test that binman still produces a FIT image if mkimage is missing"""
3936 with test_util.capture_sys_output() as (_, stderr):
3937 self._DoTestFile('162_fit_external.dts',
3938 force_missing_bintools='mkimage')
3939 err = stderr.getvalue()
3940 self.assertRegex(err,
3941 "Image 'main-section'.*missing bintools.*: mkimage")
3942
Alper Nebi Yasak6aae2392020-08-31 12:58:18 +03003943 def testSectionIgnoreHashSignature(self):
3944 """Test that sections ignore hash, signature nodes for its data"""
3945 data = self._DoReadFile('165_section_ignore_hash_signature.dts')
3946 expected = (U_BOOT_DATA + U_BOOT_DATA)
3947 self.assertEqual(expected, data)
3948
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003949 def testPadInSections(self):
3950 """Test pad-before, pad-after for entries in sections"""
Simon Glassd12599d2020-10-26 17:40:09 -06003951 data, _, _, out_dtb_fname = self._DoReadFileDtb(
3952 '166_pad_in_sections.dts', update_dtb=True)
Simon Glass80025522022-01-29 14:14:04 -07003953 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
3954 U_BOOT_DATA + tools.get_bytes(ord('!'), 6) +
Alper Nebi Yasakc5030602020-08-31 12:58:19 +03003955 U_BOOT_DATA)
3956 self.assertEqual(expected, data)
3957
Simon Glassd12599d2020-10-26 17:40:09 -06003958 dtb = fdt.Fdt(out_dtb_fname)
3959 dtb.Scan()
3960 props = self._GetPropTree(dtb, ['size', 'image-pos', 'offset'])
3961 expected = {
3962 'image-pos': 0,
3963 'offset': 0,
3964 'size': 12 + 6 + 3 * len(U_BOOT_DATA),
3965
3966 'section:image-pos': 0,
3967 'section:offset': 0,
3968 'section:size': 12 + 6 + 3 * len(U_BOOT_DATA),
3969
3970 'section/before:image-pos': 0,
3971 'section/before:offset': 0,
3972 'section/before:size': len(U_BOOT_DATA),
3973
3974 'section/u-boot:image-pos': 4,
3975 'section/u-boot:offset': 4,
3976 'section/u-boot:size': 12 + len(U_BOOT_DATA) + 6,
3977
3978 'section/after:image-pos': 26,
3979 'section/after:offset': 26,
3980 'section/after:size': len(U_BOOT_DATA),
3981 }
3982 self.assertEqual(expected, props)
3983
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003984 def testFitImageSubentryAlignment(self):
3985 """Test relative alignability of FIT image subentries"""
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03003986 self._SetupSplElf()
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03003987 entry_args = {
3988 'test-id': TEXT_DATA,
3989 }
3990 data, _, _, _ = self._DoReadFileDtb('167_fit_image_subentry_alignment.dts',
3991 entry_args=entry_args)
3992 dtb = fdt.Fdt.FromData(data)
3993 dtb.Scan()
3994
3995 node = dtb.GetNode('/images/kernel')
3996 data = dtb.GetProps(node)["data"].bytes
3997 align_pad = 0x10 - (len(U_BOOT_SPL_DATA) % 0x10)
Simon Glass80025522022-01-29 14:14:04 -07003998 expected = (tools.get_bytes(0, 0x20) + U_BOOT_SPL_DATA +
3999 tools.get_bytes(0, align_pad) + U_BOOT_DATA)
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004000 self.assertEqual(expected, data)
4001
4002 node = dtb.GetNode('/images/fdt-1')
4003 data = dtb.GetProps(node)["data"].bytes
Simon Glass80025522022-01-29 14:14:04 -07004004 expected = (U_BOOT_SPL_DTB_DATA + tools.get_bytes(0, 20) +
4005 tools.to_bytes(TEXT_DATA) + tools.get_bytes(0, 30) +
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004006 U_BOOT_DTB_DATA)
4007 self.assertEqual(expected, data)
4008
4009 def testFitExtblobMissingOk(self):
4010 """Test a FIT with a missing external blob that is allowed"""
4011 with test_util.capture_sys_output() as (stdout, stderr):
4012 self._DoTestFile('168_fit_missing_blob.dts',
4013 allow_missing=True)
4014 err = stderr.getvalue()
Simon Glassa820af72020-09-06 10:39:09 -06004015 self.assertRegex(err, "Image 'main-section'.*missing.*: atf-bl31")
Alper Nebi Yasakc261ec12020-08-31 12:58:20 +03004016
Simon Glass21db0ff2020-09-01 05:13:54 -06004017 def testBlobNamedByArgMissing(self):
4018 """Test handling of a missing entry arg"""
4019 with self.assertRaises(ValueError) as e:
4020 self._DoReadFile('068_blob_named_by_arg.dts')
4021 self.assertIn("Missing required properties/entry args: cros-ec-rw-path",
4022 str(e.exception))
4023
Simon Glass559c4de2020-09-01 05:13:58 -06004024 def testPackBl31(self):
4025 """Test that an image with an ATF BL31 binary can be created"""
4026 data = self._DoReadFile('169_atf_bl31.dts')
4027 self.assertEqual(ATF_BL31_DATA, data[:len(ATF_BL31_DATA)])
4028
Samuel Holland9d8cc632020-10-21 21:12:15 -05004029 def testPackScp(self):
4030 """Test that an image with an SCP binary can be created"""
4031 data = self._DoReadFile('172_scp.dts')
4032 self.assertEqual(SCP_DATA, data[:len(SCP_DATA)])
4033
Simon Glassa435cd12020-09-01 05:13:59 -06004034 def testFitFdt(self):
4035 """Test an image with an FIT with multiple FDT images"""
4036 def _CheckFdt(seq, expected_data):
4037 """Check the FDT nodes
4038
4039 Args:
4040 seq: Sequence number to check (0 or 1)
4041 expected_data: Expected contents of 'data' property
4042 """
4043 name = 'fdt-%d' % seq
4044 fnode = dtb.GetNode('/images/%s' % name)
4045 self.assertIsNotNone(fnode)
4046 self.assertEqual({'description','type', 'compression', 'data'},
4047 set(fnode.props.keys()))
4048 self.assertEqual(expected_data, fnode.props['data'].bytes)
4049 self.assertEqual('fdt-test-fdt%d.dtb' % seq,
4050 fnode.props['description'].value)
Jan Kiszkaa1419df2022-02-28 17:06:20 +01004051 self.assertEqual(fnode.subnodes[0].name, 'hash')
Simon Glassa435cd12020-09-01 05:13:59 -06004052
4053 def _CheckConfig(seq, expected_data):
4054 """Check the configuration nodes
4055
4056 Args:
4057 seq: Sequence number to check (0 or 1)
4058 expected_data: Expected contents of 'data' property
4059 """
4060 cnode = dtb.GetNode('/configurations')
4061 self.assertIn('default', cnode.props)
Simon Glass1032acc2020-09-06 10:39:08 -06004062 self.assertEqual('config-2', cnode.props['default'].value)
Simon Glassa435cd12020-09-01 05:13:59 -06004063
4064 name = 'config-%d' % seq
4065 fnode = dtb.GetNode('/configurations/%s' % name)
4066 self.assertIsNotNone(fnode)
4067 self.assertEqual({'description','firmware', 'loadables', 'fdt'},
4068 set(fnode.props.keys()))
4069 self.assertEqual('conf-test-fdt%d.dtb' % seq,
4070 fnode.props['description'].value)
4071 self.assertEqual('fdt-%d' % seq, fnode.props['fdt'].value)
4072
4073 entry_args = {
4074 'of-list': 'test-fdt1 test-fdt2',
Simon Glass1032acc2020-09-06 10:39:08 -06004075 'default-dt': 'test-fdt2',
Simon Glassa435cd12020-09-01 05:13:59 -06004076 }
4077 data = self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004078 '170_fit_fdt.dts',
Simon Glassa435cd12020-09-01 05:13:59 -06004079 entry_args=entry_args,
4080 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4081 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4082 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4083
4084 dtb = fdt.Fdt.FromData(fit_data)
4085 dtb.Scan()
4086 fnode = dtb.GetNode('/images/kernel')
4087 self.assertIn('data', fnode.props)
4088
4089 # Check all the properties in fdt-1 and fdt-2
4090 _CheckFdt(1, TEST_FDT1_DATA)
4091 _CheckFdt(2, TEST_FDT2_DATA)
4092
4093 # Check configurations
4094 _CheckConfig(1, TEST_FDT1_DATA)
4095 _CheckConfig(2, TEST_FDT2_DATA)
4096
4097 def testFitFdtMissingList(self):
4098 """Test handling of a missing 'of-list' entry arg"""
4099 with self.assertRaises(ValueError) as e:
Bin Meng16cf5662021-05-10 20:23:32 +08004100 self._DoReadFile('170_fit_fdt.dts')
Simon Glassa435cd12020-09-01 05:13:59 -06004101 self.assertIn("Generator node requires 'of-list' entry argument",
4102 str(e.exception))
4103
4104 def testFitFdtEmptyList(self):
4105 """Test handling of an empty 'of-list' entry arg"""
4106 entry_args = {
4107 'of-list': '',
4108 }
4109 data = self._DoReadFileDtb('170_fit_fdt.dts', entry_args=entry_args)[0]
4110
4111 def testFitFdtMissingProp(self):
4112 """Test handling of a missing 'fit,fdt-list' property"""
4113 with self.assertRaises(ValueError) as e:
4114 self._DoReadFile('171_fit_fdt_missing_prop.dts')
4115 self.assertIn("Generator node requires 'fit,fdt-list' property",
4116 str(e.exception))
Simon Glass559c4de2020-09-01 05:13:58 -06004117
Simon Glass1032acc2020-09-06 10:39:08 -06004118 def testFitFdtMissing(self):
4119 """Test handling of a missing 'default-dt' entry arg"""
4120 entry_args = {
4121 'of-list': 'test-fdt1 test-fdt2',
4122 }
4123 with self.assertRaises(ValueError) as e:
4124 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004125 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004126 entry_args=entry_args,
4127 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4128 self.assertIn("Generated 'default' node requires default-dt entry argument",
4129 str(e.exception))
4130
4131 def testFitFdtNotInList(self):
4132 """Test handling of a default-dt that is not in the of-list"""
4133 entry_args = {
4134 'of-list': 'test-fdt1 test-fdt2',
4135 'default-dt': 'test-fdt3',
4136 }
4137 with self.assertRaises(ValueError) as e:
4138 self._DoReadFileDtb(
Bin Meng16cf5662021-05-10 20:23:32 +08004139 '170_fit_fdt.dts',
Simon Glass1032acc2020-09-06 10:39:08 -06004140 entry_args=entry_args,
4141 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
4142 self.assertIn("default-dt entry argument 'test-fdt3' not found in fdt list: test-fdt1, test-fdt2",
4143 str(e.exception))
4144
Simon Glassa820af72020-09-06 10:39:09 -06004145 def testFitExtblobMissingHelp(self):
4146 """Test display of help messages when an external blob is missing"""
4147 control.missing_blob_help = control._ReadMissingBlobHelp()
4148 control.missing_blob_help['wibble'] = 'Wibble test'
4149 control.missing_blob_help['another'] = 'Another test'
4150 with test_util.capture_sys_output() as (stdout, stderr):
4151 self._DoTestFile('168_fit_missing_blob.dts',
4152 allow_missing=True)
4153 err = stderr.getvalue()
4154
4155 # We can get the tag from the name, the type or the missing-msg
4156 # property. Check all three.
4157 self.assertIn('You may need to build ARM Trusted', err)
4158 self.assertIn('Wibble test', err)
4159 self.assertIn('Another test', err)
4160
Simon Glass6f1f4d42020-09-06 10:35:32 -06004161 def testMissingBlob(self):
4162 """Test handling of a blob containing a missing file"""
4163 with self.assertRaises(ValueError) as e:
4164 self._DoTestFile('173_missing_blob.dts', allow_missing=True)
4165 self.assertIn("Filename 'missing' not found in input path",
4166 str(e.exception))
4167
Simon Glassa0729502020-09-06 10:35:33 -06004168 def testEnvironment(self):
4169 """Test adding a U-Boot environment"""
4170 data = self._DoReadFile('174_env.dts')
4171 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
4172 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
4173 env = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
4174 self.assertEqual(b'\x1b\x97\x22\x7c\x01var1=1\0var2="2"\0\0\xff\xff',
4175 env)
4176
4177 def testEnvironmentNoSize(self):
4178 """Test that a missing 'size' property is detected"""
4179 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004180 self._DoTestFile('175_env_no_size.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004181 self.assertIn("'u-boot-env' entry must have a size property",
4182 str(e.exception))
4183
4184 def testEnvironmentTooSmall(self):
4185 """Test handling of an environment that does not fit"""
4186 with self.assertRaises(ValueError) as e:
Simon Glass8cdc08a2020-10-26 17:40:00 -06004187 self._DoTestFile('176_env_too_small.dts')
Simon Glassa0729502020-09-06 10:35:33 -06004188
4189 # checksum, start byte, environment with \0 terminator, final \0
4190 need = 4 + 1 + len(ENV_DATA) + 1 + 1
4191 short = need - 0x8
4192 self.assertIn("too small to hold data (need %#x more bytes)" % short,
4193 str(e.exception))
4194
Simon Glassd1fdf752020-10-26 17:40:01 -06004195 def testSkipAtStart(self):
4196 """Test handling of skip-at-start section"""
4197 data = self._DoReadFile('177_skip_at_start.dts')
4198 self.assertEqual(U_BOOT_DATA, data)
4199
4200 image = control.images['image']
4201 entries = image.GetEntries()
4202 section = entries['section']
4203 self.assertEqual(0, section.offset)
4204 self.assertEqual(len(U_BOOT_DATA), section.size)
4205 self.assertEqual(U_BOOT_DATA, section.GetData())
4206
4207 entry = section.GetEntries()['u-boot']
4208 self.assertEqual(16, entry.offset)
4209 self.assertEqual(len(U_BOOT_DATA), entry.size)
4210 self.assertEqual(U_BOOT_DATA, entry.data)
4211
4212 def testSkipAtStartPad(self):
4213 """Test handling of skip-at-start section with padded entry"""
4214 data = self._DoReadFile('178_skip_at_start_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004215 before = tools.get_bytes(0, 8)
4216 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004217 all = before + U_BOOT_DATA + after
4218 self.assertEqual(all, data)
4219
4220 image = control.images['image']
4221 entries = image.GetEntries()
4222 section = entries['section']
4223 self.assertEqual(0, section.offset)
4224 self.assertEqual(len(all), section.size)
4225 self.assertEqual(all, section.GetData())
4226
4227 entry = section.GetEntries()['u-boot']
4228 self.assertEqual(16, entry.offset)
4229 self.assertEqual(len(all), entry.size)
4230 self.assertEqual(U_BOOT_DATA, entry.data)
4231
4232 def testSkipAtStartSectionPad(self):
4233 """Test handling of skip-at-start section with padding"""
4234 data = self._DoReadFile('179_skip_at_start_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004235 before = tools.get_bytes(0, 8)
4236 after = tools.get_bytes(0, 4)
Simon Glassd1fdf752020-10-26 17:40:01 -06004237 all = before + U_BOOT_DATA + after
Simon Glass510ef0f2020-10-26 17:40:13 -06004238 self.assertEqual(all, data)
Simon Glassd1fdf752020-10-26 17:40:01 -06004239
4240 image = control.images['image']
4241 entries = image.GetEntries()
4242 section = entries['section']
4243 self.assertEqual(0, section.offset)
4244 self.assertEqual(len(all), section.size)
Simon Glass72eeff12020-10-26 17:40:16 -06004245 self.assertEqual(U_BOOT_DATA, section.data)
Simon Glass510ef0f2020-10-26 17:40:13 -06004246 self.assertEqual(all, section.GetPaddedData())
Simon Glassd1fdf752020-10-26 17:40:01 -06004247
4248 entry = section.GetEntries()['u-boot']
4249 self.assertEqual(16, entry.offset)
4250 self.assertEqual(len(U_BOOT_DATA), entry.size)
4251 self.assertEqual(U_BOOT_DATA, entry.data)
Simon Glassa0729502020-09-06 10:35:33 -06004252
Simon Glassbb395742020-10-26 17:40:14 -06004253 def testSectionPad(self):
4254 """Testing padding with sections"""
4255 data = self._DoReadFile('180_section_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004256 expected = (tools.get_bytes(ord('&'), 3) +
4257 tools.get_bytes(ord('!'), 5) +
Simon Glassbb395742020-10-26 17:40:14 -06004258 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004259 tools.get_bytes(ord('!'), 1) +
4260 tools.get_bytes(ord('&'), 2))
Simon Glassbb395742020-10-26 17:40:14 -06004261 self.assertEqual(expected, data)
4262
4263 def testSectionAlign(self):
4264 """Testing alignment with sections"""
4265 data = self._DoReadFileDtb('181_section_align.dts', map=True)[0]
4266 expected = (b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004267 tools.get_bytes(ord('&'), 1) + # padding to section align
Simon Glassbb395742020-10-26 17:40:14 -06004268 b'\0' + # fill section
Simon Glass80025522022-01-29 14:14:04 -07004269 tools.get_bytes(ord('!'), 3) + # padding to u-boot align
Simon Glassbb395742020-10-26 17:40:14 -06004270 U_BOOT_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004271 tools.get_bytes(ord('!'), 4) + # padding to u-boot size
4272 tools.get_bytes(ord('!'), 4)) # padding to section size
Simon Glassbb395742020-10-26 17:40:14 -06004273 self.assertEqual(expected, data)
4274
Simon Glassd92c8362020-10-26 17:40:25 -06004275 def testCompressImage(self):
4276 """Test compression of the entire image"""
4277 self._CheckLz4()
4278 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4279 '182_compress_image.dts', use_real_dtb=True, update_dtb=True)
4280 dtb = fdt.Fdt(out_dtb_fname)
4281 dtb.Scan()
4282 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4283 'uncomp-size'])
4284 orig = self._decompress(data)
4285 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4286
4287 # Do a sanity check on various fields
4288 image = control.images['image']
4289 entries = image.GetEntries()
4290 self.assertEqual(2, len(entries))
4291
4292 entry = entries['blob']
4293 self.assertEqual(COMPRESS_DATA, entry.data)
4294 self.assertEqual(len(COMPRESS_DATA), entry.size)
4295
4296 entry = entries['u-boot']
4297 self.assertEqual(U_BOOT_DATA, entry.data)
4298 self.assertEqual(len(U_BOOT_DATA), entry.size)
4299
4300 self.assertEqual(len(data), image.size)
4301 self.assertEqual(COMPRESS_DATA + U_BOOT_DATA, image.uncomp_data)
4302 self.assertEqual(len(COMPRESS_DATA + U_BOOT_DATA), image.uncomp_size)
4303 orig = self._decompress(image.data)
4304 self.assertEqual(orig, image.uncomp_data)
4305
4306 expected = {
4307 'blob:offset': 0,
4308 'blob:size': len(COMPRESS_DATA),
4309 'u-boot:offset': len(COMPRESS_DATA),
4310 'u-boot:size': len(U_BOOT_DATA),
4311 'uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4312 'offset': 0,
4313 'image-pos': 0,
4314 'size': len(data),
4315 }
4316 self.assertEqual(expected, props)
4317
4318 def testCompressImageLess(self):
4319 """Test compression where compression reduces the image size"""
4320 self._CheckLz4()
4321 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4322 '183_compress_image_less.dts', use_real_dtb=True, update_dtb=True)
4323 dtb = fdt.Fdt(out_dtb_fname)
4324 dtb.Scan()
4325 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4326 'uncomp-size'])
4327 orig = self._decompress(data)
4328
4329 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA + U_BOOT_DATA, orig)
4330
4331 # Do a sanity check on various fields
4332 image = control.images['image']
4333 entries = image.GetEntries()
4334 self.assertEqual(2, len(entries))
4335
4336 entry = entries['blob']
4337 self.assertEqual(COMPRESS_DATA_BIG, entry.data)
4338 self.assertEqual(len(COMPRESS_DATA_BIG), entry.size)
4339
4340 entry = entries['u-boot']
4341 self.assertEqual(U_BOOT_DATA, entry.data)
4342 self.assertEqual(len(U_BOOT_DATA), entry.size)
4343
4344 self.assertEqual(len(data), image.size)
4345 self.assertEqual(COMPRESS_DATA_BIG + U_BOOT_DATA, image.uncomp_data)
4346 self.assertEqual(len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4347 image.uncomp_size)
4348 orig = self._decompress(image.data)
4349 self.assertEqual(orig, image.uncomp_data)
4350
4351 expected = {
4352 'blob:offset': 0,
4353 'blob:size': len(COMPRESS_DATA_BIG),
4354 'u-boot:offset': len(COMPRESS_DATA_BIG),
4355 'u-boot:size': len(U_BOOT_DATA),
4356 'uncomp-size': len(COMPRESS_DATA_BIG + U_BOOT_DATA),
4357 'offset': 0,
4358 'image-pos': 0,
4359 'size': len(data),
4360 }
4361 self.assertEqual(expected, props)
4362
4363 def testCompressSectionSize(self):
4364 """Test compression of a section with a fixed size"""
4365 self._CheckLz4()
4366 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4367 '184_compress_section_size.dts', use_real_dtb=True, update_dtb=True)
4368 dtb = fdt.Fdt(out_dtb_fname)
4369 dtb.Scan()
4370 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4371 'uncomp-size'])
4372 orig = self._decompress(data)
4373 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4374 expected = {
4375 'section/blob:offset': 0,
4376 'section/blob:size': len(COMPRESS_DATA),
4377 'section/u-boot:offset': len(COMPRESS_DATA),
4378 'section/u-boot:size': len(U_BOOT_DATA),
4379 'section:offset': 0,
4380 'section:image-pos': 0,
4381 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4382 'section:size': 0x30,
4383 'offset': 0,
4384 'image-pos': 0,
4385 'size': 0x30,
4386 }
4387 self.assertEqual(expected, props)
4388
4389 def testCompressSection(self):
4390 """Test compression of a section with no fixed size"""
4391 self._CheckLz4()
4392 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4393 '185_compress_section.dts', use_real_dtb=True, update_dtb=True)
4394 dtb = fdt.Fdt(out_dtb_fname)
4395 dtb.Scan()
4396 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4397 'uncomp-size'])
4398 orig = self._decompress(data)
4399 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, orig)
4400 expected = {
4401 'section/blob:offset': 0,
4402 'section/blob:size': len(COMPRESS_DATA),
4403 'section/u-boot:offset': len(COMPRESS_DATA),
4404 'section/u-boot:size': len(U_BOOT_DATA),
4405 'section:offset': 0,
4406 'section:image-pos': 0,
4407 'section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4408 'section:size': len(data),
4409 'offset': 0,
4410 'image-pos': 0,
4411 'size': len(data),
4412 }
4413 self.assertEqual(expected, props)
4414
4415 def testCompressExtra(self):
4416 """Test compression of a section with no fixed size"""
4417 self._CheckLz4()
4418 data, _, _, out_dtb_fname = self._DoReadFileDtb(
4419 '186_compress_extra.dts', use_real_dtb=True, update_dtb=True)
4420 dtb = fdt.Fdt(out_dtb_fname)
4421 dtb.Scan()
4422 props = self._GetPropTree(dtb, ['offset', 'image-pos', 'size',
4423 'uncomp-size'])
4424
4425 base = data[len(U_BOOT_DATA):]
4426 self.assertEquals(U_BOOT_DATA, base[:len(U_BOOT_DATA)])
4427 rest = base[len(U_BOOT_DATA):]
4428
4429 # Check compressed data
Simon Glassdd5c14ec2022-01-09 20:14:04 -07004430 expect1 = comp_util.compress(COMPRESS_DATA + U_BOOT_DATA, 'lz4')
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004431 data1 = rest[:len(expect1)]
4432 section1 = self._decompress(data1)
4433 self.assertEquals(expect1, data1)
Simon Glassd92c8362020-10-26 17:40:25 -06004434 self.assertEquals(COMPRESS_DATA + U_BOOT_DATA, section1)
4435 rest1 = rest[len(expect1):]
4436
Simon Glassdd5c14ec2022-01-09 20:14:04 -07004437 expect2 = comp_util.compress(COMPRESS_DATA + COMPRESS_DATA, 'lz4')
Stefan Herbrechtsmeier86f1fc02022-08-19 16:25:23 +02004438 data2 = rest1[:len(expect2)]
4439 section2 = self._decompress(data2)
4440 self.assertEquals(expect2, data2)
Simon Glassd92c8362020-10-26 17:40:25 -06004441 self.assertEquals(COMPRESS_DATA + COMPRESS_DATA, section2)
4442 rest2 = rest1[len(expect2):]
4443
4444 expect_size = (len(U_BOOT_DATA) + len(U_BOOT_DATA) + len(expect1) +
4445 len(expect2) + len(U_BOOT_DATA))
4446 #self.assertEquals(expect_size, len(data))
4447
4448 #self.assertEquals(U_BOOT_DATA, rest2)
4449
4450 self.maxDiff = None
4451 expected = {
4452 'u-boot:offset': 0,
4453 'u-boot:image-pos': 0,
4454 'u-boot:size': len(U_BOOT_DATA),
4455
4456 'base:offset': len(U_BOOT_DATA),
4457 'base:image-pos': len(U_BOOT_DATA),
4458 'base:size': len(data) - len(U_BOOT_DATA),
4459 'base/u-boot:offset': 0,
4460 'base/u-boot:image-pos': len(U_BOOT_DATA),
4461 'base/u-boot:size': len(U_BOOT_DATA),
4462 'base/u-boot2:offset': len(U_BOOT_DATA) + len(expect1) +
4463 len(expect2),
4464 'base/u-boot2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1) +
4465 len(expect2),
4466 'base/u-boot2:size': len(U_BOOT_DATA),
4467
4468 'base/section:offset': len(U_BOOT_DATA),
4469 'base/section:image-pos': len(U_BOOT_DATA) * 2,
4470 'base/section:size': len(expect1),
4471 'base/section:uncomp-size': len(COMPRESS_DATA + U_BOOT_DATA),
4472 'base/section/blob:offset': 0,
4473 'base/section/blob:size': len(COMPRESS_DATA),
4474 'base/section/u-boot:offset': len(COMPRESS_DATA),
4475 'base/section/u-boot:size': len(U_BOOT_DATA),
4476
4477 'base/section2:offset': len(U_BOOT_DATA) + len(expect1),
4478 'base/section2:image-pos': len(U_BOOT_DATA) * 2 + len(expect1),
4479 'base/section2:size': len(expect2),
4480 'base/section2:uncomp-size': len(COMPRESS_DATA + COMPRESS_DATA),
4481 'base/section2/blob:offset': 0,
4482 'base/section2/blob:size': len(COMPRESS_DATA),
4483 'base/section2/blob2:offset': len(COMPRESS_DATA),
4484 'base/section2/blob2:size': len(COMPRESS_DATA),
4485
4486 'offset': 0,
4487 'image-pos': 0,
4488 'size': len(data),
4489 }
4490 self.assertEqual(expected, props)
4491
Simon Glassecbe4732021-01-06 21:35:15 -07004492 def testSymbolsSubsection(self):
4493 """Test binman can assign symbols from a subsection"""
Alper Nebi Yasak9634dc92022-06-18 15:13:11 +03004494 self.checkSymbols('187_symbols_sub.dts', U_BOOT_SPL_DATA, 0x1c)
Simon Glassecbe4732021-01-06 21:35:15 -07004495
Simon Glass3fb25402021-01-06 21:35:16 -07004496 def testReadImageEntryArg(self):
4497 """Test reading an image that would need an entry arg to generate"""
4498 entry_args = {
4499 'cros-ec-rw-path': 'ecrw.bin',
4500 }
4501 data = self.data = self._DoReadFileDtb(
4502 '188_image_entryarg.dts',use_real_dtb=True, update_dtb=True,
4503 entry_args=entry_args)
4504
Simon Glass80025522022-01-29 14:14:04 -07004505 image_fname = tools.get_output_filename('image.bin')
Simon Glass3fb25402021-01-06 21:35:16 -07004506 orig_image = control.images['image']
4507
4508 # This should not generate an error about the missing 'cros-ec-rw-path'
4509 # since we are reading the image from a file. Compare with
4510 # testEntryArgsRequired()
4511 image = Image.FromFile(image_fname)
4512 self.assertEqual(orig_image.GetEntries().keys(),
4513 image.GetEntries().keys())
4514
Simon Glassa2af7302021-01-06 21:35:18 -07004515 def testFilesAlign(self):
4516 """Test alignment with files"""
4517 data = self._DoReadFile('190_files_align.dts')
4518
4519 # The first string is 15 bytes so will align to 16
4520 expect = FILES_DATA[:15] + b'\0' + FILES_DATA[15:]
4521 self.assertEqual(expect, data)
4522
Simon Glassdb84b562021-01-06 21:35:19 -07004523 def testReadImageSkip(self):
4524 """Test reading an image and accessing its FDT map"""
4525 data = self.data = self._DoReadFileRealDtb('191_read_image_skip.dts')
Simon Glass80025522022-01-29 14:14:04 -07004526 image_fname = tools.get_output_filename('image.bin')
Simon Glassdb84b562021-01-06 21:35:19 -07004527 orig_image = control.images['image']
4528 image = Image.FromFile(image_fname)
4529 self.assertEqual(orig_image.GetEntries().keys(),
4530 image.GetEntries().keys())
4531
4532 orig_entry = orig_image.GetEntries()['fdtmap']
4533 entry = image.GetEntries()['fdtmap']
4534 self.assertEqual(orig_entry.offset, entry.offset)
4535 self.assertEqual(orig_entry.size, entry.size)
4536 self.assertEqual(16, entry.image_pos)
4537
4538 u_boot = image.GetEntries()['section'].GetEntries()['u-boot']
4539
4540 self.assertEquals(U_BOOT_DATA, u_boot.ReadData())
4541
Simon Glassc98de972021-03-18 20:24:57 +13004542 def testTplNoDtb(self):
4543 """Test that an image with tpl/u-boot-tpl-nodtb.bin can be created"""
Simon Glass13089cc2021-04-25 08:39:32 +12004544 self._SetupTplElf()
Simon Glassc98de972021-03-18 20:24:57 +13004545 data = self._DoReadFile('192_u_boot_tpl_nodtb.dts')
4546 self.assertEqual(U_BOOT_TPL_NODTB_DATA,
4547 data[:len(U_BOOT_TPL_NODTB_DATA)])
4548
Simon Glass63f41d42021-03-18 20:24:58 +13004549 def testTplBssPad(self):
4550 """Test that we can pad TPL's BSS with zeros"""
4551 # ELF file with a '__bss_size' symbol
4552 self._SetupTplElf()
4553 data = self._DoReadFile('193_tpl_bss_pad.dts')
Simon Glass80025522022-01-29 14:14:04 -07004554 self.assertEqual(U_BOOT_TPL_DATA + tools.get_bytes(0, 10) + U_BOOT_DATA,
Simon Glass63f41d42021-03-18 20:24:58 +13004555 data)
4556
4557 def testTplBssPadMissing(self):
4558 """Test that a missing symbol is detected"""
4559 self._SetupTplElf('u_boot_ucode_ptr')
4560 with self.assertRaises(ValueError) as e:
4561 self._DoReadFile('193_tpl_bss_pad.dts')
4562 self.assertIn('Expected __bss_size symbol in tpl/u-boot-tpl',
4563 str(e.exception))
4564
Simon Glass718b5292021-03-18 20:25:07 +13004565 def checkDtbSizes(self, data, pad_len, start):
4566 """Check the size arguments in a dtb embedded in an image
4567
4568 Args:
4569 data: The image data
4570 pad_len: Length of the pad section in the image, in bytes
4571 start: Start offset of the devicetree to examine, within the image
4572
4573 Returns:
4574 Size of the devicetree in bytes
4575 """
4576 dtb_data = data[start:]
4577 dtb = fdt.Fdt.FromData(dtb_data)
4578 fdt_size = dtb.GetFdtObj().totalsize()
4579 dtb.Scan()
4580 props = self._GetPropTree(dtb, 'size')
4581 self.assertEqual({
4582 'size': len(data),
4583 'u-boot-spl/u-boot-spl-bss-pad:size': pad_len,
4584 'u-boot-spl/u-boot-spl-dtb:size': 801,
4585 'u-boot-spl/u-boot-spl-nodtb:size': len(U_BOOT_SPL_NODTB_DATA),
4586 'u-boot-spl:size': 860,
4587 'u-boot-tpl:size': len(U_BOOT_TPL_DATA),
4588 'u-boot/u-boot-dtb:size': 781,
4589 'u-boot/u-boot-nodtb:size': len(U_BOOT_NODTB_DATA),
4590 'u-boot:size': 827,
4591 }, props)
4592 return fdt_size
4593
4594 def testExpanded(self):
4595 """Test that an expanded entry type is selected when needed"""
4596 self._SetupSplElf()
4597 self._SetupTplElf()
4598
4599 # SPL has a devicetree, TPL does not
4600 entry_args = {
4601 'spl-dtb': '1',
4602 'spl-bss-pad': 'y',
4603 'tpl-dtb': '',
4604 }
4605 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4606 entry_args=entry_args)
4607 image = control.images['image']
4608 entries = image.GetEntries()
4609 self.assertEqual(3, len(entries))
4610
4611 # First, u-boot, which should be expanded into u-boot-nodtb and dtb
4612 self.assertIn('u-boot', entries)
4613 entry = entries['u-boot']
4614 self.assertEqual('u-boot-expanded', entry.etype)
4615 subent = entry.GetEntries()
4616 self.assertEqual(2, len(subent))
4617 self.assertIn('u-boot-nodtb', subent)
4618 self.assertIn('u-boot-dtb', subent)
4619
4620 # Second, u-boot-spl, which should be expanded into three parts
4621 self.assertIn('u-boot-spl', entries)
4622 entry = entries['u-boot-spl']
4623 self.assertEqual('u-boot-spl-expanded', entry.etype)
4624 subent = entry.GetEntries()
4625 self.assertEqual(3, len(subent))
4626 self.assertIn('u-boot-spl-nodtb', subent)
4627 self.assertIn('u-boot-spl-bss-pad', subent)
4628 self.assertIn('u-boot-spl-dtb', subent)
4629
4630 # Third, u-boot-tpl, which should be not be expanded, since TPL has no
4631 # devicetree
4632 self.assertIn('u-boot-tpl', entries)
4633 entry = entries['u-boot-tpl']
4634 self.assertEqual('u-boot-tpl', entry.etype)
4635 self.assertEqual(None, entry.GetEntries())
4636
4637 def testExpandedTpl(self):
4638 """Test that an expanded entry type is selected for TPL when needed"""
4639 self._SetupTplElf()
4640
4641 entry_args = {
4642 'tpl-bss-pad': 'y',
4643 'tpl-dtb': 'y',
4644 }
4645 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4646 entry_args=entry_args)
4647 image = control.images['image']
4648 entries = image.GetEntries()
4649 self.assertEqual(1, len(entries))
4650
4651 # We only have u-boot-tpl, which be expanded
4652 self.assertIn('u-boot-tpl', entries)
4653 entry = entries['u-boot-tpl']
4654 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4655 subent = entry.GetEntries()
4656 self.assertEqual(3, len(subent))
4657 self.assertIn('u-boot-tpl-nodtb', subent)
4658 self.assertIn('u-boot-tpl-bss-pad', subent)
4659 self.assertIn('u-boot-tpl-dtb', subent)
4660
4661 def testExpandedNoPad(self):
4662 """Test an expanded entry without BSS pad enabled"""
4663 self._SetupSplElf()
4664 self._SetupTplElf()
4665
4666 # SPL has a devicetree, TPL does not
4667 entry_args = {
4668 'spl-dtb': 'something',
4669 'spl-bss-pad': 'n',
4670 'tpl-dtb': '',
4671 }
4672 self._DoReadFileDtb('194_fdt_incl.dts', use_expanded=True,
4673 entry_args=entry_args)
4674 image = control.images['image']
4675 entries = image.GetEntries()
4676
4677 # Just check u-boot-spl, which should be expanded into two parts
4678 self.assertIn('u-boot-spl', entries)
4679 entry = entries['u-boot-spl']
4680 self.assertEqual('u-boot-spl-expanded', entry.etype)
4681 subent = entry.GetEntries()
4682 self.assertEqual(2, len(subent))
4683 self.assertIn('u-boot-spl-nodtb', subent)
4684 self.assertIn('u-boot-spl-dtb', subent)
4685
4686 def testExpandedTplNoPad(self):
4687 """Test that an expanded entry type with padding disabled in TPL"""
4688 self._SetupTplElf()
4689
4690 entry_args = {
4691 'tpl-bss-pad': '',
4692 'tpl-dtb': 'y',
4693 }
4694 self._DoReadFileDtb('195_fdt_incl_tpl.dts', use_expanded=True,
4695 entry_args=entry_args)
4696 image = control.images['image']
4697 entries = image.GetEntries()
4698 self.assertEqual(1, len(entries))
4699
4700 # We only have u-boot-tpl, which be expanded
4701 self.assertIn('u-boot-tpl', entries)
4702 entry = entries['u-boot-tpl']
4703 self.assertEqual('u-boot-tpl-expanded', entry.etype)
4704 subent = entry.GetEntries()
4705 self.assertEqual(2, len(subent))
4706 self.assertIn('u-boot-tpl-nodtb', subent)
4707 self.assertIn('u-boot-tpl-dtb', subent)
4708
4709 def testFdtInclude(self):
4710 """Test that an Fdt is update within all binaries"""
4711 self._SetupSplElf()
4712 self._SetupTplElf()
4713
4714 # SPL has a devicetree, TPL does not
4715 self.maxDiff = None
4716 entry_args = {
4717 'spl-dtb': '1',
4718 'spl-bss-pad': 'y',
4719 'tpl-dtb': '',
4720 }
4721 # Build the image. It includes two separate devicetree binaries, each
4722 # with their own contents, but all contain the binman definition.
4723 data = self._DoReadFileDtb(
4724 '194_fdt_incl.dts', use_real_dtb=True, use_expanded=True,
4725 update_dtb=True, entry_args=entry_args)[0]
4726 pad_len = 10
4727
4728 # Check the U-Boot dtb
4729 start = len(U_BOOT_NODTB_DATA)
4730 fdt_size = self.checkDtbSizes(data, pad_len, start)
4731
4732 # Now check SPL
4733 start += fdt_size + len(U_BOOT_SPL_NODTB_DATA) + pad_len
4734 fdt_size = self.checkDtbSizes(data, pad_len, start)
4735
4736 # TPL has no devicetree
4737 start += fdt_size + len(U_BOOT_TPL_DATA)
4738 self.assertEqual(len(data), start)
Simon Glassbb395742020-10-26 17:40:14 -06004739
Simon Glass7098b7f2021-03-21 18:24:30 +13004740 def testSymbolsExpanded(self):
4741 """Test binman can assign symbols in expanded entries"""
4742 entry_args = {
4743 'spl-dtb': '1',
4744 }
4745 self.checkSymbols('197_symbols_expand.dts', U_BOOT_SPL_NODTB_DATA +
4746 U_BOOT_SPL_DTB_DATA, 0x38,
4747 entry_args=entry_args, use_expanded=True)
4748
Simon Glasse1915782021-03-21 18:24:31 +13004749 def testCollection(self):
4750 """Test a collection"""
4751 data = self._DoReadFile('198_collection.dts')
4752 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
Simon Glass80025522022-01-29 14:14:04 -07004753 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
4754 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
Simon Glasse1915782021-03-21 18:24:31 +13004755 data)
4756
Simon Glass27a7f772021-03-21 18:24:32 +13004757 def testCollectionSection(self):
4758 """Test a collection where a section must be built first"""
4759 # Sections never have their contents when GetData() is called, but when
Simon Glass7e3f89f2021-11-23 11:03:47 -07004760 # BuildSectionData() is called with required=True, a section will force
Simon Glass27a7f772021-03-21 18:24:32 +13004761 # building the contents, producing an error is anything is still
4762 # missing.
4763 data = self._DoReadFile('199_collection_section.dts')
4764 section = U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA
Simon Glass80025522022-01-29 14:14:04 -07004765 self.assertEqual(section + U_BOOT_DATA + tools.get_bytes(0xff, 2) +
4766 section + tools.get_bytes(0xfe, 3) + U_BOOT_DATA,
Simon Glass27a7f772021-03-21 18:24:32 +13004767 data)
4768
Simon Glassf427c5f2021-03-21 18:24:33 +13004769 def testAlignDefault(self):
4770 """Test that default alignment works on sections"""
4771 data = self._DoReadFile('200_align_default.dts')
Simon Glass80025522022-01-29 14:14:04 -07004772 expected = (U_BOOT_DATA + tools.get_bytes(0, 8 - len(U_BOOT_DATA)) +
Simon Glassf427c5f2021-03-21 18:24:33 +13004773 U_BOOT_DATA)
4774 # Special alignment for section
Simon Glass80025522022-01-29 14:14:04 -07004775 expected += tools.get_bytes(0, 32 - len(expected))
Simon Glassf427c5f2021-03-21 18:24:33 +13004776 # No alignment within the nested section
4777 expected += U_BOOT_DATA + U_BOOT_NODTB_DATA;
4778 # Now the final piece, which should be default-aligned
Simon Glass80025522022-01-29 14:14:04 -07004779 expected += tools.get_bytes(0, 88 - len(expected)) + U_BOOT_NODTB_DATA
Simon Glassf427c5f2021-03-21 18:24:33 +13004780 self.assertEqual(expected, data)
Simon Glass27a7f772021-03-21 18:24:32 +13004781
Bin Mengc0b15742021-05-10 20:23:33 +08004782 def testPackOpenSBI(self):
4783 """Test that an image with an OpenSBI binary can be created"""
4784 data = self._DoReadFile('201_opensbi.dts')
4785 self.assertEqual(OPENSBI_DATA, data[:len(OPENSBI_DATA)])
4786
Simon Glass76f496d2021-07-06 10:36:37 -06004787 def testSectionsSingleThread(self):
4788 """Test sections without multithreading"""
4789 data = self._DoReadFileDtb('055_sections.dts', threads=0)[0]
Simon Glass80025522022-01-29 14:14:04 -07004790 expected = (U_BOOT_DATA + tools.get_bytes(ord('!'), 12) +
4791 U_BOOT_DATA + tools.get_bytes(ord('a'), 12) +
4792 U_BOOT_DATA + tools.get_bytes(ord('&'), 4))
Simon Glass76f496d2021-07-06 10:36:37 -06004793 self.assertEqual(expected, data)
4794
4795 def testThreadTimeout(self):
4796 """Test handling a thread that takes too long"""
4797 with self.assertRaises(ValueError) as e:
4798 self._DoTestFile('202_section_timeout.dts',
4799 test_section_timeout=True)
Simon Glass2d59d152021-10-18 12:13:15 -06004800 self.assertIn("Timed out obtaining contents", str(e.exception))
Simon Glass76f496d2021-07-06 10:36:37 -06004801
Simon Glass748a1d42021-07-06 10:36:41 -06004802 def testTiming(self):
4803 """Test output of timing information"""
4804 data = self._DoReadFile('055_sections.dts')
4805 with test_util.capture_sys_output() as (stdout, stderr):
4806 state.TimingShow()
4807 self.assertIn('read:', stdout.getvalue())
4808 self.assertIn('compress:', stdout.getvalue())
4809
Simon Glassadfb8492021-11-03 21:09:18 -06004810 def testUpdateFdtInElf(self):
4811 """Test that we can update the devicetree in an ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004812 if not elf.ELF_TOOLS:
4813 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004814 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4815 outfile = os.path.join(self._indir, 'u-boot.out')
4816 begin_sym = 'dtb_embed_begin'
4817 end_sym = 'dtb_embed_end'
4818 retcode = self._DoTestFile(
4819 '060_fdt_update.dts', update_dtb=True,
4820 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4821 self.assertEqual(0, retcode)
4822
4823 # Check that the output file does in fact contact a dtb with the binman
4824 # definition in the correct place
4825 syms = elf.GetSymbolFileOffset(infile,
4826 ['dtb_embed_begin', 'dtb_embed_end'])
Simon Glass80025522022-01-29 14:14:04 -07004827 data = tools.read_file(outfile)
Simon Glassadfb8492021-11-03 21:09:18 -06004828 dtb_data = data[syms['dtb_embed_begin'].offset:
4829 syms['dtb_embed_end'].offset]
4830
4831 dtb = fdt.Fdt.FromData(dtb_data)
4832 dtb.Scan()
4833 props = self._GetPropTree(dtb, BASE_DTB_PROPS + REPACK_DTB_PROPS)
4834 self.assertEqual({
4835 'image-pos': 0,
4836 'offset': 0,
4837 '_testing:offset': 32,
4838 '_testing:size': 2,
4839 '_testing:image-pos': 32,
4840 'section@0/u-boot:offset': 0,
4841 'section@0/u-boot:size': len(U_BOOT_DATA),
4842 'section@0/u-boot:image-pos': 0,
4843 'section@0:offset': 0,
4844 'section@0:size': 16,
4845 'section@0:image-pos': 0,
4846
4847 'section@1/u-boot:offset': 0,
4848 'section@1/u-boot:size': len(U_BOOT_DATA),
4849 'section@1/u-boot:image-pos': 16,
4850 'section@1:offset': 16,
4851 'section@1:size': 16,
4852 'section@1:image-pos': 16,
4853 'size': 40
4854 }, props)
4855
4856 def testUpdateFdtInElfInvalid(self):
4857 """Test that invalid args are detected with --update-fdt-in-elf"""
4858 with self.assertRaises(ValueError) as e:
4859 self._DoTestFile('060_fdt_update.dts', update_fdt_in_elf='fred')
4860 self.assertIn("Invalid args ['fred'] to --update-fdt-in-elf",
4861 str(e.exception))
4862
4863 def testUpdateFdtInElfNoSyms(self):
4864 """Test that missing symbols are detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004865 if not elf.ELF_TOOLS:
4866 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004867 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed')
4868 outfile = ''
4869 begin_sym = 'wrong_begin'
4870 end_sym = 'wrong_end'
4871 with self.assertRaises(ValueError) as e:
4872 self._DoTestFile(
4873 '060_fdt_update.dts',
4874 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4875 self.assertIn("Expected two symbols 'wrong_begin' and 'wrong_end': got 0:",
4876 str(e.exception))
4877
4878 def testUpdateFdtInElfTooSmall(self):
4879 """Test that an over-large dtb is detected with --update-fdt-in-elf"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02004880 if not elf.ELF_TOOLS:
4881 self.skipTest('Python elftools not available')
Simon Glassadfb8492021-11-03 21:09:18 -06004882 infile = elf_fname = self.ElfTestFile('u_boot_binman_embed_sm')
4883 outfile = os.path.join(self._indir, 'u-boot.out')
4884 begin_sym = 'dtb_embed_begin'
4885 end_sym = 'dtb_embed_end'
4886 with self.assertRaises(ValueError) as e:
4887 self._DoTestFile(
4888 '060_fdt_update.dts', update_dtb=True,
4889 update_fdt_in_elf=','.join([infile,outfile,begin_sym,end_sym]))
4890 self.assertRegex(
4891 str(e.exception),
4892 "Not enough space in '.*u_boot_binman_embed_sm' for data length.*")
4893
Simon Glass88e04da2021-11-23 11:03:42 -07004894 def testVersion(self):
4895 """Test we can get the binman version"""
4896 version = '(unreleased)'
4897 self.assertEqual(version, state.GetVersion(self._indir))
4898
4899 with self.assertRaises(SystemExit):
4900 with test_util.capture_sys_output() as (_, stderr):
4901 self._DoBinman('-V')
4902 self.assertEqual('Binman %s\n' % version, stderr.getvalue())
4903
4904 # Try running the tool too, just to be safe
4905 result = self._RunBinman('-V')
4906 self.assertEqual('Binman %s\n' % version, result.stderr)
4907
4908 # Set up a version file to make sure that works
4909 version = 'v2025.01-rc2'
Simon Glass80025522022-01-29 14:14:04 -07004910 tools.write_file(os.path.join(self._indir, 'version'), version,
Simon Glass88e04da2021-11-23 11:03:42 -07004911 binary=False)
4912 self.assertEqual(version, state.GetVersion(self._indir))
4913
Simon Glass637958f2021-11-23 21:09:50 -07004914 def testAltFormat(self):
4915 """Test that alternative formats can be used to extract"""
4916 self._DoReadFileRealDtb('213_fdtmap_alt_format.dts')
4917
4918 try:
4919 tmpdir, updated_fname = self._SetupImageInTmpdir()
4920 with test_util.capture_sys_output() as (stdout, _):
4921 self._DoBinman('extract', '-i', updated_fname, '-F', 'list')
4922 self.assertEqual(
4923 '''Flag (-F) Entry type Description
4924fdt fdtmap Extract the devicetree blob from the fdtmap
4925''',
4926 stdout.getvalue())
4927
4928 dtb = os.path.join(tmpdir, 'fdt.dtb')
4929 self._DoBinman('extract', '-i', updated_fname, '-F', 'fdt', '-f',
4930 dtb, 'fdtmap')
4931
4932 # Check that we can read it and it can be scanning, meaning it does
4933 # not have a 16-byte fdtmap header
Simon Glass80025522022-01-29 14:14:04 -07004934 data = tools.read_file(dtb)
Simon Glass637958f2021-11-23 21:09:50 -07004935 dtb = fdt.Fdt.FromData(data)
4936 dtb.Scan()
4937
4938 # Now check u-boot which has no alt_format
4939 fname = os.path.join(tmpdir, 'fdt.dtb')
4940 self._DoBinman('extract', '-i', updated_fname, '-F', 'dummy',
4941 '-f', fname, 'u-boot')
Simon Glass80025522022-01-29 14:14:04 -07004942 data = tools.read_file(fname)
Simon Glass637958f2021-11-23 21:09:50 -07004943 self.assertEqual(U_BOOT_DATA, data)
4944
4945 finally:
4946 shutil.rmtree(tmpdir)
4947
Simon Glass0b00ae62021-11-23 21:09:52 -07004948 def testExtblobList(self):
4949 """Test an image with an external blob list"""
4950 data = self._DoReadFile('215_blob_ext_list.dts')
4951 self.assertEqual(REFCODE_DATA + FSP_M_DATA, data)
4952
4953 def testExtblobListMissing(self):
4954 """Test an image with a missing external blob"""
4955 with self.assertRaises(ValueError) as e:
4956 self._DoReadFile('216_blob_ext_list_missing.dts')
4957 self.assertIn("Filename 'missing-file' not found in input path",
4958 str(e.exception))
4959
4960 def testExtblobListMissingOk(self):
4961 """Test an image with an missing external blob that is allowed"""
4962 with test_util.capture_sys_output() as (stdout, stderr):
4963 self._DoTestFile('216_blob_ext_list_missing.dts',
4964 allow_missing=True)
4965 err = stderr.getvalue()
4966 self.assertRegex(err, "Image 'main-section'.*missing.*: blob-ext")
4967
Simon Glass3efb2972021-11-23 21:08:59 -07004968 def testFip(self):
4969 """Basic test of generation of an ARM Firmware Image Package (FIP)"""
4970 data = self._DoReadFile('203_fip.dts')
4971 hdr, fents = fip_util.decode_fip(data)
4972 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
4973 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
4974 self.assertEqual(0x123, hdr.flags)
4975
4976 self.assertEqual(2, len(fents))
4977
4978 fent = fents[0]
4979 self.assertEqual(
4980 bytes([0x47, 0xd4, 0x08, 0x6d, 0x4c, 0xfe, 0x98, 0x46,
4981 0x9b, 0x95, 0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x0]), fent.uuid)
4982 self.assertEqual('soc-fw', fent.fip_type)
4983 self.assertEqual(0x88, fent.offset)
4984 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4985 self.assertEqual(0x123456789abcdef, fent.flags)
4986 self.assertEqual(ATF_BL31_DATA, fent.data)
4987 self.assertEqual(True, fent.valid)
4988
4989 fent = fents[1]
4990 self.assertEqual(
4991 bytes([0x65, 0x92, 0x27, 0x03, 0x2f, 0x74, 0xe6, 0x44,
4992 0x8d, 0xff, 0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10]), fent.uuid)
4993 self.assertEqual('scp-fwu-cfg', fent.fip_type)
4994 self.assertEqual(0x8c, fent.offset)
4995 self.assertEqual(len(ATF_BL31_DATA), fent.size)
4996 self.assertEqual(0, fent.flags)
4997 self.assertEqual(ATF_BL2U_DATA, fent.data)
4998 self.assertEqual(True, fent.valid)
4999
5000 def testFipOther(self):
5001 """Basic FIP with something that isn't a external blob"""
5002 data = self._DoReadFile('204_fip_other.dts')
5003 hdr, fents = fip_util.decode_fip(data)
5004
5005 self.assertEqual(2, len(fents))
5006 fent = fents[1]
5007 self.assertEqual('rot-cert', fent.fip_type)
5008 self.assertEqual(b'aa', fent.data)
5009
Simon Glass3efb2972021-11-23 21:08:59 -07005010 def testFipNoType(self):
5011 """FIP with an entry of an unknown type"""
5012 with self.assertRaises(ValueError) as e:
5013 self._DoReadFile('205_fip_no_type.dts')
5014 self.assertIn("Must provide a fip-type (node name 'u-boot' is not a known FIP type)",
5015 str(e.exception))
5016
5017 def testFipUuid(self):
5018 """Basic FIP with a manual uuid"""
5019 data = self._DoReadFile('206_fip_uuid.dts')
5020 hdr, fents = fip_util.decode_fip(data)
5021
5022 self.assertEqual(2, len(fents))
5023 fent = fents[1]
5024 self.assertEqual(None, fent.fip_type)
5025 self.assertEqual(
5026 bytes([0xfc, 0x65, 0x13, 0x92, 0x4a, 0x5b, 0x11, 0xec,
5027 0x94, 0x35, 0xff, 0x2d, 0x1c, 0xfc, 0x79, 0x9c]),
5028 fent.uuid)
5029 self.assertEqual(U_BOOT_DATA, fent.data)
5030
5031 def testFipLs(self):
5032 """Test listing a FIP"""
5033 data = self._DoReadFileRealDtb('207_fip_ls.dts')
5034 hdr, fents = fip_util.decode_fip(data)
5035
5036 try:
5037 tmpdir, updated_fname = self._SetupImageInTmpdir()
5038 with test_util.capture_sys_output() as (stdout, stderr):
5039 self._DoBinman('ls', '-i', updated_fname)
5040 finally:
5041 shutil.rmtree(tmpdir)
5042 lines = stdout.getvalue().splitlines()
5043 expected = [
5044'Name Image-pos Size Entry-type Offset Uncomp-size',
5045'----------------------------------------------------------------',
5046'main-section 0 2d3 section 0',
5047' atf-fip 0 90 atf-fip 0',
5048' soc-fw 88 4 blob-ext 88',
5049' u-boot 8c 4 u-boot 8c',
5050' fdtmap 90 243 fdtmap 90',
5051]
5052 self.assertEqual(expected, lines)
5053
5054 image = control.images['image']
5055 entries = image.GetEntries()
5056 fdtmap = entries['fdtmap']
5057
5058 fdtmap_data = data[fdtmap.image_pos:fdtmap.image_pos + fdtmap.size]
5059 magic = fdtmap_data[:8]
5060 self.assertEqual(b'_FDTMAP_', magic)
Simon Glass80025522022-01-29 14:14:04 -07005061 self.assertEqual(tools.get_bytes(0, 8), fdtmap_data[8:16])
Simon Glass3efb2972021-11-23 21:08:59 -07005062
5063 fdt_data = fdtmap_data[16:]
5064 dtb = fdt.Fdt.FromData(fdt_data)
5065 dtb.Scan()
5066 props = self._GetPropTree(dtb, BASE_DTB_PROPS, prefix='/')
5067 self.assertEqual({
5068 'atf-fip/soc-fw:image-pos': 136,
5069 'atf-fip/soc-fw:offset': 136,
5070 'atf-fip/soc-fw:size': 4,
5071 'atf-fip/u-boot:image-pos': 140,
5072 'atf-fip/u-boot:offset': 140,
5073 'atf-fip/u-boot:size': 4,
5074 'atf-fip:image-pos': 0,
5075 'atf-fip:offset': 0,
5076 'atf-fip:size': 144,
5077 'image-pos': 0,
5078 'offset': 0,
5079 'fdtmap:image-pos': fdtmap.image_pos,
5080 'fdtmap:offset': fdtmap.offset,
5081 'fdtmap:size': len(fdtmap_data),
5082 'size': len(data),
5083 }, props)
5084
5085 def testFipExtractOneEntry(self):
5086 """Test extracting a single entry fron an FIP"""
5087 self._DoReadFileRealDtb('207_fip_ls.dts')
Simon Glass80025522022-01-29 14:14:04 -07005088 image_fname = tools.get_output_filename('image.bin')
Simon Glass3efb2972021-11-23 21:08:59 -07005089 fname = os.path.join(self._indir, 'output.extact')
5090 control.ExtractEntries(image_fname, fname, None, ['atf-fip/u-boot'])
Simon Glass80025522022-01-29 14:14:04 -07005091 data = tools.read_file(fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005092 self.assertEqual(U_BOOT_DATA, data)
5093
5094 def testFipReplace(self):
5095 """Test replacing a single file in a FIP"""
Simon Glass80025522022-01-29 14:14:04 -07005096 expected = U_BOOT_DATA + tools.get_bytes(0x78, 50)
Simon Glass3efb2972021-11-23 21:08:59 -07005097 data = self._DoReadFileRealDtb('208_fip_replace.dts')
Simon Glass80025522022-01-29 14:14:04 -07005098 updated_fname = tools.get_output_filename('image-updated.bin')
5099 tools.write_file(updated_fname, data)
Simon Glass3efb2972021-11-23 21:08:59 -07005100 entry_name = 'atf-fip/u-boot'
5101 control.WriteEntry(updated_fname, entry_name, expected,
5102 allow_resize=True)
5103 actual = control.ReadEntry(updated_fname, entry_name)
5104 self.assertEqual(expected, actual)
5105
Simon Glass80025522022-01-29 14:14:04 -07005106 new_data = tools.read_file(updated_fname)
Simon Glass3efb2972021-11-23 21:08:59 -07005107 hdr, fents = fip_util.decode_fip(new_data)
5108
5109 self.assertEqual(2, len(fents))
5110
5111 # Check that the FIP entry is updated
5112 fent = fents[1]
5113 self.assertEqual(0x8c, fent.offset)
5114 self.assertEqual(len(expected), fent.size)
5115 self.assertEqual(0, fent.flags)
5116 self.assertEqual(expected, fent.data)
5117 self.assertEqual(True, fent.valid)
5118
5119 def testFipMissing(self):
5120 with test_util.capture_sys_output() as (stdout, stderr):
5121 self._DoTestFile('209_fip_missing.dts', allow_missing=True)
5122 err = stderr.getvalue()
5123 self.assertRegex(err, "Image 'main-section'.*missing.*: rmm-fw")
5124
5125 def testFipSize(self):
5126 """Test a FIP with a size property"""
5127 data = self._DoReadFile('210_fip_size.dts')
5128 self.assertEqual(0x100 + len(U_BOOT_DATA), len(data))
5129 hdr, fents = fip_util.decode_fip(data)
5130 self.assertEqual(fip_util.HEADER_MAGIC, hdr.name)
5131 self.assertEqual(fip_util.HEADER_SERIAL, hdr.serial)
5132
5133 self.assertEqual(1, len(fents))
5134
5135 fent = fents[0]
5136 self.assertEqual('soc-fw', fent.fip_type)
5137 self.assertEqual(0x60, fent.offset)
5138 self.assertEqual(len(ATF_BL31_DATA), fent.size)
5139 self.assertEqual(ATF_BL31_DATA, fent.data)
5140 self.assertEqual(True, fent.valid)
5141
5142 rest = data[0x60 + len(ATF_BL31_DATA):0x100]
Simon Glass80025522022-01-29 14:14:04 -07005143 self.assertEqual(tools.get_bytes(0xff, len(rest)), rest)
Simon Glass3efb2972021-11-23 21:08:59 -07005144
5145 def testFipBadAlign(self):
5146 """Test that an invalid alignment value in a FIP is detected"""
5147 with self.assertRaises(ValueError) as e:
5148 self._DoTestFile('211_fip_bad_align.dts')
5149 self.assertIn(
5150 "Node \'/binman/atf-fip\': FIP alignment 31 must be a power of two",
5151 str(e.exception))
5152
5153 def testFipCollection(self):
5154 """Test using a FIP in a collection"""
5155 data = self._DoReadFile('212_fip_collection.dts')
5156 entry1 = control.images['image'].GetEntries()['collection']
5157 data1 = data[:entry1.size]
5158 hdr1, fents2 = fip_util.decode_fip(data1)
5159
5160 entry2 = control.images['image'].GetEntries()['atf-fip']
5161 data2 = data[entry2.offset:entry2.offset + entry2.size]
5162 hdr1, fents2 = fip_util.decode_fip(data2)
5163
5164 # The 'collection' entry should have U-Boot included at the end
5165 self.assertEqual(entry1.size - len(U_BOOT_DATA), entry2.size)
5166 self.assertEqual(data1, data2 + U_BOOT_DATA)
5167 self.assertEqual(U_BOOT_DATA, data1[-4:])
5168
5169 # There should be a U-Boot after the final FIP
5170 self.assertEqual(U_BOOT_DATA, data[-4:])
Simon Glass76f496d2021-07-06 10:36:37 -06005171
Simon Glassccae6862022-01-12 13:10:35 -07005172 def testFakeBlob(self):
5173 """Test handling of faking an external blob"""
5174 with test_util.capture_sys_output() as (stdout, stderr):
5175 self._DoTestFile('217_fake_blob.dts', allow_missing=True,
5176 allow_fake_blobs=True)
5177 err = stderr.getvalue()
5178 self.assertRegex(
5179 err,
5180 "Image '.*' has faked external blobs and is non-functional: .*")
Simon Glassccae6862022-01-12 13:10:35 -07005181
Simon Glassceb5f912022-01-09 20:13:46 -07005182 def testExtblobListFaked(self):
5183 """Test an extblob with missing external blob that are faked"""
5184 with test_util.capture_sys_output() as (stdout, stderr):
5185 self._DoTestFile('216_blob_ext_list_missing.dts',
5186 allow_fake_blobs=True)
5187 err = stderr.getvalue()
5188 self.assertRegex(err, "Image 'main-section'.*faked.*: blob-ext-list")
5189
Simon Glass162017b2022-01-09 20:13:57 -07005190 def testListBintools(self):
5191 args = ['tool', '--list']
5192 with test_util.capture_sys_output() as (stdout, _):
5193 self._DoBinman(*args)
5194 out = stdout.getvalue().splitlines()
5195 self.assertTrue(len(out) >= 2)
5196
5197 def testFetchBintools(self):
5198 def fail_download(url):
Simon Glass80025522022-01-29 14:14:04 -07005199 """Take the tools.download() function by raising an exception"""
Simon Glass162017b2022-01-09 20:13:57 -07005200 raise urllib.error.URLError('my error')
5201
5202 args = ['tool']
5203 with self.assertRaises(ValueError) as e:
5204 self._DoBinman(*args)
5205 self.assertIn("Invalid arguments to 'tool' subcommand",
5206 str(e.exception))
5207
5208 args = ['tool', '--fetch']
5209 with self.assertRaises(ValueError) as e:
5210 self._DoBinman(*args)
5211 self.assertIn('Please specify bintools to fetch', str(e.exception))
5212
5213 args = ['tool', '--fetch', '_testing']
Simon Glass80025522022-01-29 14:14:04 -07005214 with unittest.mock.patch.object(tools, 'download',
Simon Glass162017b2022-01-09 20:13:57 -07005215 side_effect=fail_download):
5216 with test_util.capture_sys_output() as (stdout, _):
5217 self._DoBinman(*args)
5218 self.assertIn('failed to fetch with all methods', stdout.getvalue())
5219
Simon Glassdab7c142022-01-09 20:14:10 -07005220 def testInvalidCompress(self):
5221 with self.assertRaises(ValueError) as e:
5222 comp_util.compress(b'', 'invalid')
5223 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5224
5225 with self.assertRaises(ValueError) as e:
5226 comp_util.decompress(b'1234', 'invalid')
5227 self.assertIn("Unknown algorithm 'invalid'", str(e.exception))
5228
Simon Glass620c4462022-01-09 20:14:11 -07005229 def testBintoolDocs(self):
5230 """Test for creation of bintool documentation"""
5231 with test_util.capture_sys_output() as (stdout, stderr):
5232 control.write_bintool_docs(control.bintool.Bintool.get_tool_list())
5233 self.assertTrue(len(stdout.getvalue()) > 0)
5234
5235 def testBintoolDocsMissing(self):
5236 """Test handling of missing bintool documentation"""
5237 with self.assertRaises(ValueError) as e:
5238 with test_util.capture_sys_output() as (stdout, stderr):
5239 control.write_bintool_docs(
5240 control.bintool.Bintool.get_tool_list(), 'mkimage')
5241 self.assertIn('Documentation is missing for modules: mkimage',
5242 str(e.exception))
5243
Jan Kiszka58c407f2022-01-28 20:37:53 +01005244 def testListWithGenNode(self):
5245 """Check handling of an FDT map when the section cannot be found"""
5246 entry_args = {
5247 'of-list': 'test-fdt1 test-fdt2',
5248 }
5249 data = self._DoReadFileDtb(
5250 '219_fit_gennode.dts',
5251 entry_args=entry_args,
5252 use_real_dtb=True,
5253 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])
5254
5255 try:
5256 tmpdir, updated_fname = self._SetupImageInTmpdir()
5257 with test_util.capture_sys_output() as (stdout, stderr):
5258 self._RunBinman('ls', '-i', updated_fname)
5259 finally:
5260 shutil.rmtree(tmpdir)
5261
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005262 def testFitSubentryUsesBintool(self):
5263 """Test that binman FIT subentries can use bintools"""
5264 command.test_result = self._HandleGbbCommand
5265 entry_args = {
5266 'keydir': 'devkeys',
5267 'bmpblk': 'bmpblk.bin',
5268 }
5269 data, _, _, _ = self._DoReadFileDtb('220_fit_subentry_bintool.dts',
5270 entry_args=entry_args)
5271
Alper Nebi Yasakd4553262022-02-08 01:08:07 +03005272 expected = (GBB_DATA + GBB_DATA + tools.get_bytes(0, 8) +
5273 tools.get_bytes(0, 0x2180 - 16))
Alper Nebi Yasake706d872022-02-08 01:08:05 +03005274 self.assertIn(expected, data)
5275
5276 def testFitSubentryMissingBintool(self):
5277 """Test that binman reports missing bintools for FIT subentries"""
5278 entry_args = {
5279 'keydir': 'devkeys',
5280 }
5281 with test_util.capture_sys_output() as (_, stderr):
5282 self._DoTestFile('220_fit_subentry_bintool.dts',
5283 force_missing_bintools='futility', entry_args=entry_args)
5284 err = stderr.getvalue()
5285 self.assertRegex(err,
5286 "Image 'main-section'.*missing bintools.*: futility")
Simon Glassccae6862022-01-12 13:10:35 -07005287
Alper Nebi Yasak1e4ffd82022-02-09 22:02:35 +03005288 def testFitSubentryHashSubnode(self):
5289 """Test an image with a FIT inside"""
5290 data, _, _, out_dtb_name = self._DoReadFileDtb(
5291 '221_fit_subentry_hash.dts', use_real_dtb=True, update_dtb=True)
5292
5293 mkimage_dtb = fdt.Fdt.FromData(data)
5294 mkimage_dtb.Scan()
5295 binman_dtb = fdt.Fdt(out_dtb_name)
5296 binman_dtb.Scan()
5297
5298 # Check that binman didn't add hash values
5299 fnode = binman_dtb.GetNode('/binman/fit/images/kernel/hash')
5300 self.assertNotIn('value', fnode.props)
5301
5302 fnode = binman_dtb.GetNode('/binman/fit/images/fdt-1/hash')
5303 self.assertNotIn('value', fnode.props)
5304
5305 # Check that mkimage added hash values
5306 fnode = mkimage_dtb.GetNode('/images/kernel/hash')
5307 self.assertIn('value', fnode.props)
5308
5309 fnode = mkimage_dtb.GetNode('/images/fdt-1/hash')
5310 self.assertIn('value', fnode.props)
5311
Roger Quadros5cdcea02022-02-19 20:50:04 +02005312 def testPackTeeOs(self):
5313 """Test that an image with an TEE binary can be created"""
5314 data = self._DoReadFile('222_tee_os.dts')
5315 self.assertEqual(TEE_OS_DATA, data[:len(TEE_OS_DATA)])
5316
Simon Glass912339f2022-02-08 11:50:03 -07005317 def testFitFdtOper(self):
5318 """Check handling of a specified FIT operation"""
5319 entry_args = {
5320 'of-list': 'test-fdt1 test-fdt2',
5321 'default-dt': 'test-fdt2',
5322 }
5323 self._DoReadFileDtb(
5324 '223_fit_fdt_oper.dts',
5325 entry_args=entry_args,
5326 extra_indirs=[os.path.join(self._indir, TEST_FDT_SUBDIR)])[0]
5327
5328 def testFitFdtBadOper(self):
5329 """Check handling of an FDT map when the section cannot be found"""
5330 with self.assertRaises(ValueError) as exc:
5331 self._DoReadFileDtb('224_fit_bad_oper.dts')
Simon Glass05f71dc2022-03-05 20:19:09 -07005332 self.assertIn("Node '/binman/fit': subnode 'images/@fdt-SEQ': Unknown operation 'unknown'",
Simon Glass912339f2022-02-08 11:50:03 -07005333 str(exc.exception))
5334
Simon Glassdd156a42022-03-05 20:18:59 -07005335 def test_uses_expand_size(self):
5336 """Test that the 'expand-size' property cannot be used anymore"""
5337 with self.assertRaises(ValueError) as e:
5338 data = self._DoReadFile('225_expand_size_bad.dts')
5339 self.assertIn(
5340 "Node '/binman/u-boot': Please use 'extend-size' instead of 'expand-size'",
5341 str(e.exception))
5342
Simon Glassfc5a1682022-03-05 20:19:05 -07005343 def testMkimageMissingBlob(self):
5344 """Test using mkimage to build an image"""
5345 with test_util.capture_sys_output() as (stdout, stderr):
5346 self._DoTestFile('229_mkimage_missing.dts', allow_missing=True,
5347 allow_fake_blobs=True)
5348 err = stderr.getvalue()
5349 self.assertRegex(
5350 err,
5351 "Image '.*' has faked external blobs and is non-functional: .*")
5352
Simon Glass5f423422022-03-05 20:19:12 -07005353 def testFitSplitElf(self):
5354 """Test an image with an FIT with an split-elf operation"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005355 if not elf.ELF_TOOLS:
5356 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005357 entry_args = {
5358 'of-list': 'test-fdt1 test-fdt2',
5359 'default-dt': 'test-fdt2',
5360 'atf-bl31-path': 'bl31.elf',
5361 'tee-os-path': 'tee.elf',
5362 }
5363 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5364 data = self._DoReadFileDtb(
5365 '226_fit_split_elf.dts',
5366 entry_args=entry_args,
5367 extra_indirs=[test_subdir])[0]
5368
5369 self.assertEqual(U_BOOT_NODTB_DATA, data[-len(U_BOOT_NODTB_DATA):])
5370 fit_data = data[len(U_BOOT_DATA):-len(U_BOOT_NODTB_DATA)]
5371
5372 base_keys = {'description', 'type', 'arch', 'os', 'compression',
5373 'data', 'load'}
5374 dtb = fdt.Fdt.FromData(fit_data)
5375 dtb.Scan()
5376
5377 elf_data = tools.read_file(os.path.join(self._indir, 'bl31.elf'))
5378 segments, entry = elf.read_loadable_segments(elf_data)
5379
5380 # We assume there are two segments
5381 self.assertEquals(2, len(segments))
5382
5383 atf1 = dtb.GetNode('/images/atf-1')
5384 _, start, data = segments[0]
5385 self.assertEqual(base_keys | {'entry'}, atf1.props.keys())
5386 self.assertEqual(entry,
5387 fdt_util.fdt32_to_cpu(atf1.props['entry'].value))
5388 self.assertEqual(start,
5389 fdt_util.fdt32_to_cpu(atf1.props['load'].value))
5390 self.assertEqual(data, atf1.props['data'].bytes)
5391
5392 atf2 = dtb.GetNode('/images/atf-2')
5393 self.assertEqual(base_keys, atf2.props.keys())
5394 _, start, data = segments[1]
5395 self.assertEqual(start,
5396 fdt_util.fdt32_to_cpu(atf2.props['load'].value))
5397 self.assertEqual(data, atf2.props['data'].bytes)
5398
5399 conf = dtb.GetNode('/configurations')
5400 self.assertEqual({'default'}, conf.props.keys())
5401
5402 for subnode in conf.subnodes:
5403 self.assertEqual({'description', 'fdt', 'loadables'},
5404 subnode.props.keys())
5405 self.assertEqual(
5406 ['atf-1', 'atf-2', 'tee-1', 'tee-2'],
5407 fdt_util.GetStringList(subnode, 'loadables'))
5408
5409 def _check_bad_fit(self, dts):
5410 """Check a bad FIT
5411
5412 This runs with the given dts and returns the assertion raised
5413
5414 Args:
5415 dts (str): dts filename to use
5416
5417 Returns:
5418 str: Assertion string raised
5419 """
5420 entry_args = {
5421 'of-list': 'test-fdt1 test-fdt2',
5422 'default-dt': 'test-fdt2',
5423 'atf-bl31-path': 'bl31.elf',
5424 'tee-os-path': 'tee.elf',
5425 }
5426 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5427 with self.assertRaises(ValueError) as exc:
5428 self._DoReadFileDtb(dts, entry_args=entry_args,
5429 extra_indirs=[test_subdir])[0]
5430 return str(exc.exception)
5431
5432 def testFitSplitElfBadElf(self):
5433 """Test a FIT split-elf operation with an invalid ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005434 if not elf.ELF_TOOLS:
5435 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005436 TestFunctional._MakeInputFile('bad.elf', tools.get_bytes(100, 100))
5437 entry_args = {
5438 'of-list': 'test-fdt1 test-fdt2',
5439 'default-dt': 'test-fdt2',
5440 'atf-bl31-path': 'bad.elf',
5441 'tee-os-path': 'tee.elf',
5442 }
5443 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5444 with self.assertRaises(ValueError) as exc:
5445 self._DoReadFileDtb(
5446 '226_fit_split_elf.dts',
5447 entry_args=entry_args,
5448 extra_indirs=[test_subdir])[0]
5449 self.assertIn(
5450 "Node '/binman/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Magic number does not match",
5451 str(exc.exception))
5452
5453 def testFitSplitElfBadDirective(self):
5454 """Test a FIT split-elf invalid fit,xxx directive in an image node"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005455 if not elf.ELF_TOOLS:
5456 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005457 err = self._check_bad_fit('227_fit_bad_dir.dts')
5458 self.assertIn(
5459 "Node '/binman/fit': subnode 'images/@atf-SEQ': Unknown directive 'fit,something'",
5460 err)
5461
5462 def testFitSplitElfBadDirectiveConfig(self):
5463 """Test a FIT split-elf with invalid fit,xxx directive in config"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005464 if not elf.ELF_TOOLS:
5465 self.skipTest('Python elftools not available')
Simon Glass5f423422022-03-05 20:19:12 -07005466 err = self._check_bad_fit('228_fit_bad_dir_config.dts')
5467 self.assertEqual(
5468 "Node '/binman/fit': subnode 'configurations/@config-SEQ': Unknown directive 'fit,config'",
5469 err)
5470
5471 def checkFitSplitElf(self, **kwargs):
Simon Glass7d3e4072022-08-07 09:46:46 -06005472 """Test an split-elf FIT with a missing ELF file
5473
5474 Args:
5475 kwargs (dict of str): Arguments to pass to _DoTestFile()
5476
5477 Returns:
5478 tuple:
5479 str: stdout result
5480 str: stderr result
5481 """
Simon Glass5f423422022-03-05 20:19:12 -07005482 entry_args = {
5483 'of-list': 'test-fdt1 test-fdt2',
5484 'default-dt': 'test-fdt2',
5485 'atf-bl31-path': 'bl31.elf',
5486 'tee-os-path': 'missing.elf',
5487 }
5488 test_subdir = os.path.join(self._indir, TEST_FDT_SUBDIR)
5489 with test_util.capture_sys_output() as (stdout, stderr):
5490 self._DoTestFile(
5491 '226_fit_split_elf.dts', entry_args=entry_args,
Simon Glass7d3e4072022-08-07 09:46:46 -06005492 extra_indirs=[test_subdir], verbosity=3, **kwargs)
5493 out = stdout.getvalue()
5494 err = stderr.getvalue()
5495 return out, err
Simon Glass5f423422022-03-05 20:19:12 -07005496
5497 def testFitSplitElfMissing(self):
5498 """Test an split-elf FIT with a missing ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005499 if not elf.ELF_TOOLS:
5500 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005501 out, err = self.checkFitSplitElf(allow_missing=True)
Simon Glass5f423422022-03-05 20:19:12 -07005502 self.assertRegex(
5503 err,
5504 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005505 self.assertNotRegex(out, '.*Faked blob.*')
5506 fname = tools.get_output_filename('binman-fake/missing.elf')
5507 self.assertFalse(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005508
5509 def testFitSplitElfFaked(self):
5510 """Test an split-elf FIT with faked ELF file"""
Stefan Herbrechtsmeier732742e2022-08-19 16:25:18 +02005511 if not elf.ELF_TOOLS:
5512 self.skipTest('Python elftools not available')
Simon Glass7d3e4072022-08-07 09:46:46 -06005513 out, err = self.checkFitSplitElf(allow_missing=True, allow_fake_blobs=True)
Simon Glass5f423422022-03-05 20:19:12 -07005514 self.assertRegex(
5515 err,
5516 "Image '.*' is missing external blobs and is non-functional: .*")
Simon Glass7d3e4072022-08-07 09:46:46 -06005517 self.assertRegex(
5518 out,
5519 "Entry '/binman/fit/images/@tee-SEQ/tee-os': Faked blob '.*binman-fake/missing.elf")
5520 fname = tools.get_output_filename('binman-fake/missing.elf')
5521 self.assertTrue(os.path.exists(fname))
Simon Glass5f423422022-03-05 20:19:12 -07005522
Philippe Reynesebe96cb2022-03-28 22:57:04 +02005523 def testPreLoad(self):
5524 """Test an image with a pre-load header"""
5525 entry_args = {
5526 'pre-load-key-path': '.',
5527 }
5528 data, _, _, _ = self._DoReadFileDtb('225_pre_load.dts',
5529 entry_args=entry_args)
5530 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5531 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5532 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5533 data = self._DoReadFile('225_pre_load.dts')
5534 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5535 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5536 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5537
5538 def testPreLoadPkcs(self):
5539 """Test an image with a pre-load header with padding pkcs"""
5540 data = self._DoReadFile('226_pre_load_pkcs.dts')
5541 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5542 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5543 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5544
5545 def testPreLoadPss(self):
5546 """Test an image with a pre-load header with padding pss"""
5547 data = self._DoReadFile('227_pre_load_pss.dts')
5548 self.assertEqual(PRE_LOAD_MAGIC, data[:len(PRE_LOAD_MAGIC)])
5549 self.assertEqual(PRE_LOAD_VERSION, data[4:4 + len(PRE_LOAD_VERSION)])
5550 self.assertEqual(PRE_LOAD_HDR_SIZE, data[8:8 + len(PRE_LOAD_HDR_SIZE)])
5551
5552 def testPreLoadInvalidPadding(self):
5553 """Test an image with a pre-load header with an invalid padding"""
5554 with self.assertRaises(ValueError) as e:
5555 data = self._DoReadFile('228_pre_load_invalid_padding.dts')
5556
5557 def testPreLoadInvalidSha(self):
5558 """Test an image with a pre-load header with an invalid hash"""
5559 with self.assertRaises(ValueError) as e:
5560 data = self._DoReadFile('229_pre_load_invalid_sha.dts')
5561
5562 def testPreLoadInvalidAlgo(self):
5563 """Test an image with a pre-load header with an invalid algo"""
5564 with self.assertRaises(ValueError) as e:
5565 data = self._DoReadFile('230_pre_load_invalid_algo.dts')
5566
5567 def testPreLoadInvalidKey(self):
5568 """Test an image with a pre-load header with an invalid key"""
5569 with self.assertRaises(ValueError) as e:
5570 data = self._DoReadFile('231_pre_load_invalid_key.dts')
Roger Quadros5cdcea02022-02-19 20:50:04 +02005571
Alper Nebi Yasak5cff63f2022-03-27 18:31:44 +03005572 def _CheckSafeUniqueNames(self, *images):
5573 """Check all entries of given images for unsafe unique names"""
5574 for image in images:
5575 entries = {}
5576 image._CollectEntries(entries, {}, image)
5577 for entry in entries.values():
5578 uniq = entry.GetUniqueName()
5579
5580 # Used as part of a filename, so must not be absolute paths.
5581 self.assertFalse(os.path.isabs(uniq))
5582
5583 def testSafeUniqueNames(self):
5584 """Test entry unique names are safe in single image configuration"""
5585 data = self._DoReadFileRealDtb('230_unique_names.dts')
5586
5587 orig_image = control.images['image']
5588 image_fname = tools.get_output_filename('image.bin')
5589 image = Image.FromFile(image_fname)
5590
5591 self._CheckSafeUniqueNames(orig_image, image)
5592
5593 def testSafeUniqueNamesMulti(self):
5594 """Test entry unique names are safe with multiple images"""
5595 data = self._DoReadFileRealDtb('231_unique_names_multi.dts')
5596
5597 orig_image = control.images['image']
5598 image_fname = tools.get_output_filename('image.bin')
5599 image = Image.FromFile(image_fname)
5600
5601 self._CheckSafeUniqueNames(orig_image, image)
5602
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005603 def testReplaceCmdWithBintool(self):
5604 """Test replacing an entry that needs a bintool to pack"""
5605 data = self._DoReadFileRealDtb('232_replace_with_bintool.dts')
5606 expected = U_BOOT_DATA + b'aa'
5607 self.assertEqual(expected, data[:len(expected)])
5608
5609 try:
5610 tmpdir, updated_fname = self._SetupImageInTmpdir()
5611 fname = os.path.join(tmpdir, 'update-testing.bin')
5612 tools.write_file(fname, b'zz')
5613 self._DoBinman('replace', '-i', updated_fname,
5614 '_testing', '-f', fname)
5615
5616 data = tools.read_file(updated_fname)
5617 expected = U_BOOT_DATA + b'zz'
5618 self.assertEqual(expected, data[:len(expected)])
5619 finally:
5620 shutil.rmtree(tmpdir)
5621
5622 def testReplaceCmdOtherWithBintool(self):
5623 """Test replacing an entry when another needs a bintool to pack"""
5624 data = self._DoReadFileRealDtb('232_replace_with_bintool.dts')
5625 expected = U_BOOT_DATA + b'aa'
5626 self.assertEqual(expected, data[:len(expected)])
5627
5628 try:
5629 tmpdir, updated_fname = self._SetupImageInTmpdir()
5630 fname = os.path.join(tmpdir, 'update-u-boot.bin')
5631 tools.write_file(fname, b'x' * len(U_BOOT_DATA))
5632 self._DoBinman('replace', '-i', updated_fname,
5633 'u-boot', '-f', fname)
5634
5635 data = tools.read_file(updated_fname)
5636 expected = b'x' * len(U_BOOT_DATA) + b'aa'
5637 self.assertEqual(expected, data[:len(expected)])
5638 finally:
5639 shutil.rmtree(tmpdir)
5640
Alper Nebi Yasak00c68f12022-03-27 18:31:46 +03005641 def testReplaceResizeNoRepackSameSize(self):
5642 """Test replacing entries with same-size data without repacking"""
5643 expected = b'x' * len(U_BOOT_DATA)
5644 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', expected)
5645 self.assertEqual(expected, data)
5646
5647 path, fdtmap = state.GetFdtContents('fdtmap')
5648 self.assertIsNotNone(path)
5649 self.assertEqual(expected_fdtmap, fdtmap)
5650
5651 def testReplaceResizeNoRepackSmallerSize(self):
5652 """Test replacing entries with smaller-size data without repacking"""
5653 new_data = b'x'
5654 data, expected_fdtmap, _ = self._RunReplaceCmd('u-boot', new_data)
5655 expected = new_data.ljust(len(U_BOOT_DATA), b'\0')
5656 self.assertEqual(expected, data)
5657
5658 path, fdtmap = state.GetFdtContents('fdtmap')
5659 self.assertIsNotNone(path)
5660 self.assertEqual(expected_fdtmap, fdtmap)
5661
Alper Nebi Yasak6cadc502022-03-27 18:31:48 +03005662 def testExtractFit(self):
5663 """Test extracting a FIT section"""
5664 self._DoReadFileRealDtb('233_fit_extract_replace.dts')
5665 image_fname = tools.get_output_filename('image.bin')
5666
5667 fit_data = control.ReadEntry(image_fname, 'fit')
5668 fit = fdt.Fdt.FromData(fit_data)
5669 fit.Scan()
5670
5671 # Check subentry data inside the extracted fit
5672 for node_path, expected in [
5673 ('/images/kernel', U_BOOT_DATA),
5674 ('/images/fdt-1', U_BOOT_NODTB_DATA),
5675 ('/images/scr-1', COMPRESS_DATA),
5676 ]:
5677 node = fit.GetNode(node_path)
5678 data = fit.GetProps(node)['data'].bytes
5679 self.assertEqual(expected, data)
5680
5681 def testExtractFitSubentries(self):
5682 """Test extracting FIT section subentries"""
5683 self._DoReadFileRealDtb('233_fit_extract_replace.dts')
5684 image_fname = tools.get_output_filename('image.bin')
5685
5686 for entry_path, expected in [
5687 ('fit/kernel', U_BOOT_DATA),
5688 ('fit/kernel/u-boot', U_BOOT_DATA),
5689 ('fit/fdt-1', U_BOOT_NODTB_DATA),
5690 ('fit/fdt-1/u-boot-nodtb', U_BOOT_NODTB_DATA),
5691 ('fit/scr-1', COMPRESS_DATA),
5692 ('fit/scr-1/blob', COMPRESS_DATA),
5693 ]:
5694 data = control.ReadEntry(image_fname, entry_path)
5695 self.assertEqual(expected, data)
5696
Alper Nebi Yasak49892642022-03-27 18:31:49 +03005697 def testReplaceFitSubentryLeafSameSize(self):
5698 """Test replacing a FIT leaf subentry with same-size data"""
5699 new_data = b'x' * len(U_BOOT_DATA)
5700 data, expected_fdtmap, _ = self._RunReplaceCmd(
5701 'fit/kernel/u-boot', new_data,
5702 dts='233_fit_extract_replace.dts')
5703 self.assertEqual(new_data, data)
5704
5705 path, fdtmap = state.GetFdtContents('fdtmap')
5706 self.assertIsNotNone(path)
5707 self.assertEqual(expected_fdtmap, fdtmap)
5708
5709 def testReplaceFitSubentryLeafBiggerSize(self):
5710 """Test replacing a FIT leaf subentry with bigger-size data"""
5711 new_data = b'ub' * len(U_BOOT_NODTB_DATA)
5712 data, expected_fdtmap, _ = self._RunReplaceCmd(
5713 'fit/fdt-1/u-boot-nodtb', new_data,
5714 dts='233_fit_extract_replace.dts')
5715 self.assertEqual(new_data, data)
5716
5717 # Will be repacked, so fdtmap must change
5718 path, fdtmap = state.GetFdtContents('fdtmap')
5719 self.assertIsNotNone(path)
5720 self.assertNotEqual(expected_fdtmap, fdtmap)
5721
5722 def testReplaceFitSubentryLeafSmallerSize(self):
5723 """Test replacing a FIT leaf subentry with smaller-size data"""
5724 new_data = b'x'
5725 expected = new_data.ljust(len(U_BOOT_NODTB_DATA), b'\0')
5726 data, expected_fdtmap, _ = self._RunReplaceCmd(
5727 'fit/fdt-1/u-boot-nodtb', new_data,
5728 dts='233_fit_extract_replace.dts')
5729 self.assertEqual(expected, data)
5730
5731 path, fdtmap = state.GetFdtContents('fdtmap')
5732 self.assertIsNotNone(path)
5733 self.assertEqual(expected_fdtmap, fdtmap)
5734
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005735 def testReplaceSectionSimple(self):
5736 """Test replacing a simple section with arbitrary data"""
5737 new_data = b'w' * len(COMPRESS_DATA + U_BOOT_DATA)
Simon Glassc6b283f2022-08-13 11:40:46 -06005738 with self.assertRaises(ValueError) as exc:
5739 self._RunReplaceCmd('section', new_data,
5740 dts='234_replace_section_simple.dts')
5741 self.assertIn(
5742 "Node '/section': Replacing sections is not implemented yet",
5743 str(exc.exception))
Alper Nebi Yasak1d44c8e2022-03-27 18:31:50 +03005744
Simon Glass8fbca772022-08-13 11:40:48 -06005745 def testMkimageImagename(self):
5746 """Test using mkimage with -n holding the data too"""
5747 data = self._DoReadFile('235_mkimage_name.dts')
5748
5749 # Check that the data appears in the file somewhere
5750 self.assertIn(U_BOOT_SPL_DATA, data)
5751
5752 # Get struct image_header -> ih_name
5753 name = data[0x20:0x40]
5754
5755 # Build the filename that we expect to be placed in there, by virtue of
5756 # the -n paraameter
5757 expect = os.path.join(tools.get_output_dir(), 'mkimage.mkimage')
5758
5759 # Check that the image name is set to the temporary filename used
5760 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5761
Simon Glassb1669752022-08-13 11:40:49 -06005762 def testMkimageImage(self):
5763 """Test using mkimage with -n holding the data too"""
5764 data = self._DoReadFile('236_mkimage_image.dts')
5765
5766 # Check that the data appears in the file somewhere
5767 self.assertIn(U_BOOT_SPL_DATA, data)
5768
5769 # Get struct image_header -> ih_name
5770 name = data[0x20:0x40]
5771
5772 # Build the filename that we expect to be placed in there, by virtue of
5773 # the -n paraameter
5774 expect = os.path.join(tools.get_output_dir(), 'mkimage-n.mkimage')
5775
5776 # Check that the image name is set to the temporary filename used
5777 self.assertEqual(expect.encode('utf-8')[:0x20], name)
5778
5779 # Check the corect data is in the imagename file
5780 self.assertEqual(U_BOOT_DATA, tools.read_file(expect))
5781
5782 def testMkimageImageNoContent(self):
5783 """Test using mkimage with -n and no data"""
5784 with self.assertRaises(ValueError) as exc:
5785 self._DoReadFile('237_mkimage_image_no_content.dts')
5786 self.assertIn('Could not complete processing of contents',
5787 str(exc.exception))
5788
5789 def testMkimageImageBad(self):
5790 """Test using mkimage with imagename node and data-to-imagename"""
5791 with self.assertRaises(ValueError) as exc:
5792 self._DoReadFile('238_mkimage_image_bad.dts')
5793 self.assertIn('Cannot use both imagename node and data-to-imagename',
5794 str(exc.exception))
5795
Simon Glassbd5cd882022-08-13 11:40:50 -06005796 def testCollectionOther(self):
5797 """Test a collection where the data comes from another section"""
5798 data = self._DoReadFile('239_collection_other.dts')
5799 self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA +
5800 tools.get_bytes(0xff, 2) + U_BOOT_NODTB_DATA +
5801 tools.get_bytes(0xfe, 3) + U_BOOT_DTB_DATA,
5802 data)
5803
5804 def testMkimageCollection(self):
5805 """Test using a collection referring to an entry in a mkimage entry"""
5806 data = self._DoReadFile('240_mkimage_coll.dts')
5807 expect = U_BOOT_SPL_DATA + U_BOOT_DATA
5808 self.assertEqual(expect, data[:len(expect)])
5809
Stefan Herbrechtsmeier11121d32022-08-19 16:25:25 +02005810 def testCompressDtbPrependInvalid(self):
5811 """Test that invalid header is detected"""
5812 with self.assertRaises(ValueError) as e:
5813 self._DoReadFileDtb('235_compress_dtb_prepend_invalid.dts')
5814 self.assertIn("Node '/binman/u-boot-dtb': Invalid prepend in "
5815 "'u-boot-dtb': 'invalid'", str(e.exception))
5816
5817 def testCompressDtbPrependLength(self):
5818 """Test that compress with length header works as expected"""
5819 data = self._DoReadFileRealDtb('236_compress_dtb_prepend_length.dts')
5820 image = control.images['image']
5821 entries = image.GetEntries()
5822 self.assertIn('u-boot-dtb', entries)
5823 u_boot_dtb = entries['u-boot-dtb']
5824 self.assertIn('fdtmap', entries)
5825 fdtmap = entries['fdtmap']
5826
5827 image_fname = tools.get_output_filename('image.bin')
5828 orig = control.ReadEntry(image_fname, 'u-boot-dtb')
5829 dtb = fdt.Fdt.FromData(orig)
5830 dtb.Scan()
5831 props = self._GetPropTree(dtb, ['size', 'uncomp-size'])
5832 expected = {
5833 'u-boot:size': len(U_BOOT_DATA),
5834 'u-boot-dtb:uncomp-size': len(orig),
5835 'u-boot-dtb:size': u_boot_dtb.size,
5836 'fdtmap:size': fdtmap.size,
5837 'size': len(data),
5838 }
5839 self.assertEqual(expected, props)
5840
5841 # Check implementation
5842 self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
5843 rest = data[len(U_BOOT_DATA):]
5844 comp_data_len = struct.unpack('<I', rest[:4])[0]
5845 comp_data = rest[4:4 + comp_data_len]
5846 orig2 = self._decompress(comp_data)
5847 self.assertEqual(orig, orig2)
5848
Alper Nebi Yasake63ca5a2022-03-27 18:31:45 +03005849
Simon Glassac599912017-11-12 21:52:22 -07005850if __name__ == "__main__":
5851 unittest.main()